Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/i2s.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ any input or output can happen.
bool setSlave()
~~~~~~~~~~~~~~~
Enables slave mode. BCLK and LRCLK are inputs and used to control the
timing of the DOUT output. Only normal I2S output mode is supported in
slave mode.
timing of the DOUT output. Only normal I2S output and input modes are
supported in slave mode.

In I2S input slave mode, the clock pins and swapClocks are ignored. The pins
must be consecutive starting with DIN, then BCLK, then LRCLK.

bool setBCLK(pin_size_t pin)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 4 additions & 0 deletions libraries/I2S/src/I2S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ bool I2S::begin() {
pgm = &pio_i2s_out_program;
init = pio_i2s_out_program_init;
break;
case _SLAVE + _INPUT:
pgm = &pio_i2s_in_slave_program;
init = pio_i2s_in_slave_program_init;
break;
case _INPUT:
pgm = &pio_i2s_in_program;
init = pio_i2s_in_program_init;
Expand Down
50 changes: 50 additions & 0 deletions libraries/I2S/src/pio_i2s.pio
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,34 @@ right1:
; Loop back to beginning...


.program pio_i2s_in_slave
; The C code should update SHIFTCTRL to be 24 or 32 (for 16- and 32- bit mode)

; IN 0 = DIN
; IN 1 = BCLK
; IN 2 = LRCLK

waitfirstbit:
wait 0 pin 1
wait 1 pin 1
jmp pin waitfirstbit; LRCLK==1, so this is right channel...wait for left

.wrap_target
readleft:
wait 0 pin 1
wait 1 pin 1
in pins, 1 ; read din on rising edge
jmp pin readright
jmp readleft

readright:
wait 0 pin 1
wait 1 pin 1
in pins, 1
jmp pin readright
.wrap


.program pio_i2s_inout
.side_set 2 ; 0 = bclk, 1=wclk

Expand Down Expand Up @@ -399,6 +427,28 @@ static inline void pio_i2s_in_program_init I2S_INIT_PARAMS {
pio_sm_exec(pio, sm, pio_encode_in(pio_pins, bits - 1)); // Shift in 1st R data modulo one bit, avoiding bit shift from #2037
}

static inline void pio_i2s_in_slave_program_init I2S_INIT_PARAMS {
I2S_INIT_PARAMS_VOID;
// Note that the CLOCK_BASE pin is ignored. It's DIN, BCLK, LRCLK consecutive due to PIO limitations
pio_gpio_init(pio, data_in_pin);
pio_gpio_init(pio, data_in_pin + 1);
pio_gpio_init(pio, data_in_pin + 2);

pio_sm_config sm_config = pio_i2s_in_slave_program_get_default_config(offset);

sm_config_set_in_pins(&sm_config, data_in_pin);
sm_config_set_in_pin_count(&sm_config, 3);
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
sm_config_set_jmp_pin(&sm_config, data_in_pin + 2);

pio_sm_init(pio, sm, offset, &sm_config);

pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 3, false);
}



static inline void pio_i2s_inout_program_init I2S_INIT_PARAMS {
I2S_INIT_PARAMS_VOID;
pio_gpio_init(pio, data_in_pin);
Expand Down
58 changes: 58 additions & 0 deletions libraries/I2S/src/pio_i2s.pio.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,49 @@ static inline pio_sm_config pio_i2s_in_program_get_default_config(uint offset) {
}
#endif

// ---------------- //
// pio_i2s_in_slave //
// ---------------- //

#define pio_i2s_in_slave_wrap_target 3
#define pio_i2s_in_slave_wrap 11
#define pio_i2s_in_slave_pio_version 0

static const uint16_t pio_i2s_in_slave_program_instructions[] = {
0x2021, // 0: wait 0 pin, 1
0x20a1, // 1: wait 1 pin, 1
0x00c0, // 2: jmp pin, 0
// .wrap_target
0x2021, // 3: wait 0 pin, 1
0x20a1, // 4: wait 1 pin, 1
0x4001, // 5: in pins, 1
0x00c8, // 6: jmp pin, 8
0x0003, // 7: jmp 3
0x2021, // 8: wait 0 pin, 1
0x20a1, // 9: wait 1 pin, 1
0x4001, // 10: in pins, 1
0x00c8, // 11: jmp pin, 8
// .wrap
};

#if !PICO_NO_HARDWARE
static const struct pio_program pio_i2s_in_slave_program = {
.instructions = pio_i2s_in_slave_program_instructions,
.length = 12,
.origin = -1,
.pio_version = pio_i2s_in_slave_pio_version,
#if PICO_PIO_VERSION > 0
.used_gpio_ranges = 0x0
#endif
};

static inline pio_sm_config pio_i2s_in_slave_program_get_default_config(uint offset) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, offset + pio_i2s_in_slave_wrap_target, offset + pio_i2s_in_slave_wrap);
return c;
}
#endif

// ------------- //
// pio_i2s_inout //
// ------------- //
Expand Down Expand Up @@ -511,6 +554,21 @@ static inline void pio_i2s_in_program_init I2S_INIT_PARAMS {
pio_sm_exec(pio, sm, pio_encode_in(pio_pins, bits)); // Shift in 1st L data
pio_sm_exec(pio, sm, pio_encode_in(pio_pins, bits - 1)); // Shift in 1st R data modulo one bit, avoiding bit shift from #2037
}
static inline void pio_i2s_in_slave_program_init I2S_INIT_PARAMS {
I2S_INIT_PARAMS_VOID;
// Note that the CLOCK_BASE pin is ignored. It's DIN, BCLK, LRCLK consecutive due to PIO limitations
pio_gpio_init(pio, data_in_pin);
pio_gpio_init(pio, data_in_pin + 1);
pio_gpio_init(pio, data_in_pin + 2);
pio_sm_config sm_config = pio_i2s_in_slave_program_get_default_config(offset);
sm_config_set_in_pins(&sm_config, data_in_pin);
sm_config_set_in_pin_count(&sm_config, 3);
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
sm_config_set_jmp_pin(&sm_config, data_in_pin + 2);
pio_sm_init(pio, sm, offset, &sm_config);
pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 3, false);
}
static inline void pio_i2s_inout_program_init I2S_INIT_PARAMS {
I2S_INIT_PARAMS_VOID;
pio_gpio_init(pio, data_in_pin);
Expand Down