nRF24 / RF24Mesh

OSI Layer 7 Mesh Networking for RF24Network & nrf24L01+ & nrf52x devices
http://nrf24.github.io/RF24Mesh
GNU General Public License v2.0
422 stars 154 forks source link

issues using core 0 on esp32. #227

Closed ripjohnbrown1859 closed 11 months ago

ripjohnbrown1859 commented 11 months ago

i am using an esp32 and need to run the networking on core 0 as I have time critical stuff running on core 1. node running on core 0

void networkTaskCode( void * pvParameters ){
  radio.setPALevel(RF24_PA_MIN);
  if (!mesh.begin()) {
    if (radio.isChipConnected()) {
      do {
        // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect
        latestMessage = ("connecting to mesh");
      } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS);
    } else {
      Serial.println(F("Radio hardware not responding."));

    }
  }

  for(;;){

   mesh.update();

    if (!mesh.checkConnection()) {
  //refresh the network address
  latestMessage = ("Renewing Address");
  if (mesh.renewAddress() == MESH_DEFAULT_ADDRESS) {
      //If address renewal fails, reconfigure the radio and restart the mesh
      //This allows recovery from most if not all radio errors
      mesh.begin();
      latestMessage = ("Failed to renew Address");}
    }else{
      latestMessage = ("Connected");
    }

    RF24NetworkHeader header;
    payload = {systolic, diastolic, lastValidSpO2, lastValidBPM, irBuffer[1]};

    if(!mesh.write(&payload,77, sizeof(payload))){
      latestMessage = ("failed to send");
    }else{
      latestMessage = ("sent");
    }
  yield();
  }
}

master

  mesh.update();
  mesh.DHCP();
  btn.tick();
  newPos = encoder.getCount()/2; 
  if(network.available()){
    latestMessage = "message received";
    RF24NetworkHeader header;
    //payload_t payload;
    network.read(header, &payload, sizeof(payload));

  }

im getting a mesh connection but failing to send any data between the node and the master. mesh.write returns false

ripjohnbrown1859 commented 11 months ago

i changed it to channel 100, also one of my cats knocked it off the table at some point and the solder joint on the capacitor broke without me noticing so i fixed that. the mesh is only getting maybe 50% of the packets through, and it is still not working on my program.

2bndy5 commented 11 months ago

Ah yes, cats + DIY electronics = rework; I know this too well.

Unfortunately, I don't have any fresh advice.

ripjohnbrown1859 commented 11 months ago

I suspect it could be the voltage drop across the regulator from 4.2 volts to 3.1v

2bndy5 commented 11 months ago

Its funny you mention that. Another user that bought modules from ebyte directly found that his battery would cause brown outs after a few hours as the battery discharged. While these brown outs went unnoticed, he had a bad habit of calling radio.begin() to keep the drone going... I think he doubled up on the battery pack (2 in parallel) to ensure the battery discharge remained above optimal levels.

Not sure if any of that would be helpful to you.

ripjohnbrown1859 commented 11 months ago

ok so ive gotten the demo to work with the ebyte modules 100%. but still no luck on my code.

2bndy5 commented 11 months ago

That may be a task priority problem with the RTOS. I can't help you at all with that.

ripjohnbrown1859 commented 11 months ago

its the only thing running on core 0, theres no wifi running, so i dont think its that.

2bndy5 commented 11 months ago

Well, now that we know that the radio is working, I would suggest seeking advice about using the ESP32 dual core/multiprocessing from people that are more knowledgeable on that subject.

Lastly, RF24Network/RF24Mesh nodes should not constantly spam messages out as that would clog the network/mesh channel which essentially blocks other nodes from being able to transmit/respond. Instead, users should regulate their nodes' outgoings with timed intervals (as is done in the examples).

ripjohnbrown1859 commented 11 months ago

what is the biggest size struct you can send? i wonder if im trying to send too much data at once?

2bndy5 commented 11 months ago

Payloads over 24 bytes get split up into multiple "frames" (separate transmissions) by the RF24Network layer. Default max size is 144 bytes on non-linux platforms (1514 for Linux platforms). The required RF24NetworkHeader occupies 8 bytes.

ripjohnbrown1859 commented 11 months ago

That was it! my struct was too big! now to figure out how to send all this data. thanks for all the help!

2bndy5 commented 11 months ago

Now that this thread has become the longest thread on this repo, can we close this as complete?

ripjohnbrown1859 commented 11 months ago

Yes

2bndy5 commented 11 months ago

BTW, you can change the MAX_PAYLOAD_SIZE to your liking using the build_flags key in your platformio.ini:

build_flags =
  -D MAX_PAYLOAD_SIZE=288 # or whatever integer you want
ripjohnbrown1859 commented 11 months ago

I cant seem to get it to send an 240 member array of uint8_t. Even when i set it to max payload of 4096.

2bndy5 commented 11 months ago

The max payload size needs to be set on both ends.

In our troubleshooting experience, ESP32 (& ESP8266) chips tend to require byte aligned structures. And some data types aren't allocated the same size as on other chips. Not sure if any of that helps.

ripjohnbrown1859 commented 11 months ago

it is set on both ends, ill look into byte aligned structures i guess. could it be timing out due to the length of data?

2bndy5 commented 11 months ago

The timeouts are only applied to each individual transmission (including fragmented payloads), so I doubt that is the problem.

ripjohnbrown1859 commented 11 months ago

ok, well even when i manually go into the config and change the max payload size to 512 it fails to send.

2bndy5 commented 11 months ago

I'm assuming it doesn't seg fault and write() just returns false.

ripjohnbrown1859 commented 11 months ago

write returns false, it doesnt crash.

2bndy5 commented 11 months ago

Just to make sure it is a payload size issue, does the code behave as expected when the payload is 24 bytes or less?

ripjohnbrown1859 commented 11 months ago

Yes it does. Although i havent tried with a small array. Just u8int_ts and it works with them.

ripjohnbrown1859 commented 11 months ago

ok so far ive sent 40 bytes and it goes through but when i send 140 bytes it doesnt go through.

2bndy5 commented 11 months ago

Is the stack size for core 0 task large enough?

ripjohnbrown1859 commented 11 months ago

Its set to 10000, that should be enough right? Also if i send less than 144 bits but more than 64 it doesnt even connect but when i send more than 144 it connects but fails to send.

2bndy5 commented 11 months ago

Its set to 10000, that should be enough right?

Stack size calculation is very specific to the app, so I can't say if 10000 is enough (seems like it should be). The FreeRTOS docs say that if this needs adjusting, then the dev needs to play around with different values. If you have a debugger attached, then it might be easier to calculate.

Also if i send less than 144 bits but more than 64 it doesnt even connect but when i send more than 144 it connects but fails to send.

This is strange indeed. No idea why that is though.

ripjohnbrown1859 commented 11 months ago

Ive narrowed it down to sizes less < 72 bytes send Sizes between 72 and 144 dont even connect Sizes >144 connect but fail to send. This is regardless of what i set the max payload to.

TMRh20 commented 11 months ago

I can't replicate the issue on my end, can you post your test code that demonstrates the issue?

ripjohnbrown1859 commented 11 months ago

sender

//uint8_t arraySize = 70;
//byte test[70];
String latestMessage;
TaskHandle_t networkTask;
TaskHandle_t mainTask;
QueueHandle_t xQueue;
QueueHandle_t xQueue2;
    struct payload_t{
      u_int8_t systolic;
      u_int8_t diastolic;
      uint8_t lastValidSpO2;
      uint8_t lastValidBPM;
      bool leftOff;
      bool rightOff;
      //byte test[70];
      //uint8_t PLETHbuffer[240];
      //uint8_t EKGbuffer[240];
    }payload;

void networkTaskCode( void * pvParameters ){
  if (!mesh.begin()) {
    if (radio.isChipConnected()) {
      do {
        // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect
        latestMessage = ("connecting to mesh");
      } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS);
    } else {
      Serial.println(F("Radio hardware not responding."));

    }
  }

  for(;;){

  mesh.update();
  payload_t payload;
  xQueueReceive(xQueue, &payload, 0);
  if(!mesh.write(&payload,77, sizeof(payload))){
      latestMessage = ("failed to send");
      //network.write(header, &payload, sizeof(payload)); 
    if (!mesh.checkConnection()) {
  //refresh the network address
  latestMessage = ("Renewing Address");
  if (mesh.renewAddress() == MESH_DEFAULT_ADDRESS) {
      //If address renewal fails, reconfigure the radio and restart the mesh
      //This allows recovery from most if not all radio errors
      mesh.begin();
      latestMessage = ("Failed to renew Address");}
    }else{
      latestMessage = ("Connected");
    }
  }else{
    latestMessage = ("sent");
  }
  Pressure = mpr.readPressure(INHG)/25.4;

   vTaskDelay(500);
  }
}

receiver

void loop(){
   mesh.update();
    mesh.DHCP();
    if (network.available())
  {
    latestMessage = "message received";
    RF24NetworkHeader header;
    network.peek(header);
    switch (header.type)
    {
    case 77:
      network.read(header, &payload, sizeof(payload));
      topSPO2 = payload.lastValidSpO2;
      topBPM = payload.lastValidBPM;
      topSys = payload.systolic;
      topDia = payload.diastolic;
      latestMessage = payload.lastValidSpO2;
      break;
    default:
      network.read(header, 0, 0);
      break;
    }
  }else{
    latestMessage = "no network available";
  }
  spr[0].fillSprite(TFT_BLACK);
  spr[2].setTextSize(1);
  spr[2].drawNumber(topMAP, 0, 150);
  spr[2].drawNumber((millis() - benchmark), 0, 0);
  benchmark = millis();
  spr[2].drawString("spO2%",0,90);
  spr[2].drawString("NIBP" , 0, 140);
  spr[2].drawString("HR", 0, 40);
  spr[2].setTextSize(4);
  spr[2].drawNumber(topSys, 2, 160);
  spr[2].drawNumber(topDia, 2, 200);
  spr[2].drawNumber(topSPO2, 2, 100);
  spr[2].drawNumber(topBPM, 2, 50);
  spr[5].fillSprite(TFT_BLACK);
  spr[5].setTextSize(1);
  spr[5].drawString("spO2%",0,90);
  spr[5].drawString("NIBP" , 0, 140);
  spr[5].drawString("HR", 0, 40);
  spr[5].setTextSize(4);
  spr[5].drawNumber(bottomSys, 2, 160);
  spr[5].drawNumber(bottomDia, 2, 200);
  spr[6].fillSprite(TFT_BLACK);
  spr[6].drawString(latestMessage.c_str(), 0, 0);
  spr[6].pushSprite(0, 0);
  spr[2].pushSprite(240, 0);
  spr[5].pushSprite(240, 240);

}
TMRh20 commented 11 months ago

This compiles and appears to work fine with my ESP32, payload sizes of 77, 120 and 1020 tested. Change pins and nodeID to test out.


#include "RF24.h"
#include "RF24Network.h"
#include "RF24Mesh.h"
#include <SPI.h>
#include "printf.h"

/**** Configure the nrf24l01 CE and CS pins ****/
RF24 radio(12,14);
RF24Network network(radio);
RF24Mesh mesh(radio, network);

/*
 * User Configuration: nodeID - A unique identifier for each radio. Allows addressing
 * to change dynamically with physical changes to the mesh.
 *
 * In this example, configuration takes place below, prior to uploading the sketch to the device
 * A unique value from 1-255 must be configured for each node.
 */
#define nodeID 11

String latestMessage;
TaskHandle_t networkTask;
TaskHandle_t mainTask;
QueueHandle_t xQueue;
QueueHandle_t xQueue2;
    struct payload_t{
      //u_int8_t systolic;
      //u_int8_t diastolic;
      //uint8_t lastValidSpO2;
      //uint8_t lastValidBPM;
      //bool leftOff;
      //bool rightOff;
      uint8_t test[120];
      //uint8_t PLETHbuffer[240];
      //uint8_t EKGbuffer[240];
    }payload;

void networkTaskCode( void * pvParameters ){
  if (!mesh.begin()) {
    if (radio.isChipConnected()) {
      do {
        // mesh.renewAddress() will return MESH_DEFAULT_ADDRESS on failure to connect
        latestMessage = ("connecting to mesh");
      } while (mesh.renewAddress() == MESH_DEFAULT_ADDRESS);
    } else {
      Serial.println(F("Radio hardware not responding."));

    }
  }
  radio.printDetails();
  for(;;){

  mesh.update();
  payload_t payload;
  //xQueueReceive(xQueue, &payload, 0);
  if(!mesh.write(&payload,77, sizeof(payload))){
      latestMessage = ("failed to send");
      //network.write(header, &payload, sizeof(payload)); 
    if (!mesh.checkConnection()) {
  //refresh the network address
  latestMessage = ("Renewing Address");
  if (mesh.renewAddress() == MESH_DEFAULT_ADDRESS) {
      //If address renewal fails, reconfigure the radio and restart the mesh
      //This allows recovery from most if not all radio errors
      mesh.begin();
      latestMessage = ("Failed to renew Address");}
    }else{
      latestMessage = ("Connected");
    }
  }else{
    latestMessage = ("sent");
  }
  Serial.println(latestMessage);
  //Pressure = 25.4;

   vTaskDelay(500);
  }
}

uint32_t displayTimer = 0;

void setup() {

  Serial.begin(115200);
  while (!Serial) {
    // some boards need this because of native USB capability
  }
  printf_begin();
  // Set the nodeID manually
  mesh.setNodeID(nodeID);

  // Set the PA Level to MIN and disable LNA for testing & power supply related issues
  //radio.begin();
  //radio.setPALevel(RF24_PA_MIN, 0);

  // Connect to the mesh
xTaskCreatePinnedToCore(
                    networkTaskCode,   /* Task function. */
                    "networkTask",     /* name of task. */
                    50000,       /* Stack size of task */
                    NULL,        /* parameter of the task */
                    1,           /* priority of the task */
                    &networkTask,      /* Task handle to keep track of created task */
                    0);          /* pin task to core 0 */    
}

void loop() {
delay(1000);

}
2bndy5 commented 11 months ago

I'll say this again with more detail: The code updating the display might be taking so long that the radio's RX FIFO is filling up which prevents any further reception of new payloads. To ensure the radio's RX FIFO isn't filling up, you might have to call mesh.update() multiple times in master's loop().

Note Using RF24NetworkHeaders, the radio's RX FIFO can only hold up to 24 * 3 = 72 bytes.

2bndy5 commented 11 months ago

It might be easier to only update the display when actually needed. And even when updating the display, you might want to only update info that actually changes, as opposed to rewriting old or constant info. Based on the given details, I'm not sure if this advice is possible or practical.

ripjohnbrown1859 commented 11 months ago

i got it to send by running the receiver on core 0 as well. now the display is all messed up and not pushing one of the sprites, but that's not your issue, thanks for the help.