From 4ccfef6fe068bbae8106d0d1f072c7f997472040 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Mar 2025 16:49:31 -0500 Subject: [PATCH] A few fixes for RP2350B I2S (#91) * Fixes audio i2s for pins >32 / RP2350B * Adds PICO_AUDIO_I2S_CLOCK_PINS_SWAPPED to reverse the pin order of LRCLK and BCLK --- src/rp2_common/pico_audio_i2s/audio_i2s.c | 16 ++++++++++- src/rp2_common/pico_audio_i2s/audio_i2s.pio | 28 +++++++++++++++++-- .../pico_audio_i2s/include/pico/audio_i2s.h | 6 ++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/rp2_common/pico_audio_i2s/audio_i2s.c b/src/rp2_common/pico_audio_i2s/audio_i2s.c index 7cdc835..959a3e7 100644 --- a/src/rp2_common/pico_audio_i2s/audio_i2s.c +++ b/src/rp2_common/pico_audio_i2s/audio_i2s.c @@ -52,10 +52,24 @@ const audio_format_t *audio_i2s_setup(const audio_format_t *intended_audio_forma gpio_set_function(config->clock_pin_base, func); gpio_set_function(config->clock_pin_base + 1, func); +#if PICO_PIO_USE_GPIO_BASE + if(config->data_pin >= 32 || config->clock_pin_base + 1 >= 32) { + assert(config->data_pin >= 16 && config->clock_pin_base >= 16); + pio_set_gpio_base(audio_pio, 16); + } +#endif uint8_t sm = shared_state.pio_sm = config->pio_sm; pio_sm_claim(audio_pio, sm); - uint offset = pio_add_program(audio_pio, &audio_i2s_program); + + const struct pio_program *program = +#if PICO_AUDIO_I2S_CLOCK_PINS_SWAPPED + &audio_i2s_swapped_program +#else + &audio_i2s_program +#endif + ; + uint offset = pio_add_program(audio_pio, program); audio_i2s_program_init(audio_pio, sm, offset, config->data_pin, config->clock_pin_base); diff --git a/src/rp2_common/pico_audio_i2s/audio_i2s.pio b/src/rp2_common/pico_audio_i2s/audio_i2s.pio index 7b9ab6e..fcc0a39 100644 --- a/src/rp2_common/pico_audio_i2s/audio_i2s.pio +++ b/src/rp2_common/pico_audio_i2s/audio_i2s.pio @@ -20,7 +20,8 @@ ; but for common syslck freqs this should still give a constant word select period. ; ; One output pin is used for the data output. -; Two side-set pins are used. Bit 0 is clock, bit 1 is word select. +; Two side-set pins are used. Two versions of the program are provided, so that +; the clock and word select pins can be in either order. ; Send 16 bit words to the PIO for mono, 32 bit words for stereo @@ -42,6 +43,24 @@ bitloop0: public entry_point: set x, 14 side 0b11 +.program audio_i2s_swapped +.side_set 2 + + ; /--- BCLK + ; |/-- LRCLK +bitloop1: ; || + out pins, 1 side 0b01 + jmp x-- bitloop1 side 0b11 + out pins, 1 side 0b00 + set x, 14 side 0b10 + +bitloop0: + out pins, 1 side 0b00 + jmp x-- bitloop0 side 0b10 + out pins, 1 side 0b01 +public entry_point: + set x, 14 side 0b11 + % c-sdk { static inline void audio_i2s_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base) { @@ -54,8 +73,13 @@ static inline void audio_i2s_program_init(PIO pio, uint sm, uint offset, uint da pio_sm_init(pio, sm, offset, &sm_config); - uint pin_mask = (1u << data_pin) | (3u << clock_pin_base); +#if PICO_PIO_USE_GPIO_BASE + uint64_t pin_mask = (1ull << data_pin) | (3ull << clock_pin_base); + pio_sm_set_pindirs_with_mask64(pio, sm, pin_mask, pin_mask); +#else + uint32_t pin_mask = (1u << data_pin) | (3u << clock_pin_base); pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask); +#endif pio_sm_set_pins(pio, sm, 0); // clear pins pio_sm_exec(pio, sm, pio_encode_jmp(offset + audio_i2s_offset_entry_point)); diff --git a/src/rp2_common/pico_audio_i2s/include/pico/audio_i2s.h b/src/rp2_common/pico_audio_i2s/include/pico/audio_i2s.h index 3e97d29..485409b 100644 --- a/src/rp2_common/pico_audio_i2s/include/pico/audio_i2s.h +++ b/src/rp2_common/pico_audio_i2s/include/pico/audio_i2s.h @@ -106,6 +106,12 @@ extern "C" { #define PICO_AUDIO_I2S_CLOCK_PIN_BASE 26 #endif +// The default order is CLOCK_PIN_BASE=LRCLK, CLOCK_PIN_BASE+1=BCLK +// The swapped order is CLOCK_PIN_BASE=BCLK, CLOCK_PIN_BASE+1=LRCLK +#ifndef PICO_AUDIO_I2S_CLOCK_PINS_SWAPPED +#define PICO_AUDIO_I2S_CLOCK_PINS_SWAPPED 0 +#endif + // todo this needs to come from a build config /** \brief Base configuration structure used when setting up * \ingroup pico_audio_i2s