[MOD] Rework for buffered SPI (#776)

This commit is contained in:
jgromes 2023-06-26 19:36:45 +02:00
parent 8acaca4884
commit a01b02fae2
7 changed files with 163 additions and 132 deletions

View file

@ -84,8 +84,10 @@ void inline ArduinoHal::spiBeginTransaction() {
spi->beginTransaction(spiSettings); spi->beginTransaction(spiSettings);
} }
uint8_t inline ArduinoHal::spiTransfer(uint8_t b) { void ArduinoHal::spiTransfer(uint8_t* out, size_t len, uint8_t* in) {
return(spi->transfer(b)); for(size_t i = 0; i < len; i++) {
in[i] = spi->transfer(out[i]);
}
} }
void inline ArduinoHal::spiEndTransaction() { void inline ArduinoHal::spiEndTransaction() {

View file

@ -47,7 +47,7 @@ class ArduinoHal : public RadioLibHal {
long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override; long pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) override;
void spiBegin() override; void spiBegin() override;
void spiBeginTransaction() 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 spiEndTransaction() override;
void spiEnd() override; void spiEnd() override;

View file

@ -20,16 +20,16 @@ void RadioLibHal::tone(uint32_t pin, unsigned int frequency, unsigned long durat
(void)pin; (void)pin;
(void)frequency; (void)frequency;
(void)duration; (void)duration;
}; }
void RadioLibHal::noTone(uint32_t pin) { void RadioLibHal::noTone(uint32_t pin) {
(void)pin; (void)pin;
}; }
void RadioLibHal::yield() { void RadioLibHal::yield() {
}; }
uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) { uint32_t RadioLibHal::pinToInterrupt(uint32_t pin) {
return(pin); return(pin);
}; }

View file

@ -146,11 +146,12 @@ class RadioLibHal {
virtual void spiBeginTransaction() = 0; virtual void spiBeginTransaction() = 0;
/*! /*!
\brief Method to transfer one byte over SPI. \brief Method to transfer buffer over SPI.
\param b Byte to send. \param out Buffer to send.
\returns Received byte. \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. \brief Method to end SPI transaction.

View file

@ -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) { void Module::SPItransfer(uint8_t cmd, uint16_t reg, uint8_t* dataOut, uint8_t* dataIn, size_t numBytes) {
// start SPI transaction // prepare the buffers
this->hal->spiBeginTransaction(); size_t buffLen = this->SPIaddrWidth/8 + numBytes;
#if defined(RADIOLIB_STATIC_ONLY)
// pull CS low uint8_t buffOut[RADIOLIB_STATIC_ARRAY_SIZE];
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); uint8_t buffIn[RADIOLIB_STATIC_ARRAY_SIZE];
#else
// send SPI register address with access command uint8_t* buffOut = new uint8_t[buffLen];
if(this->SPIaddrWidth <= 8) { uint8_t* buffIn = new uint8_t[buffLen];
this->hal->spiTransfer(reg | cmd);
} else {
this->hal->spiTransfer((reg >> 8) | cmd);
this->hal->spiTransfer(reg & 0xFF);
}
#if defined(RADIOLIB_VERBOSE)
if(cmd == SPIwriteCommand) {
RADIOLIB_VERBOSE_PRINT("W");
} else if(cmd == SPIreadCommand) {
RADIOLIB_VERBOSE_PRINT("R");
}
RADIOLIB_VERBOSE_PRINT("\t%X\t", reg);
#endif #endif
uint8_t* buffOutPtr = buffOut;
// send data or get response // copy the command
if(this->SPIaddrWidth <= 8) {
*(buffOutPtr++) = reg | cmd;
} else {
*(buffOutPtr++) = (reg >> 8) | cmd;
*(buffOutPtr++) = reg & 0xFF;
}
// copy the data
if(cmd == SPIwriteCommand) { if(cmd == SPIwriteCommand) {
if(dataOut != NULL) { memcpy(buffOutPtr, dataOut, numBytes);
for(size_t n = 0; n < numBytes; n++) { } else {
this->hal->spiTransfer(dataOut[n]); memset(buffOutPtr, this->SPInopCommand, numBytes);
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 // 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); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh);
// end SPI transaction // copy the data
this->hal->spiEndTransaction(); 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\t%X\t", reg);
debugBuffPtr = &buffOut[this->SPIaddrWidth/8];
} else if(cmd == SPIreadCommand) {
RADIOLIB_VERBOSE_PRINT("R\t%X\t", reg);
debugBuffPtr = &buffIn[this->SPIaddrWidth/8];
}
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t", debugBuffPtr[n]);
}
RADIOLIB_VERBOSE_PRINTLN();
#endif
#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) { 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) { 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) // prepare the buffers
uint8_t debugBuff[RADIOLIB_STATIC_ARRAY_SIZE]; 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 #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 // ensure GPIO is low
if(this->gpioPin == RADIOLIB_NC) { 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)) { while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield(); this->hal->yield();
if(this->hal->millis() - start >= timeout) { 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); return(RADIOLIB_ERR_SPI_CMD_TIMEOUT);
} }
} }
} }
// pull NSS low // do the transfer
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow); this->hal->digitalWrite(this->csPin, this->hal->GpioLevelLow);
// start transfer
this->hal->spiBeginTransaction(); this->hal->spiBeginTransaction();
this->hal->spiTransfer(buffOut, buffLen, buffIn);
// 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->spiEndTransaction(); this->hal->spiEndTransaction();
this->hal->digitalWrite(this->csPin, this->hal->GpioLevelHigh); 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)) { while(this->hal->digitalRead(this->gpioPin)) {
this->hal->yield(); this->hal->yield();
if(this->hal->millis() - start >= timeout) { if(this->hal->millis() - start >= timeout) {
state = RADIOLIB_ERR_SPI_CMD_TIMEOUT; RADIOLIB_DEBUG_PRINTLN("GPIO post-transfer timeout, is it connected?");
break; #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) #if defined(RADIOLIB_VERBOSE)
// print command byte(s) // print command byte(s)
RADIOLIB_VERBOSE_PRINT("CMD\t"); RADIOLIB_VERBOSE_PRINT("CMD");
for(uint8_t n = 0; n < cmdLen; n++) { 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_PRINT("%X\t", cmd[n]);
} }
RADIOLIB_VERBOSE_PRINTLN(); RADIOLIB_VERBOSE_PRINTLN();
// print data bytes // print data bytes
RADIOLIB_VERBOSE_PRINT("DAT"); RADIOLIB_VERBOSE_PRINT("SI\t");
if(write) { for(; n < buffLen; n++) {
RADIOLIB_VERBOSE_PRINT("W\t"); RADIOLIB_VERBOSE_PRINT("%X\t", buffOut[n]);
for(size_t n = 0; n < numBytes; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", dataOut[n], debugBuff[n]);
} }
RADIOLIB_VERBOSE_PRINTLN(); RADIOLIB_VERBOSE_PRINTLN();
} else { RADIOLIB_VERBOSE_PRINT("SO\t");
RADIOLIB_VERBOSE_PRINT("R\t%X\t%X\t", this->SPInopCommand, debugBuff[0]); for(n = cmdLen; n < buffLen; n++) {
RADIOLIB_VERBOSE_PRINT("%X\t", buffIn[n]);
}
RADIOLIB_VERBOSE_PRINTLN();
#endif
for(size_t n = 0; n < numBytes; n++) { #if !defined(RADIOLIB_STATIC_ONLY)
RADIOLIB_VERBOSE_PRINT("%X\t%X\t", this->SPInopCommand, dataIn[n]); delete[] buffOut;
} delete[] buffIn;
RADIOLIB_VERBOSE_PRINTLN();
}
RADIOLIB_VERBOSE_PRINTLN();
#endif #endif
return(state); return(state);

View file

@ -1181,7 +1181,8 @@ void CC1101::SPIsendCommand(uint8_t cmd) {
this->mod->hal->spiBeginTransaction(); this->mod->hal->spiBeginTransaction();
// send the command byte // 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 // stop transfer
this->mod->hal->spiEndTransaction(); this->mod->hal->spiEndTransaction();

View file

@ -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) { void nRF24::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes) {
// start transfer // 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;
// copy the command
*(buffOutPtr++) = cmd;
// copy the data
if(write) {
memcpy(buffOutPtr, dataOut, numBytes);
} else {
memset(buffOutPtr, 0x00, numBytes);
}
// do the transfer
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow); this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow);
this->mod->hal->spiBeginTransaction(); this->mod->hal->spiBeginTransaction();
this->mod->hal->spiTransfer(buffOut, buffLen, buffIn);
// send command
this->mod->hal->spiTransfer(cmd);
// send data
if(write) {
for(uint8_t i = 0; i < numBytes; i++) {
this->mod->hal->spiTransfer(dataOut[i]);
}
} else {
for(uint8_t i = 0; i < numBytes; i++) {
dataIn[i] = this->mod->hal->spiTransfer(0x00);
}
}
// stop transfer
this->mod->hal->spiEndTransaction(); this->mod->hal->spiEndTransaction();
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh); 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 #endif