From 059c87e2f891eefdc45c48186153797c12619f18 Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Sat, 7 May 2022 18:01:58 +0200 Subject: [PATCH 1/9] chunked transfers for a big improvement in performance If the code doesn't run on an 8bit-AVR, the data is prepared by transmitting the reads and writes in chunks instead of byte for byte. A constant is used for the chunk size. This is a tradeof between RAM/CPU and bus speed: on the 'bigger' arduino platforms the CPU is a lot faster than the SPI and there is a lot of RAM avaible, so using more RAM/CPU cycles and then letting the DMA do its work is the way to go. The chunked transfers also combine the reads and writes, so the dead time in between is removed, which is especially important for register reads of SPI-attached chips. Chunked transfers give an improvement of about 40% over bytewise ones, additionally +5% in the case of small reads/writes as used in BusIO_Register by removing the dead time between writing and reading. This is for all supported platforms except 8bit AVRs, which are specifically #if'd out. The special case for the ESP32 is therefore removed and ARM M0/M4, ESP8266, teensy etc should profit of this improvement too, without special casing each platform by using non standard arduino core extensions. --- Adafruit_SPIDevice.cpp | 266 ++++++++++++++++++++++++++++++----------- 1 file changed, 194 insertions(+), 72 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 44a8f55..6cabac4 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -1,10 +1,55 @@ #include "Adafruit_SPIDevice.h" +#if !defined(__AVR__) +#include +#endif + #if !defined(SPI_INTERFACES_COUNT) || \ (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) +//! constant for the buffer size for the chunked transfer +constexpr size_t maxBufferSizeForChunkedTransfer = 64; + //#define DEBUG_SERIAL Serial +#ifdef DEBUG_SERIAL +#if !defined(__AVR__) +template +static void printChunk(const char *title, const T &buffer, const uint8_t size, + const uint16_t chunkNumber) { + DEBUG_SERIAL.print(F("\t")); + DEBUG_SERIAL.print(title); + DEBUG_SERIAL.print(F(" Chunk #")); + DEBUG_SERIAL.print(chunkNumber); + DEBUG_SERIAL.print(F(", size ")); + DEBUG_SERIAL.println(size); + DEBUG_SERIAL.print(F("\t")); + + for (uint8_t i = 0; i < size; ++i) { + DEBUG_SERIAL.print(F("0x")); + DEBUG_SERIAL.print(buffer[i], HEX); + DEBUG_SERIAL.print(F(", ")); + } + DEBUG_SERIAL.println(); +} +#endif + +static void printBuffer(const char *title, const uint8_t *buffer, + const size_t len) { + DEBUG_SERIAL.print(F("\t")); + DEBUG_SERIAL.println(title); + for (size_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 + /*! * @brief Create an SPI device with the given CS pin and settings * @param cspin The arduino pin number to use for chip select @@ -160,7 +205,6 @@ void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { // 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); } @@ -326,49 +370,77 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, const uint8_t *prefix_buffer, size_t prefix_len) { +#if !defined(__AVR__) + std::array chunkBuffer; + + auto chunkBufferIterator = chunkBuffer.begin(); + +#ifdef DEBUG_SERIAL + uint8_t chunkNumber = 1; +#endif + beginTransactionWithAssertingCS(); - // do the writing -#if defined(ARDUINO_ARCH_ESP32) - if (_spi) { - if (prefix_len > 0) { - _spi->transferBytes(prefix_buffer, nullptr, prefix_len); - } - if (len > 0) { - _spi->transferBytes(buffer, nullptr, len); - } - } else + for (size_t i = 0; i < prefix_len; ++i) { + *chunkBufferIterator++ = prefix_buffer[i]; + + if (chunkBufferIterator == chunkBuffer.end()) { + transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); + chunkBufferIterator = chunkBuffer.begin(); + +#ifdef DEBUG_SERIAL + printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, + chunkNumber++); #endif - { - for (size_t i = 0; i < prefix_len; i++) { - transfer(prefix_buffer[i]); - } - for (size_t i = 0; i < len; i++) { - transfer(buffer[i]); } } - endTransactionWithDeassertingCS(); + + for (size_t i = 0; i < len; ++i) { + *chunkBufferIterator++ = buffer[i]; + + if (chunkBufferIterator == chunkBuffer.end()) { + transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); + chunkBufferIterator = chunkBuffer.begin(); #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); - if ((prefix_len != 0) && (prefix_buffer != nullptr)) { - 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(", ")); + printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, + chunkNumber++); +#endif } } - 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(); - } + + if (chunkBufferIterator != chunkBuffer.begin()) { + auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); + transfer(chunkBuffer.data(), numberByteToTransfer); + +#ifdef DEBUG_SERIAL + printChunk("write() Wrote remaining", chunkBuffer, numberByteToTransfer, + chunkNumber++); +#endif } - DEBUG_SERIAL.println(); + + endTransactionWithDeassertingCS(); + +#else // !defined(__AVR__) + + beginTransactionWithAssertingCS(); + + for (size_t i = 0; i < prefix_len; i++) { + transfer(prefix_buffer[i]); + } + for (size_t i = 0; i < len; i++) { + transfer(buffer[i]); + } + + endTransactionWithDeassertingCS(); + +#ifdef DEBUG_SERIAL + printBuffer("write() prefix_buffer", prefix_buffer, prefix_len); + printBuffer("write() buffer", buffer, len); #endif +#endif // !defined(__AVR__) + return true; } @@ -390,16 +462,7 @@ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { endTransactionWithDeassertingCS(); #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(); + printBuffer("read() buffer", buffer, len); #endif return true; @@ -421,53 +484,112 @@ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue) { +#if !defined(__AVR__) + std::array chunkBuffer; + + auto chunkBufferIterator = chunkBuffer.begin(); + +#ifdef DEBUG_SERIAL + uint8_t chunkNumber = 1; +#endif + beginTransactionWithAssertingCS(); - // do the writing -#if defined(ARDUINO_ARCH_ESP32) - if (_spi) { - if (write_len > 0) { - _spi->transferBytes(write_buffer, nullptr, write_len); - } - } else + + for (size_t i = 0; i < write_len; ++i) { + *chunkBufferIterator++ = write_buffer[i]; + + if (chunkBufferIterator == chunkBuffer.end()) { + transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); + chunkBufferIterator = chunkBuffer.begin(); + +#ifdef DEBUG_SERIAL + printChunk("write_then_read() Wrote", chunkBuffer, + maxBufferSizeForChunkedTransfer, chunkNumber++); #endif - { - for (size_t i = 0; i < write_len; i++) { - transfer(write_buffer[i]); } } + auto readBufferIterator = read_buffer; + auto readFromIterator = chunkBufferIterator; + size_t readBufferLen = read_len; + + for (size_t i = 0; i < read_len; ++i) { + *chunkBufferIterator++ = sendvalue; + + if (chunkBufferIterator == chunkBuffer.end()) { #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(); + printChunk("write_then_read() before transmit", chunkBuffer, + maxBufferSizeForChunkedTransfer, chunkNumber); +#endif + + transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); + + while (readBufferLen) { + if (readFromIterator != chunkBuffer.end()) { + *readBufferIterator++ = *readFromIterator++; + --readBufferLen; + } else { + break; + } + } + +#ifdef DEBUG_SERIAL + printChunk("write_then_read() after transmit", chunkBuffer, + maxBufferSizeForChunkedTransfer, chunkNumber++); +#endif + + chunkBufferIterator = chunkBuffer.begin(); + readFromIterator = chunkBuffer.begin(); } } - DEBUG_SERIAL.println(); + + if (chunkBufferIterator != chunkBuffer.begin()) { + auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); + +#ifdef DEBUG_SERIAL + printChunk("write_then_read() before transmit remaining", chunkBuffer, + numberByteToTransfer, chunkNumber); +#endif + + transfer(chunkBuffer.data(), numberByteToTransfer); + +#ifdef DEBUG_SERIAL + printChunk("write_then_read() after transmit remaining", chunkBuffer, + numberByteToTransfer, chunkNumber); #endif - // do the reading + while (readBufferLen) { + if (readFromIterator != chunkBuffer.end()) { + *readBufferIterator++ = *readFromIterator++; + --readBufferLen; + } else { + break; + } + } + } + + endTransactionWithDeassertingCS(); + +#else // !defined(__AVR__) + + beginTransactionWithAssertingCS(); + + for (size_t i = 0; i < write_len; i++) { + transfer(write_buffer[i]); + } + for (size_t i = 0; i < read_len; i++) { read_buffer[i] = transfer(sendvalue); } + endTransactionWithDeassertingCS(); + #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(); + printBuffer("write_then_read() write_buffer", write_buffer, write_len); + printBuffer("write_then_read() read_buffer", read_buffer, read_len); #endif - endTransactionWithDeassertingCS(); +#endif // !defined(__AVR__) return true; } From f08f37661607f0ac4eb07a61c584c18cf4b70627 Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Sat, 14 May 2022 16:03:58 +0200 Subject: [PATCH 2/9] added protected template to replace std::array<>, chunked transfer for AVR The AVR arduino platform doesn't have std::array. To use the chunked transfer mode, I added a template to replace it. It has roughly the same semantics as std::array<> and is protected to Adafruit_SPIDevice. With this template, the chunked transfer is also possible for 8bit AVRs. --- Adafruit_SPIDevice.cpp | 52 ++------------------------------------ Adafruit_SPIDevice.h | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 50 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 6cabac4..cb60721 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -7,13 +7,9 @@ #if !defined(SPI_INTERFACES_COUNT) || \ (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) -//! constant for the buffer size for the chunked transfer -constexpr size_t maxBufferSizeForChunkedTransfer = 64; - //#define DEBUG_SERIAL Serial #ifdef DEBUG_SERIAL -#if !defined(__AVR__) template static void printChunk(const char *title, const T &buffer, const uint8_t size, const uint16_t chunkNumber) { @@ -32,7 +28,6 @@ static void printChunk(const char *title, const T &buffer, const uint8_t size, } DEBUG_SERIAL.println(); } -#endif static void printBuffer(const char *title, const uint8_t *buffer, const size_t len) { @@ -370,8 +365,7 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, const uint8_t *prefix_buffer, size_t prefix_len) { -#if !defined(__AVR__) - std::array chunkBuffer; + Array chunkBuffer; auto chunkBufferIterator = chunkBuffer.begin(); @@ -421,26 +415,6 @@ bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, endTransactionWithDeassertingCS(); -#else // !defined(__AVR__) - - beginTransactionWithAssertingCS(); - - for (size_t i = 0; i < prefix_len; i++) { - transfer(prefix_buffer[i]); - } - for (size_t i = 0; i < len; i++) { - transfer(buffer[i]); - } - - endTransactionWithDeassertingCS(); - -#ifdef DEBUG_SERIAL - printBuffer("write() prefix_buffer", prefix_buffer, prefix_len); - printBuffer("write() buffer", buffer, len); -#endif - -#endif // !defined(__AVR__) - return true; } @@ -484,8 +458,7 @@ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue) { -#if !defined(__AVR__) - std::array chunkBuffer; + Array chunkBuffer; auto chunkBufferIterator = chunkBuffer.begin(); @@ -570,27 +543,6 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, endTransactionWithDeassertingCS(); -#else // !defined(__AVR__) - - beginTransactionWithAssertingCS(); - - for (size_t i = 0; i < write_len; i++) { - transfer(write_buffer[i]); - } - - for (size_t i = 0; i < read_len; i++) { - read_buffer[i] = transfer(sendvalue); - } - - endTransactionWithDeassertingCS(); - -#ifdef DEBUG_SERIAL - printBuffer("write_then_read() write_buffer", write_buffer, write_len); - printBuffer("write_then_read() read_buffer", read_buffer, read_len); -#endif - -#endif // !defined(__AVR__) - return true; } diff --git a/Adafruit_SPIDevice.h b/Adafruit_SPIDevice.h index 3a792c7..3e41614 100644 --- a/Adafruit_SPIDevice.h +++ b/Adafruit_SPIDevice.h @@ -109,6 +109,7 @@ class Adafruit_SPIDevice { uint32_t _freq; BusIOBitOrder _dataOrder; uint8_t _dataMode; + void setChipSelect(int value); int8_t _cs, _sck, _mosi, _miso; @@ -116,7 +117,63 @@ class Adafruit_SPIDevice { BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort; BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask; #endif + + //! constant for the buffer size for the chunked transfer + static constexpr size_t maxBufferSizeForChunkedTransfer = +#ifdef __AVR__ + 32; +#else + 64; +#endif bool _begun; + +protected: + /*! + * @brief Template to encypsulate a C-array, provides STL-style accessors + * analoguous to std::array<> + * @param Type the type of the array + * @param Size the size of the array + */ + template class Array { + public: + /*! @brief returns a pointer the start of the buffer + * @returns a pointer the start of the buffer + */ + Type *begin() { return buffer; } + + /*! @brief returns a pointer the one increment beyond the end of the buffer + * @returns a pointer the one increment beyond the end of the buffer + */ + Type *end() { return endPointer; } + + /*! @brief returns the size of the buffer + * @returns the size of the buffer + */ + constexpr size_t size() { return Size; } + + /*! @brief returns the buffer + * @returns the buffer + */ + Type *data() { return buffer; } + + /*! @brief returns a reference to the element at @param i + * @param i the index + * @returns a reference to the element at @param i + */ + Type &operator[](size_t i) { return buffer[i]; } + + /*! @brief returns a reference to the element at @param i + * @param i the index + * @returns a reference to the element at @param i + */ + const Type &operator[](size_t i) const { return buffer[i]; } + + private: + //! the buffer + Type buffer[Size]; + //! address buffer one increment after the end + Type *endPointer = buffer + Size; + }; }; #endif // has SPI defined From a97c62ad078525afd2279f8541a68eaf5046e545 Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Sat, 14 May 2022 19:14:06 +0200 Subject: [PATCH 3/9] moved the chunked transfer management to their own private methods --- Adafruit_SPIDevice.cpp | 238 +++++++++++++++++++---------------------- Adafruit_SPIDevice.h | 70 +++++++----- 2 files changed, 155 insertions(+), 153 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index cb60721..1b76d8b 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -1,23 +1,16 @@ #include "Adafruit_SPIDevice.h" -#if !defined(__AVR__) -#include -#endif - #if !defined(SPI_INTERFACES_COUNT) || \ (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) -//#define DEBUG_SERIAL Serial +// #define DEBUG_SERIAL Serial #ifdef DEBUG_SERIAL template -static void printChunk(const char *title, const T &buffer, const uint8_t size, - const uint16_t chunkNumber) { +static void printChunk(const char *title, const T &buffer, const uint8_t size) { DEBUG_SERIAL.print(F("\t")); DEBUG_SERIAL.print(title); - DEBUG_SERIAL.print(F(" Chunk #")); - DEBUG_SERIAL.print(chunkNumber); - DEBUG_SERIAL.print(F(", size ")); + DEBUG_SERIAL.print(F(" Chunk, size ")); DEBUG_SERIAL.println(size); DEBUG_SERIAL.print(F("\t")); @@ -45,6 +38,20 @@ static void printBuffer(const char *title, const uint8_t *buffer, } #endif +// The Arduino Core of AVR defines min() as a macro. It also has no std::min, so +// undef the macro and create std::min +#if defined(__AVR__) +#undef min +namespace std { +template constexpr T min(const T a, const T b) { + return (a < b) ? a : b; +} +}; // namespace std +#else +// all other platforms have stdlib's , so include the real deal +#include +#endif + /*! * @brief Create an SPI device with the given CS pin and settings * @param cspin The arduino pin number to use for chip select @@ -351,67 +358,118 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { endTransaction(); } -/*! - * @brief Write a buffer or two to the SPI device, with transaction - * management. - * @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(const uint8_t *buffer, size_t len, - const uint8_t *prefix_buffer, - size_t prefix_len) { - Array chunkBuffer; +void Adafruit_SPIDevice::transferFilledChunk( + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, + const uint8_t *bufferToSend, const size_t bufferLen) { + auto bytesToTransferLen = bufferLen; + auto bytesToTransferBuffer = bufferToSend; - auto chunkBufferIterator = chunkBuffer.begin(); + while (bytesToTransferLen) { + auto bytesToTransferLenThisChunk = std::min( + bytesToTransferLen, + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); -#ifdef DEBUG_SERIAL - uint8_t chunkNumber = 1; -#endif + memcpy(iteratorToIncrement, bytesToTransferBuffer, + bytesToTransferLenThisChunk); - beginTransactionWithAssertingCS(); + bytesToTransferLen -= bytesToTransferLenThisChunk; + bytesToTransferBuffer += bytesToTransferLenThisChunk; - for (size_t i = 0; i < prefix_len; ++i) { - *chunkBufferIterator++ = prefix_buffer[i]; + if (bytesToTransferLen) { + transfer(chunkBuffer.data(), chunkBuffer.size()); - if (chunkBufferIterator == chunkBuffer.end()) { - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); - chunkBufferIterator = chunkBuffer.begin(); + iteratorToIncrement = chunkBuffer.begin(); #ifdef DEBUG_SERIAL - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, - chunkNumber++); + printChunk("transferFilledChunk()", chunkBuffer, chunkBuffer.size()); #endif + } else { + iteratorToIncrement = iteratorToIncrement + bytesToTransferLenThisChunk; } } +} - for (size_t i = 0; i < len; ++i) { - *chunkBufferIterator++ = buffer[i]; +void Adafruit_SPIDevice::transferPartiallyFilledChunk( + ChunkBuffer &chunkBuffer, + const ChunkBuffer::Iterator &chunkBufferIterator) { + if (chunkBufferIterator != chunkBuffer.begin()) { + auto bytesToTransferLenThisChunk = + chunkBufferIterator - chunkBuffer.begin(); - if (chunkBufferIterator == chunkBuffer.end()) { - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); - chunkBufferIterator = chunkBuffer.begin(); + transfer(chunkBuffer.data(), bytesToTransferLenThisChunk); #ifdef DEBUG_SERIAL - printChunk("write() Wrote", chunkBuffer, maxBufferSizeForChunkedTransfer, - chunkNumber++); + printChunk("transferPartiallyFilledChunk()", chunkBuffer, + bytesToTransferLenThisChunk); #endif - } } +} - if (chunkBufferIterator != chunkBuffer.begin()) { - auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); - transfer(chunkBuffer.data(), numberByteToTransfer); +void Adafruit_SPIDevice::transferAndReadChunks( + ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, + uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal) { + auto bytesToTransferLen = readLen; + auto readFromIterator = iteratorToIncrement; + + while (bytesToTransferLen) { + auto bytesToTransferLenThisChunk = std::min( + bytesToTransferLen, + chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); + memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk); + + iteratorToIncrement += bytesToTransferLenThisChunk; + bytesToTransferLen -= bytesToTransferLenThisChunk; + + { + auto tranferLen = iteratorToIncrement - chunkBuffer.begin(); +#if defined(DEBUG_SERIAL) && defined(DEBUG_VERBOSE) + printChunk("transferAndReadChunks() before transmit", chunkBuffer, + tranferLen); +#endif + transfer(chunkBuffer.data(), tranferLen); #ifdef DEBUG_SERIAL - printChunk("write() Wrote remaining", chunkBuffer, numberByteToTransfer, - chunkNumber++); + printChunk("transferAndReadChunks() after transmit", chunkBuffer, + tranferLen); #endif + } + + memcpy(readBuffer, readFromIterator, bytesToTransferLenThisChunk); + + readBuffer += bytesToTransferLenThisChunk; + + readFromIterator = iteratorToIncrement = chunkBuffer.begin(); + + if (!bytesToTransferLen) { + break; + } } +} + +/*! + * @brief Write a buffer or two to the SPI device, with transaction + * management. + * @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(const uint8_t *buffer, size_t len, + const uint8_t *prefix_buffer, + size_t prefix_len) { + Array chunkBuffer; + + auto chunkBufferIterator = chunkBuffer.begin(); + + beginTransactionWithAssertingCS(); + + transferFilledChunk(chunkBuffer, chunkBufferIterator, prefix_buffer, + prefix_len); + transferFilledChunk(chunkBuffer, chunkBufferIterator, buffer, len); + transferPartiallyFilledChunk(chunkBuffer, chunkBufferIterator); endTransactionWithDeassertingCS(); @@ -462,84 +520,12 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, auto chunkBufferIterator = chunkBuffer.begin(); -#ifdef DEBUG_SERIAL - uint8_t chunkNumber = 1; -#endif - beginTransactionWithAssertingCS(); - for (size_t i = 0; i < write_len; ++i) { - *chunkBufferIterator++ = write_buffer[i]; - - if (chunkBufferIterator == chunkBuffer.end()) { - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); - chunkBufferIterator = chunkBuffer.begin(); - -#ifdef DEBUG_SERIAL - printChunk("write_then_read() Wrote", chunkBuffer, - maxBufferSizeForChunkedTransfer, chunkNumber++); -#endif - } - } - - auto readBufferIterator = read_buffer; - auto readFromIterator = chunkBufferIterator; - size_t readBufferLen = read_len; - - for (size_t i = 0; i < read_len; ++i) { - *chunkBufferIterator++ = sendvalue; - - if (chunkBufferIterator == chunkBuffer.end()) { -#ifdef DEBUG_SERIAL - printChunk("write_then_read() before transmit", chunkBuffer, - maxBufferSizeForChunkedTransfer, chunkNumber); -#endif - - transfer(chunkBuffer.data(), maxBufferSizeForChunkedTransfer); - - while (readBufferLen) { - if (readFromIterator != chunkBuffer.end()) { - *readBufferIterator++ = *readFromIterator++; - --readBufferLen; - } else { - break; - } - } - -#ifdef DEBUG_SERIAL - printChunk("write_then_read() after transmit", chunkBuffer, - maxBufferSizeForChunkedTransfer, chunkNumber++); -#endif - - chunkBufferIterator = chunkBuffer.begin(); - readFromIterator = chunkBuffer.begin(); - } - } - - if (chunkBufferIterator != chunkBuffer.begin()) { - auto numberByteToTransfer = chunkBufferIterator - chunkBuffer.begin(); - -#ifdef DEBUG_SERIAL - printChunk("write_then_read() before transmit remaining", chunkBuffer, - numberByteToTransfer, chunkNumber); -#endif - - transfer(chunkBuffer.data(), numberByteToTransfer); - -#ifdef DEBUG_SERIAL - printChunk("write_then_read() after transmit remaining", chunkBuffer, - numberByteToTransfer, chunkNumber); -#endif - - while (readBufferLen) { - if (readFromIterator != chunkBuffer.end()) { - *readBufferIterator++ = *readFromIterator++; - --readBufferLen; - } else { - break; - } - } - } + transferFilledChunk(chunkBuffer, chunkBufferIterator, write_buffer, + write_len); + transferAndReadChunks(chunkBuffer, chunkBufferIterator, read_buffer, read_len, + sendvalue); endTransactionWithDeassertingCS(); diff --git a/Adafruit_SPIDevice.h b/Adafruit_SPIDevice.h index 3e41614..e023c34 100644 --- a/Adafruit_SPIDevice.h +++ b/Adafruit_SPIDevice.h @@ -103,30 +103,6 @@ class Adafruit_SPIDevice { void beginTransactionWithAssertingCS(); void endTransactionWithDeassertingCS(); -private: - SPIClass *_spi; - SPISettings *_spiSetting; - uint32_t _freq; - BusIOBitOrder _dataOrder; - uint8_t _dataMode; - - void setChipSelect(int value); - - int8_t _cs, _sck, _mosi, _miso; -#ifdef BUSIO_USE_FAST_PINIO - BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort; - BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask; -#endif - - //! constant for the buffer size for the chunked transfer - static constexpr size_t maxBufferSizeForChunkedTransfer = -#ifdef __AVR__ - 32; -#else - 64; -#endif - bool _begun; - protected: /*! * @brief Template to encypsulate a C-array, provides STL-style accessors @@ -136,15 +112,18 @@ class Adafruit_SPIDevice { */ template class Array { public: + //! Iterator type + using Iterator = Type *; + /*! @brief returns a pointer the start of the buffer * @returns a pointer the start of the buffer */ - Type *begin() { return buffer; } + Iterator begin() { return buffer; } /*! @brief returns a pointer the one increment beyond the end of the buffer * @returns a pointer the one increment beyond the end of the buffer */ - Type *end() { return endPointer; } + Iterator end() { return endPointer; } /*! @brief returns the size of the buffer * @returns the size of the buffer @@ -172,8 +151,45 @@ class Adafruit_SPIDevice { //! the buffer Type buffer[Size]; //! address buffer one increment after the end - Type *endPointer = buffer + Size; + Iterator endPointer = buffer + Size; }; + +private: + //! constant for the buffer size for the chunked transfer + static constexpr size_t maxBufferSizeForChunkedTransfer = +#ifdef __AVR__ + 32; +#else + 64; +#endif + + using ChunkBuffer = Array; + + SPIClass *_spi; + SPISettings *_spiSetting; + uint32_t _freq; + BusIOBitOrder _dataOrder; + uint8_t _dataMode; + + void setChipSelect(int value); + void transferFilledChunk(ChunkBuffer &chunkBuffer, + ChunkBuffer::Iterator &iteratorToIncrement, + const uint8_t *bufferToSend, const size_t bufferLen); + void transferPartiallyFilledChunk( + ChunkBuffer &chunkBuffer, + const ChunkBuffer::Iterator &chunkBufferIterator); + + void transferAndReadChunks(ChunkBuffer &chunkBuffer, + ChunkBuffer::Iterator &iteratorToIncrement, + uint8_t *readBuffer, const size_t readLen, + const uint8_t sendVal); + + int8_t _cs, _sck, _mosi, _miso; +#ifdef BUSIO_USE_FAST_PINIO + BusIO_PortReg *mosiPort, *clkPort, *misoPort, *csPort; + BusIO_PortMask mosiPinMask, misoPinMask, clkPinMask, csPinMask; +#endif + bool _begun; }; #endif // has SPI defined From 177e50494ebe5dbf0342afcabe89e256d97bca43 Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Sat, 14 May 2022 19:19:28 +0200 Subject: [PATCH 4/9] added an additional debug level: if enabled, print the actual data too --- Adafruit_SPIDevice.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 1b76d8b..c9e7330 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -4,6 +4,7 @@ (defined(SPI_INTERFACES_COUNT) && (SPI_INTERFACES_COUNT > 0)) // #define DEBUG_SERIAL Serial +// #define DEBUG_VERBOSE #ifdef DEBUG_SERIAL template @@ -12,6 +13,7 @@ static void printChunk(const char *title, const T &buffer, const uint8_t size) { DEBUG_SERIAL.print(title); DEBUG_SERIAL.print(F(" Chunk, size ")); DEBUG_SERIAL.println(size); +#ifdef DEBUG_VERBOSE DEBUG_SERIAL.print(F("\t")); for (uint8_t i = 0; i < size; ++i) { @@ -20,12 +22,14 @@ static void printChunk(const char *title, const T &buffer, const uint8_t size) { DEBUG_SERIAL.print(F(", ")); } DEBUG_SERIAL.println(); +#endif } static void printBuffer(const char *title, const uint8_t *buffer, const size_t len) { DEBUG_SERIAL.print(F("\t")); DEBUG_SERIAL.println(title); +#ifdef DEBUG_VERBOSE for (size_t i = 0; i < len; i++) { DEBUG_SERIAL.print(F("0x")); DEBUG_SERIAL.print(buffer[i], HEX); @@ -35,6 +39,7 @@ static void printBuffer(const char *title, const uint8_t *buffer, } } DEBUG_SERIAL.println(); +#endif } #endif From 59cd422041d2df5f158e2c5a65e31f5d5194d853 Mon Sep 17 00:00:00 2001 From: eringerli <48175951+eringerli@users.noreply.github.com> Date: Mon, 16 May 2022 14:40:31 +0200 Subject: [PATCH 5/9] Removed redundant code --- Adafruit_SPIDevice.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index c9e7330..2ddac4f 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -444,10 +444,6 @@ void Adafruit_SPIDevice::transferAndReadChunks( readBuffer += bytesToTransferLenThisChunk; readFromIterator = iteratorToIncrement = chunkBuffer.begin(); - - if (!bytesToTransferLen) { - break; - } } } From 1bc392fdd2c13fadc6a93aaad3f7e0348a7d14cc Mon Sep 17 00:00:00 2001 From: eringerli <48175951+eringerli@users.noreply.github.com> Date: Mon, 16 May 2022 17:40:21 +0200 Subject: [PATCH 6/9] use the typedef of the chunkbuffer type --- Adafruit_SPIDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 2ddac4f..4d380f0 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -461,7 +461,7 @@ void Adafruit_SPIDevice::transferAndReadChunks( bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, const uint8_t *prefix_buffer, size_t prefix_len) { - Array chunkBuffer; + ChunkBuffer chunkBuffer; auto chunkBufferIterator = chunkBuffer.begin(); @@ -517,7 +517,7 @@ bool Adafruit_SPIDevice::read(uint8_t *buffer, size_t len, uint8_t sendvalue) { bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue) { - Array chunkBuffer; + ChunkBuffer chunkBuffer; auto chunkBufferIterator = chunkBuffer.begin(); From 033dc80241debbec8ca38d0ad0e3f264772e6ae8 Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Wed, 18 May 2022 21:04:21 +0200 Subject: [PATCH 7/9] removed template Adafruit_SPIDevice::Array --- Adafruit_SPIDevice.cpp | 44 +++++++++++++--------------- Adafruit_SPIDevice.h | 66 +++++------------------------------------- 2 files changed, 28 insertions(+), 82 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 4d380f0..2534ff3 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -364,15 +364,15 @@ void Adafruit_SPIDevice::endTransactionWithDeassertingCS() { } void Adafruit_SPIDevice::transferFilledChunk( - ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, + ChunkBuffer &chunkBuffer, ChunkBufferIterator &iteratorToIncrement, const uint8_t *bufferToSend, const size_t bufferLen) { auto bytesToTransferLen = bufferLen; auto bytesToTransferBuffer = bufferToSend; while (bytesToTransferLen) { - auto bytesToTransferLenThisChunk = std::min( - bytesToTransferLen, - chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); + auto bytesToTransferLenThisChunk = + std::min(bytesToTransferLen, + ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); memcpy(iteratorToIncrement, bytesToTransferBuffer, bytesToTransferLenThisChunk); @@ -381,12 +381,12 @@ void Adafruit_SPIDevice::transferFilledChunk( bytesToTransferBuffer += bytesToTransferLenThisChunk; if (bytesToTransferLen) { - transfer(chunkBuffer.data(), chunkBuffer.size()); + transfer(chunkBuffer, ChunkBufferSize); - iteratorToIncrement = chunkBuffer.begin(); + iteratorToIncrement = chunkBuffer; #ifdef DEBUG_SERIAL - printChunk("transferFilledChunk()", chunkBuffer, chunkBuffer.size()); + printChunk("transferFilledChunk()", chunkBuffer, ChunkBufferSize); #endif } else { iteratorToIncrement = iteratorToIncrement + bytesToTransferLenThisChunk; @@ -395,13 +395,11 @@ void Adafruit_SPIDevice::transferFilledChunk( } void Adafruit_SPIDevice::transferPartiallyFilledChunk( - ChunkBuffer &chunkBuffer, - const ChunkBuffer::Iterator &chunkBufferIterator) { - if (chunkBufferIterator != chunkBuffer.begin()) { - auto bytesToTransferLenThisChunk = - chunkBufferIterator - chunkBuffer.begin(); + ChunkBuffer &chunkBuffer, const ChunkBufferIterator &chunkBufferIterator) { + if (chunkBufferIterator != chunkBuffer) { + auto bytesToTransferLenThisChunk = chunkBufferIterator - chunkBuffer; - transfer(chunkBuffer.data(), bytesToTransferLenThisChunk); + transfer(chunkBuffer, bytesToTransferLenThisChunk); #ifdef DEBUG_SERIAL printChunk("transferPartiallyFilledChunk()", chunkBuffer, @@ -411,15 +409,15 @@ void Adafruit_SPIDevice::transferPartiallyFilledChunk( } void Adafruit_SPIDevice::transferAndReadChunks( - ChunkBuffer &chunkBuffer, ChunkBuffer::Iterator &iteratorToIncrement, + ChunkBuffer &chunkBuffer, ChunkBufferIterator &iteratorToIncrement, uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal) { auto bytesToTransferLen = readLen; auto readFromIterator = iteratorToIncrement; while (bytesToTransferLen) { - auto bytesToTransferLenThisChunk = std::min( - bytesToTransferLen, - chunkBuffer.size() - (iteratorToIncrement - chunkBuffer.begin())); + auto bytesToTransferLenThisChunk = + std::min(bytesToTransferLen, + ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk); @@ -427,12 +425,12 @@ void Adafruit_SPIDevice::transferAndReadChunks( bytesToTransferLen -= bytesToTransferLenThisChunk; { - auto tranferLen = iteratorToIncrement - chunkBuffer.begin(); + auto tranferLen = iteratorToIncrement - chunkBuffer; #if defined(DEBUG_SERIAL) && defined(DEBUG_VERBOSE) printChunk("transferAndReadChunks() before transmit", chunkBuffer, tranferLen); #endif - transfer(chunkBuffer.data(), tranferLen); + transfer(chunkBuffer, tranferLen); #ifdef DEBUG_SERIAL printChunk("transferAndReadChunks() after transmit", chunkBuffer, tranferLen); @@ -443,7 +441,7 @@ void Adafruit_SPIDevice::transferAndReadChunks( readBuffer += bytesToTransferLenThisChunk; - readFromIterator = iteratorToIncrement = chunkBuffer.begin(); + readFromIterator = iteratorToIncrement = chunkBuffer; } } @@ -462,8 +460,7 @@ bool Adafruit_SPIDevice::write(const uint8_t *buffer, size_t len, const uint8_t *prefix_buffer, size_t prefix_len) { ChunkBuffer chunkBuffer; - - auto chunkBufferIterator = chunkBuffer.begin(); + ChunkBufferIterator chunkBufferIterator = chunkBuffer; beginTransactionWithAssertingCS(); @@ -518,8 +515,7 @@ bool Adafruit_SPIDevice::write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue) { ChunkBuffer chunkBuffer; - - auto chunkBufferIterator = chunkBuffer.begin(); + ChunkBufferIterator chunkBufferIterator = chunkBuffer; beginTransactionWithAssertingCS(); diff --git a/Adafruit_SPIDevice.h b/Adafruit_SPIDevice.h index e023c34..63d72a2 100644 --- a/Adafruit_SPIDevice.h +++ b/Adafruit_SPIDevice.h @@ -103,67 +103,17 @@ class Adafruit_SPIDevice { void beginTransactionWithAssertingCS(); void endTransactionWithDeassertingCS(); -protected: - /*! - * @brief Template to encypsulate a C-array, provides STL-style accessors - * analoguous to std::array<> - * @param Type the type of the array - * @param Size the size of the array - */ - template class Array { - public: - //! Iterator type - using Iterator = Type *; - - /*! @brief returns a pointer the start of the buffer - * @returns a pointer the start of the buffer - */ - Iterator begin() { return buffer; } - - /*! @brief returns a pointer the one increment beyond the end of the buffer - * @returns a pointer the one increment beyond the end of the buffer - */ - Iterator end() { return endPointer; } - - /*! @brief returns the size of the buffer - * @returns the size of the buffer - */ - constexpr size_t size() { return Size; } - - /*! @brief returns the buffer - * @returns the buffer - */ - Type *data() { return buffer; } - - /*! @brief returns a reference to the element at @param i - * @param i the index - * @returns a reference to the element at @param i - */ - Type &operator[](size_t i) { return buffer[i]; } - - /*! @brief returns a reference to the element at @param i - * @param i the index - * @returns a reference to the element at @param i - */ - const Type &operator[](size_t i) const { return buffer[i]; } - - private: - //! the buffer - Type buffer[Size]; - //! address buffer one increment after the end - Iterator endPointer = buffer + Size; - }; - private: //! constant for the buffer size for the chunked transfer - static constexpr size_t maxBufferSizeForChunkedTransfer = + static constexpr size_t ChunkBufferSize = #ifdef __AVR__ 32; #else 64; #endif - using ChunkBuffer = Array; + using ChunkBuffer = uint8_t[ChunkBufferSize]; + using ChunkBufferIterator = uint8_t *; SPIClass *_spi; SPISettings *_spiSetting; @@ -173,14 +123,14 @@ class Adafruit_SPIDevice { void setChipSelect(int value); void transferFilledChunk(ChunkBuffer &chunkBuffer, - ChunkBuffer::Iterator &iteratorToIncrement, + ChunkBufferIterator &iteratorToIncrement, const uint8_t *bufferToSend, const size_t bufferLen); - void transferPartiallyFilledChunk( - ChunkBuffer &chunkBuffer, - const ChunkBuffer::Iterator &chunkBufferIterator); + void + transferPartiallyFilledChunk(ChunkBuffer &chunkBuffer, + const ChunkBufferIterator &chunkBufferIterator); void transferAndReadChunks(ChunkBuffer &chunkBuffer, - ChunkBuffer::Iterator &iteratorToIncrement, + ChunkBufferIterator &iteratorToIncrement, uint8_t *readBuffer, const size_t readLen, const uint8_t sendVal); From 14d73363703f8558faca09df16436d9ec481d2eb Mon Sep 17 00:00:00 2001 From: Christian Riggenbach Date: Wed, 18 May 2022 21:16:34 +0200 Subject: [PATCH 8/9] replaced std::min with a custom templated function --- Adafruit_SPIDevice.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index 2534ff3..c71758e 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -43,19 +43,15 @@ static void printBuffer(const char *title, const uint8_t *buffer, } #endif -// The Arduino Core of AVR defines min() as a macro. It also has no std::min, so -// undef the macro and create std::min -#if defined(__AVR__) -#undef min -namespace std { -template constexpr T min(const T a, const T b) { +/*! + * @brief returns the smaller of both arguments + * @param a argument 1 + * @param b argument 2 + * @return the smaller of both arguments + */ +template constexpr T minimum(const T a, const T b) { return (a < b) ? a : b; } -}; // namespace std -#else -// all other platforms have stdlib's , so include the real deal -#include -#endif /*! * @brief Create an SPI device with the given CS pin and settings @@ -371,8 +367,8 @@ void Adafruit_SPIDevice::transferFilledChunk( while (bytesToTransferLen) { auto bytesToTransferLenThisChunk = - std::min(bytesToTransferLen, - ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); + minimum(bytesToTransferLen, + ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); memcpy(iteratorToIncrement, bytesToTransferBuffer, bytesToTransferLenThisChunk); @@ -416,8 +412,8 @@ void Adafruit_SPIDevice::transferAndReadChunks( while (bytesToTransferLen) { auto bytesToTransferLenThisChunk = - std::min(bytesToTransferLen, - ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); + minimum(bytesToTransferLen, + ChunkBufferSize - (iteratorToIncrement - chunkBuffer)); memset(iteratorToIncrement, sendVal, bytesToTransferLenThisChunk); From 839e32cdbb9e98fb823e795ac53495fa0f731785 Mon Sep 17 00:00:00 2001 From: eringerli <48175951+eringerli@users.noreply.github.com> Date: Tue, 24 May 2022 06:58:57 +0200 Subject: [PATCH 9/9] Changed templated function printChunk to non-templated --- Adafruit_SPIDevice.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Adafruit_SPIDevice.cpp b/Adafruit_SPIDevice.cpp index c71758e..973f87f 100644 --- a/Adafruit_SPIDevice.cpp +++ b/Adafruit_SPIDevice.cpp @@ -7,8 +7,8 @@ // #define DEBUG_VERBOSE #ifdef DEBUG_SERIAL -template -static void printChunk(const char *title, const T &buffer, const uint8_t size) { +static void printChunk(const char *title, const uint8_t *buffer, + const uint8_t size) { DEBUG_SERIAL.print(F("\t")); DEBUG_SERIAL.print(title); DEBUG_SERIAL.print(F(" Chunk, size "));