Most slaves have an active low chip select input. So proper code to initialize and use a chip select pin is this:
#define CSPIN 1 // or whatever else your CS pin is
// init:
pinMode(CSPIN, OUTPUT);
digitalWrite(CSPIN, 1); // deselect
// use:
digitalWrite(CSPIN, 0); // select
... perform data transfer ...
digitalWrite(CSPIN, 1); // deselect
Deselecting a slave is just as important as selecting it, because a slave may drive the MISO line while it is selected. There may be many slaves, but only one may drive MISO. If a slave is not deselected properly, two or more slaves might be driving MISO, which may lead to shorts between their outputs and might damage the devices.
Transactions serve two purposes:
The clock line has different idle states in the different SPI modes. Changing the SPI mode while a slave is selected might confuse the slave, so always set the SPI mode before selecting a slave. The SPI mode can be set with an SPISettings
object passed to SPI.beginTransaction
:
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(CSPIN, 0);
... perform data transfer ...
digitalWrite(CSPIN, 1);
SPI.endTransaction();
SPISettings
may also be stored elsewhere:
SPISettings mySettings(1000000, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(mySettings);
If another part of the code tries to use the SPI between a pair of calls to beginTransaction()
and endTransaction()
, an error may be raised - how that is done depends on the implementation.
Also see Arduino Reference: SPISettings
If the SPI has to be used within an ISR, no other transaction may be taking place at the same time. The SPI library provides usingInterrupt(interrupt_number)
to facilitate this. It works by disabling the given interrupt whenever beginTransaction()
is called, so the interrupt cannot fire between that pair fo calls to beginTransaction()
and endTransaction()
.