audiocore: Support swapping dclk and lrclk pins for I2S
Signed-off-by: Matthias Blankertz <matthias@blankertz.org>
This commit is contained in:
@@ -40,7 +40,7 @@ void __time_critical_func(core1_main)(void)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
bool running = true, playing = false;
|
||||
if (!i2s_init(shared_context.out_pin, shared_context.sideset_base)) {
|
||||
if (!i2s_init(shared_context.out_pin, shared_context.sideset_base, shared_context.sideset_dclk_first)) {
|
||||
ret = MP_EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ struct audiocore_shared_context {
|
||||
|
||||
// Set by module.c before core1 is launched and then never changed, can be read without lock
|
||||
int out_pin, sideset_base, samplerate;
|
||||
bool sideset_dclk_first;
|
||||
|
||||
// Must hold lock. The indices 0..MP3_BUFFER_PREAREA-1 may only be read and written on core1 (no
|
||||
// lock needed) The buffer is aligned to, and MP3_BUFFER_PREAREA is a multiple of, the machine
|
||||
|
||||
@@ -8,11 +8,10 @@ from utils import get_pin_index
|
||||
|
||||
class Audiocore:
|
||||
def __init__(self, din, dclk, lrclk):
|
||||
assert get_pin_index(lrclk) == get_pin_index(dclk)+1 # TODO: Support different pin arrangements
|
||||
# PIO requires sideset pins to be adjacent
|
||||
assert get_pin_index(lrclk) == get_pin_index(dclk)+1 or get_pin_index(lrclk) == get_pin_index(dclk)-1
|
||||
self.notify = ThreadSafeFlag()
|
||||
self.pin = din
|
||||
self.sideset = dclk
|
||||
self._audiocore = _audiocore.Audiocore(self.pin, self.sideset, self._interrupt)
|
||||
self._audiocore = _audiocore.Audiocore(din, dclk, lrclk, self._interrupt)
|
||||
|
||||
def deinit(self):
|
||||
self._audiocore.deinit()
|
||||
|
||||
@@ -113,17 +113,18 @@ void i2s_stop(void)
|
||||
pio_sm_clear_fifos(audiocore_pio, i2s_context.pio_sm);
|
||||
}
|
||||
|
||||
bool i2s_init(int out_pin, int sideset_base)
|
||||
bool i2s_init(int out_pin, int sideset_base, bool dclk_first)
|
||||
{
|
||||
memset(i2s_context.dma_buf, 0, sizeof(i2s_context.dma_buf[0][0]) * AUDIO_BUFS * I2S_DMA_BUF_SIZE);
|
||||
if (!pio_can_add_program(audiocore_pio, (const pio_program_t *)&i2s_max98357_program))
|
||||
const pio_program_t *program = dclk_first ? &i2s_max98357_program : &i2s_max98357_lrclk_program;
|
||||
if (!pio_can_add_program(audiocore_pio, program))
|
||||
return false;
|
||||
i2s_context.pio_sm = pio_claim_unused_sm(audiocore_pio, false);
|
||||
i2s_context.out_pin = out_pin;
|
||||
i2s_context.sideset_base = sideset_base;
|
||||
if (i2s_context.pio_sm == -1)
|
||||
return false;
|
||||
i2s_context.pio_program_offset = pio_add_program(audiocore_pio, (const pio_program_t *)&i2s_max98357_program);
|
||||
i2s_context.pio_program_offset = pio_add_program(audiocore_pio, program);
|
||||
|
||||
i2s_context.dma_ch = dma_claim_unused_channel(false);
|
||||
if (i2s_context.dma_ch == -1)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#define I2S_DMA_BUF_SIZE (1152)
|
||||
|
||||
bool i2s_init(int out_pin, int sideset_base);
|
||||
bool i2s_init(int out_pin, int sideset_base, bool dclk_first);
|
||||
void i2s_deinit(void);
|
||||
|
||||
void i2s_play(int samplerate);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
.lang_opt python autopull = True
|
||||
|
||||
// data - DOUT
|
||||
// sideset - 2-BCLK, 1-LRCLK
|
||||
// sideset - 2-LRCLK, 1-BCLK
|
||||
|
||||
set x,15 side 0
|
||||
nop side 1
|
||||
@@ -33,6 +33,38 @@ right_loop:
|
||||
set x, 14 side 1
|
||||
.wrap
|
||||
|
||||
.program i2s_max98357_lrclk
|
||||
.side_set 2
|
||||
|
||||
.lang_opt python sideset_init = pico.PIO.OUT_LOW
|
||||
.lang_opt python out_init = pico.PIO.OUT_LOW
|
||||
.lang_opt python out_shiftdir = pcio.PIO.SHIFT_LEFT
|
||||
.lang_opt python autopull = True
|
||||
|
||||
// data - DOUT
|
||||
// sideset - 2-BCLK, 1-LRCLK
|
||||
|
||||
set x,15 side 0
|
||||
nop side 2
|
||||
startup_loop:
|
||||
nop side 1
|
||||
jmp x-- startup_loop side 3
|
||||
nop side 0
|
||||
set x, 14 side 2
|
||||
|
||||
left_loop:
|
||||
.wrap_target
|
||||
out pins, 1 side 0
|
||||
jmp x-- left_loop side 2
|
||||
out pins, 1 side 1
|
||||
set x, 14 side 3
|
||||
right_loop:
|
||||
out pins, 1 side 1
|
||||
jmp x-- right_loop side 3
|
||||
out pins, 1 side 0
|
||||
set x, 14 side 2
|
||||
.wrap
|
||||
|
||||
% c-sdk {
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
|
||||
@@ -170,10 +170,11 @@ static MP_DEFINE_CONST_FUN_OBJ_2(audiocore_set_volume_obj, audiocore_set_volume)
|
||||
*/
|
||||
static void audiocore_init(struct audiocore_obj *obj, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
|
||||
{
|
||||
enum { ARG_pin, ARG_sideset, ARG_handler };
|
||||
enum { ARG_pin, ARG_dclk, ARG_lrclk, ARG_handler };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
{MP_QSTR_sideset, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
{MP_QSTR_dclk, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
{MP_QSTR_lrclk, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
{MP_QSTR_handler, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
|
||||
};
|
||||
if (initialized)
|
||||
@@ -188,7 +189,8 @@ static void audiocore_init(struct audiocore_obj *obj, size_t n_args, const mp_ob
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
const mp_hal_pin_obj_t pin = mp_hal_get_pin_obj(args[ARG_pin].u_obj);
|
||||
const mp_hal_pin_obj_t sideset_pin = mp_hal_get_pin_obj(args[ARG_sideset].u_obj);
|
||||
const mp_hal_pin_obj_t dclk_pin = mp_hal_get_pin_obj(args[ARG_dclk].u_obj);
|
||||
const mp_hal_pin_obj_t lrclk_pin = mp_hal_get_pin_obj(args[ARG_lrclk].u_obj);
|
||||
if (args[ARG_handler].u_obj != MP_OBJ_NULL) {
|
||||
obj->irq_obj = mp_irq_new(&audiocore_irq_methods, MP_OBJ_FROM_PTR(obj));
|
||||
obj->irq_obj->handler = args[ARG_handler].u_obj;
|
||||
@@ -203,7 +205,14 @@ static void audiocore_init(struct audiocore_obj *obj, size_t n_args, const mp_ob
|
||||
memset(shared_context.mp3_buffer, 0, MP3_BUFFER_PREAREA + MP3_BUFFER_SIZE);
|
||||
multicore_reset_core1();
|
||||
shared_context.out_pin = pin;
|
||||
shared_context.sideset_base = sideset_pin;
|
||||
// PIO requires sideset pins to be adjacent, but we support both dclk first and lrclk first
|
||||
if (lrclk_pin == dclk_pin + 1) {
|
||||
shared_context.sideset_base = dclk_pin;
|
||||
shared_context.sideset_dclk_first = true;
|
||||
} else {
|
||||
shared_context.sideset_base = lrclk_pin;
|
||||
shared_context.sideset_dclk_first = false;
|
||||
}
|
||||
initialized = true;
|
||||
multicore_launch_core1(&core1_main);
|
||||
uint32_t result = get_fifo_read_value_blocking(obj);
|
||||
|
||||
@@ -15,7 +15,7 @@ static unsigned multicore_fifo_push_last;
|
||||
|
||||
static unsigned (*multicore_fifo_pop_blocking_cb)(void);
|
||||
|
||||
bool i2s_init(int out_pin, int sideset_base)
|
||||
bool i2s_init(int out_pin, int sideset_base, bool dclk_first)
|
||||
{
|
||||
TEST_ASSERT_FALSE(i2s_initialized);
|
||||
if (i2s_init_return)
|
||||
|
||||
Reference in New Issue
Block a user