Hello,
I am trying to program two esp32 for live audio streaming. I am trying to use esp-now for the communication between the transmitter and the receiver, but I am facing some problems.
To understand if what I want to achieve is at all feasible, I started by sending 250 bytes from transmitter to receiver, measuring the time between esp_now_send() and the acknowledgement from the receiver. This time varies from 600us to more than 20ms in a seemingly random fashion. Is this normal?
I then set up a more complex system to try and measure overall latency.
Transmitter:
- The transmitter has a sine wave signal stored in 250 bytes in memory.
- Using a timer interrupt (20kHz frequency), this sine wave is output on DAC1 pin in cycles.
- Every time the 250 bytes have been written to the DAC, they get sent using esp-now to the receiver.
Receiver: - The receiver has a timer interrupt with a frequency of 20kHz
- Every time a new esp-now frame (250 bytes) has been received, it gets copied to a buffer
- In the ISR of the timer, if new data is available, the content of the 250 byte buffer gets sent, one byte at a time to DAC1
Overall, probing the DAC1 pins of the 2 esp32, one would expect to see a first full sine wave (1 period) on the transitter, followed by both sine waves on the two DAC1 pins perfectly aligned (0 latency). In reality, due to latency, the sine wave on the receiver side will always be out-of-phase with respect to the transmitter one.
This is the code I am using on the transmiter:
#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 0
#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 0
#include <esp_now.h>
#include <esp_wifi.h>
#include <driver/adc.h>
#include <driver/dac.h>
uint8_t broadcastAddress[] = {0xC0, 0x49, 0xEF, 0xCA, 0x3B, 0x00}; //
uint8_t IN_BUFF[250]={128, 131, 134, 138, 141, 144, 147, 150, 153, 157, 160, 163, 166, 169, 172, 175, 178, 181, 184, 187, 189, 192, 195, 198, 200, 203, 205, 208, 210, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 236, 237, 239, 240, 242, 243, 244, 246, 247, 248, 249, 250, 251, 252, 252, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 242, 241, 240, 238, 236, 235, 233, 231, 229, 227, 225, 223, 221, 219, 216, 214, 212, 209, 207, 204, 202, 199, 196, 194, 191, 188, 185, 182, 179, 176, 173, 170, 167, 164, 161, 158, 155, 152, 149, 146, 142, 139, 136, 133, 130, 126, 123, 120, 117, 114, 110, 107, 104, 101, 98, 95, 92, 89, 86, 83, 80, 77, 74, 71, 68, 65, 62, 60, 57, 54, 52, 49, 47, 44, 42, 40, 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 16, 15, 14, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 16, 17, 19, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 41, 43, 46, 48, 51, 53, 56, 58, 61, 64, 67, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99, 103, 106, 109, 112, 115, 118, 122, 125, 128};
uint8_t OUT_BUFF[250];
volatile uint8_t i=0;
volatile uint8_t sent=1;
volatile uint8_t ack=1;
volatile uint8_t dataReady=0;
volatile uint8_t pin_state=0;
hw_timer_t *My_timer = NULL;
esp_now_peer_info_t peerInfo;
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
if(status){
Serial.println("PACKET ERROR!");
}
else{
ack=1;
}
}
void IRAM_ATTR sampleADC(){
//Send a new sine wave byte to DAC1
dac_output_voltage(DAC_CHANNEL_1, IN_BUFF[i++]);
if(i==250){
//If all 250 bytes have been sent, reset counter and prepare esp-now send if previous esp-now frame has been already sent out.
i=0;
if(sent){
memcpy(OUT_BUFF, IN_BUFF, 250);
dataReady=1;
sent=0;
}
}
}
void setup() {
Serial.begin(115200);
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_0);
dac_output_enable(DAC_CHANNEL_1);
// Set device as a Wi-Fi Station
esp_netif_init();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40);
esp_wifi_set_storage(WIFI_STORAGE_RAM);
esp_wifi_set_ps(WIFI_PS_NONE);
esp_wifi_start();
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_54M);
esp_now_register_send_cb(OnDataSent);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}
//Setting up a timer interrupt with freq. of 20kHz
My_timer = timerBegin(0, 8, true);
timerAttachInterrupt(My_timer, &sampleADC, true);
timerAlarmWrite(My_timer, 500, true);
uint8_t started=0;
while(!started){
if(Serial.available()>0){
char c=Serial.read();
if(c=='1'){
started=1;
}
}
}
Serial.println("Entering loop...");
timerAlarmEnable(My_timer);
}
void loop() {
//If there is new data to send and previous frame was acknowledged by receiver
if(dataReady && ack){
esp_err_t result = esp_now_send(broadcastAddress, OUT_BUFF, sizeof(OUT_BUFF));
sent=1;
dataReady=0;
ack=0;
}
}
This is the code for the receiver:
#define CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED 0
#define CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED 0
#include <esp_now.h>
#include <esp_wifi.h>
#include <driver/dac.h>
// Structure example to receive data
// Must match the sender structure
uint8_t IN_BUFF[250];
uint8_t OUT_BUFF[250];
volatile uint8_t i=0;
volatile uint8_t data4dac=0;
hw_timer_t *My_timer = NULL;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
//Copying received bytes to buffer and setting flag for new data for the DAC
memcpy(IN_BUFF, incomingData, sizeof(IN_BUFF));
data4dac=1;
}
void IRAM_ATTR writeDAC(){
//If there is new data for the DAC
if(data4dac){
if(i==0){
//If we finished sending previous 250 bytes, copy new ones from IN_BUFF to OUT_BUFF
memcpy(OUT_BUFF, IN_BUFF, sizeof(OUT_BUFF));
}
dac_output_voltage(DAC_CHANNEL_1, OUT_BUFF[i++]);
if(i==250){
//If we reached end of 250 bytes, reset counter and data4dac flag
i=0;
data4dac=0;
}
}
}
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
dac_output_enable(DAC_CHANNEL_1);
// Set device as a Wi-Fi Station
esp_netif_init();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_wifi_set_mode(WIFI_MODE_STA);
esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW_HT40);
esp_wifi_set_storage(WIFI_STORAGE_RAM);
esp_wifi_set_ps(WIFI_PS_NONE);
esp_wifi_start();
// Init ESP-NOW
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_wifi_config_espnow_rate(WIFI_IF_STA, WIFI_PHY_RATE_54M);
//Setting up a timer interrupt with a freq. of 20kHz
My_timer = timerBegin(0, 8, true);
timerAttachInterrupt(My_timer, &writeDAC, true);
timerAlarmWrite(My_timer, 500, true);
timerAlarmEnable(My_timer);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
The two esp32 are communicating and probing the DAC1 pins with an oscilloscope shows the two sine waves, the issue is that there are a lot of "skipped" sine waves on the receiver end, during which the DAC signal doesn't change. Also, the latency is varying a lot, as mentioned in the beginning. The WIFI_PHY_RATE which sets the speed of the communication doesn't seem to have a real influence: I tried both slower and faster speeds. Am I missing something here? I have very little experience with the esp32, so I hope it's me and there is an easy fix for this.
Any suggestions?
Thanks a lot!

