21
21
#include < Arduino.h>
22
22
#include " I2S.h"
23
23
#include " pio_i2s.pio.h"
24
+ #include < pico/stdlib.h>
24
25
25
26
26
27
I2S::I2S (PinMode direction) {
@@ -30,6 +31,8 @@ I2S::I2S(PinMode direction) {
30
31
_isOutput = direction == OUTPUT;
31
32
_pinBCLK = 26 ;
32
33
_pinDOUT = 28 ;
34
+ _pinMCLK = 25 ;
35
+ _MCLKenabled = false ;
33
36
#ifdef PIN_I2S_BCLK
34
37
_pinBCLK = PIN_I2S_BCLK;
35
38
#endif
@@ -53,6 +56,7 @@ I2S::I2S(PinMode direction) {
53
56
_silenceSample = 0 ;
54
57
_isLSBJ = false ;
55
58
_swapClocks = false ;
59
+ _multMCLK = 256 ;
56
60
}
57
61
58
62
I2S::~I2S () {
@@ -67,6 +71,14 @@ bool I2S::setBCLK(pin_size_t pin) {
67
71
return true ;
68
72
}
69
73
74
+
75
+ bool I2S::setMCLK (pin_size_t pin) {
76
+ if (_running || (pin > 28 )) {
77
+ return false ;
78
+ }
79
+ _pinMCLK = pin;
80
+ return true ;
81
+ }
70
82
bool I2S::setDATA (pin_size_t pin) {
71
83
if (_running || (pin > 29 )) {
72
84
return false ;
@@ -96,12 +108,41 @@ bool I2S::setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample)
96
108
bool I2S::setFrequency (int newFreq) {
97
109
_freq = newFreq;
98
110
if (_running) {
99
- float bitClk = _freq * _bps * 2.0 /* channels */ * 2.0 /* edges per clock */ ;
100
- pio_sm_set_clkdiv (_pio, _sm, (float )clock_get_hz (clk_sys) / bitClk);
111
+ if (_MCLKenabled) {
112
+ int bitClk = _freq * _bps * 2.0 /* channels */ * 2.0 /* edges per clock */ ;
113
+ pio_sm_set_clkdiv_int_frac (_pio, _sm, clock_get_hz (clk_sys) / bitClk, 0 );
114
+ } else {
115
+ float bitClk = _freq * _bps * 2.0 /* channels */ * 2.0 /* edges per clock */ ;
116
+ pio_sm_set_clkdiv (_pio, _sm, (float )clock_get_hz (clk_sys) / bitClk);
117
+ }
101
118
}
102
119
return true ;
103
120
}
104
121
122
+ bool I2S::setSysClk (int samplerate) { // optimise sys_clk for desired samplerate
123
+ if (samplerate % 11025 == 0 ) {
124
+ set_sys_clock_khz (I2SSYSCLK_44_1, false ); // 147.6 unsuccessful - no I2S no USB
125
+ return true ;
126
+ }
127
+ if (samplerate % 8000 == 0 ) {
128
+ set_sys_clock_khz (I2SSYSCLK_8, false );
129
+ return true ;
130
+ }
131
+ return false ;
132
+ }
133
+
134
+ bool I2S::setMCLKmult (int mult) {
135
+ if (_running || !_isOutput) {
136
+ return false ;
137
+ }
138
+ if ((mult % 64 ) == 0 ) {
139
+ _MCLKenabled = true ;
140
+ _multMCLK = mult;
141
+ return true ;
142
+ }
143
+ return false ;
144
+ }
145
+
105
146
bool I2S::setLSBJFormat () {
106
147
if (_running || !_isOutput) {
107
148
return false ;
@@ -136,6 +177,16 @@ void I2S::onReceive(void(*fn)(void)) {
136
177
}
137
178
}
138
179
180
+ void I2S::MCLKbegin () {
181
+ int off = 0 ;
182
+ _i2sMCLK = new PIOProgram (&pio_i2s_mclk_program);
183
+ _i2sMCLK->prepare (&_pioMCLK, &_smMCLK, &off); // not sure how to use the same PIO
184
+ pio_i2s_MCLK_program_init (_pioMCLK, _smMCLK, off, _pinMCLK);
185
+ int mClk = _multMCLK * _freq * 2.0 /* edges per clock */ ;
186
+ pio_sm_set_clkdiv_int_frac (_pioMCLK, _smMCLK, clock_get_hz (clk_sys) / mClk , 0 );
187
+ pio_sm_set_enabled (_pioMCLK, _smMCLK, true );
188
+ }
189
+
139
190
bool I2S::begin () {
140
191
_running = true ;
141
192
_hasPeeked = false ;
@@ -162,6 +213,9 @@ bool I2S::begin() {
162
213
pio_i2s_in_program_init (_pio, _sm, off, _pinDOUT, _pinBCLK, _bps, _swapClocks);
163
214
}
164
215
setFrequency (_freq);
216
+ if (_MCLKenabled) {
217
+ MCLKbegin ();
218
+ }
165
219
if (_bps == 8 ) {
166
220
uint8_t a = _silenceSample & 0xff ;
167
221
_silenceSample = (a << 24 ) | (a << 16 ) | (a << 8 ) | a;
@@ -189,6 +243,11 @@ bool I2S::begin() {
189
243
190
244
void I2S::end () {
191
245
if (_running) {
246
+ if (_MCLKenabled) {
247
+ pio_sm_set_enabled (_pioMCLK, _smMCLK, false );
248
+ delete _i2sMCLK;
249
+ _i2sMCLK = nullptr ;
250
+ }
192
251
pio_sm_set_enabled (_pio, _sm, false );
193
252
_running = false ;
194
253
delete _arb;
@@ -204,8 +263,13 @@ int I2S::available() {
204
263
} else {
205
264
auto avail = _arb->available ();
206
265
avail *= 4 ; // 4 samples per 32-bits
207
- if (_bps < 24 && !_isOutput) {
208
- avail += _isHolding / 8 ;
266
+ if (_bps < 24 ) {
267
+ if (_isOutput) {
268
+ // 16- and 8-bit can have holding bytes available
269
+ avail += (32 - _isHolding) / 8 ;
270
+ } else {
271
+ avail += _isHolding / 8 ;
272
+ }
209
273
}
210
274
return avail;
211
275
}
0 commit comments