summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/spi.c62
1 files changed, 47 insertions, 15 deletions
diff --git a/ports/stm32/spi.c b/ports/stm32/spi.c
index c578ac7da..e8621b0ab 100644
--- a/ports/stm32/spi.c
+++ b/ports/stm32/spi.c
@@ -401,8 +401,7 @@ void spi_deinit(const spi_t *spi_obj) {
}
}
-STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeout) {
- uint32_t start = HAL_GetTick();
+STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t t_start, uint32_t timeout) {
volatile HAL_SPI_StateTypeDef *state = &spi->spi->State;
for (;;) {
// Do an atomic check of the state; WFI will exit even if IRQs are disabled
@@ -413,7 +412,7 @@ STATIC HAL_StatusTypeDef spi_wait_dma_finished(const spi_t *spi, uint32_t timeou
}
__WFI();
enable_irq(irq_state);
- if (HAL_GetTick() - start >= timeout) {
+ if (HAL_GetTick() - t_start >= timeout) {
return HAL_TIMEOUT;
}
}
@@ -430,6 +429,8 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint
// time directly after the SPI/DMA is initialised. The cause of this is
// unknown but we sidestep the issue by using polling for 1 byte transfer.
+ // Note: DMA transfers are limited to 65535 bytes at a time.
+
HAL_StatusTypeDef status;
if (dest == NULL) {
@@ -442,10 +443,20 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint
self->spi->hdmatx = &tx_dma;
self->spi->hdmarx = NULL;
MP_HAL_CLEAN_DCACHE(src, len);
- status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_Transmit_DMA(self->spi, (uint8_t*)src, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ src += l;
+ } while (len);
dma_deinit(self->tx_dma_descr);
}
} else if (src == NULL) {
@@ -464,10 +475,20 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint
dma_init(&rx_dma, self->rx_dma_descr, self->spi);
self->spi->hdmarx = &rx_dma;
MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
- status = HAL_SPI_Receive_DMA(self->spi, dest, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_Receive_DMA(self->spi, dest, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ dest += l;
+ } while (len);
if (self->spi->hdmatx != NULL) {
dma_deinit(self->tx_dma_descr);
}
@@ -485,10 +506,21 @@ STATIC void spi_transfer(const spi_t *self, size_t len, const uint8_t *src, uint
self->spi->hdmarx = &rx_dma;
MP_HAL_CLEAN_DCACHE(src, len);
MP_HAL_CLEANINVALIDATE_DCACHE(dest, len);
- status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, len);
- if (status == HAL_OK) {
- status = spi_wait_dma_finished(self, timeout);
- }
+ uint32_t t_start = HAL_GetTick();
+ do {
+ uint32_t l = MIN(len, 65535);
+ status = HAL_SPI_TransmitReceive_DMA(self->spi, (uint8_t*)src, dest, l);
+ if (status != HAL_OK) {
+ break;
+ }
+ status = spi_wait_dma_finished(self, t_start, timeout);
+ if (status != HAL_OK) {
+ break;
+ }
+ len -= l;
+ src += l;
+ dest += l;
+ } while (len);
dma_deinit(self->tx_dma_descr);
dma_deinit(self->rx_dma_descr);
}