Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion ports/raspberrypi/audio_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,25 @@ void __not_in_flash_func(isr_dma_0)(void) {
}
if (MP_STATE_PORT(background_pio)[i] != NULL) {
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);
}
}
}
Expand Down
207 changes: 192 additions & 15 deletions ports/raspberrypi/bindings/rp2pio/StateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
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);
if (stride > 4) {
mp_raise_ValueError(MP_ERROR_TEXT("Buffer elements must be 4 bytes long or less"));
Expand All @@ -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) {
enum { ARG_once, ARG_loop, ARG_swap };
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_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]);
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);

sm_buf_info once_info;
sm_buf_info loop_info;
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) {
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()) {
return mp_const_none;
Expand Down Expand Up @@ -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);


//| writing: bool
//| """Returns True if a background write is in progress"""
static mp_obj_t rp2pio_statemachine_obj_get_writing(mp_obj_t self_in) {
Expand All @@ -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_obj_t)&rp2pio_statemachine_get_writing_obj);

//| pending_write: int
//| pending: int
//| """Returns the number of pending buffers for background writing.
//|
//| 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) {
//| If the number is 0, then a `StateMachine.background_write` call will not block.
//| 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);
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_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(
//| self,
Expand Down Expand Up @@ -924,6 +1054,42 @@ MP_PROPERTY_GETTER(rp2pio_statemachine_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[] = {
{ 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) },
Expand All @@ -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_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_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_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_rxstall), MP_ROM_PTR(&rp2pio_statemachine_rxstall_obj) },
Expand All @@ -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_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);

Expand Down
22 changes: 19 additions & 3 deletions ports/raspberrypi/bindings/rp2pio/StateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
bool wait_for_txstall,
bool auto_push, uint8_t push_threshold, bool in_shift_right,
bool user_interruptible,
int wrap_taget, int wrap,
int wrap_target, int wrap,
int offset,
int fifo_type,
int mov_status_type,
Expand All @@ -50,10 +50,22 @@ void common_hal_rp2pio_statemachine_run(rp2pio_statemachine_obj_t *self, const u

// 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_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);
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_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_write_readinto(rp2pio_statemachine_obj_t *self,
const uint8_t *data_out, size_t out_len, uint8_t out_stride_in_bytes,
Expand All @@ -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);
void common_hal_rp2pio_statemachine_clear_rxfifo(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);
size_t common_hal_rp2pio_statemachine_get_in_waiting(rp2pio_statemachine_obj_t *self);
Expand All @@ -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);

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);
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"

CIRCUITPY__EVE = 1
CIRCUITPY_SSL = 1
CIRCUITPY_USB_HOST = 0
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ"

CIRCUITPY__EVE = 1
CIRCUITPY_SSL = 1
CIRCUITPY_USB_HOST = 0
Loading