2025-05-10 6:39 AM
Select PA1 as TIM2 CH2, those code are copy from ST official example(TIM21), and changed to TIM2.
no output from PA1, code as below:
void ConfigureTIM2AsPWM_EdgeAligned(void)
{
/* (1) Enable the peripheral clock of Timer x */
/* (2) Enable the peripheral clock of GPIOA */
/* (3) Select alternate function mode on GPIOA pin 1 */
/* (4) Select AF2 on PA1 in AFRH for TIM2_CH2 */
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; /* (1) */
RCC->IOPENR |= RCC_IOPENR_GPIOAEN; /* (2) */
GPIOA->MODER |= 0X00000008; /* (3) */
GPIOA->AFR[0] |= 0X00000020; /* (4) */
/* (1) Set prescaler to 15, so APBCLK/16 i.e 1MHz */
/* (2) Set ARR = 8, as timer clock is 1MHz the period is 9 us */
/* (3) Set CCRx = 4, , the signal will be high during 4 us */
/* (4) Select PWM mode 1 on OC2 (OC2M = 110),
enable preload register on OC2 (OC2PE = 1) */
/* (5) Select active high polarity on OC2 (CC2P = 0, reset value),
enable the output on OC2 (CC2E = 1)*/
/* (6) Enable output (MOE = 1)*/
/* (7) Enable counter (CEN = 1)
select edge aligned mode (CMS = 00, reset value)
select direction as upcounter (DIR = 0, reset value) */
/* (8) Force update generation (UG = 1) */
TIM2->PSC = 15; /* (1) */
TIM2->ARR = 8; /* (2) */
TIM2->CCR1 = 4; /* (3) */
TIM2->CCMR1 |= TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE; /* (4) */
TIM2->CCER |= TIM_CCER_CC2E; /* (5) */
TIM2->CR1 |= TIM_CR1_CEN; /* (7) */
TIM2->EGR |= TIM_EGR_UG; /* (8) */
}
Solved! Go to Solution.
2025-05-12 12:26 PM
> TIM2->CCR1 = 4; /* (3) */
does not set TIM2_CH2 but TIM2_CH1. You would spot it yourself, would you print out and check the TIM2 registers content.
JW
2025-05-11 1:05 PM
The |= is wrong for MODER (and in general for AFR too). You need to set some bit(s) and clear other(s).
A general pattern is
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODE1_Msk) | (2 << GPIO_MODER_MODE1_Pos); // alternate mode
or some macros wrapping that.
hth
KnarfB
2025-05-11 5:44 PM
thanks, KnarfB, I realize default value for MODE is 0XFFFF FFFF, so I should clear some bits.
but seems still have other problems, still no PWM.
2025-05-12 1:10 AM
Read out and check/post content of GPIO and TIM registers.
Check given pin's connection by setting it as GPIO Output and toggling it "manually".
JW
2025-05-12 5:26 AM
I use USART2 to print the register value, the value is HEX format.
GPIOA->MODER:EBEBFCF9
GPIOA->AFR[0]:20
PA1 configuration is correct.
2025-05-12 8:40 AM
Okay, and what about the TIM2 registers?
And did you test the pin's connection as I recommended, by setting it to output and toggling in software?
JW
2025-05-12 8:59 AM
Hello,
I have made an example code which is below. The code sets TIM2 to generate PWM on PA1. It comes from LL library so it can be reduced for your specific case, but it works right, I have tested it on my NUCLEO board.
SET_BIT(RCC->APBENR1, RCC_APBENR1_TIM2EN); /* TIM2 clock enable */
SET_BIT(RCC->IOPENR, RCC_IOPENR_GPIOAEN); /* GPIOA clock enable */
MODIFY_REG(GPIOA->MODER, ((GPIO_PIN_1 * GPIO_PIN_1) * GPIO_MODER_MODE0), ((GPIO_PIN_1 * GPIO_PIN_1) * GPIO_MODER_MODE0_1)); /* Set PA5 pin mode to alternate function */
MODIFY_REG(GPIOA->AFR[0], ((((GPIO_PIN_1 * GPIO_PIN_1) * GPIO_PIN_1) * GPIO_PIN_1) * GPIO_AFRL_AFSEL0),
((((GPIO_PIN_1 * GPIO_PIN_1) * GPIO_PIN_1) * GPIO_PIN_1) * 0x2U)); /* Set PA5 pin alternate function to AF2 */
TIM2->PSC = 15; /* */
TIM2->ARR = 199999; /* */
TIM2->CCR2 = 99999; /* */
MODIFY_REG(TIM2->CCMR1, (TIM_CCMR1_OC2M_Msk | TIM_CCMR1_OC2PE_Msk), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE)); /* Enable PWM1 mode, enable pre-load */
TIM2->CCER |= TIM_CCER_CC2E; /* */
TIM2->CR1 |= TIM_CR1_CEN; /* */
TIM2->EGR |= TIM_EGR_UG; /* */
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2025-05-12 12:19 PM - edited 2025-05-12 12:24 PM
Hi @Hl_st ,
Can you please explain
(GPIO_PIN_1 * GPIO_PIN_1)
in setting GPIOA->MODER?
Thanks,
JW
[EDIT] OK never mind, I see it now - if GPIO_PIN_N == 1 << N, this expression results in 1 << (2*N). Quite unusual nonetheless.
2025-05-12 12:26 PM
> TIM2->CCR1 = 4; /* (3) */
does not set TIM2_CH2 but TIM2_CH1. You would spot it yourself, would you print out and check the TIM2 registers content.
JW
2025-05-12 5:54 PM
Many thanks, it works now.