add background read files
This commit is contained in:
parent
b83a1d763f
commit
f14b4c6636
5 changed files with 565 additions and 91 deletions
|
|
@ -480,7 +480,25 @@ void __not_in_flash_func(isr_dma_0)(void) {
|
||||||
}
|
}
|
||||||
if (MP_STATE_PORT(background_pio)[i] != NULL) {
|
if (MP_STATE_PORT(background_pio)[i] != NULL) {
|
||||||
rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio)[i];
|
rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio)[i];
|
||||||
rp2pio_statemachine_dma_complete(pio, i);
|
rp2pio_statemachine_dma_complete_write(pio, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __not_in_flash_func(isr_dma_1)(void) {
|
||||||
|
for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) {
|
||||||
|
uint32_t mask = 1 << i;
|
||||||
|
if ((dma_hw->intr & mask) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// acknowledge interrupt early. Doing so late means that you could lose an
|
||||||
|
// interrupt if the buffer is very small and the DMA operation
|
||||||
|
// completed by the time callback_add() / dma_complete() returned. This
|
||||||
|
// affected PIO continuous write more than audio.
|
||||||
|
dma_hw->ints1 = mask;
|
||||||
|
if (MP_STATE_PORT(background_pio)[i] != NULL) {
|
||||||
|
rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio)[i];
|
||||||
|
rp2pio_statemachine_dma_complete_read(pio, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -535,10 +535,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_write_obj, 2, rp2pio_statemachine
|
||||||
//| """
|
//| """
|
||||||
//| ...
|
//| ...
|
||||||
|
|
||||||
static void fill_buf_info(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_bytes) {
|
static void fill_buf_info(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_bytes, mp_uint_t direction) {
|
||||||
if (obj != mp_const_none) {
|
if (obj != mp_const_none) {
|
||||||
info->obj = obj;
|
info->obj = obj;
|
||||||
mp_get_buffer_raise(obj, &info->info, MP_BUFFER_READ);
|
mp_get_buffer_raise(obj, &info->info, direction);
|
||||||
size_t stride = mp_binary_get_size('@', info->info.typecode, NULL);
|
size_t stride = mp_binary_get_size('@', info->info.typecode, NULL);
|
||||||
if (stride > 4) {
|
if (stride > 4) {
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("Buffer elements must be 4 bytes long or less"));
|
mp_raise_ValueError(MP_ERROR_TEXT("Buffer elements must be 4 bytes long or less"));
|
||||||
|
|
@ -553,27 +553,29 @@ static void fill_buf_info(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_byt
|
||||||
}
|
}
|
||||||
|
|
||||||
static mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
static mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
enum { ARG_once, ARG_loop, ARG_swap };
|
enum { ARG_once, ARG_loop, ARG_loop2, ARG_swap };
|
||||||
static const mp_arg_t allowed_args[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
{ MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
|
{ MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
|
||||||
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||||
};
|
};
|
||||||
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||||
check_for_deinit(self);
|
check_for_deinit(self);
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
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_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
sm_buf_info once_info;
|
|
||||||
sm_buf_info loop_info;
|
|
||||||
size_t stride_in_bytes = 0;
|
size_t stride_in_bytes = 0;
|
||||||
fill_buf_info(&once_info, args[ARG_once].u_obj, &stride_in_bytes);
|
|
||||||
fill_buf_info(&loop_info, args[ARG_loop].u_obj, &stride_in_bytes);
|
fill_buf_info(&self->once_write_buf_info, args[ARG_once].u_obj, &stride_in_bytes, MP_BUFFER_READ);
|
||||||
|
fill_buf_info(&self->loop_write_buf_info, args[ARG_loop].u_obj, &stride_in_bytes, MP_BUFFER_READ);
|
||||||
|
fill_buf_info(&self->loop2_write_buf_info, args[ARG_loop2].u_obj, &stride_in_bytes, MP_BUFFER_READ);
|
||||||
|
|
||||||
if (!stride_in_bytes) {
|
if (!stride_in_bytes) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = common_hal_rp2pio_statemachine_background_write(self, &once_info, &loop_info, stride_in_bytes, args[ARG_swap].u_bool);
|
bool ok = common_hal_rp2pio_statemachine_background_write(self, stride_in_bytes, args[ARG_swap].u_bool);
|
||||||
|
|
||||||
if (mp_hal_is_interrupted()) {
|
if (mp_hal_is_interrupted()) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
|
|
@ -602,6 +604,7 @@ static mp_obj_t rp2pio_statemachine_obj_stop_background_write(mp_obj_t self_in)
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_background_write_obj, rp2pio_statemachine_obj_stop_background_write);
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_background_write_obj, rp2pio_statemachine_obj_stop_background_write);
|
||||||
|
|
||||||
|
|
||||||
//| writing: bool
|
//| writing: bool
|
||||||
//| """Returns True if a background write is in progress"""
|
//| """Returns True if a background write is in progress"""
|
||||||
static mp_obj_t rp2pio_statemachine_obj_get_writing(mp_obj_t self_in) {
|
static mp_obj_t rp2pio_statemachine_obj_get_writing(mp_obj_t self_in) {
|
||||||
|
|
@ -613,18 +616,145 @@ MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_writing_obj, rp2pio_statemachi
|
||||||
MP_PROPERTY_GETTER(rp2pio_statemachine_writing_obj,
|
MP_PROPERTY_GETTER(rp2pio_statemachine_writing_obj,
|
||||||
(mp_obj_t)&rp2pio_statemachine_get_writing_obj);
|
(mp_obj_t)&rp2pio_statemachine_get_writing_obj);
|
||||||
|
|
||||||
|
//| pending_write: int
|
||||||
//| pending: int
|
//| pending: int
|
||||||
//| """Returns the number of pending buffers for background writing.
|
//| """Returns the number of pending buffers for background writing.
|
||||||
//|
|
//|
|
||||||
//| If the number is 0, then a `StateMachine.background_write` call will not block."""
|
//| If the number is 0, then a `StateMachine.background_write` call will not block.
|
||||||
static mp_obj_t rp2pio_statemachine_obj_get_pending(mp_obj_t self_in) {
|
//| Note that `pending` is a deprecated alias for `pending_write` and will be removed
|
||||||
|
//| in a future version of CircuitPython."""
|
||||||
|
|
||||||
|
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_get_pending_write(mp_obj_t self_in) {
|
||||||
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
return mp_obj_new_int(common_hal_rp2pio_statemachine_get_pending(self));
|
return mp_obj_new_int(common_hal_rp2pio_statemachine_get_pending_write(self));
|
||||||
}
|
}
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pending_obj, rp2pio_statemachine_obj_get_pending);
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pending_write_obj, rp2pio_statemachine_obj_get_pending_write);
|
||||||
|
|
||||||
MP_PROPERTY_GETTER(rp2pio_statemachine_pending_obj,
|
MP_PROPERTY_GETTER(rp2pio_statemachine_pending_obj,
|
||||||
(mp_obj_t)&rp2pio_statemachine_get_pending_obj);
|
(mp_obj_t)&rp2pio_statemachine_get_pending_write_obj);
|
||||||
|
|
||||||
|
MP_PROPERTY_GETTER(rp2pio_statemachine_pending_write_obj,
|
||||||
|
(mp_obj_t)&rp2pio_statemachine_get_pending_write_obj);
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================================================================================
|
||||||
|
|
||||||
|
//| def background_read(
|
||||||
|
//| self,
|
||||||
|
//| once: Optional[WriteableBuffer] = None,
|
||||||
|
//| *,
|
||||||
|
//| loop: Optional[WriteableBuffer] = None,
|
||||||
|
//| swap: bool = False,
|
||||||
|
//| ) -> None:
|
||||||
|
//| """Read data from the RX fifo in the background, with optional looping.
|
||||||
|
//|
|
||||||
|
//| First, if any previous ``once`` or ``loop`` buffer has not been started, this function blocks until they have been started.
|
||||||
|
//| This means that any ``once`` or ``loop`` buffer will be read at least once.
|
||||||
|
//| Then the ``once`` and/or ``loop`` buffers are queued. and the function returns.
|
||||||
|
//| The ``once`` buffer (if specified) will be read just once.
|
||||||
|
//| Finally, the ``loop`` buffer (if specified) will continue being read indefinitely.
|
||||||
|
//|
|
||||||
|
//| Reads from the FIFO will match the input buffer's element size. For example, bytearray elements
|
||||||
|
//| will perform 8 bit reads from the PIO FIFO. The RP2040's memory bus will duplicate the value into
|
||||||
|
//| the other byte positions. So, pulling more data in the PIO assembly will read the duplicated values.
|
||||||
|
//|
|
||||||
|
//| To perform 16 or 32 bits reads from the FIFO use an `array.array` with a type code of the desired
|
||||||
|
//| size, or use `memoryview.cast` to change the interpretation of an
|
||||||
|
//| existing buffer. To receive just part of a larger buffer, slice a `memoryview`
|
||||||
|
//| of it.
|
||||||
|
//|
|
||||||
|
//| Most use cases will probably only use one of ``once`` or ``loop``.
|
||||||
|
//|
|
||||||
|
//| Having neither ``once`` nor ``loop`` terminates an existing
|
||||||
|
//| background looping read after exactly a whole loop. This is in contrast to
|
||||||
|
//| `stop_background_read`, which interrupts an ongoing DMA operation.
|
||||||
|
//|
|
||||||
|
//| :param ~Optional[circuitpython_typing.WriteableBuffer] once: Data to be read once
|
||||||
|
//| :param ~Optional[circuitpython_typing.WriteableBuffer] loop: Data to be read repeatedly
|
||||||
|
//| :param bool swap: For 2- and 4-byte elements, swap (reverse) the byte order
|
||||||
|
//| """
|
||||||
|
//| ...
|
||||||
|
|
||||||
|
|
||||||
|
static mp_obj_t rp2pio_statemachine_background_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
|
enum { ARG_once, ARG_loop, ARG_loop2, ARG_swap };
|
||||||
|
static const mp_arg_t allowed_args[] = {
|
||||||
|
{ MP_QSTR_once, MP_ARG_OBJ, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_loop, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_loop2, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} },
|
||||||
|
{ MP_QSTR_swap, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
|
||||||
|
};
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||||
|
check_for_deinit(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);
|
||||||
|
|
||||||
|
size_t stride_in_bytes = 0;
|
||||||
|
|
||||||
|
fill_buf_info(&self->once_read_buf_info, args[ARG_once].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
|
||||||
|
fill_buf_info(&self->loop_read_buf_info, args[ARG_loop].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
|
||||||
|
fill_buf_info(&self->loop2_read_buf_info, args[ARG_loop2].u_obj, &stride_in_bytes, MP_BUFFER_WRITE);
|
||||||
|
|
||||||
|
if (!stride_in_bytes) {
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = common_hal_rp2pio_statemachine_background_read(self, stride_in_bytes, args[ARG_swap].u_bool);
|
||||||
|
|
||||||
|
if (mp_hal_is_interrupted()) {
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
mp_raise_OSError(MP_EIO);
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(rp2pio_statemachine_background_read_obj, 1, rp2pio_statemachine_background_read);
|
||||||
|
|
||||||
|
//| def stop_background_read(self) -> None:
|
||||||
|
//| """Immediately stop a background read, if one is in progress. Any
|
||||||
|
//| DMA in progress is halted, but items already in the RX FIFO are not
|
||||||
|
//| affected."""
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_stop_background_read(mp_obj_t self_in) {
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
bool ok = common_hal_rp2pio_statemachine_stop_background_read(self);
|
||||||
|
if (mp_hal_is_interrupted()) {
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
if (!ok) {
|
||||||
|
mp_raise_OSError(MP_EIO);
|
||||||
|
}
|
||||||
|
return mp_const_none;
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_stop_background_read_obj, rp2pio_statemachine_obj_stop_background_read);
|
||||||
|
|
||||||
|
//| reading: bool
|
||||||
|
//| """Returns True if a background read is in progress"""
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_get_reading(mp_obj_t self_in) {
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
return mp_obj_new_bool(common_hal_rp2pio_statemachine_get_reading(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_reading_obj, rp2pio_statemachine_obj_get_reading);
|
||||||
|
|
||||||
|
MP_PROPERTY_GETTER(rp2pio_statemachine_reading_obj,
|
||||||
|
(mp_obj_t)&rp2pio_statemachine_get_reading_obj);
|
||||||
|
|
||||||
|
//| pending_read: int
|
||||||
|
//| """Returns the number of pending buffers for background reading.
|
||||||
|
//|
|
||||||
|
//| If the number is 0, then a `StateMachine.background_read` call will not block."""
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_get_pending_read(mp_obj_t self_in) {
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
return mp_obj_new_int(common_hal_rp2pio_statemachine_get_pending_read(self));
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pending_read_obj, rp2pio_statemachine_obj_get_pending_read);
|
||||||
|
|
||||||
|
MP_PROPERTY_GETTER(rp2pio_statemachine_pending_read_obj,
|
||||||
|
(mp_obj_t)&rp2pio_statemachine_get_pending_read_obj);
|
||||||
|
|
||||||
|
|
||||||
|
// =================================================================================================================================
|
||||||
|
|
||||||
//| def readinto(
|
//| def readinto(
|
||||||
//| self,
|
//| self,
|
||||||
|
|
@ -924,6 +1054,42 @@ MP_PROPERTY_GETTER(rp2pio_statemachine_rxfifo_obj,
|
||||||
(mp_obj_t)&rp2pio_statemachine_get_rxfifo_obj);
|
(mp_obj_t)&rp2pio_statemachine_get_rxfifo_obj);
|
||||||
|
|
||||||
|
|
||||||
|
//| last_read: array.array
|
||||||
|
//| """Returns the buffer most recently filled by background reads.
|
||||||
|
//|
|
||||||
|
//| This property is self-clearing -- once read, subsequent reads
|
||||||
|
//| will return a zero-length buffer until the background read buffer
|
||||||
|
//| changes or restarts.
|
||||||
|
//| """
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_get_last_read(mp_obj_t self_in) {
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
check_for_deinit(self);
|
||||||
|
return common_hal_rp2pio_statemachine_get_last_read(self);
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_last_read_obj, rp2pio_statemachine_obj_get_last_read);
|
||||||
|
|
||||||
|
MP_PROPERTY_GETTER(rp2pio_statemachine_last_read_obj,
|
||||||
|
(mp_obj_t)&rp2pio_statemachine_get_last_read_obj);
|
||||||
|
|
||||||
|
|
||||||
|
//| last_write: array.array
|
||||||
|
//| """Returns the buffer most recently emptied by background writes.
|
||||||
|
//|
|
||||||
|
//| This property is self-clearing -- once read, subsequent reads
|
||||||
|
//| will return a zero-length buffer until the background write buffer
|
||||||
|
//| changes or restarts.
|
||||||
|
//| """
|
||||||
|
//|
|
||||||
|
static mp_obj_t rp2pio_statemachine_obj_get_last_write(mp_obj_t self_in) {
|
||||||
|
rp2pio_statemachine_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
check_for_deinit(self);
|
||||||
|
return common_hal_rp2pio_statemachine_get_last_write(self);
|
||||||
|
}
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_last_write_obj, rp2pio_statemachine_obj_get_last_write);
|
||||||
|
|
||||||
|
MP_PROPERTY_GETTER(rp2pio_statemachine_last_write_obj,
|
||||||
|
(mp_obj_t)&rp2pio_statemachine_get_last_write_obj);
|
||||||
|
|
||||||
static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
|
static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rp2pio_statemachine_deinit_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rp2pio_statemachine_deinit_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||||
|
|
@ -938,10 +1104,17 @@ static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&rp2pio_statemachine_readinto_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&rp2pio_statemachine_readinto_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&rp2pio_statemachine_write_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&rp2pio_statemachine_write_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&rp2pio_statemachine_write_readinto_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&rp2pio_statemachine_write_readinto_obj) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_background_write), MP_ROM_PTR(&rp2pio_statemachine_background_write_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_background_write), MP_ROM_PTR(&rp2pio_statemachine_background_write_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_stop_background_write), MP_ROM_PTR(&rp2pio_statemachine_stop_background_write_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_stop_background_write), MP_ROM_PTR(&rp2pio_statemachine_stop_background_write_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_writing), MP_ROM_PTR(&rp2pio_statemachine_writing_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_writing), MP_ROM_PTR(&rp2pio_statemachine_writing_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_pending), MP_ROM_PTR(&rp2pio_statemachine_pending_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_pending), MP_ROM_PTR(&rp2pio_statemachine_pending_write_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_pending_write), MP_ROM_PTR(&rp2pio_statemachine_pending_write_obj) },
|
||||||
|
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_background_read), MP_ROM_PTR(&rp2pio_statemachine_background_read_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_stop_background_read), MP_ROM_PTR(&rp2pio_statemachine_stop_background_read_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_reading), MP_ROM_PTR(&rp2pio_statemachine_reading_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_pending_read), MP_ROM_PTR(&rp2pio_statemachine_pending_read_obj) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&rp2pio_statemachine_frequency_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&rp2pio_statemachine_frequency_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_rxstall), MP_ROM_PTR(&rp2pio_statemachine_rxstall_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_rxstall), MP_ROM_PTR(&rp2pio_statemachine_rxstall_obj) },
|
||||||
|
|
@ -952,6 +1125,10 @@ static const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
|
||||||
{ MP_ROM_QSTR(MP_QSTR_pc), MP_ROM_PTR(&rp2pio_statemachine_pc_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_pc), MP_ROM_PTR(&rp2pio_statemachine_pc_obj) },
|
||||||
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_rxfifo), MP_ROM_PTR(&rp2pio_statemachine_rxfifo_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_rxfifo), MP_ROM_PTR(&rp2pio_statemachine_rxfifo_obj) },
|
||||||
|
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_last_read), MP_ROM_PTR(&rp2pio_statemachine_last_read_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_last_write), MP_ROM_PTR(&rp2pio_statemachine_last_write_obj) },
|
||||||
|
|
||||||
};
|
};
|
||||||
static MP_DEFINE_CONST_DICT(rp2pio_statemachine_locals_dict, rp2pio_statemachine_locals_dict_table);
|
static MP_DEFINE_CONST_DICT(rp2pio_statemachine_locals_dict, rp2pio_statemachine_locals_dict_table);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
bool wait_for_txstall,
|
bool wait_for_txstall,
|
||||||
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
bool auto_push, uint8_t push_threshold, bool in_shift_right,
|
||||||
bool user_interruptible,
|
bool user_interruptible,
|
||||||
int wrap_taget, int wrap,
|
int wrap_target, int wrap,
|
||||||
int offset,
|
int offset,
|
||||||
int fifo_type,
|
int fifo_type,
|
||||||
int mov_status_type,
|
int mov_status_type,
|
||||||
|
|
@ -50,10 +50,22 @@ void common_hal_rp2pio_statemachine_run(rp2pio_statemachine_obj_t *self, const u
|
||||||
|
|
||||||
// Lengths are in bytes.
|
// Lengths are in bytes.
|
||||||
bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap);
|
bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap);
|
||||||
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once_obj, const sm_buf_info *loop_obj, uint8_t stride_in_bytes, bool swap);
|
|
||||||
|
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self,
|
||||||
|
uint8_t stride_in_bytes, bool swap);
|
||||||
|
|
||||||
|
bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *self,
|
||||||
|
uint8_t stride_in_bytes, bool swap);
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self);
|
||||||
mp_int_t common_hal_rp2pio_statemachine_get_pending(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
|
mp_int_t common_hal_rp2pio_statemachine_get_pending_write(rp2pio_statemachine_obj_t *self);
|
||||||
|
mp_int_t common_hal_rp2pio_statemachine_get_pending_read(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_get_writing(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_get_writing(rp2pio_statemachine_obj_t *self);
|
||||||
|
bool common_hal_rp2pio_statemachine_get_reading(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap);
|
bool common_hal_rp2pio_statemachine_readinto(rp2pio_statemachine_obj_t *self, uint8_t *data, size_t len, uint8_t stride_in_bytes, bool swap);
|
||||||
bool common_hal_rp2pio_statemachine_write_readinto(rp2pio_statemachine_obj_t *self,
|
bool common_hal_rp2pio_statemachine_write_readinto(rp2pio_statemachine_obj_t *self,
|
||||||
const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes,
|
const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes,
|
||||||
|
|
@ -65,6 +77,7 @@ void common_hal_rp2pio_statemachine_set_frequency(rp2pio_statemachine_obj_t *sel
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_get_rxstall(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_get_rxstall(rp2pio_statemachine_obj_t *self);
|
||||||
void common_hal_rp2pio_statemachine_clear_rxfifo(rp2pio_statemachine_obj_t *self);
|
void common_hal_rp2pio_statemachine_clear_rxfifo(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_get_txstall(rp2pio_statemachine_obj_t *self);
|
bool common_hal_rp2pio_statemachine_get_txstall(rp2pio_statemachine_obj_t *self);
|
||||||
void common_hal_rp2pio_statemachine_clear_txstall(rp2pio_statemachine_obj_t *self);
|
void common_hal_rp2pio_statemachine_clear_txstall(rp2pio_statemachine_obj_t *self);
|
||||||
size_t common_hal_rp2pio_statemachine_get_in_waiting(rp2pio_statemachine_obj_t *self);
|
size_t common_hal_rp2pio_statemachine_get_in_waiting(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
@ -75,3 +88,6 @@ int common_hal_rp2pio_statemachine_get_pc(rp2pio_statemachine_obj_t *self);
|
||||||
void common_hal_rp2pio_statemachine_set_interrupt_handler(rp2pio_statemachine_obj_t *self, void (*handler)(void *), void *arg, int mask);
|
void common_hal_rp2pio_statemachine_set_interrupt_handler(rp2pio_statemachine_obj_t *self, void (*handler)(void *), void *arg, int mask);
|
||||||
|
|
||||||
mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *self);
|
mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
|
mp_obj_t common_hal_rp2pio_statemachine_get_last_read(rp2pio_statemachine_obj_t *self);
|
||||||
|
mp_obj_t common_hal_rp2pio_statemachine_get_last_write(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
|
||||||
|
|
@ -37,12 +37,19 @@ static bool _never_reset[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
||||||
|
|
||||||
static uint32_t _current_pins[NUM_PIOS];
|
static uint32_t _current_pins[NUM_PIOS];
|
||||||
static uint32_t _current_sm_pins[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
static uint32_t _current_sm_pins[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
||||||
static int8_t _sm_dma_plus_one[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
|
||||||
|
|
||||||
#define SM_DMA_ALLOCATED(pio_index, sm) (_sm_dma_plus_one[(pio_index)][(sm)] != 0)
|
static int8_t _sm_dma_plus_one_write[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
||||||
#define SM_DMA_GET_CHANNEL(pio_index, sm) (_sm_dma_plus_one[(pio_index)][(sm)] - 1)
|
static int8_t _sm_dma_plus_one_read[NUM_PIOS][NUM_PIO_STATE_MACHINES];
|
||||||
#define SM_DMA_CLEAR_CHANNEL(pio_index, sm) (_sm_dma_plus_one[(pio_index)][(sm)] = 0)
|
|
||||||
#define SM_DMA_SET_CHANNEL(pio_index, sm, channel) (_sm_dma_plus_one[(pio_index)][(sm)] = (channel) + 1)
|
#define SM_DMA_ALLOCATED_WRITE(pio_index, sm) (_sm_dma_plus_one_write[(pio_index)][(sm)] != 0)
|
||||||
|
#define SM_DMA_GET_CHANNEL_WRITE(pio_index, sm) (_sm_dma_plus_one_write[(pio_index)][(sm)] - 1)
|
||||||
|
#define SM_DMA_CLEAR_CHANNEL_WRITE(pio_index, sm) (_sm_dma_plus_one_write[(pio_index)][(sm)] = 0)
|
||||||
|
#define SM_DMA_SET_CHANNEL_WRITE(pio_index, sm, channel) (_sm_dma_plus_one_write[(pio_index)][(sm)] = (channel) + 1)
|
||||||
|
|
||||||
|
#define SM_DMA_ALLOCATED_READ(pio_index, sm) (_sm_dma_plus_one_read[(pio_index)][(sm)] != 0)
|
||||||
|
#define SM_DMA_GET_CHANNEL_READ(pio_index, sm) (_sm_dma_plus_one_read[(pio_index)][(sm)] - 1)
|
||||||
|
#define SM_DMA_CLEAR_CHANNEL_READ(pio_index, sm) (_sm_dma_plus_one_read[(pio_index)][(sm)] = 0)
|
||||||
|
#define SM_DMA_SET_CHANNEL_READ(pio_index, sm, channel) (_sm_dma_plus_one_read[(pio_index)][(sm)] = (channel) + 1)
|
||||||
|
|
||||||
static PIO pio_instances[NUM_PIOS] = {
|
static PIO pio_instances[NUM_PIOS] = {
|
||||||
pio0,
|
pio0,
|
||||||
|
|
@ -81,24 +88,40 @@ static void rp2pio_statemachine_set_pull(uint32_t pull_pin_up, uint32_t pull_pin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rp2pio_statemachine_clear_dma(int pio_index, int sm) {
|
static void rp2pio_statemachine_clear_dma_write(int pio_index, int sm) {
|
||||||
if (SM_DMA_ALLOCATED(pio_index, sm)) {
|
if (SM_DMA_ALLOCATED_WRITE(pio_index, sm)) {
|
||||||
int channel = SM_DMA_GET_CHANNEL(pio_index, sm);
|
int channel_write = SM_DMA_GET_CHANNEL_WRITE(pio_index, sm);
|
||||||
uint32_t channel_mask = 1u << channel;
|
uint32_t channel_mask_write = 1u << channel_write;
|
||||||
dma_hw->inte0 &= ~channel_mask;
|
dma_hw->inte0 &= ~channel_mask_write;
|
||||||
if (!dma_hw->inte0) {
|
if (!dma_hw->inte0) {
|
||||||
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
|
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
|
||||||
}
|
}
|
||||||
MP_STATE_PORT(background_pio)[channel] = NULL;
|
MP_STATE_PORT(background_pio)[channel_write] = NULL;
|
||||||
dma_channel_abort(channel);
|
dma_channel_abort(channel_write);
|
||||||
dma_channel_unclaim(channel);
|
dma_channel_unclaim(channel_write);
|
||||||
}
|
}
|
||||||
SM_DMA_CLEAR_CHANNEL(pio_index, sm);
|
SM_DMA_CLEAR_CHANNEL_WRITE(pio_index, sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rp2pio_statemachine_clear_dma_read(int pio_index, int sm) {
|
||||||
|
if (SM_DMA_ALLOCATED_READ(pio_index, sm)) {
|
||||||
|
int channel_read = SM_DMA_GET_CHANNEL_READ(pio_index, sm);
|
||||||
|
uint32_t channel_mask_read = 1u << channel_read;
|
||||||
|
dma_hw->inte0 &= ~channel_mask_read;
|
||||||
|
if (!dma_hw->inte0) {
|
||||||
|
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
|
||||||
|
}
|
||||||
|
MP_STATE_PORT(background_pio)[channel_read] = NULL;
|
||||||
|
dma_channel_abort(channel_read);
|
||||||
|
dma_channel_unclaim(channel_read);
|
||||||
|
}
|
||||||
|
SM_DMA_CLEAR_CHANNEL_READ(pio_index, sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _reset_statemachine(PIO pio, uint8_t sm, bool leave_pins) {
|
static void _reset_statemachine(PIO pio, uint8_t sm, bool leave_pins) {
|
||||||
uint8_t pio_index = pio_get_index(pio);
|
uint8_t pio_index = pio_get_index(pio);
|
||||||
rp2pio_statemachine_clear_dma(pio_index, sm);
|
rp2pio_statemachine_clear_dma_write(pio_index, sm);
|
||||||
|
rp2pio_statemachine_clear_dma_read(pio_index, sm);
|
||||||
uint32_t program_id = _current_program_id[pio_index][sm];
|
uint32_t program_id = _current_program_id[pio_index][sm];
|
||||||
if (program_id == 0) {
|
if (program_id == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -433,7 +456,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
self->sm_config = c;
|
self->sm_config = c;
|
||||||
|
|
||||||
// no DMA allocated
|
// no DMA allocated
|
||||||
SM_DMA_CLEAR_CHANNEL(pio_index, state_machine);
|
SM_DMA_CLEAR_CHANNEL_READ(pio_index, state_machine);
|
||||||
|
SM_DMA_CLEAR_CHANNEL_WRITE(pio_index, state_machine);
|
||||||
|
|
||||||
pio_sm_init(self->pio, self->state_machine, program_offset, &c);
|
pio_sm_init(self->pio, self->state_machine, program_offset, &c);
|
||||||
common_hal_rp2pio_statemachine_run(self, init, init_len);
|
common_hal_rp2pio_statemachine_run(self, init, init_len);
|
||||||
|
|
@ -1036,16 +1060,49 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) {
|
||||||
return _current_program_offset[pio_index][sm];
|
return _current_program_offset[pio_index][sm];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, const sm_buf_info *once, const sm_buf_info *loop, uint8_t stride_in_bytes, bool swap) {
|
bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *self, uint8_t stride_in_bytes, bool swap) {
|
||||||
|
|
||||||
uint8_t pio_index = pio_get_index(self->pio);
|
uint8_t pio_index = pio_get_index(self->pio);
|
||||||
uint8_t sm = self->state_machine;
|
uint8_t sm = self->state_machine;
|
||||||
|
|
||||||
int pending_buffers = (once->info.len != 0) + (loop->info.len != 0);
|
self->switched_write_buffers = false;
|
||||||
if (!once->info.len) {
|
|
||||||
once = loop;
|
int pending_buffers_write = (self->once_write_buf_info.info.len != 0) + (self->loop_write_buf_info.info.len != 0) + (self->loop2_write_buf_info.info.len != 0);
|
||||||
|
|
||||||
|
// If all buffer arguments have nonzero length, write once_write_buf, loop_write_buf, loop2_write_buf and repeat last two forever
|
||||||
|
|
||||||
|
if (!(self->once_write_buf_info.info.len)) {
|
||||||
|
if (!self->loop_write_buf_info.info.len) {
|
||||||
|
// If once_write_buf and loop_write_buf have zero length, write loop2_write_buf forever
|
||||||
|
self->once_write_buf_info = self->loop2_write_buf_info;
|
||||||
|
self->loop_write_buf_info = self->loop2_write_buf_info;
|
||||||
|
} else {
|
||||||
|
if (!(self->loop2_write_buf_info.info.len)) {
|
||||||
|
// If once_write_buf and loop2_write_buf have zero length, write loop_write_buf forever
|
||||||
|
self->once_write_buf_info = self->loop_write_buf_info;
|
||||||
|
self->loop2_write_buf_info = self->loop_write_buf_info;
|
||||||
|
} else {
|
||||||
|
// If only once_write_buf has zero length, write loop_write_buf, loop2_write_buf, and repeat last two forever
|
||||||
|
self->once_write_buf_info = self->loop_write_buf_info;
|
||||||
|
self->loop_write_buf_info = self->loop2_write_buf_info;
|
||||||
|
self->loop2_write_buf_info = self->once_write_buf_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(self->loop_write_buf_info.info.len)) {
|
||||||
|
// If once_write_buf has nonzero length and loop_write_buf has zero length, write once_write_buf, loop2_write_buf and repeat last buf forever
|
||||||
|
self->loop_write_buf_info = self->loop2_write_buf_info;
|
||||||
|
} else {
|
||||||
|
if (!self->loop2_write_buf_info.info.len) {
|
||||||
|
// If once_write_buf has nonzero length and loop2_write_buf have zero length, write once_write_buf, loop_write_buf and repeat last buf forever
|
||||||
|
self->loop2_write_buf_info = self->loop_write_buf_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SM_DMA_ALLOCATED(pio_index, sm)) {
|
// if DMA is already going (i.e. this is not the first call to background_write),
|
||||||
|
// block until once_write_buf and loop_write_buf have each been written at least once
|
||||||
|
if (SM_DMA_ALLOCATED_WRITE(pio_index, sm)) {
|
||||||
if (stride_in_bytes != self->background_stride_in_bytes) {
|
if (stride_in_bytes != self->background_stride_in_bytes) {
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched data size"));
|
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched data size"));
|
||||||
}
|
}
|
||||||
|
|
@ -1053,7 +1110,7 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched swap flag"));
|
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched swap flag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (self->pending_buffers) {
|
while (self->pending_buffers_write) {
|
||||||
RUN_BACKGROUND_TASKS;
|
RUN_BACKGROUND_TASKS;
|
||||||
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1061,13 +1118,14 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
common_hal_mcu_disable_interrupts();
|
common_hal_mcu_disable_interrupts();
|
||||||
self->once = *once;
|
self->next_write_buf_1 = self->once_write_buf_info;
|
||||||
self->loop = *loop;
|
self->next_write_buf_2 = self->loop_write_buf_info;
|
||||||
self->pending_buffers = pending_buffers;
|
self->next_write_buf_3 = self->loop2_write_buf_info;
|
||||||
|
self->pending_buffers_write = pending_buffers_write;
|
||||||
|
|
||||||
if (self->dma_completed && self->once.info.len) {
|
if (self->dma_completed_write && self->next_write_buf_1.info.len) {
|
||||||
rp2pio_statemachine_dma_complete(self, SM_DMA_GET_CHANNEL(pio_index, sm));
|
rp2pio_statemachine_dma_complete_write(self, SM_DMA_GET_CHANNEL_WRITE(pio_index, sm));
|
||||||
self->dma_completed = false;
|
self->dma_completed_write = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
common_hal_mcu_enable_interrupts();
|
common_hal_mcu_enable_interrupts();
|
||||||
|
|
@ -1075,84 +1133,258 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t *
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int channel = dma_claim_unused_channel(false);
|
int channel_write = dma_claim_unused_channel(false);
|
||||||
if (channel == -1) {
|
if (channel_write == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SM_DMA_SET_CHANNEL(pio_index, sm, channel);
|
SM_DMA_SET_CHANNEL_WRITE(pio_index, sm, channel_write);
|
||||||
|
|
||||||
volatile uint8_t *tx_destination = (volatile uint8_t *)&self->pio->txf[self->state_machine];
|
volatile uint8_t *tx_destination = (volatile uint8_t *)&self->pio->txf[self->state_machine];
|
||||||
|
|
||||||
self->tx_dreq = pio_get_dreq(self->pio, self->state_machine, true);
|
self->tx_dreq = pio_get_dreq(self->pio, self->state_machine, true);
|
||||||
|
|
||||||
dma_channel_config c;
|
dma_channel_config c_write;
|
||||||
|
|
||||||
|
self->current_write_buf = self->once_write_buf_info;
|
||||||
|
self->next_write_buf_1 = self->loop_write_buf_info;
|
||||||
|
self->next_write_buf_2 = self->loop2_write_buf_info;
|
||||||
|
self->next_write_buf_3 = self->loop_write_buf_info;
|
||||||
|
|
||||||
|
self->pending_buffers_write = pending_buffers_write;
|
||||||
|
self->dma_completed_write = false;
|
||||||
|
|
||||||
self->current = *once;
|
|
||||||
self->once = *loop;
|
|
||||||
self->loop = *loop;
|
|
||||||
self->pending_buffers = pending_buffers;
|
|
||||||
self->dma_completed = false;
|
|
||||||
self->background_stride_in_bytes = stride_in_bytes;
|
self->background_stride_in_bytes = stride_in_bytes;
|
||||||
self->byteswap = swap;
|
self->byteswap = swap;
|
||||||
|
|
||||||
c = dma_channel_get_default_config(channel);
|
c_write = dma_channel_get_default_config(channel_write);
|
||||||
channel_config_set_transfer_data_size(&c, _stride_to_dma_size(stride_in_bytes));
|
channel_config_set_transfer_data_size(&c_write, _stride_to_dma_size(stride_in_bytes));
|
||||||
channel_config_set_dreq(&c, self->tx_dreq);
|
channel_config_set_dreq(&c_write, self->tx_dreq);
|
||||||
channel_config_set_read_increment(&c, true);
|
channel_config_set_read_increment(&c_write, true);
|
||||||
channel_config_set_write_increment(&c, false);
|
channel_config_set_write_increment(&c_write, false);
|
||||||
channel_config_set_bswap(&c, swap);
|
channel_config_set_bswap(&c_write, swap);
|
||||||
dma_channel_configure(channel, &c,
|
dma_channel_configure(channel_write, &c_write,
|
||||||
tx_destination,
|
tx_destination,
|
||||||
once->info.buf,
|
self->once_write_buf_info.info.buf,
|
||||||
once->info.len / stride_in_bytes,
|
self->once_write_buf_info.info.len / stride_in_bytes,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
common_hal_mcu_disable_interrupts();
|
common_hal_mcu_disable_interrupts();
|
||||||
|
|
||||||
// Acknowledge any previous pending interrupt
|
// Acknowledge any previous pending interrupt
|
||||||
dma_hw->ints0 |= 1u << channel;
|
dma_hw->ints0 |= 1u << channel_write;
|
||||||
MP_STATE_PORT(background_pio)[channel] = self;
|
MP_STATE_PORT(background_pio)[channel_write] = self;
|
||||||
dma_hw->inte0 |= 1u << channel;
|
dma_hw->inte0 |= 1u << channel_write;
|
||||||
|
|
||||||
irq_set_mask_enabled(1 << DMA_IRQ_0, true);
|
irq_set_mask_enabled(1 << DMA_IRQ_0, true);
|
||||||
dma_start_channel_mask(1u << channel);
|
dma_start_channel_mask(1u << channel_write);
|
||||||
common_hal_mcu_enable_interrupts();
|
common_hal_mcu_enable_interrupts();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rp2pio_statemachine_dma_complete(rp2pio_statemachine_obj_t *self, int channel) {
|
void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel_write) {
|
||||||
self->current = self->once;
|
self->current_write_buf = self->next_write_buf_1;
|
||||||
self->once = self->loop;
|
self->next_write_buf_1 = self->next_write_buf_2;
|
||||||
|
self->next_write_buf_2 = self->next_write_buf_3;
|
||||||
|
self->next_write_buf_3 = self->next_write_buf_1;
|
||||||
|
|
||||||
if (self->current.info.buf) {
|
if (self->current_write_buf.info.buf) {
|
||||||
if (self->pending_buffers > 0) {
|
if (self->pending_buffers_write > 0) {
|
||||||
self->pending_buffers--;
|
self->pending_buffers_write--;
|
||||||
}
|
}
|
||||||
dma_channel_set_read_addr(channel, self->current.info.buf, false);
|
dma_channel_set_read_addr(channel_write, self->current_write_buf.info.buf, false);
|
||||||
dma_channel_set_trans_count(channel, self->current.info.len / self->background_stride_in_bytes, true);
|
dma_channel_set_trans_count(channel_write, self->current_write_buf.info.len / self->background_stride_in_bytes, true);
|
||||||
} else {
|
} else {
|
||||||
self->dma_completed = true;
|
self->dma_completed_write = true;
|
||||||
self->pending_buffers = 0; // should be a no-op
|
self->pending_buffers_write = 0; // should be a no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->switched_write_buffers = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self) {
|
bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self) {
|
||||||
uint8_t pio_index = pio_get_index(self->pio);
|
uint8_t pio_index = pio_get_index(self->pio);
|
||||||
uint8_t sm = self->state_machine;
|
uint8_t sm = self->state_machine;
|
||||||
rp2pio_statemachine_clear_dma(pio_index, sm);
|
rp2pio_statemachine_clear_dma_write(pio_index, sm);
|
||||||
memset(&self->current, 0, sizeof(self->current));
|
memset(&self->current_write_buf, 0, sizeof(self->current_write_buf));
|
||||||
memset(&self->once, 0, sizeof(self->once));
|
memset(&self->next_write_buf_1, 0, sizeof(self->next_write_buf_1));
|
||||||
memset(&self->loop, 0, sizeof(self->loop));
|
memset(&self->next_write_buf_2, 0, sizeof(self->next_write_buf_2));
|
||||||
self->pending_buffers = 0;
|
memset(&self->next_write_buf_3, 0, sizeof(self->next_write_buf_3));
|
||||||
|
self->pending_buffers_write = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_rp2pio_statemachine_get_writing(rp2pio_statemachine_obj_t *self) {
|
bool common_hal_rp2pio_statemachine_get_writing(rp2pio_statemachine_obj_t *self) {
|
||||||
return !self->dma_completed;
|
return !self->dma_completed_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_hal_rp2pio_statemachine_get_pending(rp2pio_statemachine_obj_t *self) {
|
int common_hal_rp2pio_statemachine_get_pending_write(rp2pio_statemachine_obj_t *self) {
|
||||||
return self->pending_buffers;
|
return self->pending_buffers_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =================================================================================
|
||||||
|
|
||||||
|
bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *self, uint8_t stride_in_bytes, bool swap) {
|
||||||
|
|
||||||
|
uint8_t pio_index = pio_get_index(self->pio);
|
||||||
|
uint8_t sm = self->state_machine;
|
||||||
|
|
||||||
|
self->switched_read_buffers = false;
|
||||||
|
|
||||||
|
int pending_buffers_read = (self->once_read_buf_info.info.len != 0) + (self->loop_read_buf_info.info.len != 0) + (self->loop2_read_buf_info.info.len != 0);
|
||||||
|
|
||||||
|
// If all buffer arguments have nonzero length, read once_read_buf, loop_read_buf, loop2_read_buf and repeat last two forever
|
||||||
|
|
||||||
|
if (!(self->once_read_buf_info.info.len)) {
|
||||||
|
if (!(self->loop_read_buf_info.info.len)) {
|
||||||
|
// If once_read_buf and loop_read_buf have zero length, read loop2_read_buf forever
|
||||||
|
self->once_read_buf_info = self->loop2_read_buf_info;
|
||||||
|
self->loop_read_buf_info = self->loop2_read_buf_info;
|
||||||
|
} else {
|
||||||
|
if (!(self->loop2_read_buf_info.info.len)) {
|
||||||
|
// If once_read_buf and loop2_read_buf have zero length, read loop_read_buf forever
|
||||||
|
self->once_read_buf_info = self->loop_read_buf_info;
|
||||||
|
self->loop2_read_buf_info = self->loop_read_buf_info;
|
||||||
|
} else {
|
||||||
|
// If only once_read_buf has zero length, read loop_read_buf, loop2_read_buf, and repeat last two forever
|
||||||
|
self->once_read_buf_info = self->loop_read_buf_info;
|
||||||
|
self->loop_read_buf_info = self->loop2_read_buf_info;
|
||||||
|
self->loop2_read_buf_info = self->once_read_buf_info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(self->loop_read_buf_info.info.len)) {
|
||||||
|
// If once_read_buf has nonzero length and loop_read_buf has zero length, read once_read_buf, loop2_read_buf and repeat last buf forever
|
||||||
|
self->loop_read_buf_info = self->loop2_read_buf_info;
|
||||||
|
} else {
|
||||||
|
if (!(self->loop2_read_buf_info.info.len)) {
|
||||||
|
// If once_read_buf has nonzero length and loop2_read_buf have zero length, read once_read_buf, loop_read_buf and repeat last buf forever
|
||||||
|
self->loop2_read_buf_info = self->loop_read_buf_info;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SM_DMA_ALLOCATED_READ(pio_index, sm)) {
|
||||||
|
if (stride_in_bytes != self->background_stride_in_bytes) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched data size"));
|
||||||
|
}
|
||||||
|
if (swap != self->byteswap) {
|
||||||
|
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched swap flag"));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (self->pending_buffers_read) {
|
||||||
|
RUN_BACKGROUND_TASKS;
|
||||||
|
if (self->user_interruptible && mp_hal_is_interrupted()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
common_hal_mcu_disable_interrupts();
|
||||||
|
self->next_read_buf_1 = self->once_read_buf_info;
|
||||||
|
self->next_read_buf_2 = self->loop_read_buf_info;
|
||||||
|
self->next_read_buf_3 = self->loop2_read_buf_info;
|
||||||
|
self->pending_buffers_read = pending_buffers_read;
|
||||||
|
|
||||||
|
if (self->dma_completed_read && self->next_read_buf_1.info.len) {
|
||||||
|
rp2pio_statemachine_dma_complete_read(self, SM_DMA_GET_CHANNEL_READ(pio_index, sm));
|
||||||
|
self->dma_completed_read = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
common_hal_mcu_enable_interrupts();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int channel_read = dma_claim_unused_channel(false);
|
||||||
|
if (channel_read == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SM_DMA_SET_CHANNEL_READ(pio_index, sm, channel_read);
|
||||||
|
|
||||||
|
// set up receive DMA
|
||||||
|
|
||||||
|
volatile uint8_t *rx_source = (volatile uint8_t *)&self->pio->rxf[self->state_machine];
|
||||||
|
|
||||||
|
self->rx_dreq = pio_get_dreq(self->pio, self->state_machine, false);
|
||||||
|
|
||||||
|
dma_channel_config c_read;
|
||||||
|
|
||||||
|
self->current_read_buf = self->once_read_buf_info;
|
||||||
|
self->next_read_buf_1 = self->loop_read_buf_info;
|
||||||
|
self->next_read_buf_2 = self->loop2_read_buf_info;
|
||||||
|
self->next_read_buf_3 = self->loop_read_buf_info;
|
||||||
|
|
||||||
|
self->pending_buffers_read = pending_buffers_read;
|
||||||
|
self->dma_completed_read = false;
|
||||||
|
|
||||||
|
self->background_stride_in_bytes = stride_in_bytes;
|
||||||
|
self->byteswap = swap;
|
||||||
|
|
||||||
|
c_read = dma_channel_get_default_config(channel_read);
|
||||||
|
channel_config_set_transfer_data_size(&c_read, _stride_to_dma_size(stride_in_bytes));
|
||||||
|
channel_config_set_dreq(&c_read, self->rx_dreq);
|
||||||
|
channel_config_set_read_increment(&c_read, false);
|
||||||
|
channel_config_set_write_increment(&c_read, true);
|
||||||
|
channel_config_set_bswap(&c_read, swap);
|
||||||
|
dma_channel_configure(channel_read, &c_read,
|
||||||
|
self->once_read_buf_info.info.buf,
|
||||||
|
rx_source,
|
||||||
|
self->once_read_buf_info.info.len / stride_in_bytes,
|
||||||
|
false);
|
||||||
|
|
||||||
|
common_hal_mcu_disable_interrupts();
|
||||||
|
// Acknowledge any previous pending interrupt
|
||||||
|
dma_hw->ints0 |= 1u << channel_read;
|
||||||
|
MP_STATE_PORT(background_pio)[channel_read] = self;
|
||||||
|
dma_hw->inte1 |= 1u << channel_read;
|
||||||
|
irq_set_mask_enabled(1 << DMA_IRQ_1, true);
|
||||||
|
dma_start_channel_mask((1u << channel_read));
|
||||||
|
common_hal_mcu_enable_interrupts();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel_read) {
|
||||||
|
|
||||||
|
self->current_read_buf = self->next_read_buf_1;
|
||||||
|
self->next_read_buf_1 = self->next_read_buf_2;
|
||||||
|
self->next_read_buf_2 = self->next_read_buf_3;
|
||||||
|
self->next_read_buf_3 = self->next_read_buf_1;
|
||||||
|
|
||||||
|
if (self->current_read_buf.info.buf) {
|
||||||
|
if (self->pending_buffers_read > 0) {
|
||||||
|
self->pending_buffers_read--;
|
||||||
|
}
|
||||||
|
dma_channel_set_write_addr(channel_read, self->current_read_buf.info.buf, false);
|
||||||
|
dma_channel_set_trans_count(channel_read, self->current_read_buf.info.len / self->background_stride_in_bytes, true);
|
||||||
|
} else {
|
||||||
|
self->dma_completed_read = true;
|
||||||
|
self->pending_buffers_read = 0; // should be a no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
self->switched_read_buffers = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj_t *self) {
|
||||||
|
uint8_t pio_index = pio_get_index(self->pio);
|
||||||
|
uint8_t sm = self->state_machine;
|
||||||
|
rp2pio_statemachine_clear_dma_read(pio_index, sm);
|
||||||
|
memset(&self->current_read_buf, 0, sizeof(self->current_read_buf));
|
||||||
|
memset(&self->next_read_buf_1, 0, sizeof(self->next_read_buf_1));
|
||||||
|
memset(&self->next_read_buf_2, 0, sizeof(self->next_read_buf_2));
|
||||||
|
memset(&self->next_read_buf_3, 0, sizeof(self->next_read_buf_3));
|
||||||
|
self->pending_buffers_read = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool common_hal_rp2pio_statemachine_get_reading(rp2pio_statemachine_obj_t *self) {
|
||||||
|
return !self->dma_completed_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
int common_hal_rp2pio_statemachine_get_pending_read(rp2pio_statemachine_obj_t *self) {
|
||||||
|
return self->pending_buffers_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
int common_hal_rp2pio_statemachine_get_offset(rp2pio_statemachine_obj_t *self) {
|
int common_hal_rp2pio_statemachine_get_offset(rp2pio_statemachine_obj_t *self) {
|
||||||
|
|
@ -1178,6 +1410,22 @@ mp_obj_t common_hal_rp2pio_statemachine_get_rxfifo(rp2pio_statemachine_obj_t *se
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t common_hal_rp2pio_statemachine_get_last_read(rp2pio_statemachine_obj_t *self) {
|
||||||
|
if (self->switched_read_buffers) {
|
||||||
|
self->switched_read_buffers = false;
|
||||||
|
return self->next_read_buf_1.obj;
|
||||||
|
}
|
||||||
|
return mp_const_empty_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_obj_t common_hal_rp2pio_statemachine_get_last_write(rp2pio_statemachine_obj_t *self) {
|
||||||
|
if (self->switched_write_buffers) {
|
||||||
|
self->switched_write_buffers = false;
|
||||||
|
return self->next_write_buf_1.obj;
|
||||||
|
}
|
||||||
|
return mp_const_empty_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Use a compile-time constant for MP_REGISTER_POINTER so the preprocessor will
|
// Use a compile-time constant for MP_REGISTER_POINTER so the preprocessor will
|
||||||
// not split the expansion across multiple lines.
|
// not split the expansion across multiple lines.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ typedef struct sm_buf_info {
|
||||||
mp_buffer_info_t info;
|
mp_buffer_info_t info;
|
||||||
} sm_buf_info;
|
} sm_buf_info;
|
||||||
|
|
||||||
|
#define RP2PIO_STATEMACHINE_N_BUFS 3
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
uint32_t pins; // Bitmask of what pins this state machine uses.
|
uint32_t pins; // Bitmask of what pins this state machine uses.
|
||||||
|
|
@ -47,10 +49,22 @@ typedef struct {
|
||||||
uint8_t fifo_depth; // Either 4 if FIFOs are not joined, or 8 if they are.
|
uint8_t fifo_depth; // Either 4 if FIFOs are not joined, or 8 if they are.
|
||||||
|
|
||||||
// dma-related items
|
// dma-related items
|
||||||
volatile int pending_buffers;
|
volatile int pending_buffers_write;
|
||||||
sm_buf_info current, once, loop;
|
volatile int pending_buffers_read;
|
||||||
|
int write_buf_index, read_buf_index;
|
||||||
|
sm_buf_info write_buf[RP2PIO_STATEMACHINE_N_BUFS];
|
||||||
|
sm_buf_info read_buf[RP2PIO_STATEMACHINE_N_BUFS];
|
||||||
|
|
||||||
|
sm_buf_info once_read_buf_info, loop_read_buf_info, loop2_read_buf_info;
|
||||||
|
sm_buf_info current_read_buf, next_read_buf_1, next_read_buf_2, next_read_buf_3;
|
||||||
|
sm_buf_info once_write_buf_info, loop_write_buf_info, loop2_write_buf_info;
|
||||||
|
sm_buf_info current_write_buf, next_write_buf_1, next_write_buf_2, next_write_buf_3;
|
||||||
|
|
||||||
|
bool switched_write_buffers, switched_read_buffers;
|
||||||
|
|
||||||
int background_stride_in_bytes;
|
int background_stride_in_bytes;
|
||||||
bool dma_completed, byteswap;
|
bool dma_completed_write, byteswap;
|
||||||
|
bool dma_completed_read;
|
||||||
#if PICO_PIO_VERSION > 0
|
#if PICO_PIO_VERSION > 0
|
||||||
memorymap_addressrange_obj_t rxfifo_obj;
|
memorymap_addressrange_obj_t rxfifo_obj;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -85,7 +99,8 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
|
||||||
uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);
|
uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self);
|
||||||
|
|
||||||
void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins);
|
void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins);
|
||||||
void rp2pio_statemachine_dma_complete(rp2pio_statemachine_obj_t *self, int channel);
|
void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel);
|
||||||
|
void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel);
|
||||||
|
|
||||||
void rp2pio_statemachine_reset_ok(PIO pio, int sm);
|
void rp2pio_statemachine_reset_ok(PIO pio, int sm);
|
||||||
void rp2pio_statemachine_never_reset(PIO pio, int sm);
|
void rp2pio_statemachine_never_reset(PIO pio, int sm);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue