I2S 32-Bit Rx
Posted: Tue Mar 21, 2017 4:11 am
I'm trying to get the ESP32 to work with an Audio Codec in 32-bit mode (32-bits per sample). I saw another post reference updating tx_fifo_mod setting in the driver. I've updated the tx_fifo_mod as well as the rx_fifo_mod settings in the I2S driver (code changes copied below). With these changes I've verified that the frame is now 32-bits per sample (64 bclks/wclk). I've also verified I can cleanly send a 32-bit sine wave data to the codec through I2S to it's analog output.
However, there still seems to be a problem with the 32-bit receive... When the ESP32 is receiving in 32-bit mode it only gets half of the data. In other words, when I do an I2S loopback to the codec, half of the data is missing (picture below, solid blue data is the data stream into the ESP32, Red data is attempting to simply re-send what was received). I also noticed that when I mute a channel on the codec, the I2S data output from the ESP is showing data on both channels and the data looks bit-shifted from the data that is sent.
What I suspect is happening is the I2S RX FIFOs are still cutting the data to 16-bits. However, I can't figure out why this is happening. I see the same behavior using the single push/pop sample functions as well (so its probably not the dma?). I've tried changing a number of various I2S settings (helped by the new documentation), but still can't get it to work!
Any ideas or suggestions? Has anyone gotten 32-bit I2S receive to work on the ESP32?
Thanks!
Update to i2s.h:
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT, // 1
I2S_CHANNEL_FMT_ALL_LEFT, // 2
I2S_CHANNEL_FMT_ONLY_RIGHT, // 3
I2S_CHANNEL_FMT_ONLY_LEFT, // 4
//=== Added these, to enable 32-bit FIFO data
I2S_CHANNEL_FMT_RIGHT_LEFT_32, // 5
I2S_CHANNEL_FMT_ALL_RIGHT_32, // 6
I2S_CHANNEL_FMT_ALL_LEFT_32, // 7
I2S_CHANNEL_FMT_ONLY_RIGHT_32, // 8
I2S_CHANNEL_FMT_ONLY_LEFT_32, // 9
} i2s_channel_fmt_t;
Update to the I2S Driver Code (i2s.c,i2s_param_config) :
//===============================================================================================================
//=== Start Changes to enable 32-bit FIFO mode
//=== 16-bit Mode Configuration (untouched)
if(i2s_config->channel_format <= I2S_CHANNEL_FMT_ONLY_LEFT){
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
}else{
//=== 32-bit Mode Configuration
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 1;
// tx_chan_mod: 0: dual channel, 1: mono
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? (i2s_config->channel_format-2)>>2 : ((i2s_config->channel_format-2) >> 2); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 3; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? (i2s_config->channel_format-2)>>2 : ((i2s_config->channel_format-2) >> 2); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 3; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 0 : 1; // 0-right&left channel;1-one channel
//=== Added these, they default to 32, can't find them being set elsewhere
// they are thresholds tht trigger readout to prevent overflow. Tried 63,16, didn't help in normal mode or push/pop.
I2S[i2s_num]->fifo_conf.rx_data_num = 32; // 6-bits, max value: 63
I2S[i2s_num]->fifo_conf.tx_data_num = 32;
printf("I2S Driver Param Config: channel format: 0x%x\n",i2s_config->channel_format);
printf("I2S Driver Param Config: tx_fifo_mod: 0x%x\n",I2S[i2s_num]->fifo_conf.tx_fifo_mod);
printf("I2S Driver Param Config: rx_fifo_mod: 0x%x\n",I2S[i2s_num]->fifo_conf.rx_fifo_mod);
printf("I2S Driver Param Config: rx_chan_mod: 0x%x\n",I2S[i2s_num]->conf_chan.rx_chan_mod);
}
//=== End Changes to enable 32-bit FIFO mode
//===============================================================================================================
However, there still seems to be a problem with the 32-bit receive... When the ESP32 is receiving in 32-bit mode it only gets half of the data. In other words, when I do an I2S loopback to the codec, half of the data is missing (picture below, solid blue data is the data stream into the ESP32, Red data is attempting to simply re-send what was received). I also noticed that when I mute a channel on the codec, the I2S data output from the ESP is showing data on both channels and the data looks bit-shifted from the data that is sent.
What I suspect is happening is the I2S RX FIFOs are still cutting the data to 16-bits. However, I can't figure out why this is happening. I see the same behavior using the single push/pop sample functions as well (so its probably not the dma?). I've tried changing a number of various I2S settings (helped by the new documentation), but still can't get it to work!
Any ideas or suggestions? Has anyone gotten 32-bit I2S receive to work on the ESP32?
Thanks!
Update to i2s.h:
/**
* @brief I2S channel format type
*/
typedef enum {
I2S_CHANNEL_FMT_RIGHT_LEFT = 0x00,
I2S_CHANNEL_FMT_ALL_RIGHT, // 1
I2S_CHANNEL_FMT_ALL_LEFT, // 2
I2S_CHANNEL_FMT_ONLY_RIGHT, // 3
I2S_CHANNEL_FMT_ONLY_LEFT, // 4
//=== Added these, to enable 32-bit FIFO data
I2S_CHANNEL_FMT_RIGHT_LEFT_32, // 5
I2S_CHANNEL_FMT_ALL_RIGHT_32, // 6
I2S_CHANNEL_FMT_ALL_LEFT_32, // 7
I2S_CHANNEL_FMT_ONLY_RIGHT_32, // 8
I2S_CHANNEL_FMT_ONLY_LEFT_32, // 9
} i2s_channel_fmt_t;
Update to the I2S Driver Code (i2s.c,i2s_param_config) :
//===============================================================================================================
//=== Start Changes to enable 32-bit FIFO mode
//=== 16-bit Mode Configuration (untouched)
if(i2s_config->channel_format <= I2S_CHANNEL_FMT_ONLY_LEFT){
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 2 : 1;
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? i2s_config->channel_format : (i2s_config->channel_format >> 1); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT ? 0 : 1; // 0-right&left channel;1-one channel
}else{
//=== 32-bit Mode Configuration
p_i2s_obj[i2s_num]->channel_num = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 1;
// tx_chan_mod: 0: dual channel, 1: mono
I2S[i2s_num]->conf_chan.tx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? (i2s_config->channel_format-2)>>2 : ((i2s_config->channel_format-2) >> 2); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.tx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 3; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.tx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 0 : 1; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf_chan.rx_chan_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? (i2s_config->channel_format-2)>>2 : ((i2s_config->channel_format-2) >> 2); // 0-two channel;1-right;2-left;3-righ;4-left
I2S[i2s_num]->fifo_conf.rx_fifo_mod = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 2 : 3; // 0-right&left channel;1-one channel
I2S[i2s_num]->conf.rx_mono = i2s_config->channel_format < I2S_CHANNEL_FMT_ONLY_RIGHT_32 ? 0 : 1; // 0-right&left channel;1-one channel
//=== Added these, they default to 32, can't find them being set elsewhere
// they are thresholds tht trigger readout to prevent overflow. Tried 63,16, didn't help in normal mode or push/pop.
I2S[i2s_num]->fifo_conf.rx_data_num = 32; // 6-bits, max value: 63
I2S[i2s_num]->fifo_conf.tx_data_num = 32;
printf("I2S Driver Param Config: channel format: 0x%x\n",i2s_config->channel_format);
printf("I2S Driver Param Config: tx_fifo_mod: 0x%x\n",I2S[i2s_num]->fifo_conf.tx_fifo_mod);
printf("I2S Driver Param Config: rx_fifo_mod: 0x%x\n",I2S[i2s_num]->fifo_conf.rx_fifo_mod);
printf("I2S Driver Param Config: rx_chan_mod: 0x%x\n",I2S[i2s_num]->conf_chan.rx_chan_mod);
}
//=== End Changes to enable 32-bit FIFO mode
//===============================================================================================================