Posts

Running multiple slave devices on Arduino SPI bus – data formats

Bit reversal code

Bit reversal code

This is Part 3 of 3-part series of articles. Part 1 talks about ways of tweaking SPI code while Part 2 talks about hardware modifications.

After finishing hardware modifications for my three-SPI-device setup I started coding and hit a snag. Any device would happily work by its own, WiFi and SD were also happy together, however, adding NFC Shield to the mix would disable other two. If I moved NFC initialization to the beginnig, other two devices would work but NFC would not. At the same time, if a device was just present on a bus and not initialized, other two devices were not affected. It became clear that initialization itself was the source of error.

Seeedstudio NFC Shield uses NXP PN532 transmission module. This module supports several communication interfaces, namely SPI, I2C, and HSU. In SPI mode the data format is ‘LSB first’, i.e., transmission starts from bit 0. Such format is uncommon; all other SPI shields I’m aware of – Ethernet, WiFi, USB Host, etc., are using ‘MSB first’ format – the transmission starts with bit 7.

A quick look into NFC library source code revealed the following line in PN532::begin() function:

pn532_SPI.setBitOrder(LSBFIRST);

This line sets the data format. In Atmega microcontrollers the default SPI data format is ‘MSB first’ – all other SPI devices don’t have to set it during initalization. Initial revision of PN532 code ( written by Adafruit ) was using software SPI and awkward bit order was dealt with in write() and read() functions. When Seeedstudio modified the code to work with hardware SPI, they just switched SPI to ‘LSB first’ format without much thinking, breaking compatibility with the rest of the world. Surely, when I commented out this line, NFC initialization stopped breaking WiFi. Predictably, NFC also stopped working.

Luckily for me, the SPI is pretty basic protocol and bit order setting in SPI controller doesn’t mean much. It really doesn’t matter how the bit order is set; if we need ‘MSB first’ for the majority of the devices we can initialize SPI in a normal way and then modify write() and read() functions for ‘LSB first’ device to serve it reversed bytes. This is exactly what I did. Below is modified version of Seeedstudio PN532 library (also presented on a title screenshot) – lines 6 and 16 perform bit reversing:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/************** low level SPI ********/
/*Function:Transmit a byte to PN532 through the SPI interface. */
inline void PN532::write(uint8_t _data) 
{
  /* bit reversing code copied vetbatim from http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
  _data  = ((_data * 0x0802LU & 0x22110LU) | (_data * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
 
  pn532_SPI.transfer(_data);
}
 
/*Function:Receive a byte from PN532 through the SPI interface */
inline uint8_t PN532::read(void) 
{
  uint8_t data_ = pn532_SPI.transfer(0);
  /* bit reversing code copied vetbatim from http://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious */
  data_  = ((data_ * 0x0802LU & 0x22110LU) | (data_ * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
 
  return data_;
}

After making these modifications, commenting out the ‘LSB first’ setting in the PN532:begin() and also modifying WiFi code to stay away from pin 9 (see this article for discussion) all three devices are happily working together without conflicts. The library mod for PN532 can be left there permanently – the chip will never know that it is communicating with “misconfigured” SPI host. I’m hoping Seeedstudio will fix their code eventually; in the mean time, if you have SPI compatibility issues, simply make code modifications presented in this article.

Enjoy,
Oleg.

Running multiple slave devices on Arduino SPI bus – hardware modifications.

WiFi and NFC shield stack

WiFi and NFC shield stack

This is Part 2 of 3-part series of articles. Part 1 talks about ways of tweaking SPI code while Part 3 explains how to deal with incompatible data formats.

Add-on boards AKA “shields” greatly expand the capabilities of standard Arduino platform. Typically, a shield adds a specific peripheral interface; if you need several peripherals you may need to use several shields. The biggest problem in this approach is shield compatibility. Shield developers don’t care much about interoperability and sometimes making several shields work together is difficult. In the previous article on the topic I described a project where USB Host and WiFi shields were made to share the same SPI bus. I have been recently tasked with similar project which required rather heavy hardware modifications. This article shows the necessary steps to build a system consisting of Arduino board, official WiFi Shield and Seeedstudio NFC Shield.

Here is the hardware configuration. Both shields come with stackable headers so they can be plugged into each other. Both shields use ICSP for SPI but connectors are non-stackable so at least one of the shields must have its ICSP connector replaced with the stackable variant ( I sell them). Also, both shields use pin 10 for CS so this pin needs to be re-assigned on one of the shields.

NFC shield has offset female connectors therefore if another shield is placed on top of it ICSP connector won’t mate. It means that stackable ICSP connector shall be placed on WiFi shield. At the same time, since NFC Shield does have a second row of contacts re-assigning pin 10 on this board is easy.

Before we start cutting traces and desoldering connectors, let’s establish a baseline or “a known good state”. I simply grabbed an example from NFC shield library distro called readMifareMemory, compiled, loaded and ran it. I was able to read the card and now I know that my NFC shield is functional.

One other note – both shields are assembled using lead-free solder which has higher melting point. Don’t forget to set the temperature of your soldering iron accordingly – between 700F and 750F.

Continue reading Running multiple slave devices on Arduino SPI bus – hardware modifications.