SPI over RS-485 Testing

Arduino communicating with AutoDriver via SPI over RS-485 with 100' loop of CAT5.

Arduino reading the status register from the AutoDriver via SPI over RS-485 with a 100′ loop of CAT5.

In my last post, SPI over long distances, I described a method of using RS-485 to run a SPI bus over long distances. To test this setup I created two prototype shields, an Arduino SPI over RS-485 shield and an AutoDriver shield. Because the standard Arduino only has a single SPI bus and I needed two, one acting as a master and another as a slave, I would need to find a way to simulate one.

When I designed the Arduino shield my plan was to use the hardware SPI as the master, the only option with the Arduino library, and use interrupts to capture the SPI data coming back. So this is how I designed the shield to function, also adding a LCD interface and D-Pad so it could used independently of a computer.

Arduino SPI over RS-485 shield version 1

Arduino SPI over RS-485 shield version 1

The AutoDriver shield was relatively simple, a linear regulator to supply 5V to the RS-485 transceivers on the shield and also to power the logic on the AutoDriver itself. The SPI signals were routed directly to the connectors for the AutoDriver and back to transmit side of the RS-485 transceivers. The final touch was a simple transistor switch to disable the MISO output when the chip select signal was high, allowing multiple devices to share a single MISO line.

AutoDriver SPI over RS-485 shield version 1

AutoDriver SPI over RS-485 shield version 1

For the initial testing I did not use the 50′ of cable and connected the Arduino shield to the AutoDriver shield with short jumpers using only the master SPI interface only (the distance was short enough that timing would not be an issue). This worked as expected so I then went on to do the same test with 50′ of cable on the transmit side and the short jumpers on the receive side.  Again, as expected, this test functioned beautifully and I quickly moved on to testing with the hardware based SPI master sending data and the software based SPI slave receiving.

SPI over RS-485 testing with 50 feet of CAT5 on the transmit side using only hardware SPI. Prototype Arduino SPI shield on the left and AutoDriver shield on the right.

SPI over RS-485 testing with 50 feet of CAT5 on the transmit side using only hardware SPI.

For the first pass of the software based SPI slave I had the hardware based SPI master (Channel A) transmit the value of a counter every 500ms which was looped back into the software based SPI slave (Channel B). I then used the built in Arduino interrupts to call a function every time the incoming SPI clock went low. The MISO (MISO_B) pin was then read and the value shifted into a byte. After 8 cycles the completed byte was returned and everything reset for the next byte. It was quickly obvious once I began testing that this was not going to work, the delay in the processing of the interrupt was so long that by the time the MISO pin was read the value had already changed to the next bit. I attempted to fix this by slowing down the SPI bus speed to a clock divider of 128 verses the standard 4 times divider but even at that slow of a speed incorrect data was read the majority of the time.

I then configured the interrupts directly in the registers for the ATmega168, which would bypass all of the Arduino library overhead and should give me a much better response time. I also bypassed the Arduino digitalRead() function and read the value directly from the port in order to further reduce latency. This turned out to be much better, the code would now read the correct byte roughly 80% of the time and junk the other 20%, but it was still not good enough for practical use.

At this point I had come up with two options to get this thing working. The first one was to use the UART as a SPI master, a nice feature built into the hardware, and use the normal SPI as a slave. The problem with this was that I would loose to may pins to unneeded functions, such as the MISO pin on the SPI master and the MOSI pin on the SPI slave. This would prevent me from using the LCD display and since the UART was now a SPI the serial communications to the computer, leaving me blind. The second choice, and the path I took, was to use the hardware SPI as the slave and bit-bang the SPI master. By going this way I would need to rewire the prototype Arduino shield to reverse the direction of the RS-485 transceivers and would not be able to run the SPI bus at nearly as fast of a speed. But in return I would still be able to use the LCD or the UART to send commands and look at feedback.

Red-lined Arduino shield schematic.

Red-lined Arduino shield schematic.

This method worked out great! I was receiving the correct value 100% of the time with the short jumpers installed looping back the signal and also with the 50′ of CAT5 looping back.

Next I modified the SPIXfer function of in Sparkfun’s AutoDriver library so that I could send and receive commands using this setup to the AutoDriver board. I setup the shields with 50′ of CAT5 cable on both the transmit and receive side for a total loop length of 100′ and ran a quick test to read the status register of the AutoDriver.

Arduino shield (left) and AutoDriver shield (right) connected with 50' of CAT 5 on transmit and receive side.

Arduino shield (left) and AutoDriver shield (right) connected with 50′ of CAT 5 on transmit and receive side.

What I got back was nothing, absolutely nothing, the AutoDriver did not respond to the command at all. I eventual remembered that during some previous testing that the AutoDriver seemed to have an unmentioned minimum bus speed or timeout and would not respond when the SPI bus ran to slow. I then modified once again modified that SPIXfer function to access the pins directly and hopefully speed up the bus to the point where the AutoDriver would respond. To ease the use with the library, and so that I could still reference the pins by there Arduino numbers, I used some internal Ardunio functions to pre-calculate the hardware port, pin and a mask to set or clear the bit. The complete and most up-to-date library can be found on my fork of the AutoDriver library on GitHub, though also I’ve included an excerpt below.

That did the trick! I was now able to communicate with the AutoDriver, as seen in the image at the top of this post, and perform read and write operations. After running a few motion tests to verify that everything work as it had when using SPI directly from the Arduino to the AutoDriver I called it good.

Next up is to daisy chain multiple AutoDrivers on the SPI bus and be able to communicate with them one at a time…


Leave a Reply

Your email address will not be published. Required fields are marked *