I have an ESP32 master broadcasting to a set of up to 9 ESP32 slaves using ESPNow. When I run the sketch below on the master, it works great up to 4 slaves. When I try to add one additional slave, I see a single ESP_ERR_ESPNOW_NO_MEM message with the first byte sent by esp_now_send() . If I add one more slave, I start seeing a whole sequence of these error messages (with accompanying data drop-outs reported by the slaves) I've done everything I know to reduce memory footprint of the master sketch. Is there anything I can do to solve this problem? Thanks!
#include <esp_now.h>
#include <WiFi.h>
// Global copy of slave
#define NUMSLAVES 10
esp_now_peer_info_t slaves[NUMSLAVES] = {};
int SlaveCnt = 0;
#define CHANNEL 1
bool sendCompleted = true;
// Init ESP Now with fallback
void InitESPNow() {
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println(F("ESPNow Init Success"));
} else {
Serial.println(F("ESPNow Init Failed"));
ESP.restart();
}
}
// Scan for slaves in AP mode
void ScanForSlave() {
int8_t scanResults = WiFi.scanNetworks();
//reset slaves
memset(slaves, 0, sizeof(slaves));
SlaveCnt = 0;
Serial.println(F(""));
if (scanResults == 0) {
Serial.println(F("No WiFi devices in AP Mode found"));
} else {
Serial.print(F("Found "));
Serial.print(scanResults);
Serial.println(F(" devices "));
for (uint8_t i = 0; i < scanResults; ++i) {
// Print SSID and RSSI for each device found
String SSID = WiFi.SSID(i);
int32_t RSSI = WiFi.RSSI(i);
String BSSIDstr = WiFi.BSSIDstr(i);
delay(10);
// Check if the current device starts with `Slave`
if (SSID.indexOf("Slave") == 0) {
// SSID of interest
Serial.print(i + 1);
Serial.print(F(": "));
Serial.print(SSID);
Serial.print(F(" ["));
Serial.print(BSSIDstr);
Serial.print(F("]"));
Serial.print(F(" ("));
Serial.print(RSSI);
Serial.print(F(")"));
Serial.println(F(""));
// Get BSSID => Mac Address of the Slave
int mac[6];
if (6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5])) {
for (int ii = 0; ii < 6; ++ii) {
slaves[SlaveCnt].peer_addr[ii] = (uint8_t)mac[ii];
}
}
SlaveCnt++;
}
}
}
if (SlaveCnt > 0) { // check if slave channel is defined
Serial.print(SlaveCnt);
Serial.println(F(" Slave(s) found, processing.."));
// `slave` is defined
// Add slave as peer if it has not been added already
manageSlave();
} else {
// No slave found to process
Serial.println(F("No Slave Found"));
}
// clean up ram
WiFi.scanDelete();
}
// Check if the slave is already paired with the master.
// If not, pair the slave with master
void manageSlave() {
if (SlaveCnt > 0) {
for (uint8_t i = 0; i < SlaveCnt; i++) {
Serial.print(F("Processing: "));
for (uint8_t ii = 0; ii < 6; ++ii) {
Serial.print((uint8_t)slaves[i].peer_addr[ii], HEX);
if (ii != 5) Serial.print(F(":"));
}
Serial.print(F(" Status: "));
// check if the peer exists
bool exists = esp_now_is_peer_exist(slaves[i].peer_addr);
if (exists) {
// Slave already paired.
Serial.println(F("Already Paired"));
} else {
// Slave not paired, attempt pair
esp_err_t addStatus = esp_now_add_peer(&slaves[i]);
if (addStatus == ESP_OK) {
// Pair success
Serial.println(F("Pair success"));
} else if (addStatus == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println(F("ESPNOW Not Init"));
} else if (addStatus == ESP_ERR_ESPNOW_ARG) {
Serial.println(F("Add Peer - Invalid Argument"));
} else if (addStatus == ESP_ERR_ESPNOW_FULL) {
Serial.println(F("Peer list full"));
} else if (addStatus == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println(F("Out of memory"));
} else if (addStatus == ESP_ERR_ESPNOW_EXIST) {
Serial.println(F("Peer Exists"));
} else {
Serial.println(F("Not sure what happened"));
}
delay(100);
}
}
} else {
// No slave found to process
Serial.println(F("No Slave found to process"));
}
}
void sendData(byte dataByte) {
for (uint8_t i = 0; i < SlaveCnt; i++) {
const uint8_t *peer_addr = slaves[i].peer_addr;
esp_err_t result = esp_now_send(peer_addr, &dataByte, 1);
//Serial.print(F("Send Status: "));
if (result == ESP_OK) {
//Serial.println(F("Success"));
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
// How did we get so far!!
Serial.println(F("ESPNOW not Init."));
} else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println(F("Invalid Argument"));
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println(F("Internal Error"));
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println(F("ESP_ERR_ESPNOW_NO_MEM"));
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println(F("Peer not found."));
} else {
Serial.println(F("Not sure what happened"));
}
}
delay(10); // Online documentation indicates a short delay is required to prevent ESPNOW memory errors
}
void setup() {
delay(1000);
Serial.begin(115200);
delay(1000);
Serial.println(F("MusicHub ESPNow Master"));
Serial.flush();
delay(1000);
Serial2.begin(31250); // Receive bytes from MusicHub SoftAP at MIDI rate
//Set device in STA mode to begin with
WiFi.mode(WIFI_STA);
// This is the mac address of the Master in Station Mode
Serial.print(F("STA MAC: "));
Serial.println(WiFi.macAddress());
// Init ESPNow with a fallback logic
InitESPNow();
// do an initial scan
ScanForSlave();
}
void loop() {
if (Serial.available()) // handle control input from Serial Monitor
{
byte readChar = Serial.read();
if (Serial2.available()) // handle data input from SoftAP controller
{
byte readByte = Serial2.read();
//Serial.print(F("Send: "));
//Serial.println(readByte);
sendData(readByte);
}
}