From a01b02fae207b62a5e605484822606e751c8f308 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 26 Jun 2023 19:36:45 +0200 Subject: [PATCH] [MOD] Rework for buffered SPI (#776) --- src/ArduinoHal.cpp | 6 +- src/ArduinoHal.h | 2 +- src/Hal.cpp | 8 +- src/Hal.h | 9 +- src/Module.cpp | 225 ++++++++++++++++++---------------- src/modules/CC1101/CC1101.cpp | 3 +- src/modules/nRF24/nRF24.cpp | 42 +++++-- 7 files changed, 163 insertions(+), 132 deletions(-) diff --git a/src/ArduinoHal.cpp b/src/ArduinoHal.cpp index fe471c15..d42f0d0b 100644 --- a/src/ArduinoHal.cpp +++ b/src/ArduinoHal.cpp @@ -84,8 +84,10 @@ void inline ArduinoHal::spiBeginTransaction() { spi->beginTransaction(spiSettings); } -uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { - return(spi->transfer(b)); +void ArduinoHal::spiTransfer(uint8_t* out, size_t len, uint8_t* in) { + for(size_t i = 0; i < len; i++) { + in[i] = spi->transfer(out[i]); + } } void inline ArduinoHal::spiEndTransaction() { diff --git a/src/ArduinoHal.h b/src/ArduinoHal.h index 69fe50f5..59b0f1aa 100644 --- a/src/ArduinoHal.h +++ b/src/ArduinoHal.h @@ -47,7 +47,7 @@ class ArduinoHal : public RadioLibHal { long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; void spiBegin() override; void spiBeginTransaction() override; - uint8_t spiTransfer(uint8_t b) override; + void spiTransfer(uint8_t* out, size_t len, uint8_t* in) override; void spiEndTransaction() override; void spiEnd() override; diff --git a/src/Hal.cpp b/src/Hal.cpp index 0961fa4f..1a42aa15 100644 --- a/src/Hal.cpp +++ b/src/Hal.cpp @@ -20,16 +20,16 @@ void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long durat (void)pin; (void)frequency; (void)duration; -}; +} void RadioLibHal::noTone(uint32_t pin) { (void)pin; -}; +} void RadioLibHal::yield() { -}; +} uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { return(pin); -}; +} diff --git a/src/Hal.h b/src/Hal.h index 64bfea2f..87fb561e 100644 --- a/src/Hal.h +++ b/src/Hal.h @@ -146,11 +146,12 @@ class RadioLibHal { virtual void spiBeginTransaction() = 0; /*! - \brief Method to transfer one byte over SPI. - \param b Byte to send. - \returns Received byte. + \brief Method to transfer buffer over SPI. + \param out Buffer to send. + \param len Number of data to send or receive. + \param in Buffer to save received data into. */ - virtual uint8_t spiTransfer(uint8_t b) = 0; + virtual void spiTransfer(uint8_t* out, size_t len, uint8_t* in) = 0; /*! \brief Method to end SPI transaction. diff --git a/src/Module.cpp b/src/Module.cpp index 3959dee8..37da31d6 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -139,52 +139,64 @@ void Module::SPIwriteRegister(uint16_t reg, uint8_t data) { } void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) { - // start SPI transaction - this->hal->spiBeginTransaction(); + // prepare the buffers + size_t buffLen = this->SPIaddrWidth/8 + numBytes; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; - // pull CS low - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); - - // send SPI register address with access command + // copy the command if(this->SPIaddrWidth <= 8) { - this->hal->spiTransfer(reg | cmd); + *(buffOutPtr++) = reg | cmd; } else { - this->hal->spiTransfer((reg >> 8) | cmd); - this->hal->spiTransfer(reg & 0xFF); + *(buffOutPtr++) = (reg >> 8) | cmd; + *(buffOutPtr++) = reg & 0xFF; } + // copy the data + if(cmd == SPIwriteCommand) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes); + } + + // do the transfer + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); + this->hal->spiBeginTransaction(); + this->hal->spiTransfer(buffOut, buffLen, buffIn); + this->hal->spiEndTransaction(); + this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); + + // copy the data + if(cmd == SPIreadCommand) { + memcpy(dataIn, &buffIn[this->SPIaddrWidth/8], numBytes); + } + + // print debug information #if defined(RADIOLIB_VERBOSE) + uint8_t* debugBuffPtr = NULL; if(cmd == SPIwriteCommand) { - RADIOLIB_VERBOSE_PRINT("W"); + RADIOLIB_VERBOSE_PRINT("W\t%X\t", reg); + debugBuffPtr = &buffOut[this->SPIaddrWidth/8]; } else if(cmd == SPIreadCommand) { - RADIOLIB_VERBOSE_PRINT("R"); + RADIOLIB_VERBOSE_PRINT("R\t%X\t", reg); + debugBuffPtr = &buffIn[this->SPIaddrWidth/8]; } - RADIOLIB_VERBOSE_PRINT("\t%X\t", reg); + for(size_t n = 0; n < numBytes; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", debugBuffPtr[n]); + } + RADIOLIB_VERBOSE_PRINTLN(); #endif - // send data or get response - if(cmd == SPIwriteCommand) { - if(dataOut != NULL) { - for(size_t n = 0; n < numBytes; n++) { - this->hal->spiTransfer(dataOut[n]); - RADIOLIB_VERBOSE_PRINT("%X\t", dataOut[n]); - } - } - } else if (cmd == SPIreadCommand) { - if(dataIn != NULL) { - for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->hal->spiTransfer(0x00); - RADIOLIB_VERBOSE_PRINT("%X\t", dataIn[n]); - } - } - } - RADIOLIB_VERBOSE_PRINTLN(); - - // release CS - this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); - - // end SPI transaction - this->hal->spiEndTransaction(); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif } int16_t Module::SPIreadStream(uint8_t cmd, uint8_t* data, size_t numBytes, bool waitForGpio, bool verify) { @@ -241,9 +253,31 @@ int16_t Module::SPIcheckStream() { } int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes, bool waitForGpio, uint32_t timeout) { - #if defined(RADIOLIB_VERBOSE) - uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; + // prepare the buffers + size_t buffLen = cmdLen + numBytes; + if(!write) { + buffLen++; + } + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; #endif + uint8_t* buffOutPtr = buffOut; + + // copy the command + for(uint8_t n = 0; n < cmdLen; n++) { + *(buffOutPtr++) = cmd[n]; + } + + // copy the data + if(write) { + memcpy(buffOutPtr, dataOut, numBytes); + } else { + memset(buffOutPtr, this->SPInopCommand, numBytes + 1); + } // ensure GPIO is low if(this->gpioPin == RADIOLIB_NC) { @@ -253,64 +287,20 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - RADIOLIB_DEBUG_PRINTLN("Timed out waiting for GPIO pin, is it connected?"); + RADIOLIB_DEBUG_PRINTLN("GPIO pre-transfer timeout, is it connected?"); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } } - // pull NSS low + // do the transfer this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); - - // start transfer this->hal->spiBeginTransaction(); - - // send command byte(s) - for(uint8_t n = 0; n < cmdLen; n++) { - this->hal->spiTransfer(cmd[n]); - } - - // variable to save error during SPI transfer - int16_t state = RADIOLIB_ERR_NONE; - - // send/receive all bytes - if(write) { - for(size_t n = 0; n < numBytes; n++) { - // send byte - uint8_t in = this->hal->spiTransfer(dataOut[n]); - #if defined(RADIOLIB_VERBOSE) - debugBuff[n] = in; - #endif - - // check status - if(this->SPIparseStatusCb != nullptr) { - state = this->SPIparseStatusCb(in); - } - } - - } else { - // skip the first byte for read-type commands (status-only) - uint8_t in = this->hal->spiTransfer(this->SPInopCommand); - #if defined(RADIOLIB_VERBOSE) - debugBuff[0] = in; - #endif - - // check status - if(this->SPIparseStatusCb != nullptr) { - state = this->SPIparseStatusCb(in); - } else { - state = RADIOLIB_ERR_NONE; - } - - // read the data - if(state == RADIOLIB_ERR_NONE) { - for(size_t n = 0; n < numBytes; n++) { - dataIn[n] = this->hal->spiTransfer(this->SPInopCommand); - } - } - } - - // stop transfer + this->hal->spiTransfer(buffOut, buffLen, buffIn); this->hal->spiEndTransaction(); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); @@ -324,39 +314,60 @@ int16_t Module::SPItransferStream(uint8_t* cmd, uint8_t cmdLen, bool write, uint while(this->hal->digitalRead(this->gpioPin)) { this->hal->yield(); if(this->hal->millis() - start >= timeout) { - state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; - break; + RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?"); + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif + return(RADIOLIB_ERR_SPI_CMD_TIMEOUT); } } } } - // print debug output + // parse status + int16_t state = RADIOLIB_ERR_NONE; + if(this->SPIparseStatusCb != nullptr) { + state = this->SPIparseStatusCb(buffIn[0]); + } + + // copy the data + if(!write) { + // skip the first byte for read-type commands (status-only) + memcpy(dataIn, &buffIn[cmdLen + 1], numBytes); + } + + // print debug information #if defined(RADIOLIB_VERBOSE) // print command byte(s) - RADIOLIB_VERBOSE_PRINT("CMD\t"); - for(uint8_t n = 0; n < cmdLen; n++) { + RADIOLIB_VERBOSE_PRINT("CMD"); + if(write) { + RADIOLIB_VERBOSE_PRINT("W\t"); + } else { + RADIOLIB_VERBOSE_PRINT("R\t"); + } + size_t n = 0; + for(; n < cmdLen; n++) { RADIOLIB_VERBOSE_PRINT("%X\t", cmd[n]); } RADIOLIB_VERBOSE_PRINTLN(); // print data bytes - RADIOLIB_VERBOSE_PRINT("DAT"); - if(write) { - RADIOLIB_VERBOSE_PRINT("W\t"); - for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]); - } - RADIOLIB_VERBOSE_PRINTLN(); - } else { - RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]); - - for(size_t n = 0; n < numBytes; n++) { - RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]); - } - RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_VERBOSE_PRINT("SI\t"); + for(; n < buffLen; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", buffOut[n]); } RADIOLIB_VERBOSE_PRINTLN(); + RADIOLIB_VERBOSE_PRINT("SO\t"); + for(n = cmdLen; n < buffLen; n++) { + RADIOLIB_VERBOSE_PRINT("%X\t", buffIn[n]); + } + RADIOLIB_VERBOSE_PRINTLN(); + #endif + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; #endif return(state); diff --git a/src/modules/CC1101/CC1101.cpp b/src/modules/CC1101/CC1101.cpp index 52a9b6bc..235ef13d 100644 --- a/src/modules/CC1101/CC1101.cpp +++ b/src/modules/CC1101/CC1101.cpp @@ -1181,7 +1181,8 @@ void CC1101::SPIsendCommand(uint8_t cmd) { this->mod->hal->spiBeginTransaction(); // send the command byte - uint8_t status = this->mod->hal->spiTransfer(cmd); + uint8_t status = 0; + this->mod->hal->spiTransfer(&cmd, 1, &status); // stop transfer this->mod->hal->spiEndTransaction(); diff --git a/src/modules/nRF24/nRF24.cpp b/src/modules/nRF24/nRF24.cpp index 3257187b..c48b5b17 100644 --- a/src/modules/nRF24/nRF24.cpp +++ b/src/modules/nRF24/nRF24.cpp @@ -615,27 +615,43 @@ void nRF24::SPIwriteTxPayload(uint8_t* data, uint8_t numBytes) { } void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) { - // start transfer - this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); - this->mod->hal->spiBeginTransaction(); + // prepare the buffers + size_t buffLen = 1 + numBytes; + #if defined(RADIOLIB_STATIC_ONLY) + uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE]; + uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE]; + #else + uint8_t* buffOut = new uint8_t[buffLen]; + uint8_t* buffIn = new uint8_t[buffLen]; + #endif + uint8_t* buffOutPtr = buffOut; - // send command - this->mod->hal->spiTransfer(cmd); + // copy the command + *(buffOutPtr++) = cmd; - // send data + // copy the data if(write) { - for(uint8_t i = 0; i < numBytes; i++) { - this->mod->hal->spiTransfer(dataOut[i]); - } + memcpy(buffOutPtr, dataOut, numBytes); } else { - for(uint8_t i = 0; i < numBytes; i++) { - dataIn[i] = this->mod->hal->spiTransfer(0x00); - } + memset(buffOutPtr, 0x00, numBytes); } - // stop transfer + // do the transfer + this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); + this->mod->hal->spiBeginTransaction(); + this->mod->hal->spiTransfer(buffOut, buffLen, buffIn); this->mod->hal->spiEndTransaction(); this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); + + // copy the data + if(!write) { + memcpy(dataIn, &buffIn[1], numBytes); + } + + #if !defined(RADIOLIB_STATIC_ONLY) + delete[] buffOut; + delete[] buffIn; + #endif } #endif