The SPI is a four wire serial interface even though sometimes only two of the wires are used. This is the case if there is only one slave device connected and if it never sends data back to the master. Unlike the I2C (Wire) bus the SPI bus can work in full duplex. The bus consists of the following signals that are self-explanatory
- Master Out Slave In (MOSI)
- Master In Slave Out (MISO)
- Serial ClocK (SCK)
- Slave Select (SS)
Therefore each slave has to be selected to listen on the bus. This means that the pins can also be used for something else if the SS pin is not active. Often the SS is not connected between the master and the slave if there is only one slave connected. If so the SS on the slave will have to be activated whether it is high or low. The datasheet for the slave device will tell. If the SS is needed the programmer has manually to code this in the software.
Many slave devices can only listen to a master, i.e. they can’t send anything themselves. When this is the case the MISO doesn’t have to be connected.
The SPI bus speed depends on the capabilities of the master and the slaves devices. But speeds in the MHz range is not unusual.
The default SPI bus on the RFzero is bus available on D16 (MISO), D17 (SS), D18 (MOSI) and D19 (SCK) on the JP8 connector. The program below shows how to activate and use the RFzero SPI bus connected to a Microchip MCP23S17 port expander device. The principle is the same for the default SPI bus on the Arduino Zero and Arduino M0 boards.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
// Arduino includes #include <SPI.h> // RFzero include and object creation #include <RFzero.h> // MUST ALWAYS be included for RFzero #define MCP23S17_Addr 0 // The MCP23S17 A2:A0 chip address #define MCP23S17_pinCS 17 // CS (L) pin on the MCP23S17 int MCP23S17_ReadByte(byte devAddr, byte regAddr) { digitalWrite(MCP23S17_pinCS, LOW); // Set CS low SPI.transfer(0x41 | (devAddr << 1)); SPI.transfer(regAddr); int value = SPI.transfer(0x00); // Read the byte digitalWrite(MCP23S17_pinCS, HIGH); // Set CS high if (value > 0xFF) if (value > 0xFF) return -1; else return value; } void MCP23S17_WriteByte(byte devAddr, byte regAddr, byte value) { digitalWrite(MCP23S17_pinCS, LOW); // Set CS low SPI.transfer(0x40 | (devAddr << 1)); SPI.transfer(regAddr); SPI.transfer(value); // Send the byte digitalWrite(MCP23S17_pinCS, HIGH); // Set CS high } void setup() { // USB initialize SerialUSB.begin(9600); // Enable SPI bus pinMode(MCP23S17_pinCS, OUTPUT); // Set CS pin as output digitalWrite(MCP23S17_pinCS, HIGH); // Set CS high SPI.begin(); // Set I/O directions and GPIOB pullup, see datasheet pp. 13-25 MCP23S17_WriteByte(MCP23S17_Addr, 0x00, 0x00); // Set I/O 7 to 0/GPIOA as output, datasheet 3.5.1 MCP23S17_WriteByte(MCP23S17_Addr, 0x01, 0xFF); // Set I/O 15 to 7/GPIOB as input, datasheet 3.5.1 } void loop() { // Flash outputs 250 ms on and 250 ms off interlaced MCP23S17_WriteByte(MCP23S17_Addr, 0x12, 0x55); delay(250); MCP23S17_WriteByte(MCP23S17_Addr, 0x12, 0xAA); delay(250); // Read the input and print on the USB port int input = MCP23S17_ReadByte(MCP23S17_Addr, 0x13); if (input == -1) SerialUSB.println("No data available"); else SerialUSB.println(input, HEX); } |
If you want to use the above example on your Arduino Zero or Arduino M0 default SPI pins please note that the pins don’t match directly with the RFzero as the below table shows.
SPI signal | Pin/Port | Arduino Zero/M0 pinout |
---|---|---|
MISO | D16 | 4 (SPI connector) |
SS | D17 | Not assigned |
MOSI | D18 | 1 (SPI connector) |
SCK | D19 | 3 (SPI connector) |
Please note that if your SPI device(s) uses 5 V you will need a 3,3 V to/from 5 V level converter that can be made either by discrete components, ready made board or an IC. Please see the Third party accessories section on the Shop page.