Skip to content

Commit 0ec1dc6

Browse files
authored
Bidirectional TDM Support (#2843)
* Initial commit. * Works with AK4619 in TDM128 I2S compatibility mode set to rising BCLK. * Works with I2S compat mode with BCLK mode set to 0 on AK4619.
1 parent 15d1c68 commit 0ec1dc6

File tree

3 files changed

+184
-5
lines changed

3 files changed

+184
-5
lines changed

libraries/I2S/src/I2S.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ bool I2S::setLSBJFormat() {
178178
}
179179

180180
bool I2S::setTDMFormat() {
181-
if (_running || !_isOutput || _isInput) {
181+
if (_running || !_isOutput) {
182182
return false;
183183
}
184184
_isTDM = true;
185185
return true;
186186
}
187187

188188
bool I2S::setTDMChannels(int channels) {
189-
if (_running || !_isOutput || _isInput) {
189+
if (_running || !_isOutput) {
190190
return false;
191191
}
192192
_tdmChannels = channels;
@@ -255,9 +255,9 @@ bool I2S::begin() {
255255
_isHolding = 0;
256256
int off = 0;
257257
if (!_swapClocks) {
258-
_i2s = new PIOProgram(_isOutput ? (_isInput ? &pio_i2s_inout_program : (_isTDM ? &pio_tdm_out_program : (_isLSBJ ? &pio_lsbj_out_program : &pio_i2s_out_program))) : &pio_i2s_in_program);
258+
_i2s = new PIOProgram(_isOutput ? (_isInput ? (_isTDM ? &pio_tdm_inout_program : &pio_i2s_inout_program) : (_isTDM ? &pio_tdm_out_program : (_isLSBJ ? &pio_lsbj_out_program : &pio_i2s_out_program))) : &pio_i2s_in_program);
259259
} else {
260-
_i2s = new PIOProgram(_isOutput ? (_isInput ? &pio_i2s_inout_swap_program : (_isTDM ? &pio_tdm_out_swap_program : (_isLSBJ ? &pio_lsbj_out_swap_program : &pio_i2s_out_swap_program))) : &pio_i2s_in_swap_program);
260+
_i2s = new PIOProgram(_isOutput ? (_isInput ? (_isTDM ? &pio_tdm_inout_swap_program : &pio_i2s_inout_swap_program) : (_isTDM ? &pio_tdm_out_swap_program : (_isLSBJ ? &pio_lsbj_out_swap_program : &pio_i2s_out_swap_program))) : &pio_i2s_in_swap_program);
261261
}
262262
int minpin, maxpin;
263263
if (_isOutput && _isInput) {
@@ -278,7 +278,11 @@ bool I2S::begin() {
278278
}
279279
if (_isOutput) {
280280
if (_isInput) {
281-
pio_i2s_inout_program_init(_pio, _sm, off, _pinDIN, _pinDOUT, _pinBCLK, _bps, _swapClocks);
281+
if (_isTDM) {
282+
pio_tdm_inout_program_init(_pio, _sm, off, _pinDIN, _pinDOUT, _pinBCLK, _bps, _swapClocks, _tdmChannels);
283+
} else {
284+
pio_i2s_inout_program_init(_pio, _sm, off, _pinDIN, _pinDOUT, _pinBCLK, _bps, _swapClocks);
285+
}
282286
} else if (_isTDM) {
283287
pio_tdm_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps, _swapClocks, _tdmChannels);
284288
} else if (_isLSBJ) {

libraries/I2S/src/pio_i2s.pio

+71
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,41 @@ lastbit:
104104
; Loop back to the beginning
105105

106106

107+
.program pio_tdm_inout
108+
.side_set 2 ; 0 = bclk, 1 = wclk
109+
; The C code should place (number of bits * channels - 1) in Y and update SHIFTCTRL
110+
; to be 32 (as per the TDM specs)
111+
; +----- WCLK
112+
; |+---- BCLK
113+
mov x, y side 0b01 [1]
114+
bitloop:
115+
out pins, 1 side 0b00 ; Output changes on falling edge
116+
in pins, 1 side 0b00 ; Sample input on falling edge
117+
jmp x-- bitloop side 0b11 [1] ; Last bit toggles WCLK to mark frame boundary
118+
119+
lastbit:
120+
in pins, 1 side 0b10
121+
out pins, 1 side 0b10
122+
; Loop back to the beginning
123+
124+
125+
.program pio_tdm_inout_swap
126+
.side_set 2 ; 0 = bclk, 1 = wclk
127+
; The C code should place (number of bits * channels - 1) in Y and update SHIFTCTRL
128+
; to be 32 (as per the TDM specs)
129+
; +----- WCLK
130+
; |+---- BCLK
131+
mov x, y side 0b10 [1]
132+
bitloop:
133+
out pins, 1 side 0b00 ; Output changes on falling edge
134+
in pins, 1 side 0b00 ; Sample input on falling edge
135+
jmp x-- bitloop side 0b11 [1] ; Last bit toggles WCLK to mark frame boundary
136+
137+
lastbit:
138+
in pins, 1 side 0b01
139+
out pins, 1 side 0b01
140+
; Loop back to the beginning
141+
107142

108143
.program pio_lsbj_out
109144
.side_set 2 ; 0 = bclk, 1=wclk
@@ -313,6 +348,42 @@ static inline void pio_tdm_out_program_init(PIO pio, uint sm, uint offset, uint
313348
pio_sm_exec(pio, sm, pio_encode_out(pio_osr, 32));
314349
}
315350

351+
static inline void pio_tdm_inout_program_init(PIO pio, uint sm, uint offset, uint data_in_pin, uint data_out_pin, uint clock_pin_base, uint bits, bool swap, uint channels) {
352+
pio_gpio_init(pio, data_in_pin);
353+
pio_gpio_init(pio, data_out_pin);
354+
pio_gpio_init(pio, clock_pin_base);
355+
pio_gpio_init(pio, clock_pin_base + 1);
356+
357+
pio_sm_config c = swap ? pio_tdm_inout_swap_program_get_default_config(offset) : pio_tdm_inout_program_get_default_config(offset);
358+
359+
sm_config_set_in_pins(&c, data_in_pin);
360+
sm_config_set_out_pins(&c, data_out_pin, 1);
361+
sm_config_set_sideset_pins(&c, clock_pin_base);
362+
sm_config_set_in_shift(&c, false, true, 32);
363+
sm_config_set_out_shift(&c, false, true, 32);
364+
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE);
365+
366+
pio_sm_init(pio, sm, offset, &c);
367+
368+
pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 1, false);
369+
pio_sm_set_consecutive_pindirs(pio, sm, data_out_pin, 1, true);
370+
pio_sm_set_consecutive_pindirs(pio, sm, clock_pin_base, 2, true);
371+
pio_sm_set_set_pins(pio, sm, data_out_pin, 1);
372+
pio_sm_set_set_pins(pio, sm, clock_pin_base, 2);
373+
374+
// Initialize PIO state for TDM
375+
// Can't set constant > 31, so push and pop/mov if needed
376+
if (bits * channels - 1 > 31) {
377+
pio_sm_put_blocking(pio, sm, bits * channels - 2);
378+
pio_sm_exec(pio, sm, pio_encode_pull(false, false));
379+
pio_sm_exec(pio, sm, pio_encode_mov(pio_y, pio_osr));
380+
} else {
381+
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits * channels - 2));
382+
}
383+
384+
// Need to make OSR believe there's nothing left to shift out
385+
pio_sm_exec(pio, sm, pio_encode_out(pio_osr, 32));
386+
}
316387

317388
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits, bool swap) {
318389
pio_gpio_init(pio, data_pin);

libraries/I2S/src/pio_i2s.pio.h

+104
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,80 @@ static inline pio_sm_config pio_tdm_out_swap_program_get_default_config(uint off
193193
}
194194
#endif
195195

196+
// ------------- //
197+
// pio_tdm_inout //
198+
// ------------- //
199+
200+
#define pio_tdm_inout_wrap_target 0
201+
#define pio_tdm_inout_wrap 5
202+
203+
static const uint16_t pio_tdm_inout_program_instructions[] = {
204+
// .wrap_target
205+
0xa922, // 0: mov x, y side 1 [1]
206+
0x6001, // 1: out pins, 1 side 0
207+
0x4001, // 2: in pins, 1 side 0
208+
0x1941, // 3: jmp x--, 1 side 3 [1]
209+
0x5001, // 4: in pins, 1 side 2
210+
0x7001, // 5: out pins, 1 side 2
211+
// .wrap
212+
};
213+
214+
#if !PICO_NO_HARDWARE
215+
static const struct pio_program pio_tdm_inout_program = {
216+
.instructions = pio_tdm_inout_program_instructions,
217+
.length = 6,
218+
.origin = -1,
219+
.pio_version = 0,
220+
#if PICO_PIO_VERSION > 0
221+
.used_gpio_ranges = 0x0
222+
#endif
223+
};
224+
225+
static inline pio_sm_config pio_tdm_inout_program_get_default_config(uint offset) {
226+
pio_sm_config c = pio_get_default_sm_config();
227+
sm_config_set_wrap(&c, offset + pio_tdm_inout_wrap_target, offset + pio_tdm_inout_wrap);
228+
sm_config_set_sideset(&c, 2, false, false);
229+
return c;
230+
}
231+
#endif
232+
233+
// ------------------ //
234+
// pio_tdm_inout_swap //
235+
// ------------------ //
236+
237+
#define pio_tdm_inout_swap_wrap_target 0
238+
#define pio_tdm_inout_swap_wrap 5
239+
240+
static const uint16_t pio_tdm_inout_swap_program_instructions[] = {
241+
// .wrap_target
242+
0xb122, // 0: mov x, y side 2 [1]
243+
0x6001, // 1: out pins, 1 side 0
244+
0x4001, // 2: in pins, 1 side 0
245+
0x1941, // 3: jmp x--, 1 side 3 [1]
246+
0x4801, // 4: in pins, 1 side 1
247+
0x6801, // 5: out pins, 1 side 1
248+
// .wrap
249+
};
250+
251+
#if !PICO_NO_HARDWARE
252+
static const struct pio_program pio_tdm_inout_swap_program = {
253+
.instructions = pio_tdm_inout_swap_program_instructions,
254+
.length = 6,
255+
.origin = -1,
256+
.pio_version = 0,
257+
#if PICO_PIO_VERSION > 0
258+
.used_gpio_ranges = 0x0
259+
#endif
260+
};
261+
262+
static inline pio_sm_config pio_tdm_inout_swap_program_get_default_config(uint offset) {
263+
pio_sm_config c = pio_get_default_sm_config();
264+
sm_config_set_wrap(&c, offset + pio_tdm_inout_swap_wrap_target, offset + pio_tdm_inout_swap_wrap);
265+
sm_config_set_sideset(&c, 2, false, false);
266+
return c;
267+
}
268+
#endif
269+
196270
// ------------ //
197271
// pio_lsbj_out //
198272
// ------------ //
@@ -490,6 +564,36 @@ static inline void pio_tdm_out_program_init(PIO pio, uint sm, uint offset, uint
490564
// Need to make OSR believe there's nothing left to shift out, or the 1st word will be the count we just passed in, not a sample
491565
pio_sm_exec(pio, sm, pio_encode_out(pio_osr, 32));
492566
}
567+
static inline void pio_tdm_inout_program_init(PIO pio, uint sm, uint offset, uint data_in_pin, uint data_out_pin, uint clock_pin_base, uint bits, bool swap, uint channels) {
568+
pio_gpio_init(pio, data_in_pin);
569+
pio_gpio_init(pio, data_out_pin);
570+
pio_gpio_init(pio, clock_pin_base);
571+
pio_gpio_init(pio, clock_pin_base + 1);
572+
pio_sm_config c = swap ? pio_tdm_inout_swap_program_get_default_config(offset) : pio_tdm_inout_program_get_default_config(offset);
573+
sm_config_set_in_pins(&c, data_in_pin);
574+
sm_config_set_out_pins(&c, data_out_pin, 1);
575+
sm_config_set_sideset_pins(&c, clock_pin_base);
576+
sm_config_set_in_shift(&c, false, true, 32);
577+
sm_config_set_out_shift(&c, false, true, 32);
578+
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE);
579+
pio_sm_init(pio, sm, offset, &c);
580+
pio_sm_set_consecutive_pindirs(pio, sm, data_in_pin, 1, false);
581+
pio_sm_set_consecutive_pindirs(pio, sm, data_out_pin, 1, true);
582+
pio_sm_set_consecutive_pindirs(pio, sm, clock_pin_base, 2, true);
583+
pio_sm_set_set_pins(pio, sm, data_out_pin, 1);
584+
pio_sm_set_set_pins(pio, sm, clock_pin_base, 2);
585+
// Initialize PIO state for TDM
586+
// Can't set constant > 31, so push and pop/mov if needed
587+
if (bits * channels - 1 > 31) {
588+
pio_sm_put_blocking(pio, sm, bits * channels - 2);
589+
pio_sm_exec(pio, sm, pio_encode_pull(false, false));
590+
pio_sm_exec(pio, sm, pio_encode_mov(pio_y, pio_osr));
591+
} else {
592+
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits * channels - 2));
593+
}
594+
// Need to make OSR believe there's nothing left to shift out
595+
pio_sm_exec(pio, sm, pio_encode_out(pio_osr, 32));
596+
}
493597
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits, bool swap) {
494598
pio_gpio_init(pio, data_pin);
495599
pio_gpio_init(pio, clock_pin_base);

0 commit comments

Comments
 (0)