Skip to content

Commit c7c90f4

Browse files
committed
Add non-DMA SPI support.
This fixes SPI with PSRAM allocated buffers. DMA with SPI2 was attempted but produced junk output. This manual copy is less than 2x slower than DMA when not interrupted. Fixes #3339
1 parent 9e722c8 commit c7c90f4

File tree

2 files changed

+29
-16
lines changed

2 files changed

+29
-16
lines changed

ports/esp32s2/common-hal/busio/SPI.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
183183

184184
// spi_hal_init clears the given hal context so set everything after.
185185
spi_hal_init(hal, host_id);
186-
hal->dmadesc_tx = &self->tx_dma;
187-
hal->dmadesc_rx = &self->rx_dma;
188-
hal->dmadesc_n = 1;
189186

190187
// We don't use native CS.
191188
// hal->cs_setup = 0;
@@ -196,7 +193,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
196193
hal->half_duplex = 0;
197194
// hal->tx_lsbfirst = 0;
198195
// hal->rx_lsbfirst = 0;
199-
hal->dma_enabled = 1;
200196
hal->no_compensate = 1;
201197
// Ignore CS bits
202198

@@ -315,16 +311,34 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou
315311
hal->rcv_buffer = NULL;
316312
// Reset timing_conf in case we've moved since the last time we used it.
317313
hal->timing_conf = &self->timing_conf;
314+
lldesc_t tx_dma __attribute__((aligned(16)));
315+
lldesc_t rx_dma __attribute__((aligned(16)));
316+
hal->dmadesc_tx = &tx_dma;
317+
hal->dmadesc_rx = &rx_dma;
318+
hal->dmadesc_n = 1;
319+
320+
size_t burst_length;
321+
// If both of the incoming pointers are DMA capable then use DMA. Otherwise, do
322+
// bursts the size of the SPI data buffer without DMA.
323+
if ((data_out == NULL || esp_ptr_dma_capable(data_out)) &&
324+
(data_in == NULL || esp_ptr_dma_capable(data_out))) {
325+
hal->dma_enabled = 1;
326+
burst_length = LLDESC_MAX_NUM_PER_DESC;
327+
} else {
328+
hal->dma_enabled = 0;
329+
burst_length = sizeof(hal->hw->data_buf);
330+
}
331+
318332
// This rounds up.
319-
size_t dma_count = (len + LLDESC_MAX_NUM_PER_DESC - 1) / LLDESC_MAX_NUM_PER_DESC;
320-
for (size_t i = 0; i < dma_count; i++) {
321-
size_t offset = LLDESC_MAX_NUM_PER_DESC * i;
322-
size_t dma_len = len - offset;
323-
if (dma_len > LLDESC_MAX_NUM_PER_DESC) {
324-
dma_len = LLDESC_MAX_NUM_PER_DESC;
333+
size_t burst_count = (len + burst_length - 1) / burst_length;
334+
for (size_t i = 0; i < burst_count; i++) {
335+
size_t offset = burst_length * i;
336+
size_t this_length = len - offset;
337+
if (this_length > burst_length) {
338+
this_length = burst_length;
325339
}
326-
hal->tx_bitlen = dma_len * self->bits;
327-
hal->rx_bitlen = dma_len * self->bits;
340+
hal->tx_bitlen = this_length * self->bits;
341+
hal->rx_bitlen = this_length * self->bits;
328342
if (data_out != NULL) {
329343
hal->send_buffer = (uint8_t*) data_out + offset;
330344
}
@@ -341,6 +355,9 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou
341355
}
342356
spi_hal_fetch_result(hal);
343357
}
358+
hal->dmadesc_tx = NULL;
359+
hal->dmadesc_rx = NULL;
360+
hal->dmadesc_n = 0;
344361

345362
return true;
346363
}

ports/esp32s2/common-hal/busio/SPI.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ typedef struct {
4444
spi_hal_context_t hal_context;
4545
spi_hal_timing_conf_t timing_conf;
4646
intr_handle_t interrupt;
47-
// IDF allocates these in DMA accessible memory so they may need to move when
48-
// we use external RAM for CircuitPython.
49-
lldesc_t tx_dma;
50-
lldesc_t rx_dma;
5147
uint32_t target_frequency;
5248
int32_t real_frequency;
5349
uint8_t polarity;

0 commit comments

Comments
 (0)