1

I am implementing a oscilloscope GUI to visualize the data coming from the I2S mic connected to ESP32. The data is transmitted to ESP32 over WiFi through TCP socket connection to PC client where the GUI is made.

This is ESP32, server side code.

 
    const i2s_config_t i2s_config = {
      .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer
      .sample_rate = 16000,                         // 16KHz
      .bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT, // could only get it to work with 32bits
      .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // although the SEL config should be left, it seems to transmit on right
      .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
      .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,     // Interrupt level 1
      .dma_buf_count = 4,                           // number of buffers
      .dma_buf_len = 8                              // 8 samples per buffer (minimum)
  };

  };


void loop() {
 
  WiFiClient client = wifiServer.available();
 
  if (client) {
 
    while (client.connected()) {
 
      while (client.available()>0) {
        int32_t sample = 0;
        int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&sample, portMAX_DELAY); // no timeout
        String samplestring = String(sample*0.00000059);
        client.println(samplestring);
     }
 
      delay(10);
   }
 
    client.stop();
    Serial.println("Client disconnected");
 
  }
}

I am plotting it on a GUI in winform. But when I plot it doesn't give the correct wave format (I tried with 1kHz sine wave). I am loading the data to a textbox and getting converted to double to plot the data.

What is wrong here?

    int t;

private void Timer1_Tick(object sender, EventArgs e)
{
    one = new Thread(test);
    one.Start();
    t++;
}

public void test()
{
    byte[] bytes = new byte[client.ReceiveBufferSize];
    var readCount = stream.Read(bytes, 0, bytes.Length);

    string datastring = Encoding.UTF8.GetString(bytes);
    txtdata.Invoke((MethodInvoker)(() => txtdata.Text = datastring.Substring(0, 100)));
    
    txtno.Invoke((MethodInvoker)(() => 
        txtno.Text = ("\nnumber of bytes read: " + readCount)
    ));

    String ch1 = txtdata.Text; ;
    String[] ch1y = ch1.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

    for (int a = 1; a < ch1y.Length - 1; a++)
    {
        chart1.Invoke((MethodInvoker)(() =>
            chart1.Series[0].Points.AddXY(t, Convert.ToDouble(ch1y[a]))
        ));
    }

}

I edited the above code like this

private void Timer1_Tick(object sender, EventArgs e)
        {
            byte[] bytes = new byte[client.ReceiveBufferSize];
            var readCount = stream.Read(bytes, 0, bytes.Length);

            string datastring = Encoding.UTF8.GetString(bytes);
            txtdata.Invoke((MethodInvoker)(() =>
                        txtdata.Text = datastring.Substring(0, 100)));

            txtno.Invoke((MethodInvoker)(() =>
            txtno.Text = ("\nnumber of bytes read: " + readCount)));

            String ch1 = txtdata.Text; ;
            String[] ch1y = ch1.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            double[] val = new double[ch1y.Length];

            for (int a = 1; a < ch1y.Length - 1; a++)
            {
                val[a] = double.Parse(ch1y[a]);


                chart1.Series[0].Points.Add(val[a]);
            }
            if (chart1.Series[0].Points.Count > 5)
                chart1.Series[0].Points.RemoveAt(0);
            chart1.ChartAreas[0].AxisX.Minimum = double.NaN;
            chart1.ChartAreas[0].AxisX.Maximum = double.NaN;
        }
3
  • 1
    Not sure what language/framework you use on the receiving side, but aren’t the bounds of your loop incorrect? Shouldn’t they be 0 (inclusive) and ch1y.Length (exclusive)? Also you are adding all points in a buffer at the same X (t). What does the graph look like? Can you maybe start with a simpler signal such as a square wave?
    – jcaron
    Mar 11 at 8:14
  • @jcaron I use c# for receiver side. Yes, the array length was corrected. Instead of running a thread, I link it with timer.tick event. Now it is somewhat ok. But still not good looking sine wave.
    – Buddhika
    Mar 11 at 9:34
  • You may want to share a screenshot of the result as we have no idea how much away from the expected result you are. Note that in the edited code above you removed the incorrect X, but you're still missing bounds (it should most likely be for (int a = 0; a < ch1y.Length; a++)). Also, you may have issues with data split over a buffer boundary.
    – jcaron
    Mar 11 at 12:13
0

Here are a couple of ideas: I'm with jcaron above that you're having issues with the data split over boundary. Also, the fact that you're sampling at 16kHz for a 1kHz wave means the wave will be pretty jaggy. Try 160Hz for the input. So, here's some pseudo code that may work better: Try it. If it works, you can improve it, etc. It is not memory efficient, but you're running on a PC.

Pseudocode: Have a string that can remember contents between timer ticks. I'll call this incoming_chars. For a quick try, make it global (shudder!). Refine it later.

In your timer tick:

read bytes, convert to string and append that to incoming_chars
while incoming_chars contans '\n'
..get first substring including the '\n' from incoming_chars
..parse that as a double and add to the chart ..cut out that first substring from incoming_chars
end while
if the chart now has too many points, trim old historical ones.

2
  • byte[] bytes = new byte[7]; var readCount = stream.Read(bytes, 0, bytes.Length); string datastring = Encoding.UTF8.GetString(bytes); txtdata.Invoke((MethodInvoker)(() => txtdata.Text = datastring.Substring(0, bytes.Length))); String ch1 = txtdata.Text; ; String[] ch1y = ch1.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); i changed as mentioned here as wel as in arduino. But it doestn't draw any points now @kalyanswaroop
    – Buddhika
    Mar 13 at 3:17
  • I've changed the approach. Put in pseudocode instead. Also, I think it will be useful for you to show what you got with jcaron's suggestions above. Mar 15 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.