🌐 AI搜索 & 代理 主页
Skip to content

Commit e75fd0e

Browse files
dhalberttannewt
authored andcommitted
add SPI.write_readinto() - bidirectional SPI
1 parent 9ac6890 commit e75fd0e

File tree

5 files changed

+103
-15
lines changed

5 files changed

+103
-15
lines changed

atmel-samd/common-hal/busio/SPI.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,16 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
257257
}
258258
return status == STATUS_OK;
259259
}
260+
261+
bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) {
262+
if (len == 0) {
263+
return true;
264+
}
265+
enum status_code status;
266+
if (len >= 16) {
267+
status = shared_dma_transfer(self->spi_master_instance.hw, data_out, data_in, len, 0 /*ignored*/);
268+
} else {
269+
status = spi_transceive_buffer_wait(&self->spi_master_instance, data_out, data_in, len);
270+
}
271+
return status == STATUS_OK;
272+
}

atmel-samd/shared_dma.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_
103103
}
104104
dma_configure(general_dma_tx.channel_id, sercom_index(sercom) * 2 + 2, false);
105105

106-
// Set up TX second.
106+
// Set up TX. There is no RX job.
107107
struct dma_descriptor_config descriptor_config;
108108
dma_descriptor_get_config_defaults(&descriptor_config);
109109
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_
137137
}
138138

139139
enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx) {
140+
return shared_dma_transfer(sercom, NULL, buffer, length, tx);
141+
}
142+
143+
// Do write and read simultaneously. If buffer_out is NULL, write the tx byte over and over.
144+
// If buffer_out is a real buffer, ignore tx.
145+
enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx) {
140146
if (general_dma_tx.job_status != STATUS_OK) {
141147
return general_dma_tx.job_status;
142148
}
@@ -153,17 +159,19 @@ enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t lengt
153159
descriptor_config.block_transfer_count = length;
154160
// DATA register is consistently addressed across all SERCOM modes.
155161
descriptor_config.source_address = ((uint32_t)&sercom->SPI.DATA.reg);
156-
descriptor_config.destination_address = ((uint32_t)buffer + length);
162+
descriptor_config.destination_address = ((uint32_t)buffer_in + length);
157163

158164
dma_descriptor_create(general_dma_rx.descriptor, &descriptor_config);
159165

160-
// Set up TX to retransmit the same byte over and over.
166+
// Set up TX second.
161167
dma_descriptor_get_config_defaults(&descriptor_config);
162168
descriptor_config.beat_size = DMA_BEAT_SIZE_BYTE;
163-
descriptor_config.src_increment_enable = false;
169+
// Increment write address only if we have a real buffer.
170+
descriptor_config.src_increment_enable = buffer_out != NULL;
164171
descriptor_config.dst_increment_enable = false;
165172
descriptor_config.block_transfer_count = length;
166-
descriptor_config.source_address = ((uint32_t)&tx);
173+
//
174+
descriptor_config.source_address = ((uint32_t) (buffer_out != NULL ? buffer_out + length : &tx));
167175
// DATA register is consistently addressed across all SERCOM modes.
168176
descriptor_config.destination_address = ((uint32_t)&sercom->SPI.DATA.reg);
169177

atmel-samd/shared_dma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void init_shared_dma(void);
3939

4040
enum status_code shared_dma_write(Sercom* sercom, const uint8_t* buffer, uint32_t length);
4141
enum status_code shared_dma_read(Sercom* sercom, uint8_t* buffer, uint32_t length, uint8_t tx);
42+
enum status_code shared_dma_transfer(Sercom* sercom, uint8_t* buffer_out, uint8_t* buffer_in, uint32_t length, uint8_t tx);
4243

4344
// Allocate a counter to track how far along we are in a DMA double buffer.
4445
bool allocate_block_counter(void);

shared-bindings/busio/SPI.c

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_unlock_obj, busio_spi_obj_unlock);
206206

207207
//| .. method:: SPI.write(buffer, \*, start=0, end=len(buffer))
208208
//|
209-
//| Write the data contained in ``buf``. Requires the SPI being locked.
209+
//| Write the data contained in ``buffer``. The SPI object must be locked.
210210
//| If the buffer is empty, nothing happens.
211211
//|
212-
//| :param bytearray buffer: buffer containing the bytes to write
213-
//| :param int start: Index to start writing from
214-
//| :param int end: Index to read up to but not include
212+
//| :param bytearray buffer: Write out the data in this buffer
213+
//| :param int start: Start of the slice of ``buffer`` to write out: ``buffer[start:end]``
214+
//| :param int end: End of the slice; this index is not included
215215
//|
216216
STATIC mp_obj_t busio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
217217
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);
247247

248248
//| .. method:: SPI.readinto(buffer, \*, start=0, end=len(buffer), write_value=0)
249249
//|
250-
//| Read into the buffer specified by ``buf`` while writing zeroes.
251-
//| Requires the SPI being locked.
250+
//| Read into ``buffer`` while writing ``write_value`` for each byte read.
251+
//| The SPI object must be locked.
252252
//| If the number of bytes to read is 0, nothing happens.
253253
//|
254-
//| :param bytearray buffer: buffer to write into
255-
//| :param int start: Index to start writing at
256-
//| :param int end: Index to write up to but not include
257-
//| :param int write_value: Value to write reading. (Usually ignored.)
254+
//| :param bytearray buffer: Read data into this buffer
255+
//| :param int start: Start of the slice of ``buffer`` to read into: ``buffer[start:end]``
256+
//| :param int end: End of the slice; this index is not included
257+
//| :param int write_value: Value to write while reading. (Usually ignored.)
258258
//|
259259
STATIC mp_obj_t busio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
260260
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
288288
}
289289
MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_readinto_obj, 2, busio_spi_readinto);
290290

291+
//| .. method:: SPI.write_readinto(buffer_out, buffer_in, \*, out_start=0, out_end=len(buffer_out), in_start=0, in_end=len(buffer_in))
292+
//|
293+
//| Write out the data in ``buffer_out`` while simultaneously reading data into ``buffer_in``.
294+
//| The SPI object must be locked.
295+
//| The lengths of the slices defined by ``buffer_out[out_start:out_end]`` and ``buffer_in[in_start:in_end]``
296+
//| must be equal.
297+
//| If buffer slice lengths are both 0, nothing happens.
298+
//|
299+
//| :param bytearray buffer_out: Write out the data in this buffer
300+
//| :param bytearray buffer_in: Read data into this buffer
301+
//| :param int out_start: Start of the slice of buffer_out to write out: ``buffer_out[out_start:out_end]``
302+
//| :param int out_end: End of the slice; this index is not included
303+
//| :param int in_start: Start of the slice of ``buffer_in`` to read into: ``buffer_in[in_start:in_end]``
304+
//| :param int in_end: End of the slice; this index is not included
305+
//|
306+
STATIC mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
307+
enum { ARG_buffer_out, ARG_buffer_in, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
308+
static const mp_arg_t allowed_args[] = {
309+
{ MP_QSTR_buffer_out, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
310+
{ MP_QSTR_buffer_in, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
311+
{ MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
312+
{ MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
313+
{ MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
314+
{ MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
315+
};
316+
busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
317+
raise_error_if_deinited(common_hal_busio_spi_deinited(self));
318+
check_lock(self);
319+
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
320+
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
321+
322+
mp_buffer_info_t buf_out_info;
323+
mp_get_buffer_raise(args[ARG_buffer_out].u_obj, &buf_out_info, MP_BUFFER_READ);
324+
int32_t out_start = args[ARG_out_start].u_int;
325+
uint32_t out_length = buf_out_info.len;
326+
normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length);
327+
328+
mp_buffer_info_t buf_in_info;
329+
mp_get_buffer_raise(args[ARG_buffer_in].u_obj, &buf_in_info, MP_BUFFER_WRITE);
330+
int32_t in_start = args[ARG_in_start].u_int;
331+
uint32_t in_length = buf_in_info.len;
332+
normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length);
333+
334+
if (out_length != in_length) {
335+
mp_raise_ValueError("buffer slices must be of equal length");
336+
}
337+
338+
if (out_length == 0) {
339+
return mp_const_none;
340+
}
341+
342+
bool ok = common_hal_busio_spi_transfer(self,
343+
((uint8_t*)buf_out_info.buf) + out_start,
344+
((uint8_t*)buf_in_info.buf) + in_start,
345+
out_length);
346+
if (!ok) {
347+
mp_raise_OSError(MP_EIO);
348+
}
349+
return mp_const_none;
350+
}
351+
MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 2, busio_spi_write_readinto);
352+
291353
STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = {
292354
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) },
293355
{ 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[] = {
299361

300362
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busio_spi_readinto_obj) },
301363
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busio_spi_write_obj) },
364+
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) },
302365
};
303366
STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table);
304367

shared-bindings/busio/SPI.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,7 @@ extern bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *dat
5555
// Reads in len bytes while outputting zeroes.
5656
extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value);
5757

58+
// Reads and write len bytes simultaneously.
59+
extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len);
60+
5861
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_H

0 commit comments

Comments
 (0)