Skip to main content
Associate II
April 17, 2024
Solved

PWM problems

  • April 17, 2024
  • 5 replies
  • 2216 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 );

5 replies

waclawek.jan
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
Associate 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
Associate 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 );
waclawek.jan
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

 

PetrarkaAuthorBest answer
Associate 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 );