2018-04-24 05:15 AM
Hello, I am using a stm32f103c8 micro-controller. I am using STLINK/V2 for debugging in MDK-ARM v5 environment.
I have programmed TIMER 3 in simple PWM mode using code from Standard Peripheral Library (SPL) example. The code is attached below for reference:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;uint16_t CCR1_Val = 333;/* Compute the prescaler value */
PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1; /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 665; TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = CCR1_Val; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);/* TIM3 enable counter */
TIM_Cmd(TIM3, ENABLE); TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);Basically this software simply configures the TIMER 3 to produce a square wave with 50% duty cycle. Now I have enabled Timer Update Interrupt as well because I want interrupt every time counter overflows. The Timer ISR is given below:
void TIM3_IRQHandler(void)
{ if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit (TIM3,TIM_IT_Update); GPIO_WriteBit(GPIOC, GPIO_Pin_14, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_14))); }}The ISR simply toggles a GPIO pin which is connected to oscilloscope for viewing.
Now, I understand that every time the counter overflows, the interrupt
TIM_IT_Update should fire and the ISR should execute immediately. The ISR above simply toggles an IO, so the IO pin should change almost immediately after interrupt. However, I have achieved the result as shown in picture attached:
In image, the yellow trace is the PWM output of timer 3 and the blue trace is the GPIO being toggled in ISR. The issue I have is that there seems to be a delay between two wave shapes. The delay is almost 1us. This implies that either the ISR is being executed with a delay, i.e. the interrupt doesn't fire immediately after counter overflow, or there is some delay in the ISR itself.
The SystemCoreClock is 72 MHz. So my guess is that the interrupt is being fired with a delay. I have also tried disabling Systick interrupts. The result remains the same. I will appreciate any help in this regard. Thanks.
#stm32f103-interrupt2018-04-24 07:26 AM
The ISR above simply toggles an IO, so the IO pin should change almost immediately after interrupt.
The question is, what is 'almost immediately' and what is your expectation based on.According to your DSO pic there is almost 2us delay lets say 1.7us (if I'm reading your timebase correctly) At 72MHz thats approximately 122 instruction cycles.
I would say that the way you are toggling the pin has a lot to do with the delay - first reading the current state then writing out (1-current_state) using SPL functions is not the most efficient way to do it. Try another function such as
LL_GPIO_TogglePin or even a direct write to the BSRR/BRR registers for the GPIO port eg.
GPIO_Port->BSRR |= (1 << YOUR_PIN); // set GPIO pin
See if that makes a difference.
2018-04-24 07:37 AM
1uS is not so bad,
you can imagine that the PWM is a hardware signal developed from AND gates and the Timer Counter itself.
another hardware function is to trigger the interrupt.
these will happen at the same instant.
@ 72MHz you only get 72 cycles in 1uS.
there is a slight delay to get to the first instruction of the ISR, that could be 2-7 clocks there with no other DMA or Interrupts
then you are running this code bits:
if // 1 clock cycle
(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) // 20-30 clocks
{ TIM_ClearITPendingBit (TIM3,TIM_IT_Update); // 10-20 clocksand some more here just before the pin is actually toggled..
// 5-10 clocks
GPIO_WriteBit(GPIOC, GPIO_Pin_14, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_14)));that's about 70 clock cycles delay from the hardware interrupt to the software response: toggle pin.
2018-04-24 11:17 AM
This is really helpful. Thanks alot
2018-04-24 11:17 AM
I did try this approach. However, I will try again with your code. Thanks for help
2018-04-24 11:05 PM
You're welcome.
2018-04-24 11:22 PM
PS: I'm assuming you initialized the GPIO pin as output and connected to hi-speed clock, right ?
2018-04-25 04:09 AM
1us #= 72 ticks. That sounds a little excessive but not impossible, between your isr overhead plus execution.
If you operate on the SR or ODR registers you may be able to get that down to 30 ticks.
2018-04-25 04:36 AM
Yes I did that. I have come to the same understanding as explained by yourself and Mr. T J.
2018-04-25 06:56 PM
@dhenry, what is the correct calculation of the number of ticks in a uSec ?