RPC communication interrupts

Hi rs77can. I decided to combine a wired ethernet web server sketch (responds to simple web input to change the H7 LED), and the memory sharing routine/shetch (shares memory between cores, uses SRAM4, and has a 1ms M7 memory check). It seems to be running well. I set my router to let the connection through from the outside world to Port 80 to the Portenta H7. All seems good. I'm not passing any chunks of data between cores yet as far as I can tell in the example. The LED lights with the action of the Cores. You can probably just compile this and put your local IP in a browser to test (change MAC# and IP)... if you feel like it. I'll try and get some large chunks of data going back and forth to see if anything breaks.

Here's the mashed sketches working as one:

// 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"
#include <vector>

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 dummy_senor_data
{
  long Val;
};

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

int LED_Blink = 0;
////////////////////////////////////////////////////////////////////


#ifdef CORE_CM7    // Start M7 Core programming
//====================================================================================
#include <Arduino.h> // Only needed by https://platformio.org/
#include <Portenta_Ethernet.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0x00, 0x55, 0xD8, 0x39, 0x00, 0x4F
};
IPAddress ip(192, 168, 1, 77);  // what are these for??

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
//====================================================================================


uint32_t localm7m4      = STARTING_M7_VALUE;

uint32_t myStoreFromM4  = STARTING_M4_VALUE;

// Current 1 sec
#define M7_DELAY_US     1000UL //20230223 changed to 25ms was --> 30000UL     // microSeconds not milliSeconds (30 ms)

unsigned long delayStart = 0;

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

Thread M7Thread;

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

void MPU_Config()
{

  /*
  MPU - The MPU is an optional component for the memory protection. Including the MPU
        in the STM32 microcontrollers (MCUs) makes them more robust and reliable.
        The MPU must be programmed and enabled before using it. If the MPU is not enabled,
        there is no change in the memory system behavior.

  HAL - The STM32 Hardware Abstraction Layer (HAL) provides a simple, generic multi-instance
        set of APIs (application programming interfaces) to interact with the upper layers
        like the user application, libraries and stacks.

  */
  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(2000000);
  //===========================================================================================
  pinMode(LEDR, OUTPUT);             
  pinMode(LEDG, OUTPUT);             
  pinMode(LED_BUILTIN, OUTPUT);      // set the LED Green pin mode  
  digitalWrite(LEDR, HIGH);  
  digitalWrite(LEDG, HIGH);  
  digitalWrite(LED_BUILTIN, LOW);  
  Serial.println("Ethernet WebServer Example");

  // start the Ethernet connection and the server:
  Ethernet.begin(mac);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  digitalWrite(LEDR, LOW);  
  digitalWrite(LED_BUILTIN, HIGH); 

  //===========================================================================================
  
  //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)
  {
    yield();
    if ( (micros() - delayStart ) >= M7_DELAY_US ) //every 5ms
    {
      delayStart = micros(); //  reset the delay time
      
      //--20230227 moved above yield();
      
      localm7m4++;
      xfr_ptr->M7toM4 = localm7m4;

      //--20230223 out Serial.print("M7 to M4: "); Serial.println(xfr_ptr->M7toM4);
      //--20230223 out localIndex = xfr_ptr->M4toM7_Index;
      //--20230223 out Serial.print("M4 to M7: Index = "); Serial.print(localIndex); 
      //--20230223 out 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;
        if (LED_Blink++ >= 7) {
          LED_Blink = 0;
          digitalWrite(LEDR, !digitalRead(LEDR)); // flip red LED on and off
        }
      }
    }
  }
}

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

void loop()
{
   // listen for incoming clients
   EthernetClient client = server.available();
   if (client) {                             // if you get a client,
    
    Serial.print("server is at ");
    Serial.println(Ethernet.localIP());
  
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      yield();
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
           //client.println("{answer:42}");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("<input type=button value='LED GREEN Off' onclick='{location=\"/H\"}'>");
            client.print("<input type=button value='LED GREEN On' onclick='{location=\"/L\"}'>");

            // The HTTP response ends with another blank line:
            client.println();    
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(LEDG, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(LEDG, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
  }
  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); //--20230223 <--- I removed. Not needed.

    // 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;
      if (LED_Blink++ >= 10) {
        LED_Blink = 0;
        digitalWrite(LEDB, !digitalRead(LEDB)); // flip blue LED on and off
      }
    }
 
  }
}

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

void loop()
{
}

#endif