2013-12-24 12:18 AM
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
2013-12-24 01:54 AM
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 properly2013-12-24 04:07 AM
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.2013-12-24 08:09 PM
2013-12-24 08:10 PM
2013-12-24 11:19 PM
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.