STM32 General-purpose timer cookbook - Example of chapter 6.2 not working as intended
- June 8, 2019
- 3 replies
- 4904 views
Hi everybody,
I'm trying to test the examples of the General-purpose timer cookbook (AN4776) with a STM32 Nucleo-F446RE board and a breadboard with LEDs and resistors.
This is my first time to use timers for PWM.
I copied and adapted the code of chapter 3.2 and it is working as described:
The timer TIM1 is counting up until reaching the value of CCR1 and changes the GPIO output level from LOW to HIGH until it reaches the value of ARR. The counter starts again.
The most interesting code lines are:
- TIM1->CCMR1 |= TIM_OCMODE_PWM2; // see reference manual on page 505: In upcounting, channel 1 is inactive as long as TIMx_CNT<TIMx_CCR1 else active. In downcounting, channel 1 is active as long as TIMx_CNT>TIMx_CCR1 else inactive.
- TIM1->CCER |= TIM_OCPOLARITY_HIGH; // see reference manual on page 510 CC1E
Then I tried the code of chapter 6.2. The intended behavior is that TIM2 triggers TIM1 and the output is HIGH until CCR1 is reached. Then the output change back to LOW until ARR is reached. This is repeated (value of repition counter) and after the last repeat the output remain LOW.
But when I tried the code with my board it does not work as intended. When testing it with my board TIM1 is counting up until CCR1 and change the polarity from LOW to HIGH (so the opposite of what is intended) until ARR is reached. Then the polarity changes back from HIGH to LOW and when reaching CCR1 the polarity change from LOW to HIGH and so on. If the last pulse is send (repitition counter) the output polarity is LOW until TIM2 triggers TIM1 again and start the counting.
So the output is the same as in chapter 3.2 although the example of chapter 6.2 uses PWM mode 1 (In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1 else inactive. In downcounting, channel 1 is inactive (OC1REF=‘0’) as long as TIMx_CNT>TIMx_CCR1 else active (OC1REF=’1’).
This is my code:
void timer1_Init(){
/* TIM1 is on APB2 with clock speed 180MHz */
/* activate clock for TIM1 peripheral */
__HAL_RCC_TIM1_CLK_ENABLE();
/* neue Struktur */
/* Prescaler */
TIM1->PSC = 35999;
/* Auto-Reload-Register */
TIM1->ARR = 19999;
/* repetition counter if pulse should be displayed more than 1 time */
TIM1->RCR = 0;
/* Set the Capture Compare Register: Pulse */
TIM1->CCR1 = 4999;
/* Set Clock */
TIM1->CR1 &= ~ TIM_CR1_CKD;
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* set counter mode */
TIM1->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM1->CR1 |= TIM_COUNTERMODE_UP;
/* Reset the Output Compare Mode Bits */
TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
/* Select the Output Compare (OC) Mode */
/*
* Mode 1: In upcounting, channel 1 is active as long as TIMx_CNT<TIMx_CCR1
* else inactive. In downcounting, channel 1 is inactive (OC1REF=‘0’) as long as
* TIMx_CNT>TIMx_CCR1 else active (OC1REF=’1’).
*
* Mode 2: In upcounting, channel 1 is inactive as long as TIMx_CNT<TIMx_CCR1
* else active. In downcounting, channel 1 is active as long as TIMx_CNT>TIMx_CCR1 else
* inactive.
*/
TIM1->CCMR1 |= TIM_OCMODE_PWM1; //(TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1);
/********** One Pulse Mode Configuration **********/
/* One Pulse Mode */
TIM1->CR1 |= TIM_CR1_OPM;
/********** Slave Mode configuration: Trigger Mode **********/
TIM1->SMCR &= ~TIM_SMCR_TS;
TIM1->SMCR |= TIM_TS_ITR1;
TIM1->SMCR &= ~TIM_SMCR_SMS;
TIM1->SMCR |= (TIM_SMCR_SMS_2 | TIM_SMCR_SMS_1); // = TIM_SLAVEMODE_TRIGGER
/*************************************************/
/* Set the Output Compare Preload enable bit for channel 1 */
TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
/* update event to reload registers - set the UG Bit to enable UEV */
TIM1->EGR = TIM_EGR_UG;
/* Enable the TIM1 Main Output */
TIM1->BDTR |= TIM_BDTR_MOE;
/* Reset and set the Output N Polarity level to LOW */
TIM1->CCER &= ~TIM_CCER_CC1P;
/* Set the Output Compare Polarity */
TIM1->CCER |= TIM_OCPOLARITY_LOW; //TIM_CCER_CC1P;
/* Enable the Capture compare channel 1 on High Level*/
TIM1->CCER |= TIM_CCER_CC1E;
/* Initialization of GPIO_PIN_8 for PWM output */
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void timer2_Init(){
/* TIM2 is on APB1 with clock speed 90MHz */
/* activate clock for TIM2 peripheral */
__HAL_RCC_TIM2_CLK_ENABLE();
/* Prescaler */
TIM2->PSC = 44999; //44999; /* Oszillator might have problems. Prescaler of 44999 should get at period of 0,0005 but doesn't */
/* set counter mode */
TIM2->CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS);
TIM2->CR1 |= TIM_COUNTERMODE_UP;
/* Auto-Reload Register */
TIM2->ARR = 19999; //19999;
/* Set Clock Division */
TIM2->CR1 &= ~ TIM_CR1_CKD;
TIM2->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* Update Event - if this timer is configured as Master with output TRGO_UPDATE
* the slave timer TIM 1 will get a trigger and run one time
*
* This bit can be set by software, it is automatically cleared by hardware.
* 0: No action
* 1: Reinitialize the counter and generates an update of the registers. Note that the prescaler
* counter is cleared too (anyway the prescaler ratio is not affected). For more see manual. */
TIM2->EGR = TIM_EGR_UG;
/* Set Clock Source */
TIM2->SMCR &= ~(TIM_SMCR_SMS | TIM_SMCR_TS | TIM_SMCR_ETF | TIM_SMCR_ETPS | TIM_SMCR_ECE | TIM_SMCR_ETP);
/* Master Configuration */
TIM2->CR2 &= ~TIM_CR2_MMS;
TIM2->CR2 |= TIM_TRGO_UPDATE;
/* Enable Counter: */
TIM2->CR1 = TIM_CR1_CEN;
}I connected a resistor (330) and an LED in series to GPIOA_8.
I also configured a third timer with an interrupt handler to toggle a second LED to see when TIM2 (master) start counting.
Can anybody help me please?
Please find attached the code and a screenshot of the current behavior of chapter 6.2