bool ICACHE_FLASH_ATTR i2s_write_sample_nb(uint32_t sample) { if (i2s_curr_slc_buf_pos==SLC_BUF_LEN || i2s_curr_slc_buf==NULL) { if(i2s_slc_queue_len == 0){ return false; } ETS_SLC_INTR_DISABLE(); i2s_curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(); ETS_SLC_INTR_ENABLE(); i2s_curr_slc_buf_pos=0; } i2s_curr_slc_buf[i2s_curr_slc_buf_pos++]=sample; return true; }
//This routine is called as soon as the DMA routine has something to tell us. All we //handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose //descriptor has the 'EOF' field set to 1. void ICACHE_FLASH_ATTR i2s_slc_isr(void) { uint32_t slc_intr_status = SLCIS; SLCIC = 0xFFFFFFFF; if (slc_intr_status & SLCIRXEOF) { ETS_SLC_INTR_DISABLE(); struct slc_queue_item *finished_item = (struct slc_queue_item*)SLCRXEDA; if (i2s_slc_queue_len >= SLC_BUF_CNT-1) { //All buffers are empty. This means we have an underflow i2s_slc_queue_next_item(); //free space for finished_item } i2s_slc_queue[i2s_slc_queue_len++] = finished_item->buf_ptr; ETS_SLC_INTR_ENABLE(); } }
void ICACHE_FLASH_ATTR i2s_slc_begin(){ i2s_slc_queue_len = 0; int x, y; for (x=0; x<SLC_BUF_CNT; x++) { i2s_slc_buf_pntr[x] = malloc(SLC_BUF_LEN*4); for (y=0; y<SLC_BUF_LEN; y++) i2s_slc_buf_pntr[x][y] = 0; i2s_slc_items[x].unused = 0; i2s_slc_items[x].owner = 1; i2s_slc_items[x].eof = 1; i2s_slc_items[x].sub_sof = 0; i2s_slc_items[x].datalen = SLC_BUF_LEN*4; i2s_slc_items[x].blocksize = SLC_BUF_LEN*4; i2s_slc_items[x].buf_ptr = (uint32_t)&i2s_slc_buf_pntr[x][0]; i2s_slc_items[x].next_link_ptr = (int)((x<(SLC_BUF_CNT-1))?(&i2s_slc_items[x+1]):(&i2s_slc_items[0])); } ETS_SLC_INTR_DISABLE(); SLCC0 |= SLCRXLR | SLCTXLR; SLCC0 &= ~(SLCRXLR | SLCTXLR); SLCIC = 0xFFFFFFFF; //Configure DMA SLCC0 &= ~(SLCMM << SLCM); //clear DMA MODE SLCC0 |= (1 << SLCM); //set DMA MODE to 1 SLCRXDC |= SLCBINR | SLCBTNR; //enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE SLCRXDC &= ~(SLCBRXFE | SLCBRXEM | SLCBRXFM); //disable RX_FILL, RX_EOF_MODE and RX_FILL_MODE //Feed DMA the 1st buffer desc addr //To send data to the I2S subsystem, counter-intuitively we use the RXLINK part, not the TXLINK as you might //expect. The TXLINK part still needs a valid DMA descriptor, even if it's unused: the DMA engine will throw //an error at us otherwise. Just feed it any random descriptor. SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address SLCTXL |= (uint32)&i2s_slc_items[1] << SLCTXLA; //set TX descriptor address. any random desc is OK, we don't use TX but it needs to be valid SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address SLCRXL |= (uint32)&i2s_slc_items[0] << SLCRXLA; //set RX descriptor address ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL); SLCIE = SLCIRXEOF; //Enable only for RX EOF interrupt ETS_SLC_INTR_ENABLE(); //Start transmission SLCTXL |= SLCTXLS; SLCRXL |= SLCRXLS; }
bool ICACHE_FLASH_ATTR i2s_write_sample(uint32_t sample) { if (i2s_curr_slc_buf_pos==SLC_BUF_LEN || i2s_curr_slc_buf==NULL) { if(i2s_slc_queue_len == 0){ while(1){ if(i2s_slc_queue_len > 0){ break; } else { ets_wdt_disable(); ets_wdt_enable(); } } } ETS_SLC_INTR_DISABLE(); i2s_curr_slc_buf = (uint32_t *)i2s_slc_queue_next_item(); ETS_SLC_INTR_ENABLE(); i2s_curr_slc_buf_pos=0; } i2s_curr_slc_buf[i2s_curr_slc_buf_pos++]=sample; return true; }