A place users can post their projects. If you have a small project and would like your own dedicated place to post and have others chat about it then this is your spot.

User avatar
By John Heath
#36976
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:

Code: Select all//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.

Code: Select allCLEAR_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.
User avatar
By JohnnyBlaze
#37089 I used the code from pvvx with the ESP-01 Module and it works great! The ESP has a very stable connection with the streaming-server from the internet. I tested it on long range through multiple cement walls over very long time (>5h) and there is really no problem with the connection.

Thanks!
User avatar
By Ahmed Moneeb
#37132 Hello everyone , please I want some help in the binary files ? how to build them ? as the ./make.sh not working :D
and If someone can explain the process "in brief or in details :D " he went through to make this project work I will really appreciate it :)
and how to upload it to the chip ? :D , can it work on the Arduino IDE ??