ESP32S3 I2S strange problem, One Shot
Posted: Sat Jan 14, 2023 11:57 am
I have tried to use ESP32S3 I2S to generate the precise pulse. However, I still have a problem on how to correctly use I2S driver (IDF4.4).
In theory, if the buffer was written by i2s_write , it should fill the DMA and the shift out to I2S and sent out after the last block of DMA has been sent.
I have tried to generate a pattern and shift out to HC595, which the bit alignment seems to be correct.
The buffer was filled with a toggle pattern for 10 times ( 20 samples in total). but the capture shows that sometimes it only sent out the fragment, and some of the data, in the beginning, was dismissed.
The green pulse in the scope is when the i2s_write was called, and only one time called since it started. Why does some data was dismissed?
I have enabled .tx_desc_auto_clear = true, because I don't want a circular buffer. Each buffer should be sent out once and should not be resent.
Secondly, i2s_write should be blocked, but it means the blocking on writing to DMA , NOT blocking on transmission, How can I know the current status of the DMA buffer? How to know how much buffer is left?
In conclusion, how can I implement the TX buffer, which precisely sends out the data? I have looked on the event mechanism, but getting the data dropped isn't helpful since we can't lost any data.
here is the initial code
And the TX code
In theory, if the buffer was written by i2s_write , it should fill the DMA and the shift out to I2S and sent out after the last block of DMA has been sent.
I have tried to generate a pattern and shift out to HC595, which the bit alignment seems to be correct.
The buffer was filled with a toggle pattern for 10 times ( 20 samples in total). but the capture shows that sometimes it only sent out the fragment, and some of the data, in the beginning, was dismissed.
The green pulse in the scope is when the i2s_write was called, and only one time called since it started. Why does some data was dismissed?
I have enabled .tx_desc_auto_clear = true, because I don't want a circular buffer. Each buffer should be sent out once and should not be resent.
Secondly, i2s_write should be blocked, but it means the blocking on writing to DMA , NOT blocking on transmission, How can I know the current status of the DMA buffer? How to know how much buffer is left?
In conclusion, how can I implement the TX buffer, which precisely sends out the data? I have looked on the event mechanism, but getting the data dropped isn't helpful since we can't lost any data.
here is the initial code
Code: Select all
const i2s_config_t i2s_config = {
.mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = I2S_FREQ*2, // ONE PULSE OF i2s IS A DOUBLE SAMPLING
.bits_per_sample = i2s_bits_per_sample_t(32),
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_STAND_MSB),
.dma_buf_count = 2,
.dma_buf_len = I2S_BUFFER_LEN,
.tx_desc_auto_clear = true // enable one shot
};
i2s_driver_install(i2s_port, &i2s_config, 0, NULL);
const i2s_pin_config_t pin_config = {
.bck_io_num = pin_sck,
.ws_io_num = pin_ws,
.data_out_num = pin_sd,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_set_pin(i2s_port, &pin_config);
i2s_start(i2s_port);
Code: Select all
uint32_t rtBuffer[I2S_BUFFER_LEN];
digitalWrite(42, HIGH);
for(uint32_t * _p_buf = &rtBuffer[0];_p_buf < &rtBuffer[I2S_BUFFER_LEN] ;_p_buf++)
{
*_p_buf = 0x55;
_p_buf++;
*_p_buf =0;
}
for(uint32_t * _p_buf = &rtBuffer[20];_p_buf < &rtBuffer[I2S_BUFFER_LEN] ;_p_buf++)
{
*_p_buf = 0x500;
_p_buf++;
*_p_buf =0;
}
size_t wr_b;
esp_err_t ret = i2s_write(I2S_PORT,rtBuffer,(I2S_BUFFER_LEN)*4 ,&wr_b,portMAX_DELAY );
digitalWrite(42, LOW);
if(ret == ESP_OK )
{
log_i("wr ok %d",wr_b);
}else{
log_i("wr err %d",wr_b);
}