Hardware SPI
Class documentation: HardwareSPI
Optimized class documentation: HardwareSPI_O
Main features:
- Supports SPI periphery handling.
- Almost all configuration can be done programatically.
- Supports polling, interrupts or DMA communication modes.
- Supports Master and Slave mode
- Supports Motorola or TI transaction mode
- Can be used as Arduino SPI library
- Supports hardware CRC calculation.
- Supports callback for all available events.
- Periphery is enabled only during transaction to save power.
What not to do:
- Never use optimized HardwareSPI_O class transaction methods without calling beginTransaction() before transaction and endTransaction() after transaction.
- Do not try to write, receive or transfer data before you have called begin() method.
- Do not try to create this instance for SPI periphery, that does not exists. All methods will be disabled.
How to use:
- Check if definitions for your MCU are included in this file.
- In .ioc file settings set SPI mode to something else than "Disabled" option.
- In tab called "NVIC settings" enable all interrupts.
- In tab "Parameter Settings" set UART configuration, or set it by calling begin() method.
- (OPTIONAL) If you want to use DMA, in. ioc file add DMA channels for Rx Tx. Those channels may not be available for some peripheries or may not be available, because they are used for another periphery.
- Call begin() method in your code to initialize and enable SPI periphery.
- Note
- This code is only c++ compatible. If you want to use it, convert your project to c++.
How to add support for your MCU:
- Check if your MCU is not supported yet.
- Add elif macro to include part (#elif defined(YOUR_MCU) ...). It will mean, that you have revisited this file for your MCU.
- Check if some functions or variables does not require specific code for your MCU.
Communication modes:
1. DMA mode
- Can be used for writing, receiving and transfering.
- You can do another job, while transacting large data.
- Transaction methods, that can use DMA mode: transferNonBlocking(), writeNonBlocking(), receiveNonBlocking().
- To use this mode, just connect available DMA channels to SPI periphery Rx and Tx in .ioc file or using connectDMAtoRx() / connectDMAtoTx() methods.
- PROS:
- MCU can do another job while sending/receiving data without interrupting your code.
- CONS:
- Buffer, which data are writed/received/transfered using NonBlocking NonBlocking transaction methods have to be available during transmission.
- DMA channels for selected SPI periphery may not be available, so you cannot use DMA mode.
- You can call NonBlocking transaction methods only when data are not transacted, else it will return error.
2. IT mode
- Can be used for writing, receiving and transfering.
- You can do another job, while receiving or transmitting large data, but your program is interrupted when received or transmitted some bytes.
- Transaction methods, that can use IT mode: transferNonBlocking(), writeNonBlocking(), receiveNonBlocking().
- To use this mode, make sure, you have disconnected DMA from SPI periphery in .ioc file or you can call disconnectDMAfromRx() / disconnectDMAfromTx().
- PROS:
- MCU can do another job while sending/receiving data.
- CONS:
- Your code is interrupted every time, when some bytes are received or transmitted.
- Buffer, which data are writed/received/transfered using NonBlocking NonBlocking transaction methods have to be available during transmission.
- You can call NonBlocking transaction methods only when data are not transacted, else it will return error.
3. Polling (blocking) mode
- Can be used for writing, receiving and transfering.
- Processor is sending your data manually. You cannot do any job while sending data.
- Transaction methods, that can use polling mode: see "One word methods" and "Array methods" in transaction methods
- To use this mode just call polling methods, that are mentioned above.
- PROS:
- Buffer, which data are writed/received/transfered will be certainly available during transmission.
- You do can send data several times in a row.
- CONS:
- MCU cannot do another job while sending/receiving data in this mode.
- When you are transacting data using NonBlocking transaction methods and use polling transaction methods, flush() method (which waits until all data are sent) will be called and then your new data will be sent in blocking mode.
Special hidden functions:
1. Sleep SPI periphery
- You can easily sleep SPI periphery by calling method end(), that disables periphery clock, DMA and it's interrupts.
- If you want to wake up SPI periphery, just call begin() method with(out) parameters, that enables periphery clock, DMA and it's interrupts.
- Note
- When you wake up SPI periphery using begin() method, you don't have to set configurations again, because old configurations are still saved in registers or in SPI handle structure.
Troubleshooting:
1. I cannot set any setting, it always returns false.
- Check if periphery really exists using instanceExists() method.
- Check if periphery is not transacting data right now (use isTransacting() method to check it).
- When using HardwareSPI_O class, check if beginTransaction() was not called, because it locks periphery. Call endTransaction() to unlock it.
Check if periphery is not locked.
2. I cannot receive, write or transfer any data.
- Check in .ioc file in your periphery settings, if it has not set "Disabled" mode.
- Check in .ioc file in your periphery settings in tab "NVIC Settings" if you have enabled all interrupts.
- Check if you have called begin() in your code before transmitting or receiving data.
- Check if you have called beginTransaction() before transaction or endTransaction() after transaction when using HardwareSPI_O class.
- Check if you have set CS(chip select, somtimes referred as NSS or SS) pin value to LOW before transaction. If isHwCS() returns true, then you don't have to set it manually.
- Check if your external SPI device is connected correctly, you can also use .ioc file to check periphery pins.
- Check if you have not changed pin mode of pin reserved for SPI periphery.
- Check if you are not using two instances of HardwareSPI or HardwareSPI_O for same SPI periphery, because one of them can lock periphery.
- Check if your MCU is supported by this library.
- If nothing helped, try to call instanceExists() method, to check if periphery really exists and then call getError() and lastTransactionStatus() to get periphery and last transaction error.
Credits
- Author
- Matej Fitoš
- Date
- June 18, 2021
- See also
- HardwareSPI
-
HardwareSPI_O
-
HardwareSPI.h
Examples:
HarwareSPIExample