Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By gdhgdh
#44278 Hi,

I've been experimenting with sampling analogue audio from an electret microphone with MAX4466 op-amp and sending it over the WiFi using UDP to another machine. This works surprisingly well when all of the work is done in the loop {} - I get approx 8500Hz - i.e. about telephone quality.

I want to remove this code from the loop {} and drive the sampling using timer0 intervals. The problem is that when I do that, I can't set the interval any shorter than about 70000 cycles (~500ms) else I get no network traffic at all. Thus the loop{} driven code is about 8 times faster.

Can someone point me in the right direction?

Here is the Timer0-based code with the speed problem:

Code: Select all#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

unsigned int udppacketcount=0;
unsigned int adcvalue;

const char* ssid = "acentral-office";
const char* password = "xxxxxxxxxxx";
boolean wifiConnected = false;

IPAddress ip(10, 0, 0, 31);

WiFiUDP UDP;
char ADCBuffer[500] = "";

boolean connectWifi() {
  boolean state = true;
  int i = 0;
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 10) {
      state = false;
      break;
    }
    i++;
  }
  if (state) {
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("");
    Serial.println("Connection failed.");
  }
  return state;
}

void inline handler(void) {
    adcvalue=analogRead(A0);

    ADCBuffer[udppacketcount] = adcvalue;
//    Serial.print(ADCBuffer[udppacketcount]);
//    Serial.print(" ");

    udppacketcount++;

    if (udppacketcount == 500) {
//      Serial.println();
      UDP.beginPacket(ip, 8989);
      UDP.write(ADCBuffer, 500);
      UDP.endPacket();
     
      udppacketcount = 0;
    }

    timer0_write(ESP.getCycleCount() + 70000);
}

void setup() {
  Serial.begin(115200);
  wifiConnected = connectWifi();

  noInterrupts();
  timer0_isr_init();
  timer0_attachInterrupt(handler);
  timer0_write(ESP.getCycleCount() + 70000);
  interrupts();
}

void loop() {
}


... and here's the working loop{} based code which samples + sends UDP at about 8kHz

Code: Select all#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

unsigned int udppacketcount=0;
unsigned int adcvalue;

const char* ssid = "acentral-office";
const char* password = "xxxxxxxxx";
boolean wifiConnected = false;

IPAddress ip(10, 0, 0, 31);

WiFiUDP UDP;
char ADCBuffer[500] = "";

boolean connectWifi() {
  boolean state = true;
  int i = 0;
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 10) {
      state = false;
      break;
    }
    i++;
  }
  if (state) {
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("");
    Serial.println("Connection failed.");
  }
  return state;
}

void setup() {
  Serial.begin(115200);
  wifiConnected = connectWifi();
}

void loop() {
    adcvalue=analogRead(A0);

    ADCBuffer[udppacketcount] = adcvalue;
    udppacketcount++;

    if (udppacketcount == 500) {
      UDP.beginPacket(ip, 8989);
      UDP.write(ADCBuffer, 500);
      Serial.print(UDP.endPacket());
      udppacketcount = 0;
      delay(10); // XXX - no network traffic unless this is here!
    }
   
    yield();
}



With this I get about 16 x 500-byte packet payloads per second. If I take the delay(10) out of the loop{}, then the network traffic is very sporadic. Of course if I try to put a delay() into the Timer0 handler code, the esp8266 will 'wdt reset' immediately.

Any ideas? I'm using Arduino 1.6.8 with ESP8266 2.1.0 installed through the Boards Manager.

Cheers,
Gavin.
User avatar
By krzychb
#44497 Hi Gavin,

ADC is used by ESP for gauging internal voltage to adjust output power of Wi-Fi.
Therefore, as you observed, it cannot be sampled continuously or Wi-Fi communication will break.

Basing on my observation maximum sample rate of ADC using esp/Arduino framework is about 12 samples/ms for the period of up to 60ms. This gives maximum of about 720 samples that then should be transmitted out over Wi-Fi. After that you can collect another packet of up to 720 samples and so on. This way Wi-Fi connection is not broken.

I do not have experience with using timer and interrupts for this purpose. Instead you may consider using a state machine sequence as described in this post. Below is a screenshot from this application.


Krzysztof

f9d8e742-e234-11e5-9dfb-b91b5744a3ff.png
You do not have the required permissions to view the files attached to this post.
User avatar
By gdhgdh
#44513 Ah that's an interesting read and the Websocket project looks really cool, too :)

The thing that doesn't add up for me is that if use the loop{} based approach (i.e.sample as fast as possible) with only a delay(10) between each 500-sample batch, then I'm able to sample, send (and receive on the host PC) traffic at over 8000 samples per second - enough for telephone quality audio.

If I drop the delay(10) then nothing is sent, so I understand that the ESP8266 OS needs some headroom - it seems that my experiences allow a faster and longer 'burst' of samples than yours, which doesn't make much sense given that we're both using version 2.1.0 of the ESP8266 'board' for Arduino. (older versions were about a quarter of the speed)