I am finding a quirk with SPI port transfer complete interrupt on an ATMEGA 1284.
I post this to see if anyone else has noticed this.
I have an interrupt-driven SPI port device control program.
It can be called by any program to effect a transfer of N bytes from the starting buffer address supplied.
by the caller.
I want to suspend the calling program until the transfer is complete and give the CPU cycles to something else. When the transfer is complete, I want to reactivate the calling program.
The SPI port Device Control Program places the starting buffer address in an address pointer variable accessible to the interrupt routine and also places the byte count in a counter variable accessible to the interrupt routine. It then starts the transfer by writing the first byte to SPDR and suspends the calling program.
The SPI transfer complete interrupt should occur after every byte and the interrupt routine decrements the byte count and increments the buffer address pointer. When the byte count gets to zero, the interrupt routine reactivates the calling program that was suspended.
So pseudocode would look like this
1 PREPARE INTERRUPT ROUTINE
2 WRITE FIRST BYTE TO SPDR
3 SUSPEND THIS PROGRAM UNTIL TRANSFER COMPLETE
4 Gets to here when reactivated by the interrupt program's byte count hitting zero.
The first problem with this is, that for a single byte transfer which many instances are, the interrupt code is entered so soon after writing to SPDR that the whole thing is over and reactivating the calling program between steps 2 and 3 before it has even been suspended at step 3. So SUSPEND happens after REACTIVATE and so the calling program stays suspended and is never reactivated
So I have to delay starting the SPI port interrupt until the calling program is suspended as follows:
1 INHIBIT INTERRUPTS
2 PREPARE SPI PORT INTERRUPT ROUTINE
3 WRITE FIRST BYTE TO SPDR
4 SUSPEND THIS PROGRAM UNTIL TRANSFER COMPLETE
4 AND RESCHEDULE TO GIVE THE CPU CYCLES TO THE HIGHEST PRIORITY TASK
4 BY FINDING THE HIGHEST PRIORITTY ACTIVE TASK WHILE
4 INTERRUPTS ARE STILL INHIBITED
5 NOW RE-ENABLE INTERRUPTS WITH AN SEI
6 RETRIEVE THE REGISTERS OF THE TASK TO REACTIVATE
7 AND RESUME IT
Now here is what happens: After step 3, SPCR is F1 which means SPI transfer complete interrupts are allowed and SPSR is 80 which means an interrupt is indeed pending. It doesn't happen though because interrupts are still inhibited, as I wanted.
Now we get to step 5 where interrupts are re-enabled and I can see that INDEED they are.
Now, the manual says that the instruction after SEI will be executed before any pending interrupts happen.
The first instruction in step 6 is POP R0
(it is in a macro and I have yet to find out if something about a MACRO is the problem)
When that POP R0 is executed, SPCR goes to 71, meaning that SPI port interrupts are now inhibited, and SPSR goes to 00, which means that the pending interrupt is cancelled, without the interrupt routine ever being entered..
WHO DID THAT !!!
So just out of a wild-assed guess I put a NOP between step 5 and step 6, so that the NOP is the first instruction to be executed after SEI.
WORKS BEAUTIFUL NOW !