123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- #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;
- #ifdef BUSIO_USE_FAST_PINIO
- csPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(cspin));
- csPinMask = digitalPinToBitMask(cspin);
- if (mosipin != -1) {
- mosiPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(mosipin));
- mosiPinMask = digitalPinToBitMask(mosipin);
- }
- if (misopin != -1) {
- misoPort = (BusIO_PortReg *)portInputRegister(digitalPinToPort(misopin));
- misoPinMask = digitalPinToBitMask(misopin);
- }
- clkPort = (BusIO_PortReg *)portOutputRegister(digitalPinToPort(sckpin));
- clkPinMask = digitalPinToBitMask(sckpin);
- #endif
- _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) || (_dataMode == SPI_MODE1)) {
- // idle low on mode 0 and 1
- digitalWrite(_sck, LOW);
- } else {
- // idle high on mode 2 or 3
- digitalWrite(_sck, HIGH);
- }
- 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
- #if defined(SPARK)
- _spi->transfer(buffer, buffer, len, NULL);
- #elif defined(STM32)
- for (size_t i = 0; i < len; i++) {
- _spi->transfer(buffer[i]);
- }
- #else
- _spi->transfer(buffer, len);
- #endif
- return;
- }
- uint8_t startbit;
- if (_dataOrder == SPI_BITORDER_LSBFIRST) {
- startbit = 0x1;
- } else {
- startbit = 0x80;
- }
- bool towrite, lastmosi = !(buffer[0] & startbit);
- uint8_t bitdelay_us = (1000000 / _freq) / 2;
- // 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];
- /*
- Serial.print("\tSending software SPI byte 0x");
- Serial.print(send, HEX);
- Serial.print(" -> 0x");
- */
- // Serial.print(send, HEX);
- for (uint8_t b = startbit; b != 0;
- b = (_dataOrder == SPI_BITORDER_LSBFIRST) ? b << 1 : b >> 1) {
- if (bitdelay_us) {
- delayMicroseconds(bitdelay_us);
- }
- if (_dataMode == SPI_MODE0 || _dataMode == SPI_MODE2) {
- towrite = send & b;
- if ((_mosi != -1) && (lastmosi != towrite)) {
- #ifdef BUSIO_USE_FAST_PINIO
- if (towrite)
- *mosiPort |= mosiPinMask;
- else
- *mosiPort &= ~mosiPinMask;
- #else
- digitalWrite(_mosi, towrite);
- #endif
- lastmosi = towrite;
- }
- #ifdef BUSIO_USE_FAST_PINIO
- *clkPort |= clkPinMask; // Clock high
- #else
- digitalWrite(_sck, HIGH);
- #endif
- if (bitdelay_us) {
- delayMicroseconds(bitdelay_us);
- }
- if (_miso != -1) {
- #ifdef BUSIO_USE_FAST_PINIO
- if (*misoPort & misoPinMask) {
- #else
- if (digitalRead(_miso)) {
- #endif
- reply |= b;
- }
- }
- #ifdef BUSIO_USE_FAST_PINIO
- *clkPort &= ~clkPinMask; // Clock low
- #else
- digitalWrite(_sck, LOW);
- #endif
- } else { // if (_dataMode == SPI_MODE1 || _dataMode == SPI_MODE3)
- #ifdef BUSIO_USE_FAST_PINIO
- *clkPort |= clkPinMask; // Clock high
- #else
- digitalWrite(_sck, HIGH);
- #endif
- if (bitdelay_us) {
- delayMicroseconds(bitdelay_us);
- }
- if (_mosi != -1) {
- #ifdef BUSIO_USE_FAST_PINIO
- if (send & b)
- *mosiPort |= mosiPinMask;
- else
- *mosiPort &= ~mosiPinMask;
- #else
- digitalWrite(_mosi, send & b);
- #endif
- }
- #ifdef BUSIO_USE_FAST_PINIO
- *clkPort &= ~clkPinMask; // Clock low
- #else
- digitalWrite(_sck, LOW);
- #endif
- if (_miso != -1) {
- #ifdef BUSIO_USE_FAST_PINIO
- if (*misoPort & misoPinMask) {
- #else
- if (digitalRead(_miso)) {
- #endif
- reply |= b;
- }
- }
- }
- if (_miso != -1) {
- 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 Manually begin a transaction (calls beginTransaction if hardware
- * SPI)
- */
- void Adafruit_SPIDevice::beginTransaction(void) {
- if (_spi) {
- _spi->beginTransaction(*_spiSetting);
- }
- }
- /*!
- * @brief Manually end a transaction (calls endTransaction if hardware SPI)
- */
- void Adafruit_SPIDevice::endTransaction(void) {
- if (_spi) {
- _spi->endTransaction();
- }
- }
- /*!
- * @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 (i % 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;
- }
|