Skip to main content
daniel2
Associate III
July 13, 2015
Question

STM32F3 Timer Output Compare Mode

  • July 13, 2015
  • 4 replies
  • 1054 views
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);
}
}

    This topic has been closed for replies.

    4 replies

    Tesla DeLorean
    Guru
    July 13, 2015
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    daniel2
    daniel2Author
    Associate III
    July 13, 2015
    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. 

    Tesla DeLorean
    Guru
    July 13, 2015
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    daniel2
    daniel2Author
    Associate III
    July 13, 2015
    Posted on July 13, 2015 at 06:23

    That did the trick, thanks again!