Sprite_tm wrote:(Shameless copy of my message on the official board, but I think people may want to discuss it here too...)
As you all may know, the specsheet for the ESP8266 describes the chip as having an I2S port
Hi Sprite_TM,
We built your project and are running it on the ESP8266-12E. Clocks I2S out perfectly.
However, we need to change it from I2S data out (DAC) to data in (ADC), and are having problems.
Per the manual, we expect BCLK on GPIO13 / WCLK on GPIO14, but we never see any clock outputs.
Below is our modified i2sInit() function, from i2s_freertos.c:
//Initialize I2S subsystem for DMA circular buffer use
void ICACHE_FLASH_ATTR tx_i2sInit() {
int x, y;
overflowCnt=0;
//First, take care of the DMA buffers.
for (y=0; y<I2SDMABUFCNT; y++) {
//Allocate memory for this DMA sample buffer.
i2sBuf[y]=malloc(I2SDMABUFLEN*4);
//Clear sample buffer. We don't want noise.
for (x=0; x<I2SDMABUFLEN; x++) {
i2sBuf[y][x]=0;
}
}
//Reset DMA
SET_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
CLEAR_PERI_REG_MASK(SLC_CONF0, SLC_RXLINK_RST|SLC_TXLINK_RST);
//Clear DMA int flags
SET_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
CLEAR_PERI_REG_MASK(SLC_INT_CLR, 0xffffffff);
//Enable and configure DMA
CLEAR_PERI_REG_MASK(SLC_CONF0, (SLC_MODE<<SLC_MODE_S)); //!!!
SET_PERI_REG_MASK(SLC_CONF0,(1<<SLC_MODE_S));
SET_PERI_REG_MASK(SLC_RX_DSCR_CONF,SLC_INFOR_NO_REPLACE|SLC_TOKEN_NO_REPLACE);
CLEAR_PERI_REG_MASK(SLC_RX_DSCR_CONF, SLC_RX_FILL_EN|SLC_RX_EOF_MODE | SLC_RX_FILL_MODE);
//Initialize DMA buffer descriptors in such a way that they will form a circular
//buffer.
for (x=0; x<I2SDMABUFCNT; x++) {
i2sBufDesc[x].owner=1;
i2sBufDesc[x].eof=1;
i2sBufDesc[x].sub_sof=0;
i2sBufDesc[x].datalen=I2SDMABUFLEN*4;
i2sBufDesc[x].blocksize=I2SDMABUFLEN*4;
i2sBufDesc[x].buf_ptr=(uint32_t)&i2sBuf[x][0];
i2sBufDesc[x].unused=0;
i2sBufDesc[x].next_link_ptr=(int)((x<(I2SDMABUFCNT-1))?(&i2sBufDesc[x+1]):(&i2sBufDesc[0]));
}
//Feed dma the 1st buffer desc addr
//To rcv data from the I2S subsystem, counter-intuitively we use the TXLINK part, not the RXLINK as you might
//expect. The RXLINK 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.
CLEAR_PERI_REG_MASK(SLC_RX_LINK,SLC_RXLINK_DESCADDR_MASK);
SET_PERI_REG_MASK(SLC_RX_LINK, ((uint32)&i2sBufDesc[1]) & SLC_RXLINK_DESCADDR_MASK); //any random desc is OK, we don't use RX but it needs something valid
CLEAR_PERI_REG_MASK(SLC_TX_LINK,SLC_TXLINK_DESCADDR_MASK);
SET_PERI_REG_MASK(SLC_TX_LINK, ((uint32)&i2sBufDesc[0]) & SLC_TXLINK_DESCADDR_MASK);
//Attach the DMA interrupt
_xt_isr_attach(ETS_SLC_INUM, slc_isr);
//Enable DMA operation intr
WRITE_PERI_REG(SLC_INT_ENA, SLC_TX_EOF_INT_ENA);
//clear any interrupt flags that are set
WRITE_PERI_REG(SLC_INT_CLR, 0xffffffff);
///enable DMA intr in cpu
_xt_isr_unmask(1<<ETS_SLC_INUM);
//We use a queue to keep track of the DMA buffers that are full. The ISR will push buffers to the back of the queue,
//the proc fn will pull them from the front and empty them. For ease, the queue will contain *pointers* to the DMA
//buffers, not the data itself. The queue depth is one smaller than the amount of buffers we have, because there's
//always a buffer that is being used by the DMA subsystem *right now* and we don't want to be able to write to that
//simultaneously.
dmaQueue=xQueueCreate(I2SDMABUFCNT-1, sizeof(int*));
//Start transmission
SET_PERI_REG_MASK(SLC_TX_LINK, SLC_TXLINK_START);
SET_PERI_REG_MASK(SLC_RX_LINK, SLC_RXLINK_START);
//----
//Init pins to i2s functions
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_I2SI_DATA); //!!!
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_I2SI_WS);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_I2SI_BCK);
//Enable clock to i2s subsystem
i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);
//Reset I2S subsystem
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
CLEAR_PERI_REG_MASK(I2SCONF,I2S_I2S_RESET_MASK);
//Select 16bits per channel (FIFO_MOD=0), no DMA access (FIFO only)
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN|(I2S_I2S_RX_FIFO_MOD<<I2S_I2S_RX_FIFO_MOD_S)|(I2S_I2S_TX_FIFO_MOD<<I2S_I2S_TX_FIFO_MOD_S));
//Enable DMA in i2s subsystem
SET_PERI_REG_MASK(I2S_FIFO_CONF, I2S_I2S_DSCR_EN);
//tx/rx binaureal
CLEAR_PERI_REG_MASK(I2SCONF_CHAN, (I2S_TX_CHAN_MOD<<I2S_TX_CHAN_MOD_S)|(I2S_RX_CHAN_MOD<<I2S_RX_CHAN_MOD_S));
//Clear int
SET_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_TX_REMPTY_INT_CLR|I2S_I2S_TX_WFULL_INT_CLR|
I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
CLEAR_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_TX_REMPTY_INT_CLR|I2S_I2S_TX_WFULL_INT_CLR|
I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
//trans master&rece slave,MSB shift,right_first,msb right //!!!
CLEAR_PERI_REG_MASK(I2SCONF, I2S_TRANS_SLAVE_MOD|
(I2S_BITS_MOD<<I2S_BITS_MOD_S)|
(I2S_BCK_DIV_NUM <<I2S_BCK_DIV_NUM_S)|
(I2S_CLKM_DIV_NUM<<I2S_CLKM_DIV_NUM_S));
SET_PERI_REG_MASK(I2SCONF, I2S_RIGHT_FIRST|I2S_MSB_RIGHT|I2S_RECE_SLAVE_MOD|
I2S_RECE_MSB_SHIFT|I2S_TRANS_MSB_SHIFT|
((16&I2S_BCK_DIV_NUM )<<I2S_BCK_DIV_NUM_S)|
((7&I2S_CLKM_DIV_NUM)<<I2S_CLKM_DIV_NUM_S));
//No idea if ints are needed...
//clear int
SET_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_TX_REMPTY_INT_CLR|I2S_I2S_TX_WFULL_INT_CLR|
I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
CLEAR_PERI_REG_MASK(I2SINT_CLR, I2S_I2S_TX_REMPTY_INT_CLR|I2S_I2S_TX_WFULL_INT_CLR|
I2S_I2S_RX_WFULL_INT_CLR|I2S_I2S_PUT_DATA_INT_CLR|I2S_I2S_TAKE_DATA_INT_CLR);
//enable int
SET_PERI_REG_MASK(I2SINT_ENA, I2S_I2S_TX_REMPTY_INT_ENA|I2S_I2S_TX_WFULL_INT_ENA|
I2S_I2S_RX_REMPTY_INT_ENA|I2S_I2S_TX_PUT_DATA_INT_ENA|I2S_I2S_RX_TAKE_DATA_INT_ENA);
//Start rcv
SET_PERI_REG_MASK(I2SCONF,I2S_I2S_TX_START);
}
We also tried a variation setting both trans (data in) & receive (data out) to master. Still no clocks.
CLEAR_PERI_REG_MASK(I2SCONF, I2S_TRANS_SLAVE_MOD | I2S_RECE_SLAVE_MOD
We really need some help. Can you spot an error in our function? Do you have the I2S register manual / block diagram? Is there a working example of I2S data in?
If we can't get this this to work, we'll have to go with another vendor.