A very simple software SPI library for the MAX32630FTHR board. It was designed to support the max31865 and RadioHead libraries I ported for my Rocket mbed project.
Revision 0:8a4db0f083fc, committed 2017-06-11
- Comitter:
- danjulio
- Date:
- Sun Jun 11 04:04:19 2017 +0000
- Commit message:
- Initial commit
Changed in this revision
swspi.cpp | Show annotated file Show diff for this revision Revisions of this file |
swspi.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 8a4db0f083fc swspi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/swspi.cpp Sun Jun 11 04:04:19 2017 +0000 @@ -0,0 +1,125 @@ +// Software (bit-banged) SPI Module supporting two modes. +// Each mode consists of a CS and CPHA mode +// + +#include <swspi.h> +#include "mbed.h" + + +swspi::swspi(PinName mosiPin, PinName misoPin, PinName sckPin, PinName ss1Pin, PinName ss2Pin) +{ + mosiP = new DigitalOut(mosiPin); + misoP = new DigitalIn(misoPin); + sckP = new DigitalOut(sckPin); + ss1P = new DigitalOut(ss1Pin); + ss2P = new DigitalOut(ss2Pin); +} + +void swspi::init() +{ + sckP->write(0); + mosiP->write(0); + ss1P->write(1); + ss2P->write(1); +} + +uint8_t swspi::spiRead(uint8_t reg, int cpha, int ss) +{ + uint8_t val; + + _spi_mutex.lock(); + _cpha = cpha; + _ss = ss; + _setSlaveSelect(0); + _transfer(reg & ~SPI_WRITE_MASK); // Send the address with the write mask off + val = _transfer(0); // The written value is ignored, reg value is read + _setSlaveSelect(1); + _spi_mutex.unlock(); + + return val; +} + +uint8_t swspi::spiWrite(uint8_t reg, uint8_t val, int cpha, int ss) +{ + uint8_t status = 0; + + _spi_mutex.lock(); + _cpha = cpha; + _ss = ss; + _setSlaveSelect(0); + status = _transfer(reg | SPI_WRITE_MASK); // Send the address with the write mask on + _transfer(val); // New value follows + _setSlaveSelect(1); + _spi_mutex.unlock(); + + return status; +} + +uint8_t swspi::spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len, int cpha, int ss) +{ + uint8_t status = 0; + + _spi_mutex.lock(); + _cpha = cpha; + _ss = ss; + _setSlaveSelect(0); + status = _transfer(reg & ~SPI_WRITE_MASK); // Send the start address with the write mask off + while (len--) + *dest++ = _transfer(0); + _setSlaveSelect(1); + _spi_mutex.unlock(); + + return status; +} + +uint8_t swspi::spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len, int cpha, int ss) +{ + uint8_t status = 0; + + _spi_mutex.lock(); + _cpha = cpha; + _ss = ss; + _setSlaveSelect(0); + status = _transfer(reg | SPI_WRITE_MASK); // Send the start address with the write mask on + while (len--) + _transfer(*src++); + _setSlaveSelect(1); + _spi_mutex.unlock(); + + return status; +} + +void swspi::_setSlaveSelect(int v) +{ + if (_ss == 1) + ss1P->write(v); + else + ss2P->write(v); +} + +uint8_t swspi::_transfer(uint8_t v) +{ + uint8_t reply = 0; + + if (_cpha == 0) { + // Sample on rising clock edge + for (int i=7; i>=0; i--) { + reply <<= 1; + mosiP->write( (v & (1<<i)) != 0 ? 1 : 0 ); + sckP->write(1); + if (misoP->read() == 1) reply |= 1; + sckP->write(0); + } + } else { + // Sample on falling clock edge + for (int i=7; i>=0; i--) { + reply <<= 1; + sckP->write(1); + mosiP->write( (v & (1<<i)) != 0 ? 1 : 0 ); + sckP->write(0); + if (misoP->read() == 1) reply |= 1; + } + } + + return reply; +}
diff -r 000000000000 -r 8a4db0f083fc swspi.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/swspi.h Sun Jun 11 04:04:19 2017 +0000 @@ -0,0 +1,84 @@ +// Software (bit-banged) SPI Module supporting two CPHA modes and two +// chip select signals. Yields to allow use by different threads. +// + +#ifndef sw_spi_h +#define sw_spi_h + +#include "mbed.h" +#include <stdint.h> + +// This is the bit in the SPI address that marks it as a write +#define SPI_WRITE_MASK 0x80 + + +///////////////////////////////////////////////////////////////////// +/// \class swspi swspi.h <swspi.h> +/// \brief bit-banged SPI + +class swspi +{ +public: + /// Constructor + /// \param[in] mosiPin pin number for MOSI + /// \param[in] misoPin pin number for MISO + /// \param[in] sckPin pin number for SCK + /// \param[in] ss1Pin pin number for Slave Select 1 + /// \param[in] ss2Pin pin number for Slave Select 2 + swspi(PinName mosiPin, PinName misoPin, PinName sckPin, PinName ss1Pin, PinName ss2Pin); + + /// Initialise the Driver transport hardware and software. + /// Make sure the Driver is properly configured before calling init(). + void init(); + + /// Reads a single register from the SPI device + /// \param[in] reg Register number + /// \return The value of the register + uint8_t spiRead(uint8_t reg, int cpha, int ss); + + /// Writes a single byte to the SPI device + /// \param[in] reg Register number + /// \param[in] val The value to write + /// \return Some devices return a status byte during the first data transfer. This byte is returned. + /// it may or may not be meaningfule depending on the the type of device being accessed. + uint8_t spiWrite(uint8_t reg, uint8_t val, int cpha, int ss); + + /// Reads a number of consecutive registers from the SPI device using burst read mode + /// \param[in] reg Register number of the first register + /// \param[in] dest Array to write the register values to. Must be at least len bytes + /// \param[in] len Number of bytes to read + /// \return Some devices return a status byte during the first data transfer. This byte is returned. + /// it may or may not be meaningfule depending on the the type of device being accessed. + uint8_t spiBurstRead(uint8_t reg, uint8_t* dest, uint8_t len, int cpha, int ss); + + /// Write a number of consecutive registers using burst write mode + /// \param[in] reg Register number of the first register + /// \param[in] src Array of new register values to write. Must be at least len bytes + /// \param[in] len Number of bytes to write + /// \return Some devices return a status byte during the first data transfer. This byte is returned. + /// it may or may not be meaningfule depending on the the type of device being accessed. + uint8_t spiBurstWrite(uint8_t reg, const uint8_t* src, uint8_t len, int cpha, int ss); + +protected: + + void _setSlaveSelect(int v); + uint8_t _transfer(uint8_t v); + + /// Pins + DigitalOut* mosiP; + DigitalIn* misoP; + DigitalOut* sckP; + DigitalOut* ss1P; + DigitalOut* ss2P; + + /// The current transfer data phase + int _cpha; + + /// The current transfer slave select + uint8_t _ss; + + // Access control + Mutex _spi_mutex; +}; + +#endif