diff options
| -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 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.c | 83 | ||||
| -rw-r--r-- | shared-bindings/busio/SPI.h | 3 |
5 files changed, 103 insertions, 15 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); diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 72787af30..c4c139105 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -206,12 +206,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock); //| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer)) //| -//| Write the data contained in ``buf``. Requires the SPI being locked. +//| Write the data contained in ``buffer``. The SPI object must be locked. //| If the buffer is empty, nothing happens. //| -//| :param bytearray buffer: buffer containing the bytes to write -//| :param int start: Index to start writing from -//| :param int end: Index to read up to but not include +//| :param bytearray buffer: Write out the data in this buffer +//| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]`` +//| :param int end: End of the slice; this index is not included //| STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; @@ -247,14 +247,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_obj, 2, busio_spi_write); //| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0) //| -//| Read into the buffer specified by ``buf`` while writing zeroes. -//| Requires the SPI being locked. +//| Read into ``buffer`` while writing ``write_value`` for each byte read. +//| The SPI object must be locked. //| If the number of bytes to read is 0, nothing happens. //| -//| :param bytearray buffer: buffer to write into -//| :param int start: Index to start writing at -//| :param int end: Index to write up to but not include -//| :param int write_value: Value to write reading. (Usually ignored.) +//| :param bytearray buffer: Read data into this buffer +//| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]`` +//| :param int end: End of the slice; this index is not included +//| :param int write_value: Value to write while reading. (Usually ignored.) //| STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; @@ -288,6 +288,68 @@ STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_m } MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto); +//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in)) +//| +//| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``. +//| The SPI object must be locked. +//| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]`` +//| must be equal. +//| If buffer slice lengths are both 0, nothing happens. +//| +//| :param bytearray buffer_out: Write out the data in this buffer +//| :param bytearray buffer_in: Read data into this buffer +//| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]`` +//| :param int out_end: End of the slice; this index is not included +//| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]`` +//| :param int in_end: End of the slice; this index is not included +//| +STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + raise_error_if_deinited(common_hal_busio_spi_deinited(self)); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t buf_out_info; + mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ); + int32_t out_start = args[ARG_out_start].u_int; + uint32_t out_length = buf_out_info.len; + normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE); + int32_t in_start = args[ARG_in_start].u_int; + uint32_t in_length = buf_in_info.len; + normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + + if (out_length != in_length) { + mp_raise_ValueError("buffer slices must be of equal length"); + } + + if (out_length == 0) { + return mp_const_none; + } + + bool ok = common_hal_busio_spi_transfer(self, + ((uint8_t*)buf_out_info.buf) + out_start, + ((uint8_t*)buf_in_info.buf) + in_start, + out_length); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto); + STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, @@ -299,6 +361,7 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) }, }; STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table); diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index ac31d5060..b6e5c9b1b 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -55,4 +55,7 @@ extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *dat // Reads in len bytes while outputting zeroes. extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); +// Reads and write len bytes simultaneously. +extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H |
