#include <Adafruit_SPIDevice.h> #include <Arduino.h> //#define DEBUG_SERIAL Serial /*! * @brief Create an SPI device with the given CS pin and settins * @param cspin The arduino pin number to use for chip select * @param freq The SPI clock frequency to use, defaults to 1MHz * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST * @param dataMode The SPI mode to use, defaults to SPI_MODE0 * @param theSPI The SPI bus to use, defaults to &theSPI */ Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq, BitOrder dataOrder, uint8_t dataMode, SPIClass *theSPI) { _cs = cspin; _sck = _mosi = _miso = -1; _spi = theSPI; _begun = false; _spiSetting = new SPISettings(freq, dataOrder, dataMode); _freq = freq; _dataOrder = dataOrder; _dataMode = dataMode; } /*! * @brief Create an SPI device with the given CS pin and settins * @param cspin The arduino pin number to use for chip select * @param sckpin The arduino pin number to use for SCK * @param misopin The arduino pin number to use for MISO, set to -1 if not used * @param mosipin The arduino pin number to use for MOSI, set to -1 if not used * @param freq The SPI clock frequency to use, defaults to 1MHz * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST * @param dataMode The SPI mode to use, defaults to SPI_MODE0 */ Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin, int8_t misopin, int8_t mosipin, uint32_t freq, BitOrder dataOrder, uint8_t dataMode) { _cs = cspin; _sck = sckpin; _miso = misopin; _mosi = mosipin; _freq = freq; _dataOrder = dataOrder; _dataMode = dataMode; _begun = false; _spiSetting = new SPISettings(freq, dataOrder, dataMode); _spi = NULL; } /*! * @brief Initializes SPI bus and sets CS pin high * @return Always returns true because there's no way to test success of SPI init */ bool Adafruit_SPIDevice::begin(void) { pinMode(_cs, OUTPUT); digitalWrite(_cs, HIGH); if (_spi) { // hardware SPI _spi->begin(); } else { pinMode(_sck, OUTPUT); if (_dataMode==SPI_MODE0) { digitalWrite(_sck, HIGH); } else { digitalWrite(_sck, LOW); } if (_mosi != -1) { pinMode(_mosi, OUTPUT); digitalWrite(_mosi, HIGH); } if (_miso != -1) { pinMode(_miso, INPUT); } } _begun = true; return true; } /*! * @brief Transfer (send/receive) one byte over hard/soft SPI * @param buffer The buffer to send and receive at the same time * @param len The number of bytes to transfer */ void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { if (_spi) { // hardware SPI is easy _spi->transfer(buffer, len); return; } // for softSPI we'll do it by hand for (size_t i=0; i<len; i++) { // software SPI uint8_t reply = 0; uint8_t send = buffer[i]; if (_dataOrder == SPI_BITORDER_LSBFIRST) { // LSB is rare, if it happens we'll just flip the bits around for them uint8_t temp = 0; for (uint8_t b=0; b<8; b++) { temp |= ((send >> b) & 0x1) << (7-b); } send = temp; } for (int b=7; b>=0; b--) { reply <<= 1; if (_dataMode == SPI_MODE0) { digitalWrite(_sck, LOW); digitalWrite(_mosi, send & (1<<b)); digitalWrite(_sck, HIGH); if ((_miso != -1) && digitalRead(_miso)) { reply |= 1; } } if (_dataMode == SPI_MODE1) { digitalWrite(_sck, HIGH); digitalWrite(_mosi, send & (1<<b)); digitalWrite(_sck, LOW); if ((_miso != -1) && digitalRead(_miso)) { reply |= 1; } } } if (_dataOrder == SPI_BITORDER_LSBFIRST) { // LSB is rare, if it happens we'll just flip the bits around for them uint8_t temp = 0; for (uint8_t b=0; b<8; b++) { temp |= ((reply >> b) & 0x1) << (7-b); } reply = temp; } buffer[i] = reply; } return; } /*! * @brief Transfer (send/receive) one byte over hard/soft SPI * @param send The byte to send * @return The byte received while transmitting */ uint8_t Adafruit_SPIDevice::transfer(uint8_t send) { uint8_t data = send; transfer(&data, 1); return data; } /*! * @brief Write a buffer or two to the SPI device. * @param buffer Pointer to buffer of data to write * @param len Number of bytes from buffer to write * @param prefix_buffer Pointer to optional array of data to write before buffer. * @param prefix_len Number of bytes from prefix buffer to write * @return Always returns true because there's no way to test success of SPI writes */ bool Adafruit_SPIDevice::write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer, size_t prefix_len) { if (_spi) { _spi->beginTransaction(*_spiSetting); } digitalWrite(_cs, LOW); // do the writing for (size_t i=0; i<prefix_len; i++) { transfer(prefix_buffer[i]); } for (size_t i=0; i<len; i++) { transfer(buffer[i]); } digitalWrite(_cs, HIGH); if (_spi) { _spi->endTransaction(); } #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); if ((prefix_len != 0) && (prefix_buffer != NULL)) { for (uint16_t i=0; i<prefix_len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(prefix_buffer[i], HEX); DEBUG_SERIAL.print(F(", ")); } } for (uint16_t i=0; i<len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(buffer[i], HEX); DEBUG_SERIAL.print(F(", ")); if (len % 32 == 31) { DEBUG_SERIAL.println(); } } DEBUG_SERIAL.println(); #endif return true; } /*! * @brief Read from SPI into a buffer from the SPI device. * @param buffer Pointer to buffer of data to read into * @param len Number of bytes from buffer to read. * @param sendvalue The 8-bits of data to write when doing the data read, defaults to 0xFF * @return Always returns true because there's no way to test success of SPI writes */ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { memset(buffer, sendvalue, len); // clear out existing buffer if (_spi) { _spi->beginTransaction(*_spiSetting); } digitalWrite(_cs, LOW); transfer(buffer, len); digitalWrite(_cs, HIGH); if (_spi) { _spi->endTransaction(); } #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); for (uint16_t i=0; i<len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(buffer[i], HEX); DEBUG_SERIAL.print(F(", ")); if (len % 32 == 31) { DEBUG_SERIAL.println(); } } DEBUG_SERIAL.println(); #endif return true; } /*! * @brief Write some data, then read some data from SPI into another buffer. The buffers can point to same/overlapping locations. This does not transmit-receive at the same time! * @param write_buffer Pointer to buffer of data to write from * @param write_len Number of bytes from buffer to write. * @param read_buffer Pointer to buffer of data to read into. * @param read_len Number of bytes from buffer to read. * @param sendvalue The 8-bits of data to write when doing the data read, defaults to 0xFF * @return Always returns true because there's no way to test success of SPI writes */ bool Adafruit_SPIDevice::write_then_read(uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue) { if (_spi) { _spi->beginTransaction(*_spiSetting); } digitalWrite(_cs, LOW); // do the writing for (size_t i=0; i<write_len; i++) { transfer(write_buffer[i]); } #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); for (uint16_t i=0; i<write_len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(write_buffer[i], HEX); DEBUG_SERIAL.print(F(", ")); if (write_len % 32 == 31) { DEBUG_SERIAL.println(); } } DEBUG_SERIAL.println(); #endif // do the reading for (size_t i=0; i<read_len; i++) { read_buffer[i] = transfer(sendvalue); } #ifdef DEBUG_SERIAL DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); for (uint16_t i=0; i<read_len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(read_buffer[i], HEX); DEBUG_SERIAL.print(F(", ")); if (read_len % 32 == 31) { DEBUG_SERIAL.println(); } } DEBUG_SERIAL.println(); #endif digitalWrite(_cs, HIGH); if (_spi) { _spi->endTransaction(); } return true; }