diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 93bb027486..1ef12b6ba1 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -299,14 +299,16 @@ void SPIClass::setClockDivider(uint32_t clockDiv) { SPI1CLK = clockDiv; } -inline void SPIClass::setDataBits(uint16_t bits) { +inline void SPIClass::setDataBits(uint32_t bits) { const uint32_t mask = ~((SPIMMOSI << SPILMOSI) | (SPIMMISO << SPILMISO)); bits--; SPI1U1 = ((SPI1U1 & mask) | ((bits << SPILMOSI) | (bits << SPILMISO))); } uint8_t SPIClass::transfer(uint8_t data) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} +#endif // reset to 8Bit mode setDataBits(8); SPI1W0 = data; @@ -357,7 +359,9 @@ void SPIClass::transfer(void *buf, uint16_t count) { } void SPIClass::write(uint8_t data) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} +#endif // reset to 8Bit mode setDataBits(8); SPI1W0 = data; @@ -370,7 +374,9 @@ void SPIClass::write16(uint16_t data) { } void SPIClass::write16(uint16_t data, bool msb) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} +#endif // Set to 16Bits transfer setDataBits(16); if(msb) { @@ -389,7 +395,9 @@ void SPIClass::write32(uint32_t data) { } void SPIClass::write32(uint32_t data, bool msb) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} +#endif // Set to 32Bits transfer setDataBits(32); if(msb) { @@ -408,44 +416,45 @@ void SPIClass::write32(uint32_t data, bool msb) { /** * Note: - * data need to be aligned to 32Bit - * or you get an Fatal exception (9) + * data needs to be aligned to 32 bit boundaries like this: char outBuffer[spiBufferSize] __attribute__ ((aligned (4))); + * if not you may get an Fatal exception (9) * @param data uint8_t * * @param size uint32_t */ void SPIClass::writeBytes(const uint8_t * data, uint32_t size) { + uint32_t localSize; while(size) { - if(size > 64) { - writeBytes_(data, 64); - size -= 64; - data += 64; - } else { - writeBytes_(data, size); - size = 0; - } - } + if(size > 64) + localSize = 64; + else + localSize = size; + + writeBytes_(data, localSize); + size -= localSize; + if ((size != 0) && (data)) data += localSize; + } } -void SPIClass::writeBytes_(const uint8_t * data, uint8_t size) { +inline void SPIClass::writeBytes_(const uint8_t * data, uint32_t size) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} - // Set Bits to transfer +#endif + // Set bits to transfer setDataBits(size * 8); - uint32_t * fifoPtr = (uint32_t*)&SPI1W0; - const uint32_t * dataPtr = (uint32_t*) data; - uint32_t dataSize = ((size + 3) / 4); - - while(dataSize--) { - *fifoPtr = *dataPtr; - dataPtr++; - fifoPtr++; - } - __sync_synchronize(); + if(data) { + memcpy((uint8_t*)&SPI1W0, data, size); + } + else { + // no data buffer specified, transmit dummy data + memset((uint8_t*)&SPI1W0, 0xFFFFFFFF, size); + } + // Start SPI transfer SPI1CMD |= SPIBUSY; + // and wait for transfer to complete while(SPI1CMD & SPIBUSY) {} } - /** * @param data uint8_t * * @param size uint8_t max for size is 64Byte @@ -453,9 +462,9 @@ void SPIClass::writeBytes_(const uint8_t * data, uint8_t size) { */ void SPIClass::writePattern(const uint8_t * data, uint8_t size, uint32_t repeat) { if(size > 64) return; //max Hardware FIFO - +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} - +#endif uint32_t buffer[16]; uint8_t *bufferPtr=(uint8_t *)&buffer; const uint8_t *dataPtr = data; @@ -523,95 +532,55 @@ void SPIClass::writePattern(const uint8_t * data, uint8_t size, uint32_t repeat) } /** + * Note: + * in and out need to be aligned to 32 bit boundaries like this: char outBuffer[spiBufferSize] __attribute__ ((aligned (4))); + * if not you may get an Fatal exception (9) * @param out uint8_t * * @param in uint8_t * * @param size uint32_t */ void SPIClass::transferBytes(const uint8_t * out, uint8_t * in, uint32_t size) { + uint32_t localSize; while(size) { - if(size > 64) { - transferBytes_(out, in, 64); - size -= 64; - if(out) out += 64; - if(in) in += 64; - } else { - transferBytes_(out, in, size); - size = 0; - } - } + if(size > 64) + localSize = 64; + else + localSize = size; + + transferBytes_(out, in, localSize); + size -= localSize; + if (size != 0) + { + if(out) out += localSize; + if(in) in += localSize; + } + } } -/** - * Note: - * in and out need to be aligned to 32Bit - * or you get an Fatal exception (9) - * @param out uint8_t * - * @param in uint8_t * - * @param size uint8_t (max 64) - */ - -void SPIClass::transferBytesAligned_(const uint8_t * out, uint8_t * in, uint8_t size) { - if (!size) - return; - +inline void SPIClass::transferBytes_(uint8_t * out, uint8_t * in, uint32_t size) { +#ifndef SPI_SKIP_INITIAL_BUSY_CHECK while(SPI1CMD & SPIBUSY) {} - // Set in/out Bits to transfer - +#endif + // Set bits to transfer setDataBits(size * 8); - volatile uint32_t *fifoPtr = &SPI1W0; - - if (out) { - uint8_t outSize = ((size + 3) / 4); - uint32_t *dataPtr = (uint32_t*) out; - while (outSize--) { - *(fifoPtr++) = *(dataPtr++); - } - } else { - uint8_t outSize = ((size + 3) / 4); - // no out data only read fill with dummy data! - while (outSize--) { - *(fifoPtr++) = 0xFFFFFFFF; - } - } - + if(out) { + memcpy((uint8_t*)&SPI1W0, out, size); + } + else { + // no out buffer specified, transmit dummy data + memset((uint8_t*)&SPI1W0, 0xFFFFFFFF, size); + } + + // Start SPI transfer SPI1CMD |= SPIBUSY; + + // and wait for transfer to complete while(SPI1CMD & SPIBUSY) {} - if (in) { - uint32_t *dataPtr = (uint32_t*) in; - fifoPtr = &SPI1W0; - int inSize = size; - // Unlike outSize above, inSize tracks *bytes* since we must transfer only the requested bytes to the app to avoid overwriting other vars. - while (inSize >= 4) { - *(dataPtr++) = *(fifoPtr++); - inSize -= 4; - in += 4; - } - volatile uint8_t *fifoPtrB = (volatile uint8_t *)fifoPtr; - while (inSize--) { - *(in++) = *(fifoPtrB++); - } - } -} - - -void SPIClass::transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size) { - if (!((uint32_t)out & 3) && !((uint32_t)in & 3)) { - // Input and output are both 32b aligned or NULL - transferBytesAligned_(out, in, size); - } else { - // HW FIFO has 64b limit and ::transferBytes breaks up large xfers into 64byte chunks before calling this function - // We know at this point at least one direction is misaligned, so use temporary buffer to align everything - // No need for separate out and in aligned copies, we can overwrite our out copy with the input data safely - uint8_t aligned[64]; // Stack vars will be 32b aligned - if (out) { - memcpy(aligned, out, size); - } - transferBytesAligned_(out ? aligned : nullptr, in ? aligned : nullptr, size); - if (in) { - memcpy(in, aligned, size); - } + // then return received data + if(in) { + memcpy((uint8_t*)in, (uint8_t*)&SPI1W0, size); } } diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h index 7bc818bb39..0457a55f18 100644 --- a/libraries/SPI/SPI.h +++ b/libraries/SPI/SPI.h @@ -23,7 +23,8 @@ #include -#define SPI_HAS_TRANSACTION 1 +#define SPI_HAS_TRANSACTION +#define SPI_SKIP_INITIAL_BUSY_CHECK //comment this line for backward compatibility if really needed // This defines are not representing the real Divider of the ESP8266 // the Defines match to an AVR Arduino on 16MHz for better compatibility @@ -75,11 +76,9 @@ class SPIClass { void endTransaction(void); private: bool useHwCs; - uint8_t pinSet; - void writeBytes_(const uint8_t * data, uint8_t size); - void transferBytes_(const uint8_t * out, uint8_t * in, uint8_t size); - void transferBytesAligned_(const uint8_t * out, uint8_t * in, uint8_t size); - inline void setDataBits(uint16_t bits); + inline void writeBytes_(uint8_t * data, uint32_t size); + inline void transferBytes_(uint8_t * out, uint8_t * in, uint32_t size); + inline void setDataBits(uint32_t bits); }; #if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPI)