|Exploring Edison - SPI
|Written by Harry Fairhead
|Thursday, 02 June 2016
Page 2 of 5
The SPI Functions
There are thee functions concerned with enabling and disabling the SPI bus:
Before you make use of the SPI bus you have to initialize it using:
This returns the SPI context if successful and NULL otherwise. After this the pins allocated to the SPI bus no longer work as general purpose GPIO pins.
When you are finished using the SPI bus you can return the pins to general GPIO lines by calling:
You can also use mraa to initialize a bus without any board configuration using mraa_spi_init_raw, but this isn't something you generally want to do as the basic init doesn't do any initialization if it recognizes that it is working with the mini-expansion board.
There are a number of functions that you can use to configure the way the bus works.
The frequency sets the speed of data transfer in Hz
sets the bus frequency to 50kHz.
The theoretical maximum speed is 25MHz but in the current implementation the SPI bus doesn't always work at the speed you set.
mraa_spi_mode can be used to set the data transfer to one of:
You can also set the bit order and number of bits in each data transfer:
This sets the bit order to least significant bit first and 8-bit transfers. The lsbmode function seems to have no effect in the current version of mraa.
Notice that bit_per_word only affects data transferred in word units if it is in the range 16 or less and byte transfers if it is 8 or less.
You can't specify more than 16 bits for the transmission of a word.
Although some of the examples in the documentation use the SPI without configuring it, i.e. accepting the defaults, this isn't a good idea. If you do accept the defaults you can find the the bus behaves erratically and incorrectly - e.g. no clock pulse.
Always set the bus to reasonable values such as:
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.
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 functions is write which sends a single byte to the slave while receiving a single byte sent back. Unlike the underlying protocol it doesn't overwrite the original value with the slave's data.
So, to send and receive data, you would use something like:
Of course, you can always simply throw away the data from the slave if you just want a "write" or send meaningless data to the slave if you just want a "read".
You can specify how many bits are sent using bit_per_word.
will only send the low-order 5 bits.
The write_word function works in the same way as write but it sends a word containing up to 16 bits without deactivating the CS line. You can use bit_per_word to specify exactly how many bits are sent.
will transfers the low order 14 bits in trans to recv. In this case this means that recv will contain 0x3000. Not many SPI devices work with anything other than 8 bits.
The remaining functions all send multiple bytes of data stored in a buffer. They differ in how they return the data and each one comes in a byte or a word version. The byte versions always send eight bits at a time and the word versions send anything up to 16 bits.
Let's look at each one in turn.
The first two send a buffer of data and return a pointer to a buffer of data received. There is a byte version:
and a word version:
The difference is that in the byte version data is a byte array and in the word version it is a 16-bit array. Again the word version will send the number of bits from each word as set by bit_per_word.
sends three bytes and receives three bytes without deactivating the CS line. It is your responsibility to free up the buffer that the function returns.
The final two functions work in exactly the same way but with the difference that the received data is stored in a buffer of your choice:
sends three bytes and receives three bytes, but now into an array that you have created in your program. 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 transferring multiple bytes using write_buf or transfer_buf and simply sending the bytes individually using multiple write calls?
The answer is that each time you make a write call the chip select line is activated, the data is transferred and then it is deactivated. When you use buffer transfers the chip select is left active for the entire transfer, i.e. it isn't deactivated between each byte.
Sometimes this difference isn't important and you can transfer three bytes using three calls to transfer or one call to tranfernb. However, 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 received. That is, unlike other protocols, the whole of the send buffer isn't sent before the received data comes back. The whole transfer works a byte at a time - the first byte is sent while the first byte is being received, then the second byte is sent at the same time the second byte is being received and so on. Not fully understanding this idea can lead to some interesting bugs.
|Last Updated ( Thursday, 02 June 2016 )