Return to Robotics Tutorials

SPI slave data corruption

This is Part 3 of a series describing how to use a Remote Control (RC) transmitter to drive a robot using an Arduino / ATtiny SPI slave. If you haven't already read it, please see Part 1 & Part 2 for the background material.

Table of Contents

SPI read transactions

Successful SPI Read Transaction at 62kHz

SPI Data corruption

SPI Data corruption due to Interrupts

Read transactions (slave responding to master) are more challenging than writes because the slave needs to analyze the first byte in order to respond in time for the start of the second byte. In fact, the SPI slave may only have enough information to determine how to respond by the end of the last bit from the first byte (clocked in by SCLK). Generally, the SPI master will expect that the SPI slave will start sending the first bit of the read data by the very next SCLK cycle. As a result, one of the most difficult timing windows for the slave is the setup time in advance of the second byte.

Unfortunately, some SPI masters only provide a single SCLK cycle between the byte transfers! If we depend on interrupts to notify us when we have completed the reception of byte 1 and set up the SPI Data Register (SPDR) for the start of byte 2, then the interrupt response latency (the time it takes for our ISR to start) becomes critical.

Corrupted SPI Read Transaction at 62kHz

As mentioned earlier, there are some scenarios that can cause our SPI Data Transfer Complete ISR to become delayed in starting -- these will eat in to our critical timing window. If we take too long, then the 2nd byte will start to be shifted out from the slave before we have configured what the outgoing byte should be! Since we haven't written to it in time, the SPI slave will simply shift out whatever was left in the data shift register (typically the value of byte 1 from the master).

 


Reader's Comments:

Please leave your comments or suggestions below!
2017-09-22Linz
 If you take a look at typical SPI transfer protocols (such as AVR chip programming) you'll see the master normally expects the first byte to be echoed straight back from the slave, and it's used by the master to verify the connection is good.

The big upside of this is that the slave has the time of 8 bits to get its response ready. Doing that within one bit time is just asking for trouble.

Cheers
 Interesting... thanks for pointing this out! Providing a full byte of echo time makes a lot more sense in reducing the burden on the slave. I suppose it still may require a single-bit turnaround in the ISR response time but it doesn't have to worry about consuming additional time to perform an address lookup / response generation, etc.
2017-07-12Willem
 Hi Calvin,

What a great series of articles!
I'm looking for a way to read GPS data by I2C, exactly as you describe in these posts... Is there a full listing of the GPS to I2C bridge for the ATTiny.. I cannot find it anywhere!

Regards,
Willem
 Hi Willem --

I did write up the code for my GPS via I2C but didn't get around to completing the associated article. Nonetheless, you can check out my code posted here: GPS via I2C. Hope that helps!
2017-04-14Don
 This is very close to exactly what i need - i have an SPI radio (nrf4101 clone) that I need to read SPI from and translate to PPM or PWM for a quad flight controller.

Did this Attiny SPI Slave code ever get completed? Is it on Github anywhere?
 Hi Don -- I have now uploaded the code that I wrote for sampling the RC PWM receiver and driving a SPI slave interface on an ATtiny. You can find it here at GitHub:
RC receiver PWM to SPI slave

However, I think you might be looking for the reverse direction -- generating a series of PWM pulses from a SPI slave interface. It should be relatively easy to adapt the code I have (SPI slave). You would need to drive the PWM signals instead of the Pin Change int (PCINT*) ISRs. I am not sure which ATtiny you have and how many PWM outputs you need to drive, but this could be a good start. In general you will probably need to configure the Timer/Counter# registers with the associated Output Compare registers to get the duty cycles you need.

Good luck!

 


Leave a comment or suggestion for this page:

(Never Shown - Optional)
 

Visits!