The SPI Functions
Initialization
There are two functions concerned with enabling and disabling the SPI bus:
bcm2835_spi_begin ()
bcm2835_spi_end ()
Before you make use of the SPI bus you have to initialize it using:
bcm2835_spi_begin ()
This returns 1 is successful and 0 otherwise. After this the pins allocated to the SPI bus no longer work as general purpose GPIO pins. If this function fails the most likely reason is that you are not running the program as root.
When you are finished using the SPI bus you can return the pins to general GPIO lines by calling:
bcm2835_spi_end ()
Configuration
There are a number of functions that you can use to configure the why the bus works.
bcm2835_spi_setClockDivider (uint16_t divider)
bcm2835_spi_setBitOrder (uint8_t order)
bcm2835_spi_setDataMode (uint8_t mode)
bcm2835_spi_chipSelect (uint8_t cs)
bcm2835_spi_setChipSelectPolarity (uint8_t cs, uint8_t active)
setClockDivider sets the speed of data transfer as a fraction of the back Pi clock speed. The documentation indicates that only powers of 2 can be used for the divider and there is a predefined enumeration BCM2835_SPI_CLOCK_DIVIDER_powerof2 that you can use. In fact you can use any value for the clock divider. The clock speed is given by
clock speed=250/divider MHz
You can ignore the BitOrder function because it has no effect as the Pi's SPI bus doesn't support it.
setDataMode can be used to set the data transfer to one of:
BCM2835_SPI_MODE0 |
CPOL = 0, CPHA = 0 |
BCM2835_SPI_MODE1 |
CPOL = 0, CPHA = 1 |
BCM2835_SPI_MODE2 |
CPOL = 1, CPHA = 0 |
BCM2835_SPI_MODE3 |
CPOL = 1, CPHA = 1 |
ChipSelect sets which chip select line will be involved in all data transfer operations unitl it is changed. You can set any of
BCM2835_SPI_CS0 |
Chip Select 0 |
BCM2835_SPI_CS1 |
Chip Select 1 |
BCM2835_SPI_CS2 |
Chip Select 2 (ie pins CS1 and CS2 are asserted) |
BCM2835_SPI_CS_NONE |
No CS, control it yourself |
Finally setChipSelectPolarity can be used to set either of the chip select lines to active high or active low.
In general you should configure the operation of the SPI bus completely but the defaults are:
Mode 0 divider 65536 i.e. aprox 3.81 kHz the slowest clock possible chip select CS0 chip select polarity active low Bit order most significant bit first.
Just to make sure that you get the configuration you want you should get in the habit of including:
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536);
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
This sets the defaults but you can modify the settings as you need.
Data Transfer functions
Because of the way the SPI bus uses a full duplex transfer things are a little different from other buses when it comes to implementing functions to transfer data.
uint8_t
bcm2835_spi_transfer (uint8_t value)
bcm2835_spi_writenb (char *buf, uint32_t len)
bcm2835_spi_transfern (char *buf, uint32_t len)
bcm2835_spi_transfernb (char *tbuf, char *rbuf, uint32_t len)
If you recall that the data transfer sends a byte of data out of the register while shifting in a byte of data then the transfer functions will make sense.
The most basic of this set of function is transfer which sends a single byte to the slave while recieving a single byte sent back. Unlike the underlying protocol it doesn't overwrite the original value with the slaves data. So for example to send and recieve data you would use something like:
uint8_t SendData=0x55;
uint8_t ReadData;
Read_data = bcm2835_spi_transfer(Send_data);
Of course you can always simply throw away the data from the slave or send meaningless data to the slave to create something that looks like a read/write pair.
The remaining functions all send multiple bytes of data stored in a buffer. The differ in how they treat the data returned by the slave - writenb ignores it, transfernb stores it in a new buffer and transfern over writes the send buffer with it.
Let's look at each one in turn.
If you just want to write data to the slave and ignore what it sends back then you need to use the writenb function. This takes a char buffer and a length specification and transfers each byte in turn throwing away any data that slave sends back. For example:
char buf[] = {'A','B','C'}; bcm2835_spi_writenb(buf,3);
will send three bytes, containing the ASCII codes for A, B and C, to the slave ignoring any data sent back. Notice that you need to get the size of the buffer correct in the function call to avoid buffer overflow.
The transfern function will send the number of bytes you specify and return the slaves data in the same buffer. For example
char buf[] = {'A','B','C'}; bcm2835_spi_transfern(buf,3);
sends the ASCII codes for A, B C but over writes each element of the array with whatever the slave transfered i.e. buf no longer contains A, B, C.
Finally the transfernb function uses two buffers, one for the data to send and one for the recieved data. For example:
char buf[] = {'A','B','C'}; char readBuf[3]; bcm2835_spi_transfernb(buf,readBuf,3);
sends A,B C to the slave and stores the three bytes sent back into readBuf.
Using just these functions you should be able to deal with most SPI slaves.
Now we come to a subtle point. What is the difference between transfering multiple bytes using transfernb, transfern or writeb and simply sending the bytes individually using multiple transfer calls?
The answer is that each time you make a transfer call the chip select line is activated, the data transfered and then it is deactivated. Using the buffer transfers the chip select is left active for the entire transfer i.e. it isn't deactivated between each byte. Some times this difference isn't important and you can transfer three bytes using three calls to transfer or one call to tranfernb say. Howver some slaves will abort the current multibyte operation if the chip select line is deactivated in the middle of a multibyte transfer.
It is important to realize that the nature of the transfer is that the first byte is sent at the same time that the first byte is recieved. That is unlike other protocols the whole of the send buffer isn't sent before the recieved data comes back. The whole transfer works a byte at a time - first byte is sent while the first byte is being recieved, then the second byte is sent at the same time the second byte is being recieved and so on. Not fully understanding this idea can lead to some interesting bugs.