From 9123c8d9460017b8c8dc4a38d9a26968eacaa4cb Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 28 Nov 2017 18:48:30 -0800 Subject: [PATCH] esp32/machine_hw_spi: Fix large HW SPI transfers by splitting them up. Breaks up HW SPI transfers into maximum chunks of 32736 bits (4092 bytes), because this is the maximum that the underlying ESP IDF will accept. --- ports/esp32/machine_hw_spi.c | 54 ++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/ports/esp32/machine_hw_spi.c b/ports/esp32/machine_hw_spi.c index 437b620f5e..54790bf8d9 100644 --- a/ports/esp32/machine_hw_spi.c +++ b/ports/esp32/machine_hw_spi.c @@ -36,6 +36,9 @@ #include "driver/spi_master.h" +#define MP_HW_SPI_MAX_XFER_BYTES (4092) +#define MP_HW_SPI_MAX_XFER_BITS (MP_HW_SPI_MAX_XFER_BYTES * 8) // Has to be an even multiple of 8 + typedef struct _machine_hw_spi_obj_t { mp_obj_base_t base; spi_host_device_t host; @@ -227,35 +230,52 @@ STATIC void machine_hw_spi_deinit(mp_obj_base_t *self_in) { STATIC void machine_hw_spi_transfer(mp_obj_base_t *self_in, size_t len, const uint8_t *src, uint8_t *dest) { machine_hw_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); - int bits_to_send = len * self->bits; - bool shortMsg = len <= 4; - if (self->state == MACHINE_HW_SPI_STATE_DEINIT) { mp_raise_msg(&mp_type_OSError, "transfer on deinitialized SPI"); return; } - struct spi_transaction_t transaction = { - .flags = 0, - .length = bits_to_send, - .tx_buffer = NULL, - .rx_buffer = NULL, - }; + struct spi_transaction_t transaction = { 0 }; - if (shortMsg) { + // Round to nearest whole set of bits + int bits_to_send = len * 8 / self->bits * self->bits; + + + if (len <= 4) { if (src != NULL) { memcpy(&transaction.tx_data, src, len); } - transaction.flags |= (SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA); + + transaction.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA; + transaction.length = bits_to_send; + spi_device_transmit(self->spi, &transaction); + + if (dest != NULL) { + memcpy(dest, &transaction.rx_data, len); + } } else { - transaction.tx_buffer = src; - transaction.rx_buffer = dest; - } + int offset = 0; + int bits_remaining = bits_to_send; - spi_device_transmit(self->spi, &transaction); + while (bits_remaining) { + memset(&transaction, 0, sizeof(transaction)); - if (shortMsg && dest != NULL) { - memcpy(dest, &transaction.rx_data, len); + transaction.length = + bits_remaining > MP_HW_SPI_MAX_XFER_BITS ? MP_HW_SPI_MAX_XFER_BITS : bits_remaining; + + if (src != NULL) { + transaction.tx_buffer = src + offset; + } + if (dest != NULL) { + transaction.rx_buffer = dest + offset; + } + + spi_device_transmit(self->spi, &transaction); + bits_remaining -= transaction.length; + + // doesn't need ceil(); loop ends when bits_remaining is 0 + offset += transaction.length / 8; + } } }