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:
parent
33f5598acc
commit
33d6d55675
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user