diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.c b/os/hal/lib/complex/serial_nor/hal_serial_nor.c index 6591081b20..3bafde1bd1 100644 --- a/os/hal/lib/complex/serial_nor/hal_serial_nor.c +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.c @@ -445,6 +445,35 @@ void bus_cmd(SNORDriver *devp, uint32_t cmd) { #endif } +#if SNOR_SPI_WORKAROUND_CACHE + +#include +static void spiSendNoCache(SNORDriver *devp, size_t n, const void *txbuf) +{ + BUSDriver *busp = devp->config->busp; + while (n) { + size_t chunk = (n > SNOR_BUFFER_SIZE) ? SNOR_BUFFER_SIZE : n; + memcpy(devp->nocache->buf, txbuf, chunk); + spiSend(busp, chunk, devp->nocache->buf); + txbuf += chunk; + n -= chunk; + } +} + +static void spiReceiveNoCache(SNORDriver *devp, size_t n, void *rxbuf) +{ + BUSDriver *busp = devp->config->busp; + while (n) { + size_t chunk = (n > SNOR_BUFFER_SIZE) ? SNOR_BUFFER_SIZE : n; + spiReceive(busp, chunk, devp->nocache->buf); + memcpy(rxbuf, devp->nocache->buf, chunk); + rxbuf += chunk; + n -= chunk; + } +} + +#endif + /** * @brief Sends a command followed by a data transmit phase. * @@ -472,7 +501,11 @@ void bus_cmd_send(SNORDriver *devp, uint32_t cmd, size_t n, const uint8_t *p) { spiSelect(busp); buf[0] = cmd; spiSend(busp, 1, buf); +#if SNOR_SPI_WORKAROUND_CACHE + spiSendNoCache(devp, n, p); +#else spiSend(busp, n, p); +#endif spiUnselect(busp); #endif } @@ -507,7 +540,11 @@ void bus_cmd_receive(SNORDriver *devp, spiSelect(busp); buf[0] = cmd; spiSend(busp, 1, p); +#if SNOR_SPI_WORKAROUND_CACHE + spiReceiveNoCache(devp, n, p); +#else spiReceive(busp, n, p); +#endif spiUnselect(busp); #endif } @@ -569,7 +606,11 @@ void bus_cmd_addr_send(SNORDriver *devp, #else spiSelect(busp); snor_spi_cmd_addr(devp, cmd, offset); +#if SNOR_SPI_WORKAROUND_CACHE + spiSendNoCache(devp, n, p); +#else spiSend(busp, n, p); +#endif spiUnselect(busp); #endif } @@ -647,7 +688,11 @@ void bus_cmd_dummy_receive(SNORDriver *devp, if (dummy != 0U) { spiIgnore(busp, dummy / 8U); } +#if SNOR_SPI_WORKAROUND_CACHE + spiReceiveNoCache(devp, n, p); +#else spiReceive(busp, n, p); +#endif spiUnselect(busp); #endif } diff --git a/os/hal/lib/complex/serial_nor/hal_serial_nor.h b/os/hal/lib/complex/serial_nor/hal_serial_nor.h index 13b60a76d4..195c0d1879 100644 --- a/os/hal/lib/complex/serial_nor/hal_serial_nor.h +++ b/os/hal/lib/complex/serial_nor/hal_serial_nor.h @@ -39,11 +39,6 @@ #define SNOR_BUS_DRIVER_WSPI 1U /** @} */ -/** - * @brief Size of the buffer for internal operations. - */ -#define SNOR_BUFFER_SIZE 32 - /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -87,6 +82,26 @@ #if !defined(SNOR_SPI_4BYTES_ADDRESS) || defined(__DOXYGEN__) #define SNOR_SPI_4BYTES_ADDRESS FALSE #endif + +/** + * @brief Cache workaround switch + * @details If set to @p TRUE the device will use nocache buffer + * as intermediate buffer for all SPI tx and rx data + * This should help avoid caching issues. + */ +#if !defined(SNOR_SPI_WORKAROUND_CACHE) || defined(__DOXYGEN__) +#define SNOR_SPI_WORKAROUND_CACHE FALSE +#endif + +/** + * @brief Size of the buffer for internal operations. + * #details Size if intermediate nocache buffer for tx and rx + * operations to avoid caching issues; + */ +#if !defined(SNOR_BUFFER_SIZE) || defined(__DOXYGEN__) +#define SNOR_BUFFER_SIZE 32 +#endif + /** @} */ /*===========================================================================*/ @@ -103,6 +118,14 @@ #error "invalid SNOR_BUS_DRIVER setting" #endif +#if (SNOR_BUFFER_SIZE & (SNOR_BUFFER_SIZE - 1)) != 0 +#error "SNOR_BUFFER_SIZE is not a power of two" +#endif + +#if SNOR_BUFFER_SIZE < 32 +#error "Invalid SNOR_BUFFER_SIZE value" +#endif + /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/