Skip to content

Commit cf226fe

Browse files
Add I2S input slave support (#3244)
Due to the way the PIO inputs work, slave input mode needs to have its pins defined in a fixed order: DIN, BCLK, LRCLK For slave mode, specify ``setDATA`` . ``setBCLK`` and ``setLRCLK`` are ignored.
1 parent f8ded7c commit cf226fe

File tree

4 files changed

+117
-2
lines changed

4 files changed

+117
-2
lines changed

docs/i2s.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ any input or output can happen.
3939
bool setSlave()
4040
~~~~~~~~~~~~~~~
4141
Enables slave mode. BCLK and LRCLK are inputs and used to control the
42-
timing of the DOUT output. Only normal I2S output mode is supported in
43-
slave mode.
42+
timing of the DOUT output. Only normal I2S output and input modes are
43+
supported in slave mode.
44+
45+
In I2S input slave mode, the clock pins and swapClocks are ignored. The pins
46+
must be consecutive starting with DIN, then BCLK, then LRCLK.
4447

4548
bool setBCLK(pin_size_t pin)
4649
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

libraries/I2S/src/I2S.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,10 @@ bool I2S::begin() {
332332
pgm = &pio_i2s_out_program;
333333
init = pio_i2s_out_program_init;
334334
break;
335+
case _SLAVE + _INPUT:
336+
pgm = &pio_i2s_in_slave_program;
337+
init = pio_i2s_in_slave_program_init;
338+
break;
335339
case _INPUT:
336340
pgm = &pio_i2s_in_program;
337341
init = pio_i2s_in_program_init;

libraries/I2S/src/pio_i2s.pio

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,34 @@ right1:
182182
; Loop back to beginning...
183183

184184

185+
.program pio_i2s_in_slave
186+
; The C code should update SHIFTCTRL to be 24 or 32 (for 16- and 32- bit mode)
187+
188+
; IN 0 = DIN
189+
; IN 1 = BCLK
190+
; IN 2 = LRCLK
191+
192+
waitfirstbit:
193+
wait 0 pin 1
194+
wait 1 pin 1
195+
jmp pin waitfirstbit; LRCLK==1, so this is right channel...wait for left
196+
197+
.wrap_target
198+
readleft:
199+
wait 0 pin 1
200+
wait 1 pin 1
201+
in pins, 1 ; read din on rising edge
202+
jmp pin readright
203+
jmp readleft
204+
205+
readright:
206+
wait 0 pin 1
207+
wait 1 pin 1
208+
in pins, 1
209+
jmp pin readright
210+
.wrap
211+
212+
185213
.program pio_i2s_inout
186214
.side_set 2 ; 0 = bclk, 1=wclk
187215

@@ -399,6 +427,28 @@ static inline void pio_i2s_in_program_init I2S_INIT_PARAMS {
399427
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
400428
}
401429

430+
static inline void pio_i2s_in_slave_program_init I2S_INIT_PARAMS {
431+
I2S_INIT_PARAMS_VOID;
432+
// Note that the CLOCK_BASE pin is ignored. It's DIN, BCLK, LRCLK consecutive due to PIO limitations
433+
pio_gpio_init(pio, data_in_pin);
434+
pio_gpio_init(pio, data_in_pin + 1);
435+
pio_gpio_init(pio, data_in_pin + 2);
436+
437+
pio_sm_config sm_config = pio_i2s_in_slave_program_get_default_config(offset);
438+
439+
sm_config_set_in_pins(&sm_config, data_in_pin);
440+
sm_config_set_in_pin_count(&sm_config, 3);
441+
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
442+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
443+
sm_config_set_jmp_pin(&sm_config, data_in_pin + 2);
444+
445+
pio_sm_init(pio, sm, offset, &sm_config);
446+
447+
pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 3, false);
448+
}
449+
450+
451+
402452
static inline void pio_i2s_inout_program_init I2S_INIT_PARAMS {
403453
I2S_INIT_PARAMS_VOID;
404454
pio_gpio_init(pio, data_in_pin);

libraries/I2S/src/pio_i2s.pio.h

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,49 @@ static inline pio_sm_config pio_i2s_in_program_get_default_config(uint offset) {
324324
}
325325
#endif
326326

327+
// ---------------- //
328+
// pio_i2s_in_slave //
329+
// ---------------- //
330+
331+
#define pio_i2s_in_slave_wrap_target 3
332+
#define pio_i2s_in_slave_wrap 11
333+
#define pio_i2s_in_slave_pio_version 0
334+
335+
static const uint16_t pio_i2s_in_slave_program_instructions[] = {
336+
0x2021, // 0: wait 0 pin, 1
337+
0x20a1, // 1: wait 1 pin, 1
338+
0x00c0, // 2: jmp pin, 0
339+
// .wrap_target
340+
0x2021, // 3: wait 0 pin, 1
341+
0x20a1, // 4: wait 1 pin, 1
342+
0x4001, // 5: in pins, 1
343+
0x00c8, // 6: jmp pin, 8
344+
0x0003, // 7: jmp 3
345+
0x2021, // 8: wait 0 pin, 1
346+
0x20a1, // 9: wait 1 pin, 1
347+
0x4001, // 10: in pins, 1
348+
0x00c8, // 11: jmp pin, 8
349+
// .wrap
350+
};
351+
352+
#if !PICO_NO_HARDWARE
353+
static const struct pio_program pio_i2s_in_slave_program = {
354+
.instructions = pio_i2s_in_slave_program_instructions,
355+
.length = 12,
356+
.origin = -1,
357+
.pio_version = pio_i2s_in_slave_pio_version,
358+
#if PICO_PIO_VERSION > 0
359+
.used_gpio_ranges = 0x0
360+
#endif
361+
};
362+
363+
static inline pio_sm_config pio_i2s_in_slave_program_get_default_config(uint offset) {
364+
pio_sm_config c = pio_get_default_sm_config();
365+
sm_config_set_wrap(&c, offset + pio_i2s_in_slave_wrap_target, offset + pio_i2s_in_slave_wrap);
366+
return c;
367+
}
368+
#endif
369+
327370
// ------------- //
328371
// pio_i2s_inout //
329372
// ------------- //
@@ -511,6 +554,21 @@ static inline void pio_i2s_in_program_init I2S_INIT_PARAMS {
511554
pio_sm_exec(pio, sm, pio_encode_in(pio_pins, bits)); // Shift in 1st L data
512555
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
513556
}
557+
static inline void pio_i2s_in_slave_program_init I2S_INIT_PARAMS {
558+
I2S_INIT_PARAMS_VOID;
559+
// Note that the CLOCK_BASE pin is ignored. It's DIN, BCLK, LRCLK consecutive due to PIO limitations
560+
pio_gpio_init(pio, data_in_pin);
561+
pio_gpio_init(pio, data_in_pin + 1);
562+
pio_gpio_init(pio, data_in_pin + 2);
563+
pio_sm_config sm_config = pio_i2s_in_slave_program_get_default_config(offset);
564+
sm_config_set_in_pins(&sm_config, data_in_pin);
565+
sm_config_set_in_pin_count(&sm_config, 3);
566+
sm_config_set_in_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
567+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_RX);
568+
sm_config_set_jmp_pin(&sm_config, data_in_pin + 2);
569+
pio_sm_init(pio, sm, offset, &sm_config);
570+
pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 3, false);
571+
}
514572
static inline void pio_i2s_inout_program_init I2S_INIT_PARAMS {
515573
I2S_INIT_PARAMS_VOID;
516574
pio_gpio_init(pio, data_in_pin);

0 commit comments

Comments
 (0)