Skip to content

Commit

Permalink
add pio background read
Browse files Browse the repository at this point in the history
  • Loading branch information
timchinowsky committed Sep 24, 2024
1 parent 1ab26ba commit 25a80cc
Show file tree
Hide file tree
Showing 8 changed files with 414 additions and 87 deletions.
2 changes: 1 addition & 1 deletion frozen/Adafruit_CircuitPython_Requests
2 changes: 1 addition & 1 deletion frozen/Adafruit_CircuitPython_SD
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 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
169 changes: 160 additions & 9 deletions ports/raspberrypi/bindings/rp2pio/StateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ 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_write(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_bytes) {
if (obj != mp_const_none) {
info->obj = obj;
mp_get_buffer_raise(obj, &info->info, MP_BUFFER_READ);
Expand Down Expand Up @@ -567,8 +567,8 @@ static mp_obj_t rp2pio_statemachine_background_write(size_t n_args, const mp_obj
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_write(&once_info, args[ARG_once].u_obj, &stride_in_bytes);
fill_buf_info_write(&loop_info, args[ARG_loop].u_obj, &stride_in_bytes);
if (!stride_in_bytes) {
return mp_const_none;
}
Expand Down Expand Up @@ -602,6 +602,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 @@ -618,23 +619,166 @@ const mp_obj_property_t rp2pio_statemachine_writing_obj = {
};



//| pending: int
//| pending_write: 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) {
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_write(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_pending_write_obj, rp2pio_statemachine_obj_get_pending_write);

const mp_obj_property_t rp2pio_statemachine_pending_write_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_pending_write_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};


// =================================================================================================================================

//| 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 void fill_buf_info_read(sm_buf_info *info, mp_obj_t obj, size_t *stride_in_bytes) {
if (obj != mp_const_none) {
info->obj = obj;
mp_get_buffer_raise(obj, &info->info, MP_BUFFER_WRITE);
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"));
}
if (*stride_in_bytes && stride != *stride_in_bytes) {
mp_raise_ValueError(MP_ERROR_TEXT("Mismatched data size"));
}
*stride_in_bytes = stride;
} else {
memset(info, 0, sizeof(*info));
}
}

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_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} },
};
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_read_info;
sm_buf_info loop_read_info;
size_t stride_in_bytes = 0;
fill_buf_info_read(&once_read_info, args[ARG_once].u_obj, &stride_in_bytes);
fill_buf_info_read(&loop_read_info, args[ARG_loop].u_obj, &stride_in_bytes);
if (!stride_in_bytes) {
return mp_const_none;
}

bool ok = common_hal_rp2pio_statemachine_background_read(self, &once_read_info, &loop_read_info, 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);

const mp_obj_property_t rp2pio_statemachine_reading_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_reading_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};

//| 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(self));
return mp_obj_new_int(common_hal_rp2pio_statemachine_get_pending_read(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_read_obj, rp2pio_statemachine_obj_get_pending_read);

const mp_obj_property_t rp2pio_statemachine_pending_obj = {
const mp_obj_property_t rp2pio_statemachine_pending_read_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_pending_obj,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_pending_read_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};


// =================================================================================================================================

//| def readinto(
//| self,
//| buffer: WriteableBuffer,
Expand Down Expand Up @@ -952,10 +1096,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 Down
16 changes: 13 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,19 @@ 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, const sm_buf_info *once, const sm_buf_info *loop, uint8_t stride_in_bytes, bool swap);
bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *self, const sm_buf_info *once_read, const sm_buf_info *loop_read, 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 +74,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 Down
Loading

0 comments on commit 25a80cc

Please sign in to comment.