Having followed some forum threads about difficulties with USCI SPI slave mode, I noticed a few responses refer to an issue or limitation with the use of UCCKPH in slave mode. Unfortunately there didn't seem to be any precise information on what this problem might be. It's not listed on any errata sheet (EDIT: now logged as USCI40) and the comments about it on the forum are pretty vague.
I spent some time looking into this to see if I could reproduce the problem, and perhaps find a workaround (other than "don't use UCCKPH").
It turns out that there is indeed an issue that needs to be considered when using slave mode with UCCKPH set. There's a significant difference in the USCI's behaviour depending on the UCCKPH setting, which manifests when the firmware fails to load TXBUF in time.
The simplest way to demonstrate this is with a test program that loads TXBUF only once after taking the USCI out of reset, then busy-waits:
#include <msp430g2553.h> void main(void) { WDTCTL = WDTPW | WDTHOLD; // Configure USCIB0 for 3-wire SPI, CLK idle low, SOMI/MOSI stable on CLK falling edge UCB0CTL1 = UCSWRST; UCB0CTL0 = UCSYNC | UCMODE_0 | UCMSB /*| UCCKPH*/; P1SEL = BIT5 | BIT6 | BIT7; P1SEL2 = BIT5 | BIT6 | BIT7; UCB0CTL1 &= ~UCSWRST; while((UC0IFG & UCB0TXIFG) == 0); UCB0TXBUF = 0xD3; while(1); }
Hook up a logic analyser to P1.5/P1.7 and feed a suitable clock source in at P1.5. The clock line needs to be held low before the USCI comes out of reset to avoid desynchronisation.
Here are the results, first with UCCKPH clear:
TXBUF is initially set before the clock train begins. TXIFG goes high while the first byte is being shifted out, but by the ninth rising clock edge the TXBUF hasn't been set again. With UCCKPH clear, in this situation the USCI just shifts out the same byte over and over again.
Now with UCCKPH set:
Here the USCI "falls behind" the input clock by one cycle for each byte. Effectively it switches to a "nine bits per byte" cycle, repeating the LSB of the TXBUF value. To the master it appears that the slave's output is getting rotated to the right.
Obviously this test isn't very representative of real world use. It's more likely that the firmware will keep up with the incoming clock most of the time, only falling behind occasionally.
To simulate that I set up a program that writes a sequence of bytes to TXBUF. The SPI clock is set such that the transmit loop never falls behind, except there's a variable delay which is inserted before one of the writes in the sequence. Running this test repeatedly with an increasing delay shows the consequences of delivering a single byte to the TXBUF late:
(Correct sequence is 0x56, 0x6E, 0x1C, 0xA8, 0xD3, 0xAD)
With UCCKPH clear the results aren't too bad. The signal timing is always valid, and the USCI doesn't get into an invalid state. It outputs one or more repeated bytes and occasionally loses a byte, but subsequent bytes are output correctly. If the high-level protocol is robust enough this could be handled without needing to reset the USCI.
Now compare that to what happens with UCCKPH set:
As the delay crosses the boundary into the next byte the transition on the data line is pushed back. Eventually it reaches the rising clock edge (where the data line should be stable). Then the USCI switches to repeating the LSB of the last byte and outputs the next byte one clock cycle late. When the delay extends past the next clock edge it changes to repeating the last byte (still one cycle late). That leaves the USCI state offset from the clock, and all subsequent transmissions are garbled even if the TXBUF is set in time. The only certain way to recover from this is to reset the USCI.
To summarise, there is an issue with using the USCI as SPI slave when UCCKPH is set. It only occurs if the firmware fails to set TXBUF in time, but can result in subsequent transmission being corrupted until the next USCI reset. The MSP430F5529 and MSP430G2553 both exhibit this behaviour.
Workarounds:
- Don't set UCCKPH high in slave mode (requires the master's clock phase be changed to match)
- Ensure the firmware always loads TXBUF in time when UCCKPH is set
The good news is that the "enhanced" eUSCI in the FRAM range doesn't suffer from this problem to quite the same degree. There's some limited violation of signal timing but the eUSCI's internal state machine remains in-sync with the clock. It also doesn't ever "lose" a byte when it repeats. I'll post the images for that later.