Skip to content

Commit bccad88

Browse files
I2S driver fixes for IRQs, protocol, factoring
All redundant ICACHE_FLASH_ATTR decorators were removed, we already do this by default for all routines, anyway, The actual ISR and its called function moved to to IRAM. Used to be in flash due to the decorator, which could lead to crashes. Use ets_memset to mute buffers in ISR. Fix the I2S on-the-wire protocol by enabling the transmit delay I2STMS because I2S is supposed to send the MSB one clock after LRCLK toggles. This was causing I2S to be twice as loud as intended in the best of cases, and causing garbage/noise output when the MSB was set since data was effectively shifted. Refactor the clock divider setting to be done in one function only, as there is no reason to do the same complicated bit setting in two spots.
1 parent e1ca870 commit bccad88

File tree

1 file changed

+19
-23
lines changed

1 file changed

+19
-23
lines changed

cores/esp8266/core_esp8266_i2s.c

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,21 @@ static uint32_t *i2s_slc_buf_pntr[SLC_BUF_CNT]; //Pointer to the I2S DMA buffer
5656
static struct slc_queue_item i2s_slc_items[SLC_BUF_CNT]; //I2S DMA buffer descriptors
5757
static uint32_t *i2s_curr_slc_buf=NULL;//current buffer for writing
5858
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.
59+
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.
6060

61-
bool ICACHE_FLASH_ATTR i2s_is_full(){
61+
bool i2s_is_full(){
6262
return (i2s_curr_slc_buf_pos==SLC_BUF_LEN || i2s_curr_slc_buf==NULL) && (i2s_slc_queue_len == 0);
6363
}
6464

65-
bool ICACHE_FLASH_ATTR i2s_is_empty(){
65+
bool i2s_is_empty(){
6666
return (i2s_slc_queue_len >= SLC_BUF_CNT-1);
6767
}
6868

69-
int16_t ICACHE_FLASH_ATTR i2s_available(){
69+
int16_t i2s_available(){
7070
return (SLC_BUF_CNT - i2s_slc_queue_len) * SLC_BUF_LEN;
7171
}
7272

73-
uint32_t ICACHE_FLASH_ATTR i2s_slc_queue_next_item(){ //pop the top off the queue
73+
uint32_t ICACHE_RAM_ATTR i2s_slc_queue_next_item(){ //pop the top off the queue
7474
uint8_t i;
7575
uint32_t item = i2s_slc_queue[0];
7676
i2s_slc_queue_len--;
@@ -82,13 +82,13 @@ uint32_t ICACHE_FLASH_ATTR i2s_slc_queue_next_item(){ //pop the top off the queu
8282
//This routine is called as soon as the DMA routine has something to tell us. All we
8383
//handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose
8484
//descriptor has the 'EOF' field set to 1.
85-
void ICACHE_FLASH_ATTR i2s_slc_isr(void) {
85+
void ICACHE_RAM_ATTR i2s_slc_isr(void) {
8686
uint32_t slc_intr_status = SLCIS;
8787
SLCIC = 0xFFFFFFFF;
8888
if (slc_intr_status & SLCIRXEOF) {
8989
ETS_SLC_INTR_DISABLE();
9090
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
91+
ets_memset((void *)finished_item->buf_ptr, 0x00, SLC_BUF_LEN * 4);//zero the buffer so it is mute in case of underflow
9292
if (i2s_slc_queue_len >= SLC_BUF_CNT-1) { //All buffers are empty. This means we have an underflow
9393
i2s_slc_queue_next_item(); //free space for finished_item
9494
}
@@ -102,7 +102,7 @@ void i2s_set_callback(void (*callback) (void)){
102102
i2s_callback = callback;
103103
}
104104

105-
void ICACHE_FLASH_ATTR i2s_slc_begin(){
105+
void i2s_slc_begin(){
106106
i2s_slc_queue_len = 0;
107107
int x, y;
108108

@@ -150,7 +150,7 @@ void ICACHE_FLASH_ATTR i2s_slc_begin(){
150150
SLCRXL |= SLCRXLS;
151151
}
152152

153-
void ICACHE_FLASH_ATTR i2s_slc_end(){
153+
void i2s_slc_end(){
154154
ETS_SLC_INTR_DISABLE();
155155
SLCIC = 0xFFFFFFFF;
156156
SLCIE = 0;
@@ -166,7 +166,7 @@ void ICACHE_FLASH_ATTR i2s_slc_end(){
166166
//at least the current sample rate. You can also call it quicker: it will suspend the calling
167167
//thread if the buffer is full and resume when there's room again.
168168

169-
bool ICACHE_FLASH_ATTR i2s_write_sample(uint32_t sample) {
169+
bool i2s_write_sample(uint32_t sample) {
170170
if (i2s_curr_slc_buf_pos==SLC_BUF_LEN || i2s_curr_slc_buf==NULL) {
171171
if(i2s_slc_queue_len == 0){
172172
while(1){
@@ -187,7 +187,7 @@ bool ICACHE_FLASH_ATTR i2s_write_sample(uint32_t sample) {
187187
return true;
188188
}
189189

190-
bool ICACHE_FLASH_ATTR i2s_write_sample_nb(uint32_t sample) {
190+
bool i2s_write_sample_nb(uint32_t sample) {
191191
if (i2s_curr_slc_buf_pos==SLC_BUF_LEN || i2s_curr_slc_buf==NULL) {
192192
if(i2s_slc_queue_len == 0){
193193
return false;
@@ -201,7 +201,7 @@ bool ICACHE_FLASH_ATTR i2s_write_sample_nb(uint32_t sample) {
201201
return true;
202202
}
203203

204-
bool ICACHE_FLASH_ATTR i2s_write_lr(int16_t left, int16_t right){
204+
bool i2s_write_lr(int16_t left, int16_t right){
205205
int sample = right & 0xFFFF;
206206
sample = sample << 16;
207207
sample |= left & 0xFFFF;
@@ -215,7 +215,7 @@ bool ICACHE_FLASH_ATTR i2s_write_lr(int16_t left, int16_t right){
215215

216216
static uint32_t _i2s_sample_rate;
217217

218-
void ICACHE_FLASH_ATTR i2s_set_rate(uint32_t rate){ //Rate in HZ
218+
void i2s_set_rate(uint32_t rate){ //Rate in HZ
219219
if(rate == _i2s_sample_rate) return;
220220
_i2s_sample_rate = rate;
221221

@@ -235,26 +235,22 @@ void ICACHE_FLASH_ATTR i2s_set_rate(uint32_t rate){ //Rate in HZ
235235
}
236236
}
237237

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);
238+
i2s_set_dividers( sbd_div_best, scd_div_best );
243239
}
244240

245-
void ICACHE_FLASH_ATTR i2s_set_dividers(uint8_t div1, uint8_t div2){
241+
void i2s_set_dividers(uint8_t div1, uint8_t div2){
246242
div1 &= I2SBDM;
247243
div2 &= I2SCDM;
248244

249245
I2SC &= ~(I2STSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD));
250-
I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (div1 << I2SBD) | (div2 << I2SCD);
246+
I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | I2STMS | (div1 << I2SBD) | (div2 << I2SCD);
251247
}
252248

253-
float ICACHE_FLASH_ATTR i2s_get_real_rate(){
249+
float i2s_get_real_rate(){
254250
return (float)I2SBASEFREQ/32/((I2SC>>I2SBD) & I2SBDM)/((I2SC >> I2SCD) & I2SCDM);
255251
}
256252

257-
void ICACHE_FLASH_ATTR i2s_begin(){
253+
void i2s_begin(){
258254
_i2s_sample_rate = 0;
259255
i2s_slc_begin();
260256

@@ -278,7 +274,7 @@ void ICACHE_FLASH_ATTR i2s_begin(){
278274
I2SC |= I2STXS; //Start transmission
279275
}
280276

281-
void ICACHE_FLASH_ATTR i2s_end(){
277+
void i2s_end(){
282278
I2SC &= ~I2STXS;
283279

284280
//Reset I2S

0 commit comments

Comments
 (0)