cancel
Showing results for 
Search instead for 
Did you mean: 

Timer Output Compare Frequency Problem

blue_dolphin1987
Associate II
Posted on December 24, 2013 at 09:18

Hi ,

I am trying to generate an output pulse of 100 Hz to 300khz using time output compare where i will toggle a bit in the interrupt service routinue . I referred to one of the example which states the following

/* ---------------------------------------------------------------------------
TIM9 Configuration: Output Compare Toggle Mode:
TIM9CLK = SystemCoreClock (72MHz),
The objective is to get TIM9 counter clock at 24 MHz:
- Prescaler = (TIM9CLK / TIM9 counter clock) - 1
CC1 update rate = TIM9 counter clock / CCR1Val = 74 Hz
CC2 update rate = TIM9 counter clock / CCR2Val = 148 Hz
----------------------------------------------------------------------------*/

I first attempted to generate a 250khz pulse . So i set my TIMCLK = 1 Mhz My CCRVal will be = 1Mhz / 4 = 250khz But i get 7.6Hz instead. My code are as follows. Thanks !

uint16_t CCR1_Val = 4;
uint16_t capture = 0;
#define TIM_CLK RCC_APB1Periph_TIM2
#define TIM TIM2
#define TIM_IRQ TIM2_IRQn
#define TIM_IRQ_HANDLER TIM2_IRQHandler
#define TIM_GPIO_PORT GPIOG
#define TIM_GPIO_PIN GPIO_Pin_11
void Init_TIM (){ 
TIM_RCC_Configuration();
TIM_NVIC_Configuration();
TIM_Configuration();
}
void TIM_Configuration(){
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t PrescalerValue = 0;
/* Compute the prescaler value */
PrescalerValue = (uint16_t) (SystemCoreClock / 1000000) - 1;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM, &TIM_TimeBaseStructure);
/* Prescaler configuration */
TIM_PrescalerConfig(TIM, PrescalerValue, TIM_PSCReloadMode_Immediate);
/* 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(TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM, TIM_OCPreload_Disable);
/* TIM IT enable */
TIM_ITConfig(TIM2, TIM_IT_CC1,ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
}
void TIM_Disable(){
/* TIM2 disable counter */
TIM_Cmd(TIM, DISABLE);
}
void TIM_RCC_Configuration(void)
{
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
void TIM_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM_IRQ_HANDLER(void)
{
if (TIM_GetITStatus(TIM, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM, TIM_IT_CC1);
GPIO_WriteBit(TIM_GPIO_PORT, TIM_GPIO_PIN, (BitAction)(1 - GPIO_ReadOutputDataBit(TIM_GPIO_PORT, TIM_GPIO_PIN)));
capture = TIM_GetCapture1(TIM);
TIM_SetCompare1(TIM, capture + CCR1_Val);
}
}

Thanks . #stm32 #wait-for-you--clive1-!-!-! #timer
5 REPLIES 5
chen
Associate II
Posted on December 24, 2013 at 10:54

Hi

I am not 100% familiar with the ST Peripheral library, I have been using the

timer registers directly.

''I am trying to generate an output pulse of 100 Hz to 300khz using time output compare where i will toggle a bit in the interrupt service routinue .''

You do not need to use the output compare to generate an IRQ and then use the ISR to toggle the output.

You can do this with the basic timer up/down count mode and generate the IRQ on the overflow/update event.

This is far simpler to set up and understand.

When you use the timer in output compare mode - you can get the OutputCompare to toggle the output for you (ie you do not need the IRQ). Look at the register description for TIMx_CCMR1 and the decription for OC1M: output compare 1 mode.

OC1M mode 011 - toggle

I do not know what your experience is but if you have not used timers before - start with the basic up/down counter and update event (UEV).

The compare functions get complicated very quickly!

Ps. I do not know why you are getting 7.6Hz instead of 250Khz, not sure if this is to do with the clock/compare scalars or whether the ISR output is not working properly

Posted on December 24, 2013 at 13:07

Well I suspect the processor is saturating, I would suggest starting at a slower frequency and then finding the inflection point.

1 MHz / 65536 = 15.259 Hz, Toggling halves that to 7.629 Hz, again suggesting it is slipping a whole run of the counter. ie CCR is set to a value less than CNT, and caught on the go around.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
blue_dolphin1987
Associate II
Posted on December 25, 2013 at 05:09

Hi Clive , 

Indeed when CCR is set to more than 10 the freq is correct . Is there a workaround or alternative solution ?

Hi  , 

Do you mind posting an example of your proposed solution ?

blue_dolphin1987
Associate II
Posted on December 25, 2013 at 05:10

Hi Clive , 

Indeed when CCR is set to more than 10 the freq is correct . Is there a workaround or alternative solution ?

Hi  , 

Do you mind posting an example of your proposed solution ?

Posted on December 25, 2013 at 08:19

The solutions would depend significantly on what you're trying to achieve. The general reason to use the CCRx advancing scheme is to permit multiple frequencies to be generated by a single timer. Remember that each TIM unit has a single counting element and four comparator/latches which don't count. As you have observed the interrupt loading can be severe and limiting, I'd probably only do it for 1 KHz or less.

If your goal is to generate 4 PWM channels sharing a common frequency/period, but different widths then PWM mode is ideal. ie a servo system with a 50 Hz, 20 ms configuration and 4 different servo positions.

If your goal is to generate some phase related square waves of a common frequency, Toggle mode works well.

They'll also work for a single channel/single frequency problem. But for each new frequency you'll need another TIM unit. Depending on your needs this might chew up a lot of resources, but not a lot of CPU cycles if you set them up and leave them alone.

It might be possible to feed CCRx values via DMA, and have a large table, or at least large enough to decimate the interrupt load. This however will chew through a lot of DMA resources, which again might be undesirable.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..