Passing variable from CM7 to CM4 using RPC

Hello,
I need to pass a variable from the CM7 to the CM4.
I used the excellent exemple from "jerteach" on this forum
: my-examples-for-the-arduino-portentaH7/my02c-dual-core-RPC-variable.ino at master · hpssjellis/my-examples-for-the-arduino-portentaH7 · GitHub
Except I'm reversing the flow of data ( CM7 to CM4 instead of CM4 to CM7 in the exemple.

The code compile and works. but stopped (Portanta blink red and I need to reset it) after a certain number of "Call" function as been initiated.
I am sure it comes from the Call function and is relative to the number of time (1560) it is initiated, as if I add a delay, it will take longer before the Portanta freeze, and If I remove the Call function, everything works fine.

The thing is I don't exactly understand how the RPC is working and what could cause that. Any ideas ?

Thanks.

#ifdef CORE_CM7 //M7 Programming
#include "RPC_internal.h"
int j = 0;

void setup() {
Serial.begin(9600);
 while (!Serial) 
 {
  ; // wait for serial port to connect. Needed for native USB port only
 }
  bootM4();
  Serial.println("M4 Booted");
  RPC1.begin();
}

void loop() 
{     

 Serial.println(RPC1.call("Multiple_variable", 24,255,80,229,0,0,0,0,0,0,0,0,0,10).as<int>());
 j = j+1;
 Serial.println(j);    
 while (RPC1.available()) 
 {
  Serial.write(RPC1.read()); // check if the M4 has sent an RPC println
 }
 //delay (100);
}

#endif

#ifdef CORE_CM4    // Start M4 programming

#include "RPC_internal.h" 
  int i = 0;
  long OperationVar = 0;
  int Multiple_variables[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};

  int Multiple_variable(int id1, int id2, int id3, int id4, int Ext, int Len, int Data1, int Data2, int Data3, int Data4, int Data5, int Data6, int Data7, int Data8) 
  {
   Multiple_variables[0] = (long)id1;
   Multiple_variables[1] = (long)id2;
   Multiple_variables[2] = (long)id3;
   Multiple_variables[3] = (long)id4;
   Multiple_variables[4] = (long)Ext;
   Multiple_variables[5] = (long)Len;
   Multiple_variables[6] = (long)Data1;
   Multiple_variables[7] = (long)Data2;
   Multiple_variables[8] = (long)Data3;
   Multiple_variables[9] = (long)Data4;
   Multiple_variables[10] = (long)Data5;
   Multiple_variables[11] = (long)Data6;
   Multiple_variables[12] = (long)Data7;
   Multiple_variables[13] = (long)Data8;
   return id1;
  }

void setup() 
{
RPC1.begin();
RPC1.bind("Multiple_variable", Multiple_variable);
}

void loop() 
{
  i = i+1;
  OperationVar = (Multiple_variables[0] << 8) | Multiple_variables[1];
  OperationVar = (OperationVar << 8) | Multiple_variables[2];
  OperationVar = (OperationVar << 8) | Multiple_variables[3];
  RPC1.println("From M4 " + String(OperationVar) + " " + String(i));
  delay(100);
}
#endif
1 Like

Hi,
i am facing the exact same issue. Im trying to get data from M4 core to M7 core. After a certain amount of RPC calls, the Portenta starts blinking red (4 times fast, 4 times slow). As i do not have a serial to USB connector here, i did not try to debug the blinking error code.

What i recognized is, that if one parameter (integer) is >127 it crashes immediately. If it is <127 it crashes after a certain amount of calls (maybe thousands of calls).
Examples:

  • RPC1.call("setValues", 128, 1, 2, 3).as(); --> crashes immediately
  • RPC1.call("setValues", 127, 1, 2, 3).as(); --> crashes after certain amonts of calls (thousands)

@Smalesh can you also confirm this behaviour?

What i want to do:
M7 core establishes connection to wifi
M4 core reads analog input every e.g. 1ms and is doing a RPC call
M7 is receiving this RPC call and stores the values from M4 in a buffer
If a certain amount of values is stored in the Buffer, M7 core is sending the values over UDP to a server

Is anyone else facing this issues or has a solution for this?
Is there another way of sharing data between the cores beside RPC calls?

Best regards
Michael

1 Like

I just read the Serial (Pin13, 14) on the Portenta to get the error information of the mbed os:

Quote

++ MbedOS Fault Handler ++
FaultType: HardFault
Context:
R0 : 2402A453
R1 : 38001139
R2 : 80000000
R3 : 0000006B
R4 : 24019008
R5 : 00000017
R6 : 2401986C
R7 : 24019814
R8 : 080412A5
R9 : 00000000
R10 : 00000000
R11 : 00000000
R12 : 2402A43E
SP : 24045590
LR : 080412B9
PC : 0807C282
xPSR : A10C0000
PSP : 24045570
MSP : 2407FF78
CPUID: 411FC271
HFSR : 40000000
MMFSR: 00000000
BFSR : 00000000
UFSR : 00000100
DFSR : 00000000
AFSR : 00000000
Mode : Thread
Priv : Privileged
Stack: PSP
-- MbedOS Fault Handler --

++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255 Error Message: Fault exception
Location: 0x807C282
Error Value: 0x2401FD88
Current Thread: application_unnamed_thread Id: 0x240445C0 Entry: 0x8065E55 StackSize: 0x1000 StackMem: 0x24044610 SP: 0x24045590 For more info, visit: mbedos-error
-- MbedOS Error Info --

Is anyone able to point me in the right direction to find the problem?
Best regards
Michael

I now tried to reduce error sources and took this example from Jeremy Ellis as a minimal RPC call example:
RPC Example
After 4 hours of running, the same issue occured. Serial Port Error messege from Pin 14/15 (Baudrate 115200)

++ MbedOS Fault Handler ++
FaultType: HardFault
Context:
R0 : 2401F7E8
R1 : 00000040
R2 : 00000008
R3 : 00000004
R4 : 240015F8
R5 : 3E917261
R6 : 00000000
R7 : 2401F75C
R8 : 00000000
R9 : 080671D4
R10 : 00000004
R11 : FFFFFFD0
R12 : 0805187D
SP : 24025788
LR : 08041AAD
PC : 08041848
xPSR : 21000000
PSP : 24025768
MSP : 2407FF78
CPUID: 411FC271
HFSR : 40000000
MMFSR: 00000000
BFSR : 00000004
UFSR : 00000000
DFSR : 00000000
AFSR : 00000000
Mode : Thread
Priv : Privileged
Stack: PSP
-- MbedOS Fault Handler --

++ MbedOS Error Info ++
Error Status: 0x80FF013D Code: 317 Module: 255
Error Message: Fault exception
Location: 0x8041848
Error Value: 0x24006938
Current Thread: application_unnamed_thread Id: 0x24024898 Entry:
0x8051C59 StackSize: 0x1000 StackMem: 0x240248E8 SP: 0x24025788 For
more info, visit:
mbedos-error
-- MbedOS Error Info --

Maybe anyone can now reproduce the error.
Best regards
Michael

I'm having RPC shared variable time out issues as well. Looked at all the documentation and examples (example is my template) but nothing. Even tried switching what core does what and still the same issue. I'm hitting a dead end. It could be a library limitation but I can't find anything with regards to time or memory usage anywhere in the RPC_internal source.

My set up is similar to yours n1k1t4m4n

  • M7 receives sensor data via BLE (continuous blue led indicating connection)

  • M4 global variable is updated via M7 using RPC1.call()

  • RPC1.print() verifies data is being shared

  • After 5-30 minutes data stops printing and Portenta breathes/blinks red (or purple because the BLE connection on the M7 side is still working)

This could be a limitation they are working on. Still very well designed hardware because it technically worked just not indefinitely smh lol. But I know we all want to use the dual core capabilities while utilizing BLE and/or Wifi.

Hi Community,

has anyone found a solution how to share variables between the cores up to now which is not causing mbedOs to crash?
3 Analog inputs should be read on one core every ms and these measured values should be stored in a buffer in the second core.

Thanks for sharing your solutions

Sorry for seeing this so late. The above issues are much more complex than anything I have worked on, but here is an example of 2 variables on the M4 core which can be changed by the M7 core using RPC.

The example file is called my02h-rpc-from-m4.ino

Opposite of the other example having the variables on the M7 core.

Easier I guess to just post it here

#ifdef CORE_CM7   // Start M7 programming
 
#include "RPC_internal.h"  // comes with the mbed board installation

unsigned long previousMillis = 0;        // will store last time 
unsigned  long interval = 2000;  

void setup() {
   bootM4(); 
   Serial.begin(115200);
   RPC1.begin();
}

void loop() {
  
   while (RPC1.available()) {
      Serial.write(RPC1.read()); 
   }  
  unsigned long currentMillis = millis(); 
  if(currentMillis - previousMillis > interval) {  //wait 5 seconds to run
     // save the last time you blinked the LED 
    previousMillis = currentMillis; 
    
   int myRand1 = rand() % 100;  // from 0 to 99
   int myRand2 = rand() % 100;  // from 0 to 99
   RPC1.call("setVar", (int)myRand1, (int)myRand2);    //.as<int>();
   Serial.println("From M7 core setting M4 variable to: " + String(myRand1) +", "+ String(myRand2));
   
   Serial.println("Hello from M7 regular Serial");
  }
}

#endif              // End all M7 core programming

/////////////////////////////////////////////////////////////////////////////////////////////

#ifdef CORE_CM4    // Start M4 programming

#include "RPC_internal.h"  // comes with the mbed board installation

#define Serial RPC1  // So the M4 regular serial prints to RPC


  // Set an M4 core global variable
int myIntGlobal1 = 1234;
int myIntGlobal2 = 1234;

void setVar(int a, int b) {
  myIntGlobal1 = (int)a;
  myIntGlobal2 = (int)b;
 // return String(a) +", "+ String(b);
}


unsigned long previousMillis = 0;        // will store last time 
unsigned  long interval = 5000;  

void setup() {
   Serial.begin();   // RPC begin does not take an integer
     RPC1.bind("setVar", setVar); // do these have to be the same?

}

void loop() {
  

  unsigned long currentMillis = millis(); 
  if(currentMillis - previousMillis > interval) {  //wait 5 seconds to run
    previousMillis = currentMillis; 
   
    Serial.println("---------------------------------");
    Serial.println("From M4 showing global variable: "+ String(myIntGlobal1)+ ", "+ String(myIntGlobal2));
    Serial.println("Hello from M4 using regular serial piped through RPC");
  } 
}

#endif            // End all M4 core programming

Thanks for your reply @jerteach
Your RPC Call is done every 2000ms which is in my context very slow. I believe using this speed there is no proplem with the current implementation of rpc calls.

What i try to achieve is:
Read analog values (3 Analog Inputs) from m4 core using a timerinterrupt every 1ms
Push this values into a buffer on M7 core (or shared memory)
Read out this buffer in M7 core when there is time and send via e.g. UDP to a PC

All working examples i saw are working with delays in the seconds range between rpc calls which may not be the thing most people need. I am wondering if anyone has tried another option with shared memory or something else to share data between the cores.

Something like this on both cores on the right address may work. But i think you have to change some linker settings to "reserve" memory on the shared pointer address. Furhermore you have to take care about locking using things like HSEM (Hardware Semaphore).

struct shared_data
{
	uint32_t M4toM7; //  from M4 to M7
	uint32_t M7toM4; //  from M7 to M4
};
 
// pointer to shared_data struct (inter-core buffers)
volatile struct shared_data * const sharedMemoryPointer = (struct shared_data *)0x30040000;
*/

@jerteach are you using arduino IDE for programming?
I currently use PlatformIO and I am wondering if/how to configure linker things in platformio.ini

@n1k1t4m4n I do use the older Arduino IDE, but also like PlatformIO (Actually the more platforms the better). I am a bit surprised how hard it is to share data between the cores as it does make the dual core a bit harder to work with. Perhaps we can send in a better worded feature request.

I have been trying to find out how the memory is used on the Arduino-mbed. It seems to me some space is saved for other processes (The murata LoRa module uses some weird hidden memory), and OpenMV seems to steal the memory for both cores.

The fastest successful communication between cores I have seen has needed a 2 ms delay, especially between RPI serial writing. Not sure if the RPI memory storage is faster. Might do some testing today.

@n1k1t4m4n if I edit the above code to have a timer delay of 200 ms and things seemed fine, M7 changed the variables and M4 registered the change. but if I try at 20 ms (timer delay in both cores), I get this interesting set of data. Not sure why the M4 core is running 2-3 times faster than the M7, (Probably because it is not processing the writing to serial).

After a while the serial comm craps out over the amount of data, and once my board crashed flashing red.

Still this only shows that serial writing has issues, (I often put a 2ms delay after serial writing between cores) does not confirm anything about passing data having the same time constraints


From M7 core setting M4 variable to: 27, 34
From M4 showing global variable: 11, 54
From M4 showing global variable: 11, 54
From M4 showing global variable: 27, 34
From M7 core setting M4 variable to: 92, 86
From M4 showing global variable: 27, 34
From M4 showing global variable: 27, 34
From M7 core setting M4 variable to: 99, 87
From M4 showing global variable: 92, 86
From M4 showing global variable: 92, 86

@jerteach Thanks for trying out the code with less delay, and thanks that you can confirm the same issue, that the board is crashing when sending data to fast using RPC calls.

A feature request would be a great idea. I think a mechanism using a shared memory location in a RAM area which is not reserved for other things (would be also OK if this is limited to lets say a few hundreds of bytes) would be the fastest way and should be in the nano ns to µs range for passing a few bytes.

This is a very impressive microcontroller but for my usage i need the capability of sharing data very fast.
Sharing tasks is in my opinion the key feature of a dual core micro processor and therefore sharing data should be easily possible.

I am also using both but mostly PlatformIO. Would be great if we could find a solution which is safe and fast .

Done: Feature request entered at:

https://github.com/arduino/ArduinoCore-mbed/issues/238#issue-901690539

Please give it a thumbs up ( :+1:) emoji to help Arduino decide if the issue is important enough to have an engineer look into it.

@n1k1t4m4n do you have both the Lora Vision Shield and a Linux machine? Not sure if Mac will work.

I am testing out a bit of a weird method to communicate, mainly from the M4 core to the M7 core (only because the M7 core has serial print so I can prove when things work.) If printing was not needed this method should allow M7 to M4 comunication. It is not pretty, but uses the memory saved for the murata module of the LoRa vision shield. Anyway getting 3 ms transfers.

Actually @n1k1t4m4n ignore the above, way to complex. My latest method is just sending a character at a time use RX and TX. Much, much faster at 0.002 ms per char and probably faster, but then sending data will get more confusing as not simply saving in a variable. Anyway here is my code.

At least the below will work on any Portenta and does not need the Vision shield.


// Easy Dual Core program setup

// Need to connect pin TX D14 and RX D13 together.

#include <Arduino.h>

//////////////////// Start All Core M7 Programing /////////////////////
#ifdef CORE_CM7 

UART myUART3(PA_9,  PA_10, NC, NC); //TX, TR, RTS, CTS  NOTE: NC means not connected

void setup() { 
   bootM4();    
   Serial.begin(115200);
   myUART3.begin(9600);   
}

void loop() {
  if (myUART3.available()) {          // If anything comes in Serial3 
     Serial.write(myUART3.read());   // Read it and send it out Serial (USB)
  }




}

#endif


//////////////////// End All Core M7 Programing /////////////////////

//////////////////// Start All Core M4 Programing /////////////////////

#ifdef CORE_CM4 

int  myCount=48;  //48 = ascii 0,    58 ascii 9

UART myUART3(PA_9,  PA_10, NC, NC); //TX, TR, RTS, CTS  NOTE: NC means not connected

void setup() { 
    pinMode(LEDB, OUTPUT);   // LEDB = blue, LEDG or LED_BUILTIN = green, LEDR = red 
   // Serial.begin(115200);
    myUART3.begin(9600);   

}

void loop() {
    myCount++;
   if (myCount >= 58){myCount = 48;}   //48 = ascii 0,    58 ascii 9
   digitalWrite(LEDB, !digitalRead(LEDB));   //switch on / off
   char x = (char)myCount;  //random(48, 57);  // ascii code for numbers 0 to 9
   myUART3.write(x); 
   delayMicroseconds(2);  // start at 100000 and check the order. mine messes up at 2 microseconds
  
    
}

#endif

//////////////////// End All Core M4 Programing /////////////////////

@jerteach cool, that you also tried using "external" communication. Good to know that there is a way to get communication in the sub millisecond range.
But for this setup there would be no need for dual core microcontroller. This could also be realized using 2 boards with single core, right?

I also upvoted the feature request for that topic.

Yes. I once connected 4, $7 Seeeduino XAIO together using I2C and I can't figure out how it is any different than a quad core microcontroller. Moving data over I2C, SPI or Serial is so much more complex than just sharing a variable. It is all too bad. Not sure how to make fast transferring easy enough to teach my students.

@n1k1t4m4n I guess the main advantage of the dual microcontroller is that the physical setup is compact. Not really a big deal to anyone with a 3D Printer.

For me the compact design is not the main advantage of a dual core microcontroller. For me the processing power and the ability to do mutiple tasks separately is the main advantage. But for splitting Tasks you need to share the data between the cores which should be possible in a very fast and efficient way.
I hope your feature request will be accepted or anyone is providing a solution.

1 Like

If you want fast sharing between dual cores, get you a $10.00 ESP32. I have been struggling with the same issues. I have been very let down with this rollout. This "Pro" stuff seams far from it. I am used to ESP32 and FreeRTOS. You can quickly shove data between cores as they access the same memory. Question I have with RPC is, I assume you have to still implement some type of mutex to keep the cores from running all over each other. However, I cant find any docs on this. Has anyone looked into this? I have also noticed speed coordination issues between the cores.

1 Like

@drmartin4321 you are right, there are a lot more examples for dualcore processing when looking up ESP32. If it is not working out of the box with the portenta H7 (without doing some weird things), it is worth testing the ESP32. I do not have one here. Is there a direct support for dual core processing when using ESP32 (with or without RTOS) also including Mutex or HSEM or something simmilar?
I have not looked further into it but as it is a STM32 chip there is support for HSEM and things like that. But unfortunately this things especially dual core processing (with sharing data) is not directly suported by the arduino framework. For examples like blinking leds indipendently on different cores this controller is a little bit too expensive.
Maybe for things including the vision shield and doing image processing it might be worth its money but i am not sure.