8000 Add LSBJ format support for I2S (#1095) · dyno-project/arduino-pico@6fe6c47 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6fe6c47

Browse files
Add LSBJ format support for I2S (earlephilhower#1095)
Fixes earlephilhower#1094
1 parent be34ed1 commit 6fe6c47

File tree

6 files changed

+119
-3
lines changed

6 files changed

+119
-3
lines changed

docs/i2s.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ Sets the word clock frequency, but does not start the I2S device if not
5858
already running. May be called after ``I2S::begin()`` to change the
5959
sample rate on-the-fly.
6060

61+
bool setLSBJFormat()
62+
~~~~~~~~~~~~~~~~~~~~
63+
Enables LSB-J format for I2S output. In this mode the MSB comes out at the
64+
same time as the LRCLK changes, and not the normal 1-cycle delay. Useful for
65+
DAC chips like the PT8211.
66+
6167
bool begin()/begin(long sampleRate)
6268
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6369
Start the I2S device up with the given sample rate, or with the value set

libraries/I2S/keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ setDATA KEYWORD2
1919
setBitsPerSample KEYWORD2
2020
setFrequency KEYWORD2
2121
setBuffers KEYWORD2
22+
setLSBJFormat KEYWORD2
2223

2324
read8 KEYWORD2
2425
read16 KEYWORD2

libraries/I2S/src/I2S.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ I2S::I2S(PinMode direction) {
5151
_buffers = 8;
5252
_bufferWords = 0;
5353
_silenceSample = 0;
54+
_isLSBJ = false;
5455
}
5556

5657
I2S::~I2S() {
@@ -99,6 +100,14 @@ bool I2S::setFrequency(int newFreq) {
99100
return true;
100101
}
101102

103+
bool I2S::setLSBJFormat() {
104+
if (_running || !_isOutput) {
105+
return false;
106+
}
107+
_isLSBJ = true;
108+
return true;
109+
}
110+
102111
void I2S::onTransmit(void(*fn)(void)) {
103112
if (_isOutput) {
104113
_cb = fn;
@@ -121,10 +130,14 @@ bool I2S::begin() {
121130
_running = true;
122131
_hasPeeked = false;
123132
int off = 0;
124-
_i2s = new PIOProgram(_isOutput ? &pio_i2s_out_program : &pio_i2s_in_program);
133+
_i2s = new PIOProgram(_isOutput ? (_isLSBJ ? &pio_lsbj_out_program : &pio_i2s_out_program) : &pio_i2s_in_program);
125134
_i2s->prepare(&_pio, &_sm, &off);
126135
if (_isOutput) {
127-
pio_i2s_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
136+
if (_isLSBJ) {
137+
pio_lsbj_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
138+
} else {
139+
pio_i2s_out_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
140+
}
128141
} else {
129142
pio_i2s_in_program_init(_pio, _sm, off, _pinDOUT, _pinBCLK, _bps);
130143
}

libraries/I2S/src/I2S.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class I2S : public Stream {
3333
bool setBitsPerSample(int bps);
3434
bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0);
3535
bool setFrequency(int newFreq);
36+
bool setLSBJFormat();
3637

3738
bool begin(long sampleRate) {
3839
setFrequency(sampleRate);
@@ -104,6 +105,7 @@ class I2S : public Stream {
104105
size_t _buffers;
105106
size_t _bufferWords;
106107
int32_t _silenceSample;
108+
bool _isLSBJ;
107109
bool _isOutput;
108110

109111
bool _running;

libraries/I2S/src/pio_i2s.pio

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,29 @@ right:
4141
out pins, 1 side 0b00 ; Last bit of right also has WCLK change
4242
; Loop back to beginning...
4343

44+
45+
.program pio_lsbj_out
46+
.side_set 2 ; 0 = bclk, 1=wclk
47+
48+
; The C code should place (number of bits/sample - 2) in Y and
49+
; also update the SHIFTCTRL to be 24 or 32 as appropriate
50+
51+
; +----- WCLK
52+
; |+---- BCLK
53+
mov x, y side 0b11
54+
left:
55+
out pins, 1 side 0b00
56+
jmp x--, left side 0b01
57+
out pins, 1 side 0b00
58+
59+
mov x, y side 0b01
60+
right:
61+
out pins, 1 side 0b10
62+
jmp x--, right side 0b11
63+
out pins, 1 side 0b10
64+
; Loop back to beginning...
65+
66+
4467

4568
.program pio_i2s_in ; Note this is the same as _out, just "in" and not "out"
4669
.side_set 2 ; 0 = bclk, 1=wclk
@@ -73,7 +96,28 @@ static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint
7396
pio_gpio_init(pio, clock_pin_base + 1);
7497

7598
pio_sm_config sm_config = pio_i2s_out_program_get_default_config(offset);
76-
99+
100+
sm_config_set_out_pins(&sm_config, data_pin, 1);
101+
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
102+
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
103+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
104+
105+
pio_sm_init(pio, sm, offset, &sm_config);
106+
107+
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
108+
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
109+
pio_sm_set_pins(pio, sm, 0); // clear pins
110+
111+
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
112+
}
113+
114+
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
115+
pio_gpio_init(pio, data_pin);
116+
pio_gpio_init(pio, clock_pin_base);
117+
pio_gpio_init(pio, clock_pin_base + 1);
118+
119+
pio_sm_config sm_config = pio_lsbj_out_program_get_default_config(offset);
120+
77121
sm_config_set_out_pins(&sm_config, data_pin, 1);
78122
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
79123
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);

libraries/I2S/src/pio_i2s.pio.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,41 @@ static inline pio_sm_config pio_i2s_out_program_get_default_config(uint offset)
4343
}
4444
#endif
4545

46+
// ------------ //
47+
// pio_lsbj_out //
48+
// ------------ //
49+
50+
#define pio_lsbj_out_wrap_target 0
51+
#define pio_lsbj_out_wrap 7
52+
53+
static const uint16_t pio_lsbj_out_program_instructions[] = {
54+
// .wrap_target
55+
0xb822, // 0: mov x, y side 3
56+
0x6001, // 1: out pins, 1 side 0
57+
0x0841, // 2: jmp x--, 1 side 1
58+
0x6001, // 3: out pins, 1 side 0
59+
0xa822, // 4: mov x, y side 1
60+
0x7001, // 5: out pins, 1 side 2
61+
0x1845, // 6: jmp x--, 5 side 3
62+
0x7001, // 7: out pins, 1 side 2
63+
// .wrap
64+
};
65+
66+
#if !PICO_NO_HARDWARE
67+
static const struct pio_program pio_lsbj_out_program = {
68+
.instructions = pio_lsbj_out_program_instructions,
69+
.length = 8,
70+
.origin = -1,
71+
};
72+
73+
static inline pio_sm_config pio_lsbj_out_program_get_default_config(uint offset) {
74+
pio_sm_config c = pio_get_default_sm_config();
75+
sm_config_set_wrap(&c, offset + pio_lsbj_out_wrap_target, offset + pio_lsbj_out_wrap);
76+
sm_config_set_sideset(&c, 2, false, false);
77+
return c;
78+
}
79+
#endif
80+
4681
// ---------- //
4782
// pio_i2s_in //
4883
// ---------- //
@@ -92,6 +127,21 @@ static inline void pio_i2s_out_program_init(PIO pio, uint sm, uint offset, uint
92127
pio_sm_set_pins(pio, sm, 0); // clear pins
93128
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
94129
}
130+
static inline void pio_lsbj_out_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
131+
pio_gpio_init(pio, data_pin);
132+
pio_gpio_init(pio, clock_pin_base);
133+
pio_gpio_init(pio, clock_pin_base + 1);
134+
pio_sm_config sm_config = pio_lsbj_out_program_get_default_config(offset);
135+
sm_config_set_out_pins(&sm_config, data_pin, 1);
136+
sm_config_set_sideset_pins(&sm_config, clock_pin_base);
137+
sm_config_set_out_shift(&sm_config, false, true, (bits <= 16) ? 2 * bits : bits);
138+
sm_config_set_fifo_join(&sm_config, PIO_FIFO_JOIN_TX);
139+
pio_sm_init(pio, sm, offset, &sm_config);
140+
uint pin_mask = (1u << data_pin) | (3u << clock_pin_base);
141+
pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
142+
pio_sm_set_pins(pio, sm, 0); // clear pins
143+
pio_sm_exec(pio, sm, pio_encode_set(pio_y, bits - 2));
144+
}
95145
static inline void pio_i2s_in_program_init(PIO pio, uint sm, uint offset, uint data_pin, uint clock_pin_base, uint bits) {
96146
pio_gpio_init(pio, data_pin);
97147
pio_gpio_init(pio, clock_pin_base);

0 commit comments

Comments
 (0)
0