27
27
#include "i2s_reg.h"
28
28
#include "i2s.h"
29
29
30
- extern void ets_wdt_enable (void );
31
- extern void ets_wdt_disable (void );
30
+ // IOs used for I2S. Not defined in i2s.h, unfortunately.
31
+ // Note these are internal IOs numbers and not pins on an
32
+ // Arduino board. Users need to verify their particular wiring.
33
+ #define I2SO_WS 2
34
+ #define I2SO_DATA 3
35
+ #define I2SO_BCK 15
32
36
33
37
#define SLC_BUF_CNT (8) //Number of buffers in the I2S circular buffer
34
38
#define SLC_BUF_LEN (64) //Length of one buffer, in 32-bit words.
@@ -56,21 +60,21 @@ static uint32_t *i2s_slc_buf_pntr[SLC_BUF_CNT]; //Pointer to the I2S DMA buffer
56
60
static struct slc_queue_item i2s_slc_items [SLC_BUF_CNT ]; //I2S DMA buffer descriptors
57
61
static uint32_t * i2s_curr_slc_buf = NULL ;//current buffer for writing
58
62
static int i2s_curr_slc_buf_pos = 0 ; //position in the current buffer
59
- static void (* i2s_callback ) (void )= 0 ; //Callback function should be defined as 'void ICACHE_FLASH_ATTR function_name()', placing the function in IRAM for faster execution. Avoid long computational tasks in this function, use it to set flags and process later.
63
+ static void (* i2s_callback ) (void )= 0 ; //Callback function should be defined as 'void ICACHE_RAM_ATTR function_name()', placing the function in IRAM for faster execution. Avoid long computational tasks in this function, use it to set flags and process later.
60
64
61
- bool ICACHE_FLASH_ATTR i2s_is_full (){
65
+ bool i2s_is_full (){
62
66
return (i2s_curr_slc_buf_pos == SLC_BUF_LEN || i2s_curr_slc_buf == NULL ) && (i2s_slc_queue_len == 0 );
63
67
}
64
68
65
- bool ICACHE_FLASH_ATTR i2s_is_empty (){
69
+ bool i2s_is_empty (){
66
70
return (i2s_slc_queue_len >= SLC_BUF_CNT - 1 );
67
71
}
68
72
69
- int16_t ICACHE_FLASH_ATTR i2s_available (){
70
- return (SLC_BUF_CNT - i2s_slc_queue_len ) * SLC_BUF_LEN ;
73
+ int16_t i2s_available (){
74
+ return (SLC_BUF_CNT - i2s_slc_queue_len ) * SLC_BUF_LEN ;
71
75
}
72
76
73
- uint32_t ICACHE_FLASH_ATTR i2s_slc_queue_next_item (){ //pop the top off the queue
77
+ uint32_t ICACHE_RAM_ATTR i2s_slc_queue_next_item (){ //pop the top off the queue
74
78
uint8_t i ;
75
79
uint32_t item = i2s_slc_queue [0 ];
76
80
i2s_slc_queue_len -- ;
@@ -82,13 +86,13 @@ uint32_t ICACHE_FLASH_ATTR i2s_slc_queue_next_item(){ //pop the top off the queu
82
86
//This routine is called as soon as the DMA routine has something to tell us. All we
83
87
//handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose
84
88
//descriptor has the 'EOF' field set to 1.
85
- void ICACHE_FLASH_ATTR i2s_slc_isr (void ) {
89
+ void ICACHE_RAM_ATTR i2s_slc_isr (void ) {
86
90
uint32_t slc_intr_status = SLCIS ;
87
91
SLCIC = 0xFFFFFFFF ;
88
92
if (slc_intr_status & SLCIRXEOF ) {
89
93
ETS_SLC_INTR_DISABLE ();
90
94
struct slc_queue_item * finished_item = (struct slc_queue_item * )SLCRXEDA ;
91
- memset ((void * )finished_item -> buf_ptr , 0x00 , SLC_BUF_LEN * 4 );//zero the buffer so it is mute in case of underflow
95
+ ets_memset ((void * )finished_item -> buf_ptr , 0x00 , SLC_BUF_LEN * 4 );//zero the buffer so it is mute in case of underflow
92
96
if (i2s_slc_queue_len >= SLC_BUF_CNT - 1 ) { //All buffers are empty. This means we have an underflow
93
97
i2s_slc_queue_next_item (); //free space for finished_item
94
98
}
@@ -102,7 +106,7 @@ void i2s_set_callback(void (*callback) (void)){
102
106
i2s_callback = callback ;
103
107
}
104
108
105
- void ICACHE_FLASH_ATTR i2s_slc_begin (){
109
+ void i2s_slc_begin (){
106
110
i2s_slc_queue_len = 0 ;
107
111
int x , y ;
108
112
@@ -150,7 +154,7 @@ void ICACHE_FLASH_ATTR i2s_slc_begin(){
150
154
SLCRXL |= SLCRXLS ;
151
155
}
152
156
153
- void ICACHE_FLASH_ATTR i2s_slc_end (){
157
+ void i2s_slc_end (){
154
158
ETS_SLC_INTR_DISABLE ();
155
159
SLCIC = 0xFFFFFFFF ;
156
160
SLCIE = 0 ;
@@ -166,15 +170,14 @@ void ICACHE_FLASH_ATTR i2s_slc_end(){
166
170
//at least the current sample rate. You can also call it quicker: it will suspend the calling
167
171
//thread if the buffer is full and resume when there's room again.
168
172
169
- bool ICACHE_FLASH_ATTR i2s_write_sample (uint32_t sample ) {
173
+ bool i2s_write_sample (uint32_t sample ) {
170
174
if (i2s_curr_slc_buf_pos == SLC_BUF_LEN || i2s_curr_slc_buf == NULL ) {
171
175
if (i2s_slc_queue_len == 0 ){
172
176
while (1 ){
173
177
if (i2s_slc_queue_len > 0 ){
174
178
break ;
175
179
} else {
176
- ets_wdt_disable ();
177
- ets_wdt_enable ();
180
+ optimistic_yield (10000 );
178
181
}
179
182
}
180
183
}
@@ -187,7 +190,7 @@ bool ICACHE_FLASH_ATTR i2s_write_sample(uint32_t sample) {
187
190
return true;
188
191
}
189
192
190
- bool ICACHE_FLASH_ATTR i2s_write_sample_nb (uint32_t sample ) {
193
+ bool i2s_write_sample_nb (uint32_t sample ) {
191
194
if (i2s_curr_slc_buf_pos == SLC_BUF_LEN || i2s_curr_slc_buf == NULL ) {
192
195
if (i2s_slc_queue_len == 0 ){
193
196
return false;
@@ -201,7 +204,7 @@ bool ICACHE_FLASH_ATTR i2s_write_sample_nb(uint32_t sample) {
201
204
return true;
202
205
}
203
206
204
- bool ICACHE_FLASH_ATTR i2s_write_lr (int16_t left , int16_t right ){
207
+ bool i2s_write_lr (int16_t left , int16_t right ){
205
208
int sample = right & 0xFFFF ;
206
209
sample = sample << 16 ;
207
210
sample |= left & 0xFFFF ;
@@ -215,7 +218,7 @@ bool ICACHE_FLASH_ATTR i2s_write_lr(int16_t left, int16_t right){
215
218
216
219
static uint32_t _i2s_sample_rate ;
217
220
218
- void ICACHE_FLASH_ATTR i2s_set_rate (uint32_t rate ){ //Rate in HZ
221
+ void i2s_set_rate (uint32_t rate ){ //Rate in HZ
219
222
if (rate == _i2s_sample_rate ) return ;
220
223
_i2s_sample_rate = rate ;
221
224
@@ -235,60 +238,68 @@ void ICACHE_FLASH_ATTR i2s_set_rate(uint32_t rate){ //Rate in HZ
235
238
}
236
239
}
237
240
238
- //os_printf("Rate %u Div %u Bck %u Frq %u\n", _i2s_sample_rate, i2s_clock_div, i2s_bck_div, I2SBASEFREQ/(i2s_clock_div*i2s_bck_div*2));
239
-
240
- //!trans master, !bits mod, rece slave mod, rece msb shift, right first, msb right
241
- I2SC &= ~(I2STSM | (I2SBMM << I2SBM ) | (I2SBDM << I2SBD ) | (I2SCDM << I2SCD ));
242
- I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | ((sbd_div_best ) << I2SBD ) | ((scd_div_best ) << I2SCD );
241
+ i2s_set_dividers ( sbd_div_best , scd_div_best );
243
242
}
244
243
245
- void ICACHE_FLASH_ATTR i2s_set_dividers (uint8_t div1 , uint8_t div2 ){
244
+ void i2s_set_dividers (uint8_t div1 , uint8_t div2 ) {
245
+ // Ensure dividers fit in bit fields
246
246
div1 &= I2SBDM ;
247
247
div2 &= I2SCDM ;
248
248
249
+ // !trans master(?), !bits mod(==16 bits/chanel), clear clock dividers
249
250
I2SC &= ~(I2STSM | (I2SBMM << I2SBM ) | (I2SBDM << I2SBD ) | (I2SCDM << I2SCD ));
250
- I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (div1 << I2SBD ) | (div2 << I2SCD );
251
+
252
+ // I2SRF = Send/recv right channel first (? may be swapped form I2S spec of WS=0 => left)
253
+ // I2SMR = MSB recv/xmit first
254
+ // I2SRSM = Receive slave mode (?)
255
+ // I2SRMS, I2STMS = 1-bit delay from WS to MSB (I2S format)
256
+ // div1, div2 = Set I2S WS clock frequency. BCLK seems to be generated from 32x this
257
+ I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | I2STMS | (div1 << I2SBD ) | (div2 << I2SCD );
251
258
}
252
259
253
- float ICACHE_FLASH_ATTR i2s_get_real_rate (){
260
+ float i2s_get_real_rate (){
254
261
return (float )I2SBASEFREQ /32 /((I2SC >>I2SBD ) & I2SBDM )/((I2SC >> I2SCD ) & I2SCDM );
255
262
}
256
263
257
- void ICACHE_FLASH_ATTR i2s_begin (){
264
+ void i2s_begin () {
258
265
_i2s_sample_rate = 0 ;
259
266
i2s_slc_begin ();
260
-
261
- pinMode (2 , FUNCTION_1 ); //I2SO_WS (LRCK)
262
- pinMode (3 , FUNCTION_1 ); //I2SO_DATA (SDIN)
263
- pinMode (15 , FUNCTION_1 ); //I2SO_BCK (SCLK)
267
+
268
+ // Redirect control of IOs to the I2S block
269
+ pinMode (I2SO_WS , FUNCTION_1 );
270
+ pinMode (I2SO_DATA , FUNCTION_1 );
271
+ pinMode (I2SO_BCK , FUNCTION_1 );
264
272
265
273
I2S_CLK_ENABLE ();
266
274
I2SIC = 0x3F ;
267
275
I2SIE = 0 ;
268
276
269
- //Reset I2S
277
+ // Reset I2S
270
278
I2SC &= ~(I2SRST );
271
279
I2SC |= I2SRST ;
272
280
I2SC &= ~(I2SRST );
273
-
274
- I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM ) | (I2SRXFMM << I2SRXFM )); //Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only)
281
+
282
+ // I2STXFMM, I2SRXFMM=0 => 16-bit, dual channel data shifted in/out
283
+ I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM ) | (I2SRXFMM << I2SRXFM )); //Set RX/TX FIFO_MOD=0 (16-bit) and disable DMA (FIFO only)
275
284
I2SFC |= I2SDE ; //Enable DMA
285
+ // I2STXCMM, I2SRXCMM=0 => Dual channel mode
276
286
I2SCC &= ~((I2STXCMM << I2STXCM ) | (I2SRXCMM << I2SRXCM )); //Set RX/TX CHAN_MOD=0
277
287
i2s_set_rate (44100 );
278
288
I2SC |= I2STXS ; //Start transmission
279
289
}
280
290
281
- void ICACHE_FLASH_ATTR i2s_end (){
291
+ void i2s_end (){
282
292
I2SC &= ~I2STXS ;
283
293
284
294
//Reset I2S
285
295
I2SC &= ~(I2SRST );
286
296
I2SC |= I2SRST ;
287
297
I2SC &= ~(I2SRST );
288
298
289
- pinMode (2 , INPUT );
290
- pinMode (3 , INPUT );
291
- pinMode (15 , INPUT );
299
+ // Redirect IOs to user control/GPIO
300
+ pinMode (I2SO_WS , INPUT );
301
+ pinMode (I2SO_DATA , INPUT );
302
+ pinMode (I2SO_BCK , INPUT );
292
303
293
304
i2s_slc_end ();
294
305
}
0 commit comments