I've got a unexpected problem with Interrupts. Would be nice to discuss it.
I use Timer0 to have about 16000 fast interrupts (FIQ) per second. There is a AD-Conversation and a few lines of long long int aritmetic to compute. Inside this FIQ-routine there is a static counter. When it reaches 16000 it is reseted and a Software interrupt (SWI) is generated every second.
The SWI-routine has do to some computations and then to display it all on a special three wire conected display.
The programm does not work with 16000 Timer0 Interrupts per second. It is terminated by Abort-Mode. This comes a little unexpected to my. The effect is gone if i turn down FIQ frequency downto 100Hz. Is it possible that interrupts create a stack overflow?
Should i post my code?
How do you expect that your SWI will be finished in 1/16000th of a second, i.e. when it is time for the next FIQ? Remember, you only have 62.5us in total for both FIQ and SWI.
You only require one result/second to be displayed, so why not let your main loop handle the display output whenever it sees the flag that the FIQ has collected 16000 samples?
Soory, was my fault. I didn't explained that the SWI leads to IRQ. I expect that the FIQ can interrupt the IRQ. Isn't it so?
Here's the code:
//************************************************************************* void FIQ_Handler()__fiq __ram { static long long unsigned int ACC1,ACC2,ACC3; static unsigned int int_counter; T0CLRI = 0; ADCCON = 0x6A3; // software conv., single-ended, conv. enabled while (!ADCSTA){} // wait for end of conversion ACC1 += ADCDAT >> 16; ACC2 += ACC1; ACC3 += ACC2; if (!(int_counter++ & 0x3FFF)) // every 16384 { SWICFG = 2; // create a softwareinterrupt ACC3_transfer = ACC3; } } //************************************************************************* void IRQ_Handler()__irq { static long long unsigned int ACC3D,D1,D2,D3,D1D,D2D; char text[10]; D1 = ACC3_transfer - ACC3D; D2 = D1 - D1D; D3 = D2 - D2D; ACC3D = ACC3_transfer; D1D = D1; D2D = D2; sprintf(text,"%8.d",(D3 * 125) >> 27); SDA5708_printf(text); SWICFG = 0; // clear softwareinterrupt BIT } //*************************************************************************
The sence of this floating average computation is to increase resolution of my 12 Bit AD-Conversation while distortions are decreased. YEAH it works properly with lower rates. But with higher rates, 16384 for example, my arm likes to have a vacation in abort mode. :-)
You have given a bit too little information about what you do.
But the SWI is not an interrupt flag that will start when the FIQ handler ends. The SWI is an instruction that will immediately (unless interrupts are enabled and an interrupt occurrs before the SWI instruction is executed) make the ARM enter the SVC mode. So if your FIQ handler executes the SWI instruction, the application with enter the SVC mode and start processing the SWI while still being in the FIQ handler. If you have enabled recursive FIQ before the SWI instruction, then you will nest a second FIQ interrupt.
If you want to, you can fake a low-priority interrupt from your FIQ handler, and let this IRQ handler perform the display output. But unless your code supports nested IRQ, all other interrupts (except FIQ) will be blocked until the display output is done.
Because of this, it is best to do all time-consuming operations in the main loop - possibly in a separate thread in case you use an RTOS.
George, You are probably generating the SWI in the FIQ to speed up the handling of the results. But, at the same time you have the following instruction in the FIQ handler:
while (!ADCSTA){} // wait for end of conversion
Have you measured the duration of the loop?
In addition, if your FIQ handler generates a SWI, and the SWI generates an IRQ as you asserted (probably by setting the IRQ flag, then returning immediately?), then the FIQ and IRQ handling are asynchronous - how can you guarantee the integrity of the displayed results without a buffer?
George, I would like to take back what I said about the data integrity. that was clearly wrong!
George, I think you are indeed risking data corruption. If your FIQ generates a SWI, which sets an IRQ flag and returns, the next FIQ might interrupt your IRQ while it is doing its job.
hi Per and everyone else, thanks for your kind reply. There is no more information that i can give about my little project, just the code to initialize Timer and interrupt. At this time, the Main programm is just like
int main(void) { init_ADC(); Timer_0_init(); interrupt_init(); while(1) {} //now endlessloop, but later important stuff } //************************************************************************* void Timer_0_init(void) { T0LD = 1632 - 1; T0CON = 0xC8; // Enabled,Periodic,Clock/256 } //************************************************************************* void interrupt_init(void) { FIQEN = RTOS_TIMER_BIT; // Timer_0 IRQEN = SWI_BIT; } //*************************************************************************
My idea when i wrote this was, the Timer_0 calls FIQ 16000 times per second. Inside FIQ there is a routine that makes a IRQ call every second. The IRQ drives the 3-wire-display, it can and should be interrupted by FIQ. I have no idea what this SVC-Mode is, maybe i have to read the whole DDI0029G ARM7TDMI Technical Reference Manual and DDI0100E ARM Architekture Reference Manual? I'am afraid of doing this!
Sorry, the code i posted is the actual version. The main clock frequency is 32768 * 1275 = 41779200 Hz. The Timer_0 prescaler makes a division by 256 (41779200 / 256 = 163200). So a T0LD register value of "1632" leads to a 100Hz interrupt frequency. At this rate, there is no "running into Abort-Mode-Problem". But my goal was to have an average with 16000 ADC-samples.
SOS need further assistant urgently ;-)
George, your
ACC3_transfer
is not interrupt safe. You would need to disable IRQ and FIQ when working with it.
char text[10];
sprintf(text,"%8.d",(D3 * 125) >> 27);
static long long unsigned int ACC3D,D1,D2,D3,D1D,D2D;
George, remember that "%8.d" is a minimum width specifier, not a maximum and that D3 is a 64 bit integer that is probably increasing in value with the number of FIQs.
A 64 bit integer is then being shifted right by 27 bits before being passed to sprintf (who is probably looking at it as a 32 bit integer but it can be still big enough to cause an overflow in your 10 character buffer).
I'd guess would be that you will get a pre-fetch abort when sprintf tries to return to IRQ_Handler because the buffer overflow on "text" trashes the LR that sprintf pushed to the stack.
View all questions in Keil forum