the basics work

the sequence has to be a minimum length, 8 entries, but this problem
is not detected. I don't THINK this is an insurmountable problem.
This commit is contained in:
Jeff Epler 2022-04-19 15:14:50 -05:00
parent 33f5598acc
commit 33d6d55675
No known key found for this signature in database
GPG Key ID: D5BF15AB975AB4DE
6 changed files with 139 additions and 8 deletions

View File

@ -29,6 +29,7 @@
#include "shared-bindings/audiocore/RawSample.h"
#include "shared-bindings/audiocore/WaveFile.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "bindings/rp2pio/StateMachine.h"
#include "supervisor/background_callback.h"
#include "py/mpstate.h"
@ -324,7 +325,9 @@ void audio_dma_stop(audio_dma_t *dma) {
channel_mask |= 1 << dma->channel[1];
}
dma_hw->inte0 &= ~channel_mask;
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
if (!dma_hw->inte0) {
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
}
// Run any remaining audio tasks because we remove ourselves from
// playing_audio.
@ -442,13 +445,20 @@ STATIC void dma_callback_fun(void *arg) {
void isr_dma_0(void) {
for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) {
uint32_t mask = 1 << i;
if ((dma_hw->intr & mask) != 0 && MP_STATE_PORT(playing_audio)[i] != NULL) {
if ((dma_hw->intr & mask) == 0) {
continue;
}
if (MP_STATE_PORT(playing_audio)[i] != NULL) {
audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i];
// Record all channels whose DMA has completed; they need loading.
dma->channels_to_load_mask |= mask;
background_callback_add(&dma->callback, dma_callback_fun, (void *)dma);
dma_hw->ints0 = mask;
}
if (MP_STATE_PORT(continuous_pio)[i] != NULL) {
rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(continuous_pio)[i];
rp2pio_statemachine_dma_complete(pio, i);
}
dma_hw->ints0 = mask;
}
}

View File

@ -480,7 +480,7 @@ STATIC mp_obj_t rp2pio_statemachine_start_continuous_write(size_t n_args, const
mp_raise_ValueError(translate("Buffer elements must be 4 bytes long or less"));
}
ok = common_hal_rp2pio_statemachine_start_continuous_write(self, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes);
ok = common_hal_rp2pio_statemachine_start_continuous_write(self, args[ARG_buffer].u_obj, ((uint8_t *)bufinfo.buf) + start, length, stride_in_bytes);
}
if (!ok) {
mp_raise_OSError(MP_EIO);

View File

@ -65,7 +65,7 @@ void common_hal_rp2pio_statemachine_run(rp2pio_statemachine_obj_t *self, const u
// Writes out the given data.
bool common_hal_rp2pio_statemachine_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes);
bool common_hal_rp2pio_statemachine_start_continuous_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes);
bool common_hal_rp2pio_statemachine_start_continuous_write(rp2pio_statemachine_obj_t *self, mp_obj_t buf_obj, const uint8_t *data, size_t len, uint8_t stride_in_bytes);
bool common_hal_rp2pio_statemachine_end_continuous_write(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 common_hal_rp2pio_statemachine_write_readinto(rp2pio_statemachine_obj_t *self,

View File

@ -42,6 +42,8 @@
#include "py/objproperty.h"
#include "py/runtime.h"
#define NO_DMA_CHANNEL (-1)
// Count how many state machines are using each pin.
STATIC uint8_t _pin_reference_count[TOTAL_GPIO_COUNT];
STATIC uint32_t _current_program_id[NUM_PIOS][NUM_PIO_STATE_MACHINES];
@ -330,6 +332,9 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self,
sm_config_set_fifo_join(&c, join);
self->sm_config = c;
// no DMA allocated
self->dma_channel[0] = self->dma_channel[1] = NO_DMA_CHANNEL;
pio_sm_init(self->pio, self->state_machine, program_offset, &c);
common_hal_rp2pio_statemachine_run(self, init, init_len);
@ -581,6 +586,7 @@ void common_hal_rp2pio_statemachine_set_frequency(rp2pio_statemachine_obj_t *sel
void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins) {
common_hal_rp2pio_statemachine_stop(self);
(void)common_hal_rp2pio_statemachine_end_continuous_write(self);
uint8_t sm = self->state_machine;
uint8_t pio_index = pio_get_index(self->pio);
@ -849,10 +855,114 @@ uint8_t rp2pio_statemachine_program_offset(rp2pio_statemachine_obj_t *self) {
return _current_program_offset[pio_index][sm];
}
bool common_hal_rp2pio_statemachine_start_continuous_write(rp2pio_statemachine_obj_t *self, const uint8_t *data, size_t len, uint8_t stride_in_bytes) {
return false;
#define HERE(fmt, ...) (mp_printf(&mp_plat_print, "%s: %d: " fmt "\n", __FILE__, __LINE__,##__VA_ARGS__))
bool common_hal_rp2pio_statemachine_start_continuous_write(rp2pio_statemachine_obj_t *self, mp_obj_t buf_obj, const uint8_t *data, size_t len, uint8_t stride_in_bytes) {
if (self->dma_channel[0] != NO_DMA_CHANNEL && stride_in_bytes == self->continuous_stride_in_bytes) {
HERE("updating channel pending=%d\n", self->pending_set_data);
while (self->pending_set_data) {
RUN_BACKGROUND_TASKS;
if (self->user_interruptible && mp_hal_is_interrupted()) {
(void)common_hal_rp2pio_statemachine_end_continuous_write(self);
return false;
}
}
common_hal_mcu_disable_interrupts();
self->next_buffer = data;
self->next_size = len / stride_in_bytes;
self->pending_set_data = true;
common_hal_mcu_enable_interrupts();
// need to keep a reference alive to the buffer, lest the GC collect it while its lone remaining pointer is in the DMA peripheral register
self->buf_objs[++self->buf_obj_idx % 2] = buf_obj;
return true;
}
common_hal_rp2pio_statemachine_end_continuous_write(self);
for (int i = 0; i < 2; i++) {
HERE("allocating channel %d", i);
if (self->dma_channel[i] == -1) {
self->dma_channel[i] = dma_claim_unused_channel(false);
HERE("got channel %d", self->dma_channel[i]);
MP_STATE_PORT(continuous_pio)[self->dma_channel[i]] = self;
}
if (self->dma_channel[i] == -1) {
HERE("allocating channel %d failed", i);
(void)common_hal_rp2pio_statemachine_end_continuous_write(self);
return false;
}
}
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);
dma_channel_config c;
self->pending_set_data = false;
self->continuous_stride_in_bytes = stride_in_bytes;
self->buf_objs[0] = buf_obj;
self->buf_objs[1] = NULL;
self->next_buffer = data;
self->next_size = len / stride_in_bytes;
c = dma_channel_get_default_config(self->dma_channel[0]);
channel_config_set_transfer_data_size(&c, _stride_to_dma_size(stride_in_bytes));
channel_config_set_dreq(&c, self->tx_dreq);
channel_config_set_read_increment(&c, true);
channel_config_set_write_increment(&c, false);
// channel_config_set_chain_to(&c, self->dma_channel[1]);
dma_channel_configure(self->dma_channel[0], &c,
tx_destination,
data,
len / stride_in_bytes,
false);
#if 0
channel_config_set_chain_to(&c, self->dma_channel[0]);
dma_channel_configure(self->dma_channel[1], &c,
tx_destination,
data,
len / stride_in_bytes,
false);
#endif
dma_hw->inte0 |= (1 << self->dma_channel[0]) | (1 << self->dma_channel[1]);
irq_set_mask_enabled(1 << DMA_IRQ_0, true);
HERE("OK let's go");
dma_start_channel_mask(1u << self->dma_channel[0]);
return true;
}
void rp2pio_statemachine_dma_complete(rp2pio_statemachine_obj_t *self, int channel) {
HERE("dma complete[%d] pending set data=%d busy=%d,%d %d@%p", channel, self->pending_set_data, dma_channel_is_busy(self->dma_channel[0]), dma_channel_is_busy(self->dma_channel[1]),
self->next_size, self->next_buffer);
dma_channel_set_read_addr(channel, self->next_buffer, false);
dma_channel_set_trans_count(channel, self->next_size, true);
self->pending_set_data = false;
}
bool common_hal_rp2pio_statemachine_end_continuous_write(rp2pio_statemachine_obj_t *self) {
return false;
for (int i = 0; i < 2; i++) {
if (self->dma_channel[i] == NO_DMA_CHANNEL) {
continue;
}
int channel = self->dma_channel[i];
uint32_t channel_mask = 1u << channel;
dma_hw->inte0 &= ~channel_mask;
if (!dma_hw->inte0) {
irq_set_mask_enabled(1 << DMA_IRQ_0, false);
}
MP_STATE_PORT(continuous_pio)[channel] = NULL;
dma_channel_abort(channel);
dma_channel_unclaim(channel);
self->dma_channel[i] = NO_DMA_CHANNEL;
}
return true;
}

View File

@ -54,6 +54,15 @@ typedef struct {
bool in_shift_right;
bool user_interruptible;
uint8_t offset;
// dma-related items
uint8_t buf_obj_idx;
const uint8_t *next_buffer;
size_t next_size;
int dma_channel[2];
mp_obj_t buf_objs[2];
int continuous_stride_in_bytes;
volatile int pending_set_data;
} rp2pio_statemachine_obj_t;
void reset_rp2pio_statemachine(void);
@ -82,6 +91,7 @@ bool rp2pio_statemachine_construct(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_dma_complete(rp2pio_statemachine_obj_t *self, int channel);
extern const mp_obj_type_t rp2pio_statemachine_type;

View File

@ -46,6 +46,7 @@
#define MICROPY_PORT_ROOT_POINTERS \
mp_obj_t counting[NUM_PWM_SLICES]; \
mp_obj_t playing_audio[NUM_DMA_CHANNELS]; \
mp_obj_t continuous_pio[NUM_DMA_CHANNELS]; \
CIRCUITPY_COMMON_ROOT_POINTERS;
#endif // __INCLUDED_MPCONFIGPORT_H