SPI Module - smartel99/NilaiTFO GitHub Wiki
The Serial Peripheral Interface (SPI) module is designed to work in Full-Duplex, Half-Duplex Master or Half-Duplex Slave mode with no special configurations needed to switch the different modes.
To instantiate a SPI module in your application, you must first configure it in the CubeMX software. Don't forget to call the MX_SPIx_Init
function before instantiating the SPI module!
To instantiate the module in your application:
void MyApplication::InitializeModules()
{
AddModule(new SpiModule(&hspi1, "spi1");
}
The constructor of SpiModule
takes a pointer to a SPI_HandleTypeDef
created by the Cube and a string that is used to identify the module.
To simplify access to this new instance, you can create a macro that will get that instance in the application:
#define SPI1_MODULE() static_cast<SpiModule*>(MyApplication::GetModule("spi1")
This macro allows you to use the module like this:
SPI1_MODULE->Transmit(myData);
This API does not offer any configuration utilities. To setup the hardware SPI, please use the Cube.
The SPI module has three types of functions that can be used:
- Transmit
- Receive
- Transaction
The SPI module does not take care of controlling a chip select signal, you must do that yourself!
To transmit data on the SPI module without reading a response, use the Transmit
method of the SpiModule. This function can either take a std::vector<uint8_t>
or a pair of uint8_t*
and size_t
as parameters.
Example:
// Using std::vector:
std::vector<uint8_t> myData = { 0x00, 0x01, 0x02, 0x03 };
SPI1_MODULE->Transmit(myData);
// Using uint8_t*:
uint8_t myData2[] = { 0x00, 0x01, 0x02, 0x03 };
SPI1_MODULE->Transmit(&myData2[0], (sizeof(myData2) / sizeof(myData2[0])));
There is also two other transmission methods available: TransmitByte
and Transmit16
. As their name implies, they transmit a single byte or two bytes respectively.
To receive data with the SPI module without transmitting a packet, use the Receive
method of the SpiModule. This function can either take a reference to a std::vector<uint8_t>
or a pair of uint8_t*
and size_t
as parameters.
You can also receive a single uint8_t
or a uint16_t
using the ReceiveByte
and Receive16
methods.
Example:
// Using a std::vector:
// Initialize a vector of 8 elements.
/* The vector must already contain as many elements as you want to receive
* since the Receive method uses the size of the vector for the quantity of data to get.
* To set the number of elements in your vector, either use the explicit constructor like bellow,
* or use the resize[1] function of the vector.
*/
std::vector<uint8_t> myData = std::vector(8);
// Receive 8 bytes from the SPI port.
SPI1_MODULE->Receive(myData);
// Using uint8_t*:
uint8_t myData2[8] = { 0 };
SPI1_MODULE->Receive(&myData2[0], (sizeof(myData2) / sizeof(myData2[0])));
// Getting a single byte:
uint8_t myByte = 0;
SPI1_MODULE->ReceiveByte(&myByte);
// Getting a 16-bits word:
uint16_t myWord = 0;
SPI1_MODULE->Receive16(&myWord);
To exchange data between the master device and the slave device on the SPI peripheral, use the Transaction
methods.
The number of bytes received is the same as the amount of bytes sent.
This method can be used in two ways:
- Using
std::vector
- Using
uint8_t*
andsize_t
Example:
// Using std::vector:
/* Here, we don't need to specify the size of rxData since
* Transaction automatically resizes it to be the same size as
* txData.
*/
std::vector txData = { 0x00, 0x01, 0x02, 0x03 };
std::vector rxData;
SPI1_MODULE->Transaction(txData, rxData);
// rxData now contains 4 bytes of data that was received by the SPI peripheral.
// Using uint8_t*:
uint8_t txData2[4] = { 0x00, 0x01, 0x02, 0x03 };
uint8_t rxData2[4]; // !!!rxData2 MUST be the same size as txData2!!!
size_t txLen = sizeof(txData2) / sizeof(txData2[0]);
size_t rxLen = sizeof(rxData2) / sizeof(rxData2[0]);
SPI1_MODULE->Transaction(&txData2[0], txLen, &rxData2[0], rxLen);