diff options
Diffstat (limited to 'atmel-samd')
| -rw-r--r-- | atmel-samd/common-hal/busio/SPI.c | 13 | ||||
| -rw-r--r-- | atmel-samd/shared_dma.c | 18 | ||||
| -rw-r--r-- | atmel-samd/shared_dma.h | 1 |
3 files changed, 27 insertions, 5 deletions
diff --git a/atmel-samd/common-hal/busio/SPI.c b/atmel-samd/common-hal/busio/SPI.c index c1b13cec8..e5a945df2 100644 --- a/atmel-samd/common-hal/busio/SPI.c +++ b/atmel-samd/common-hal/busio/SPI.c @@ -257,3 +257,16 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, } return status == STATUS_OK; } + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) { + if (len == 0) { + return true; + } + enum status_code status; + if (len >= 16) { + status = shared_dma_transfer(self->spi_master_instance.hw, data_out, data_in, len, 0 /*ignored*/); + } else { + status = spi_transceive_buffer_wait(&self->spi_master_instance, data_out, data_in, len); + } + return status == STATUS_OK; +} diff --git a/atmel-samd/shared_dma.c b/atmel-samd/shared_dma.c index 461798366..c0f0d4672 100644 --- a/atmel-samd/shared_dma.c +++ b/atmel-samd/shared_dma.c @@ -103,7 +103,7 @@ enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_ } dma_configure(general_dma_tx.channel_id, sercom_index(sercom) * 2 + 2, false); - // Set up TX second. + // Set up TX. There is no RX job. struct dma_descriptor_config descriptor_config; dma_descriptor_get_config_defaults(&descriptor_config); descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; @@ -137,6 +137,12 @@ enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_ } enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx) { + return shared_dma_transfer(sercom, NULL, buffer, length, tx); +} + +// Do write and read simultaneously. If buffer_out is NULL, write the tx byte over and over. +// If buffer_out is a real buffer, ignore tx. +enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx) { if (general_dma_tx.job_status != STATUS_OK) { return general_dma_tx.job_status; } @@ -153,17 +159,19 @@ enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t lengt descriptor_config.block_transfer_count = length; // DATA register is consistently addressed across all SERCOM modes. descriptor_config.source_address = ((uint32_t)&sercom->SPI.DATA.reg); - descriptor_config.destination_address = ((uint32_t)buffer + length); + descriptor_config.destination_address = ((uint32_t)buffer_in + length); dma_descriptor_create(general_dma_rx.descriptor, &descriptor_config); - // Set up TX to retransmit the same byte over and over. + // Set up TX second. dma_descriptor_get_config_defaults(&descriptor_config); descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE; - descriptor_config.src_increment_enable = false; + // Increment write address only if we have a real buffer. + descriptor_config.src_increment_enable = buffer_out != NULL; descriptor_config.dst_increment_enable = false; descriptor_config.block_transfer_count = length; - descriptor_config.source_address = ((uint32_t)&tx); + // + descriptor_config.source_address = ((uint32_t) (buffer_out != NULL ? buffer_out + length : &tx)); // DATA register is consistently addressed across all SERCOM modes. descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg); diff --git a/atmel-samd/shared_dma.h b/atmel-samd/shared_dma.h index 7aa45547d..251b8357b 100644 --- a/atmel-samd/shared_dma.h +++ b/atmel-samd/shared_dma.h @@ -39,6 +39,7 @@ void init_shared_dma(void); enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length); enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx); +enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx); // Allocate a counter to track how far along we are in a DMA double buffer. bool allocate_block_counter(void); |
