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; + } } }