Hi there,
I searched in the forum (hopefully deep enough) but I found nothing about my problem, so here I am...
My application involves a constant clock to be generated by the micro-controller (AT91SAM7S-256 @ 48Mhz), and an interrupt to occur on each falling edge of the same clock, to do some required stuff.
In first instance I've tried to build a program which blinks a led using a simple interrupt service routine (called on each falling edge of the generated clock): TC0 module is used in Waveforme 10 mode, TIOA0 (PA0) is controlled by TC0 and is the output pin on where the constant clock is being output (in this case this is useless because the led is not there, but is a useful test for my final application). A fast forced interrupt is setup to occur on each falling edge of PA0 clock, I accomplished this by requesting TC0 module to send an interrupt request to AIC every time RC comparison occurs (this also makes TC0 restart and PA0 pin to get low by the way). In this case the interrupt should occur every about 1 second or so, and it works just fine. The led blinks at the required rate and the clock signal is there on PA0. Just fine.
After that, I wanted to do the same thing, but with a quite higher clock frequency. This one should be around 1.5Mhz. So here it is what I did to modify my existing working code: change TC0 clock input to be MCLK/2 (was MCLK/1024) and change RA and RC values. And guess what: it stopped working

In further debugging I discovered that the interrupt service routine was being called only once, and after that, not any further.
One last desperate hope drove me to place another dummy-read of the TC0 status register (which, AFAIK, clears the interrupt). This had the effect of making the interrupt to occur, but unfortunately with wrong timings! To better explain the situation I'm attacching an image which should make it clear:

The first (upper) waveform is the clock output, this is controlled by TC0 module and works just fine, the clock is correct.
The second (lower) waveform is the pin that I'm manually toggling on every interrupt entry (which should occur on every falling edge of the clock), and this doesn't work as intended. As you can see, it doesn't get low where it should, and neither it does when it should get high, it looks like the toggling, then the interrupt calling, is being delayed.
These below are the "hot" parts of the code:
This is the part of code that setup TC0 and AIC:
Code:
/* Setup the Advanced Interrupt Controller */
init_aic: ldr R0, =AT91C_BASE_AIC
ldr R1, =0x00000020
str R1, [R0, #0x04*12]
ldr R0, =AT91C_BASE_AIC
ldr R1, =(1<<12)
str R1, [R0, #0x140]
/* Setting up TC_CMR0 */
init_tc0: ldr R0, =AT91C_BASE_TC0
ldr R1, =0x0009C000
str R1, [R0, #0x04]
/* Setting up TC_IER0, interrupting on RC compare */
ldr R0, =AT91C_BASE_TC0
ldr R1, =0x00000010
str R1, [R0, #0x24]
/* Loading RA and RC (compare regs) */
ldr R0, =AT91C_BASE_TC0
ldr R1, =8
str R1, [R0, #0x14]
ldr R0, =AT91C_BASE_TC0
ldr R1, =16
str R1, [R0, #0x1C]
/* Setting up TC_CCR0, TC0 starts */
ldr R0, =AT91C_BASE_TC0
ldr R1, =0x00000005
str R1, [R0, #0x00]
/* Clearing FIQ Interrupt Mask*/
mrs R1, CPSR
bic R1, R1, #(1<<6)
msr CPSR, R1
/* Enabling TC0 Interrupt */
ldr R0, =AT91C_BASE_AIC
ldr R1, =(1<<12)
str R1, [R0, #0x120]
This is the interrupt handling routine:
Code:
fiq_handler:
/* Read TC0_SR (Interrupt Acknowledgement) */
ldr R8, =AT91C_BASE_TC0
ldr R9, [R8, #0x20]
/* Toggling PIOA18 (blinking led) */
ldr R8, =AT91C_BASE_PIOA
ldr R9, [R8, #0x38]
tst R9, #(1<<18)
ldrne R8, =AT91C_BASE_PIOA
ldrne R9, =(1 << 18)
strne R9, [R8, #0x34] /* Led OFF */
ldreq R8, =AT91C_BASE_PIOA
ldreq R9, =(1 << 18)
streq R9, [R8, #0x30] /* Led ON */
/* Read TC0_SR (Interrupt Acknowledgement),
/* without this one (theorically useless) the
/* cpu would be interrupted only once and not any further!!!!!! */
ldr R8, =AT91C_BASE_TC0
ldr R9, [R8, #0x20]
/* Clearing TC0 Interrupt */
ldr R8, =AT91C_BASE_AIC
ldr R9, =(1<<12)
str R9, [R8, #0x128]
/* Returning from fast interrupt */
subs PC, LR, #4
By the way when I build up the program for the first time (the one that blinks a led, which works) it didn't work because I did not place any dummy-read of the TC0 status register there in the interrupt handling routine. I read the AT91SAM7-S datasheet over and over but I really found nothing about reading the status register, I had to find it somewhere on the network... now I'm wondering: is there something about this in the datasheet? If yes: where? If not: Why shouldn't atmel say anything about such an important aspect of TC0 ?
Could someone help me figuering out why the program won't work? Thanks in advantage for any further help!