Skip to main content
Visitor II
April 17, 2024
Solved

PWM problems

  • April 17, 2024
  • 2 replies
  • 2171 views

Hello! Recently I got into STM programming for my internship and I cannot figure out register level programming yet, I have this piece of code 

```

RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_APB1ENR_TIM2EN;
GPIOA->MODER |=GPIO_MODER_MODE5_1 | GPIO_MODER_MODE5_0;

TIM2->CCER|=TIM_CCER_CC1E;
TIM2->CR1 |=TIM_CR1_ARPE;
TIM2->CCMR1 |=TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_0|TIM_CCMR1_OC1PE;

TIM2->PSC=42; //trivial
TIM2->ARR=1000; //trivial values
TIM2->CCR1=250; //trivial

TIM2->EGR |=TIM_EGR_UG;
TIM2->CR1 |=TIM_CR1_CEN;
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{


/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
```
Which in theory, to me, looks like it should work, however there are things I still do not fully understand, for example: Here I wanted to use Tim2 on channel 1 because I can use that on my PA5 pin which is LED2 on my Nucleo f401RE board, and I wanted to produce a PWM signal on it, however, it just doesn't display, if someone could provide some feedback or guidance it would be greatly appreciated.

    This topic has been closed for replies.
    Best answer by Petrarka

    This is the final code that worked, thank you for your help Jan

     RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
     GPIOA->MODER |= ( 0x2UL << GPIO_MODER_MODE5_Pos); //alternate mode
     GPIOA->AFR[0]|= 0x000100000;//alternate function for port A 5
     TIM2->PSC = 840 - 1; // Set prescaler
     TIM2->ARR = 1000; // Set auto-reload
     TIM2->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC1M_Pos );
     TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
     TIM2->CR1 |= TIM_CR1_ARPE|TIM_CR1_CEN|TIM_CR1_URS;
     TIM2->CCER &= ~TIM_CCER_CC1P;
     TIM2->CCER |= TIM_CCER_CC1E;
     TIM2->EGR |= TIM_EGR_UG;
     TIM2->DIER |= ( TIM_DIER_CC1IE | TIM_DIER_UIE );
     TIM2->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF );

    2 replies

    Super User
    April 17, 2024

    > GPIOA->MODER |=GPIO_MODER_MODE5_1 | GPIO_MODER_MODE5_0;

    What does this do?

    You may need to set TIMx_AFR[] too, see AF assignment table in the Datasheet.

    > TIM2->CCMR1 |=TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_0|TIM_CCMR1_OC1PE;

    What does this do? 

    JW

    PetrarkaAuthor
    Visitor II
    April 17, 2024

    Doesn't 

    > GPIOA->MODER |=GPIO_MODER_MODE5_1 | GPIO_MODER_MODE5_0;
    Set my pins mode to Alternate function? I am playing with Pin A 5 so... I figured id need to configure Mode5 to 10
    TIM2->CCMR1 |=TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_0|TIM_CCMR1_OC1PE;
    Sets my Timer's mode to PWM1, according to the data sheet pwm 1 is "110" in the OC bits, and OC1PE is for preloading the register but im not really sure what that is.

    PetrarkaAuthor
    Visitor II
    April 18, 2024

    Updated the code to this, still doesnt work 

    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
     GPIOA->MODER |= ( 0x2UL << GPIO_MODER_MODE5_Pos); //alternate mode
     GPIOA->AFR[0]|= 0x000000010;//alternate function for port A 5
     TIM2->PSC = 840 - 1; // Set prescaler
     TIM2->ARR = 1000; // Set auto-reload
     TIM2->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC1M_Pos );
     TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
     TIM2->CR1 |= TIM_CR1_ARPE;
     TIM2->CCER &= ~TIM_CCER_CC1P;
     TIM2->CCER |= TIM_CCER_CC1E;
     TIM2->CR1 |= TIM_CR1_URS;
     TIM2->EGR |= TIM_EGR_UG;
     TIM2->DIER |= ( TIM_DIER_CC1IE | TIM_DIER_UIE );
     TIM2->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF );
    Super User
    April 18, 2024

    > Doesn't 

    >> GPIOA->MODER |=GPIO_MODER_MODE5_1 | GPIO_MODER_MODE5_0;
    > Set my pins mode to Alternate function? I am playing with Pin A 5 so... I figured id need to configure Mode5 to 10

    Yes, but that code sets MODE5 to 0b11.

    > TIM2->CCMR1 |=TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_1|TIM_CCMR1_OC1M_0|TIM_CCMR1_OC1PE;
    > Sets my Timer's mode to PWM1, according to the data sheet pwm 1 is "110" in the OC bits,

    That sets mode to 0b011 (and sets the 1st bit twice).

    Reading code - including one's own - is an equally important skill as writing it.

    >and OC1PE is for
    > preloading the register but im not really sure what that is.

    If you set TIMx_CCR1 preloading, the value you write into TIMx_CCR1 does not get active immediately, but only after the next Update event.

     

    > Updated the code to this, still doesnt work

    > GPIOA->AFR[0]|= 0x000000010;//alternate function for port A 5

    That's not value for PA5 but for PA1. There are 4 bits per pin in that register.

     

    > TIM2->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF );

    This is not the source of problem here, but generally, don't use RMW to clear TIMx_SR bits.

    JW

     

    PetrarkaAuthorAnswer
    Visitor II
    April 18, 2024

    This is the final code that worked, thank you for your help Jan

     RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
     RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
     GPIOA->MODER |= ( 0x2UL << GPIO_MODER_MODE5_Pos); //alternate mode
     GPIOA->AFR[0]|= 0x000100000;//alternate function for port A 5
     TIM2->PSC = 840 - 1; // Set prescaler
     TIM2->ARR = 1000; // Set auto-reload
     TIM2->CCMR1 |= ( 0x6UL << TIM_CCMR1_OC1M_Pos );
     TIM2->CCMR1 |= TIM_CCMR1_OC1PE;
     TIM2->CR1 |= TIM_CR1_ARPE|TIM_CR1_CEN|TIM_CR1_URS;
     TIM2->CCER &= ~TIM_CCER_CC1P;
     TIM2->CCER |= TIM_CCER_CC1E;
     TIM2->EGR |= TIM_EGR_UG;
     TIM2->DIER |= ( TIM_DIER_CC1IE | TIM_DIER_UIE );
     TIM2->SR &= ~( TIM_SR_CC1IF | TIM_SR_UIF );