2013-05-20 10:28 AM
I am using TIM3 as an event timer to trigger external ADC conversions. I am having an issue where the timer interrupt fires too early and causes an out of range conversion result from the ADC. I notice that when the interrupt is enabled, the TIM3 isr immediately fires followed by another one approximately 9ms later. After that, the isr fires correctly (66ms) for a period of time until i get spurious interrupts that, again, fire at the 9ms interval. The spurious interrupts occur anywhere from every few minutes to every few hours...
Using Keil Microvision 4.6 on a STM32F103ZE. Using the Standard peripheral driver 3.5.0. Code is as follows.../* Enable the TIM3 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&NVIC_InitStructure);
/* TIM3 Peripheral Configuration */
TIM_DeInit(TIM3);
TIM_TimeBaseStructure.TIM_Period = 2666;
TIM_TimeBaseStructure.TIM_Prescaler = 719;
TIM_TimeBaseStructure.TIM_ClockDivision = 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_SetCounter(TIM3,0x0000);//clear counter reg
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//enable isr
TIM_Cmd(TIM3, ENABLE);//enable the counter
Here is the ISR...
void TIM3_IRQHandler(void){
static int iTicks240Milliseconds = 0;
static int iTicks10Seconds = 0;
TIM_ClearITPendingBit(TIM3, (TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4));
b30Milliseconds = TRUE;
if(iTicks240Milliseconds++ >= 6){
b240Milliseconds = TRUE;
iTicks240Milliseconds = 0;
}
if(iTicks10Seconds++ > 333){
bInitComplete = TRUE;//allow relays, analog out...etc to function
}
}
Any ideas what might be going on?
thanks
2013-05-20 10:50 AM
I could see you getting an initial interrupt, which you could likely address by enabling the timer, then clearing and enabling the Update interrupt.
You might want to qualify the interrupt you're receiving, and leave the other alone. ie don't shotgun clear ALL possible sources. The period should be 2666-1 for 26.66ms, the compare here is for N-1, not N I haven't observed STM32 glitching in the manner you suggest, so you should perhaps look at what other code is doing, things like dwelling in while() loops in other interrupts. Sending pulses to an external ADC might be better achieved by using PWM mode to generate a pulse on a timer pin. The internal ADC can also be paced using a TIM unit to start the conversion, which is later caught by DMA, or ADC EOC interrupt.2013-05-20 02:20 PM
I have been shutting down other interrupt sources with no change in behavior...I am only enabling the ''update event'' interrupt for TIM3. The status register always indicates 0x001F (both for correct and early isrs). I realize that there are other ways an update event can occur (during initialization...counter register rollover...etc). In theory, the counter register should never rollover since my ARR reg is below this threshold and I am up-counting...odd
2013-05-21 12:54 AM
> I am using TIM3 as an event timer to trigger external ADC conversions.
How do you do that? > I notice that when the interrupt is enabled, the TIM3 isr immediately fires followed by another one approximately 24.9ms later. > After that, the isr fires correctly (26.66ms) for a period of time until i get spurious interrupts that, again, fire at the 24.9ms interval. How do you observe that? Please post a minimal but complete compilable example producing the problem.JW
2013-05-23 03:48 PM
>How do you do that?
I am using a Delta-Sigma ADC. The ADC requires a PWM to configure it's conversion time. Currently I have the conversion time set to around 25.5 ms. I use the TIM3 isr to set a flag for background code to trigger a conversion cycle every ~26.6ms. So every time the isr sets the flag, background clears the flag and clocks in the new conversion request using the SPI2 peripheral (while simultaneously clocking out the previous result).>How do you observe that?I set a breakpoint in my conversion result code that detects an out of range condition. I have my oscilloscope monitoring the chip select line for the ADC. When an out of range condition occurs, the code hits the breakpoint and I can see the early chip select assertion on the scope>Please post a minimal but complete compilable example producing the problem.I attempted to strip down the application to just the PWM, SPI driver, and TIM3 isr...this version seems to work without fail, so probably not much use. I have added another chunk of stuff back in that does fail...seems to be related to either printf, or the UART1 peripheralI will try to post this code but the ST site keeps deleting my posts :(2013-05-23 04:03 PM
One more note on the initial TIM3 initial glitches I mentioned in my first post. These initial glitches are indeed caused by a call to printf at the conclusion of my initialization (right after the timer3 is turned on). Removing this call eliminates the initial 2 glitches right after init is complete. I then removed the entire UART1 init from the code but this doesn't stop the early TIM3 interrupts later in operation however...fyi
2013-05-24 03:23 AM
There is way too much going on in between the interrupt and the signal you observe, for the interrupt to be accused.
Why not putting a pin toggle into the interrupt service routine and watch that on the scope/LA, too? JW2013-05-24 03:37 AM
Whenever printf/scanf come up as causing issues you want to look at the stack allocation. In Keil this is done in startup_stm32f4xx.s, and usually quite small. To modify you need to take a local copy of the .s file, and remove the read-only attribute.
Not saying this is the issue here, but not much to work with. You could put a fill pattern on the stack and evaluate the depth.2013-05-24 07:42 AM
>Whenever printf/scanf come up as causing issues you want to look at the stack allocation.
My thoughts exactly...however I have an 8k stack size...probably wouldn't hurt to fill with pattern and check the depth however2013-05-25 02:25 AM
Looking at your code, it seems that the interrupt does not immediately cause your event to happen. It looks as though your interrupt sets a flag that will eventually lead to your event happening.
Am I right in thinking thatb240Milliseconds
is simply a variable that your code somehow monitors (either explicitly in your event loop, or by way of an RTOS thread that waits on it)?
What might be happening is that your interrupt is consistently called at your intended time interval. But your code might be slow in responding to the flag that you set in the interrupt one time, so when it responds promptly the next time you see the interval between your responses being too short.
Why might that be?
It could be that the processor is doing something else that is deemed to be high-priority e.g. servicing a different interrupt.
Or doing something that takes a long time before it goes round again to see if your flag was set (slow event loop).
Or you have a low-priority task that is using a resource that is needed for your high-priority handler. For example while one printf is running, it is possible that all other printfs will have to wait.
Where you have something that is time-critical, quick, and will not block, do it in the interrupt.
Hope this helps,
Danish