cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F3 Timer Output Compare Mode

daniel2
Associate II
Posted on July 13, 2015 at 04:19

I'm trying to configure TIM2 CH1-4 as per the sample code, and CH2-4 are working at the correct frequency and can be adjusted via the CCR_VAL variables. However CH1 is always toggling at the TIM2_Update frequency and is unaffected by the CCR1_VAL. Is it possible to have CH1 and the TIM2 update trigger at different frequencies?

/**
* @brief Configure the TIM IRQ Handler.
* @param None
* @retval None
*/
void TIMER_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t PrescalerValue = 0;
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* -----------------------------------------------------------------------
TIM2 Configuration: Output Compare Timing Mode:
In this example TIM2 input clock (TIM2CLK) is set to 2 * APB1 clock (PCLK1),
since APB1 prescaler is different from 1.
TIM2CLK = 2 * PCLK1
PCLK1 = HCLK / 2
=> TIM2CLK = HCLK = SystemCoreClock
To get TIM2 counter clock at 72 MHz, the prescaler is computed as follows:
Prescaler = (TIM2CLK / TIM2 counter clock) - 1
Prescaler = ((SystemCoreClock) /72 MHz) - 1
CC1 update rate = TIM2 counter clock / CCR1_Val = 1777 Hz
==> Toggling frequency = 888 Hz
C2 update rate = TIM2 counter clock / CCR2_Val = 2649 Hz
==> Toggling frequency = 124 Hz
CC3 update rate = TIM2 counter clock / CCR3_Val = 518 Hz
==> Toggling frequency = 2659 Hz
CC4 update rate = TIM2 counter clock / CCR4_Val = 1059 Hz
==> Toggling frequency = 595 Hz
Note:
SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f3xx.c file.
Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate()
function to update SystemCoreClock variable value. Otherwise, any configuration
based on this variable will be incorrect.
----------------------------------------------------------------------- */
/* Compute the prescaler value */
PrescalerValue = (uint16_t) ((SystemCoreClock) / 64000000) - 1;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Prescaler configuration */
TIM_PrescalerConfig(TIM2, PrescalerValue, TIM_PSCReloadMode_Immediate);
/* Init TIM_OCInitStructure */
TIM_OCStructInit(&TIM_OCInitStructure);
/* Output Compare Timing Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR1_Val;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel2 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel3 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR3_Val;
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
/* Output Compare Timing Mode configuration: Channel4 */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CCR4_Val;
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);
/* TIM Interrupts enable */
TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}

/**
* @brief This function handles TIM2 global interrupt request.
* @param None
* @retval None
*/
void TIM2_IRQHandler(void)
{
/* End of pulse- Reset VDDP to 5.0V */
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
HAL_GPIO_TogglePin(WS2812_PORT, GPIO_Pin_0);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_SetCounter(TIM2, 0);
}
else if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
/* LED1 toggling with frequency = 888 Hz */
HAL_GPIO_TogglePin(WS2812_PORT, GPIO_Pin_1);
TIM_SetCompare1(TIM2, capture + CCR1_Val);
}
else if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
/* LED2 toggling with frequency = 124 Hz */
HAL_GPIO_TogglePin(WS2812_PORT, GPIO_Pin_2);
capture = TIM_GetCapture2(TIM2);
TIM_SetCompare2(TIM2, capture + CCR2_Val);
}
else if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
/* LED3 toggling with frequency = 2659 Hz */
HAL_GPIO_TogglePin(WS2812_PORT, GPIO_Pin_3);
capture = TIM_GetCapture3(TIM2);
TIM_SetCompare3(TIM2, capture + CCR3_Val);
}
else
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
/* LED4 toggling with frequency = 595 Hz */
HAL_GPIO_TogglePin(WS2812_PORT, GPIO_Pin_4);
capture = TIM_GetCapture4(TIM2);
TIM_SetCompare4(TIM2, capture + CCR4_Val);
}
}

4 REPLIES 4
Posted on July 13, 2015 at 04:30

What are the defines for the CCRx_Val ?

The if/then/else in the IRQ Handler is a bit presumptive. What if more than one assert?

You don't enable the Update Interrupt

You don't read the current value when advancing CCR1

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on July 13, 2015 at 04:58

It was the fact that I wasn't doing the read. (capture = TIM_GetCapture1(TIM2);) Thanks!

Do you know why it seems like the timer is unable to keep up if I reduce the main timers period. For example: TIM_TimeBaseStructure.TIM_Period = 32000;

If I do this and adjust my CCR values to 20000, 15000, 10000, 5000, the 4 channels will only very ocassionally toggle at the right frequency but most of the time toggle at the same rate as the main timer update. 

Posted on July 13, 2015 at 05:13

You'd have to modulo the CCRx as you advance.

For 16-bit math the implied modulo is 65536  (ie Period+1)

If you set Period = 29999, the TIMx->CCRx= (TIMx->CCRx + Advance) % 30000;

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
daniel2
Associate II
Posted on July 13, 2015 at 06:23

That did the trick, thanks again!