[SOLVED] ESP32 Arduino Framework. Proper I2S ADC DMA reading and Plotting question.
Posted: Tue Oct 01, 2019 11:34 am
Hello forumers!
I want to read a 4Khz analog signal from a signal generator via i2s dma with ESP32 on arduino framework.
My basic idea is this:
-Setup i2s DMA to put the reading to a buffer.
-Assign a read function/task to the core0 to read the values from the DMA buffer.
-Assign a "plotting" functon/task to a core to plot the readings to the web with ChartJS.
What have i done so far:
I created the i2s setup function and put it to the first place on the setup().
I created the reader task on the core0 for reading and plotting to the web.
I created a html file that i store on the SPIFFS file system on the ESP32.
-In the HTMl file i created a chart on a canvas using ChartJS javascript library.
-In the JavaScript file i created a websocket client that is connected to the websocket server on the esp32.
-In the JavaScript file, when the data comes from the esp32 i assign it to the chart and visualize it.
Everything is working fine, except one little problem.
My i2s dma buffer is overflowing and i can see it in the visualized data.
What i think is happening:
-While i read the entire DMA buffer, the i2s adc is filling up this buffer again and again even if i doesn't end up reading from the entire buffer. This will result on buffer overflow and my readed data does not mach the actual reading.
What i think is the solution:
-If there will be an interrupt on the i2s adc dma, if it is filled up the entire buffer i would switch to an other buffer while i read the first, and when i done with the reading i would read from the second while the adc filling up the first and so on...
The thing is i did not find anything from this interrupt on the Arduino core. The one thing that i found is an event solution, that i think is just a flag and does not work as expected.
So my question is, how can i avoid this buffer overflow or how can i assign an interrupt to the dma buffer, or how can it be done correctly.
Here is my i2s init code:
Here is my adc reader function on core 0:
The ADC_Sampling is looks like this on core0:
My HTML and JavaScript code:
Here is a video URL from my plotted data on the WEB when the buffer overflow doesn't hit.:
https://streamable.com/9dngp
I attached some pictures from the readed data on the web.
I want to read a 4Khz analog signal from a signal generator via i2s dma with ESP32 on arduino framework.
My basic idea is this:
-Setup i2s DMA to put the reading to a buffer.
-Assign a read function/task to the core0 to read the values from the DMA buffer.
-Assign a "plotting" functon/task to a core to plot the readings to the web with ChartJS.
What have i done so far:
I created the i2s setup function and put it to the first place on the setup().
I created the reader task on the core0 for reading and plotting to the web.
I created a html file that i store on the SPIFFS file system on the ESP32.
-In the HTMl file i created a chart on a canvas using ChartJS javascript library.
-In the JavaScript file i created a websocket client that is connected to the websocket server on the esp32.
-In the JavaScript file, when the data comes from the esp32 i assign it to the chart and visualize it.
Everything is working fine, except one little problem.
My i2s dma buffer is overflowing and i can see it in the visualized data.
What i think is happening:
-While i read the entire DMA buffer, the i2s adc is filling up this buffer again and again even if i doesn't end up reading from the entire buffer. This will result on buffer overflow and my readed data does not mach the actual reading.
What i think is the solution:
-If there will be an interrupt on the i2s adc dma, if it is filled up the entire buffer i would switch to an other buffer while i read the first, and when i done with the reading i would read from the second while the adc filling up the first and so on...
The thing is i did not find anything from this interrupt on the Arduino core. The one thing that i found is an event solution, that i think is just a flag and does not work as expected.
So my question is, how can i avoid this buffer overflow or how can i assign an interrupt to the dma buffer, or how can it be done correctly.
Here is my i2s init code:
Code: Select all
void configure_i2s(){
i2s_config_t i2s_config =
{
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), // I2S receive mode with ADC
.sample_rate = 9000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // 16 bit I2S
.channel_format = I2S_CHANNEL_FMT_ALL_LEFT, // all the left channel, no other options works for me!
.communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), // I2S format
.intr_alloc_flags = 1, // Tried buffer interrupt somehow.
.dma_buf_count = 8, // number of DMA buffers. ( Tried different options )
.dma_buf_len = 1000, // number of samples. ( Tried different options )
.use_apll = 0, // no Audio PLL ( I dont need the adc to be accurate )
};
adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_11db); // ADC_CHANNEL is ADC_CHANNEL_0 - GPIO34.
adc1_config_width(ADC_WIDTH_12Bit); // I need 0 - 4095.
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); // I2S_NUM_0 works for adc.
i2s_set_adc_mode(ADC_UNIT_1, ADC_CHANNEL);
SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV); // Inverse because fifo.
i2s_adc_enable(I2S_NUM_0);
}
Code: Select all
size_t bytes_read;
static const inline void ADC_Sampling(){
uint16_t i2s_read_buff[NUM_SAMPLES];
String data;
//xQueueReceive(i2s_queue, &event, (2*samplingFrequency)/ portTICK_PERIOD_MS); // Tried some kind of an event thing. Restarts
i2s_read(I2S_NUM_0, (char*)i2s_read_buff,NUM_SAMPLES * sizeof(uint16_t), &bytes_read, portMAX_DELAY); // I2S read to buffer
if(I2S_EVENT_RX_DONE){ // This is the flag that i mentioned. Does nothing if there are no events assigned based on my observation.
//i2s_adc_disable(I2S_NUM_0); // Some comment war
//long Millis_Now = millis();
//if (((Millis_Now - Start_Sending_Millis) >= DUMP_INTERVAL)&& Chart_is_ok_to_Send_Data)
//{
//Start_Sending_Millis = Millis_Now;
for (int i=0;i<NUM_SAMPLES;i++) {
data = String((i2s_read_buff[i])/(float)40.95); // Actual read from buffer, i need the data in % format on the web.
if(olvasunk_e){ // Want to send String.
data += "}";
webSocket.broadcastTXT(data.c_str(), data.length()); // Send the data with webSocket.
}
}
//i2s_zero_dma_buffer(I2S_NUM_0); // Comment war again.
//i2s_adc_enable(I2S_NUM_0);
//}
}
}
Code: Select all
static void loop0(void * pvParameters){
for( ;; ){
vTaskDelay(1); // REQUIRED TO RESET THE WATCH DOG TIMER IF WORKFLOW DOES NOT CONTAIN ANY OTHER DELAY
ADC_Sampling1(); // RETRIVE DATA FROM DMA BUFFER FOR CALCULATION AND VISUALIZATION
}
}
Code: Select all
<!DOCTYPE HTML>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type = "text/javascript" >
/** new chart **/
var yVal , xVal = 0;
var updateCount = 0;
var dataPoints = [];
var chart;
window.onload = function () {
chart = new CanvasJS.Chart("chartContainer", {
zoomEnabled: true,
rangeChanging: customInterval,
title : {
text : "Osc_Test"
},
data : [{
type : "line",
dataPoints : dataPoints
}
],
});
chart.render();
}
var updateChart = function () {
updateCount++;
dataPoints.push({
y : yVal,
x : xVal--
});
if (dataPoints.length > 500 )
{
dataPoints.shift();
}
chart.options.title.text = "Update " + updateCount;
chart.render();
};
webSocket1 = new WebSocket('ws://' + window.location.hostname + ':81/');
webSocket1.onmessage=function(a){
var t = a.data;
if(t.indexOf('}')>-1){
var l = t.substring(0,t.length-1);
yVal = parseInt(l,10);
updateChart();
}
};
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.js"></script>
</head>
<style>
.button {
background-color: #818a8a;
color: #FFFFFF;
float: right;
padding: 10px;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
}
#mydiv {
position:fixed;
top: 40%;
left: 30%;
margin-top: -9em; /*set to a negative number 1/2 of your height*/
margin-left: -15em; /*set to a negative number 1/2 of your width*/
}
</style>
<body>
<div style = "height: 400px; width: 70%;"id="mydiv">
<div id = "chartContainer" style = "height: 400px; width: 70%;"></div>
<div class="button" width="60" height="100"><a href="MeresStop">STOP PLOTTING</a></div>
<div class="button" width="60" height="100"><a href="MeresOk">START PLOTTING</a></div>
</div>
</body>
</html>
https://streamable.com/9dngp
I attached some pictures from the readed data on the web.