summaryrefslogtreecommitdiff
path: root/atmel-samd
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2017-12-04 21:49:31 -0500
committerScott Shawcroft <scott@tannewt.org>2017-12-05 11:17:16 -0800
commite75fd0e166375727fbb4c054478c9c8d329477c4 (patch)
treee4b496088305270f1e8a72678c715f3c2b27fd64 /atmel-samd
parent9ac6890d209ed2055321b39b5ae0d95709b076ea (diff)
add SPI.write_readinto() - bidirectional SPI
Diffstat (limited to 'atmel-samd')
-rw-r--r--atmel-samd/common-hal/busio/SPI.c13
-rw-r--r--atmel-samd/shared_dma.c18
-rw-r--r--atmel-samd/shared_dma.h1
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);