Trouble using RPC to pass Arrays or Vectors from M4 to M7

Hey!

Im having some trouble trying to pass an array from the M4 core to the M7 core with RPC.
I've looked at https://forum.arduino.cc/t/passing-variable-from-cm7-to-cm4-using-rpc/692026, but I need to pass arrays or vectors that have a size of 10000> every second.

My goal is that I'm reading an analog signal on the M4, putting that in a bufferarray. Sending it after a second has passed (or array reaches a certain size) to the M7. Receiving it on the M7, copying it to an array on the M7 core and then do calculations on the array.

Any suggestions are appreciated!

Start by posting posting a complete sketch illustrating the problem

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

// Global variables used by both cores
const long BAUD = 115200;

/*---------------------------M7_CORE---------------------------*/

#ifdef CORE_CM7 

// Set an M7 core global variable

float globArray[18100];

void setArray(float a[]){
  memcpy(a, globArray, sizeof(a));
}

void setup() {
  RPC1.begin();
  LL_RCC_ForceCM4Boot();

  Serial.begin(BAUD);

  RPC1.bind("setArray", setArray);
}

void loop() {
  while (RPC1.available()) {
     Serial.write(RPC1.read()); // check if the M4 has sent an RPC println
  }
  
  /*
  Do something with the globArray
  */
}

#endif

/*---------------------------M4_CORE---------------------------*/

#ifdef CORE_CM4 

// Set an M4 core global variable
float bufferArray[18100];

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 1000;
int count = 0;

void setup() {
  RPC1.begin();
  startMillis = millis();
}

void loop() {

  bufferArray[count] = analogRead(A0);
  count++;

  currentMillis = millis();
  if (currentMillis - startMillis >= period)
  {
    auto res = RPC1.call("setArray", bufferArray); //Sends vector over RPC to the M7 Core
    RPC1.println("From M4 arraysize : " + String(sizeof(bufferArray)));
    memset(bufferArray, 0, sizeof(bufferArray));
    count = 0;
    startMillis = currentMillis;
  }
}

#endif

I've also tried using Vector.h library and std::vector with no real success.

I am not entirely clear what you are trying to do, but when you pass an array to a function what is actually passed is a pointer to the array. So, if in the function you use sizeof() to determine the size of the array what you are actually doing is to find the size of the pointer to the array

void setArray(float a[])
{
  memcpy(a, globArray, sizeof(a));
}

Try printing the value of sizeof(a) in this function. What value do you see printed ?

I might have actually had a little mistake in that function

void setArray(float a[])
{
  memcpy(globArray, a, sizeof(a));
}

I want to copy a to globArray
This doesn't have to be done with arrays, I would prefer vectors, as seen below.
The code below compiles for both cores, but as soon as the M4 code is executed the onboard LEDs blinks red. I suspect it is the stack that is getting overflowed?

Does a vector containing ~20000 floats take up that much space?

#include <Arduino.h>
#include "RPC_internal.h"  // comes with the mbed board installation
#include <vector>

// Global variables used by both cores
const long BAUD = 115200;
int myLED;

/*---------------------------M7_CORE---------------------------*/

#ifdef CORE_CM7 

// Set an M7 core global variable

std::vector<float> globArray(20000);

std::vector<float> setArray(std::vector<float> a){
  globArray = a;
  return a;
}

void setup() {
  RPC1.begin();
  LL_RCC_ForceCM4Boot();
  myLED = LEDB;
  Serial.begin(BAUD);

  RPC1.bind("setArray", setArray);
  pinMode(myLED, OUTPUT);
}

void loop() {
  while (RPC1.available()) {
     digitalWrite(myLED, !digitalRead(myLED)); //Switches LED state
     Serial.write(RPC1.read()); // check if the M4 has sent an RPC println
  }

  delay(200);
  /*
  Do something with the globArray
  */
}

#endif

/*---------------------------M4_CORE---------------------------*/

#ifdef CORE_CM4 

// Set an M4 core global variable
std::vector<float> bufferArray(20000);

unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 1000;

void setup() {
  RPC1.begin();
  pinMode(myLED, OUTPUT);
  startMillis = millis();
}

void loop() {

  bufferArray.push_back(analogRead(A0)); //Reads from pin A0 and adds the value to the bufferArray

  currentMillis = millis();
  if (currentMillis - startMillis >= period) // Executes every 1000 ms
  {
    auto res = RPC1.call("setArray", bufferArray); //Sends vector over RPC to the M7 Core
    RPC1.println("From M4 arraysize : " + String(bufferArray.size()));
    bufferArray.clear();
    digitalWrite(myLED, !digitalRead(myLED)); //Switches LED state
    startMillis = currentMillis;
  }
}

#endif

Try this example

float a[100];

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  copyArray(a);
}

void loop()
{
}

void copyArray(float b[])
{
  Serial.print("sizeof(a) ");
  Serial.println(sizeof(a));
  Serial.print("sizeof(b) ");
  Serial.println(sizeof(b));
  memcpy(a, b, sizeof(b));
}

What do expect to be printed ?
What is actually printed ?
How many bytes will be copied into the destination array ?
What values will be in the destination array ?

If you are still interested, try this code using SRAM3/4, without using RPC, to pass Structs/Arrays from M4 <-> M7

// Original by Khoi Hoang (Github @khoih-prog ) and Jeremy Ellis (Github @hpssjellis )
// Note: each core can be separated to it's own IDE folder

#define STARTING_M4_VALUE         0
#define STARTING_M7_VALUE         0

#include "mbed.h"
#include "Arduino.h"

using namespace mbed;
using namespace rtos;

#define USING_SRAM4               true

#define SRAM3_START_ADDRESS       ((uint32_t) 0x30040000)
#define SRAM4_START_ADDRESS       ((uint32_t) 0x38000000)

#if USING_SRAM4
  // Using AHB SRAM4 at 0x38000000
  #define SRAM_START_ADDRESS        SRAM4_START_ADDRESS

  #define ARRAY_SIZE                16000
  //const uint16_t ARRAY_SIZE = 16000;
  
  // Max 64K - 8 bytes (1 * uint32_t + 2 * uint8_t)
  #if ( ARRAY_SIZE > (65536 - 8) / 4 )
    #error ARRAY_SIZE must be < 16382
  #endif
#else
  // Using AHB SRAM3 at 0x30040000
  #define SRAM_START_ADDRESS        SRAM3_START_ADDRESS

  #define ARRAY_SIZE                8000
  //const uint16_t ARRAY_SIZE = 8000;        
  
  // Max 32K - 8 bytes (1 * uint32_t + 2 * uint8_t)
  #if ( ARRAY_SIZE > (32768 - 8) / 4 )
    #error ARRAY_SIZE must be < 8190
  #endif
#endif

struct shared_data
{
  uint32_t M7toM4;
  uint16_t M4toM7_Index;
  uint16_t dummy;
  uint32_t M4toM7[ARRAY_SIZE];
};

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

#ifdef CORE_CM7    // Start M7 Core programming

uint32_t localm7m4      = STARTING_M7_VALUE;

uint32_t myStoreFromM4  = STARTING_M4_VALUE;

// Current 1 sec
#define M7_DELAY_US     1000000UL     // microSeconds not milliSeconds

unsigned long delayStart = 0;

static struct shared_data * const xfr_ptr = (struct shared_data *) SRAM_START_ADDRESS;

Thread M7Thread;

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

void MPU_Config()
{
  MPU_Region_InitTypeDef MPU_InitStruct;

  /* Disable the MPU */
  HAL_MPU_Disable();

  /////////////
  
  /* Configure the MPU attributes as WT for SDRAM */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;

  // Base address of the region to protect
#if USING_SRAM4
  MPU_InitStruct.BaseAddress = SRAM4_START_ADDRESS;             // For SRAM4 only
  // Size of the region to protect, 64K for SRAM4
  MPU_InitStruct.Size = MPU_REGION_SIZE_64KB;                   // Important to access more memory
#else
  MPU_InitStruct.BaseAddress = SRAM3_START_ADDRESS;             // For SRAM3 only
  // Size of the region to protect, only 32K for SRAM3
  MPU_InitStruct.Size = MPU_REGION_SIZE_32KB;                   // Important to access more memory
#endif

  // Region access permission type
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;

  // Shareability status of the protected region
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;

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

  // Optional

  // Bufferable status of the protected region
  //MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
  // Cacheable status of the protected region
  //MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
  // Number of the region to protect
  //MPU_InitStruct.Number = MPU_REGION_NUMBER7;
  // TEX field level
  //MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  // number of the subregion protection to disable
  //MPU_InitStruct.SubRegionDisable = 0x00;
  // instruction access status
  //MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;

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

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

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

void setup()
{
  MPU_Config();
  bootM4();

  pinMode(LEDR, OUTPUT);  // portenta red LED

  Serial.begin(115200);

  //while (!Serial);

  // Following issue solved by starting RPC. Not sure why.
  // Following line is needed, not sure why?
  //Serial.println(SRAM_START_ADDRESS, HEX); // MUST HAVE

  M7Thread.start(callback(M7ThreadFunc));
}

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

void M7ThreadFunc()
{
  static uint16_t localIndex;
  
  localm7m4 = STARTING_M7_VALUE;

  while (true)
  {
    if ( (micros() - delayStart ) >= M7_DELAY_US )
    {
      delayStart = micros(); //  reset the delay time
      
      yield();
      
      localm7m4++;
      xfr_ptr->M7toM4 = localm7m4;

      Serial.print("M7 to M4: "); Serial.println(xfr_ptr->M7toM4);

      localIndex = xfr_ptr->M4toM7_Index;
     
      Serial.print("M4 to M7: Index = "); Serial.print(localIndex); 
      Serial.print(", value = "); Serial.println(xfr_ptr->M4toM7[localIndex]);

      // test if M7 detects struct changed on M4 (xfr_ptr->M4toM7_Index)
      if (myStoreFromM4 !=  xfr_ptr->M4toM7_Index)
      {   
        myStoreFromM4 = xfr_ptr->M4toM7_Index;
        digitalWrite(LEDR, !digitalRead(LEDR)); // flip red LED on and off
      }
    }
  }
}

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

void loop()
{
  // yield();
}

#endif

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

#ifdef CORE_CM4    // Start M4 Core programming

uint32_t localm4m7 = STARTING_M4_VALUE;

static struct shared_data * const xfr_ptr = (struct shared_data *) SRAM_START_ADDRESS;

uint32_t myStoreFromM7 = STARTING_M7_VALUE;


Thread M4Thread;

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

void setup()
{
  pinMode(LEDB, OUTPUT);  // portenta blue LED
  
  memset( xfr_ptr, 0, sizeof(*xfr_ptr) );

  xfr_ptr->M4toM7_Index = 0;
  
  M4Thread.start(callback(M4ThreadFunc));
}

void M4ThreadFunc()
{
  localm4m7 = STARTING_M4_VALUE;

  xfr_ptr->M4toM7[0] = 0xDEADBEEF;
  
  while (true)
  {
    // without this => not increase ???
    delayMicroseconds(0);

    // To verify if SRAM change if OK by checking index = array[index]
    //xfr_ptr->M4toM7[xfr_ptr->M4toM7_Index] = xfr_ptr->M4toM7_Index;
    //xfr_ptr->M4toM7[xfr_ptr->M4toM7_Index] = localm4m7++;
    xfr_ptr->M4toM7[xfr_ptr->M4toM7_Index] = analogRead(A0);

    xfr_ptr->M4toM7_Index = (xfr_ptr->M4toM7_Index + 1) % ARRAY_SIZE;

    // test if M4 detects struct changed on M7 (xfr_ptr->M7toM4)
    if (myStoreFromM7 !=  xfr_ptr->M7toM4)
    {   
      myStoreFromM7 = xfr_ptr->M7toM4;
      digitalWrite(LEDB, !digitalRead(LEDB)); // flip blue LED on and off
    }
 
  }
}

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

void loop()
{
}

#endif
2 Likes

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.