Forums

LPC2148 misses SPI0 interrupts if UART interrupts used

Started by l_marmsater July 3, 2006
Hi,
Here is a gotcha that may cost you some time to find and resolve.
If you are using interrupts to handle SPI0 transfers and UART0 or
UART1 in an LPC2148, you may find that SPI0 interrupts do not always
occur.
You typically initialize an SPI transfer from the user level, say
transmit the first byte of a buffer, and then let the ISR finish the
transfer, until all bytes are shifted out or in.
My first approach to start the transfer was:
S0SPDR = First_Byte; // First byte to transmit
S0SPCR |= 0x80; // Enable interrupt
The byte will always be shifted out. When done, you should get an
interrupt. The ISR will shift the next byte out etc. until all bytes
are shifted out, at what tine the ISR will disable SPI0 interrupt.

Here is the catch: If, at the end of the first byte shif-out, a UART
ISR is active serving a UART interrupt, you will not get a SPI0
interrupt in around 15% of the occurances. Very nasty.
The work-around is easy. Enable the interrupt before placing the
firat byte to transmit:
S0SPCR |= 0x80; // Enable interrupt
S0SPDR = First_Byte; // First byte to transmit
Then it all works fine.
I think there is an earlier entry regarding a similar problem, but I
have not been able to find it.
Hope this saves someone to spend a week with the logic analyzer...
Lars Marmsater

An Engineer's Guide to the LPC2100 Series

Lars, the problem you explain is not limited to UART interrupts.

I recall the SPI interrupt flag on LPC is set only if the interrupt
enable flag is set at the instant the interrupt is raised.

What most likely happened in your 15% of the time is that a UART
interrupt was taken between writing to S0SPDR but before writing to
S0SPCR. The SPI interrupt event raised on completion of transfer then
takes place before SPI interrupt was enabled, and thus lost.

Hope this helps.

Jaya
That makes perfect sense! I'll have to check for more issues, then. I
use interrupts for I2C0, I2C1, timers and USB also...
Thanks, Jaya
Lars
> That makes perfect sense! I'll have to check for more issues, then. I
> use interrupts for I2C0, I2C1, timers and USB also...
> Thanks, Jaya
> Lars

This is a fairly common race condition: I've seen it before (on other
parts) in initiating transmit interrupts:

1. Initiate action that will result in a transmit interrupt
2. One or more cycles that can be interrupted
3. Enable the transmit interrupt.

As Jaya has pointed out, it's possible for an interrupt to happen at
stage 2 and take an indeterminate amount of time, so the transmit is
complete without the transmit interrupt having been set.

One solution is to disable all interrupts whilst initiating a
transfer, as this fixes the timing. However, it's much better to get
into the habit of re-ordering stages 1 and 3 above, as this is
guaranteed to work (I've seen some peripherals with internal buffers
generate transmit interrupts almost immediately on loading the first
byte).

Of course, your problem could be something else completely....

Brendan
> That makes perfect sense! I'll have to check for more issues, then. I
> use interrupts for I2C0, I2C1, timers and USB also...
> Thanks, Jaya
> Lars

You are welcome Lars.

I forgot to mention that your original code is the most common way of
handling TX interrupts for devices like UARTs and SPI. So I would not
recommend a paradigm change.

This problem is very specific to on-chip LPC peripherals IMO because
of the way they these peripherals are interfaced to the VIC.

Regards,

Jaya