Skip to content

Imperfection Report: Arduino Portenta C33: CAN1.write() corrupts CAN0 RX FIFO (message RAM overlap) #513

@hamatyo0126

Description

@hamatyo0126

This is a bug report for ArduinoCore-renesas (RA6M5 / Portenta C33 CAN).

Summary

On Arduino Portenta C33 (RA6M5), using CAN0 and CAN1 simultaneously causes a critical issue:
Calling CAN1.write() corrupts the receive FIFO of CAN0.

As a result, CAN0 receives frames that were never sent to that bus.
The corrupted frames match the ID and payload of frames received on CAN1.

This indicates a message RAM overlap between CAN0 and CAN1.


Environment

  • Gateway board: Arduino Portenta C33 (RA6M5) with Portenta Breakout(ASX00031)
  • Parent device: Arduino UNO R4 Minima (CAN0 side)
  • Child device: Arduino UNO R4 WiFi (CAN1 side)
  • Core version: Latest ArduinoCore-renesas (installed via Boards Manager)
  • Library: Arduino_CAN (bundled with core)
  • CAN transceivers: M5Stack U085 (SN65HVD230) × 4
  • Bitrate: 500 kbps
  • BOARDS MANAGER: Arduino Renesas Portenta Boards 1.5.1

Expected Behavior

  • CAN0 and CAN1 should operate independently.
  • Calling CAN1.write() must not modify or corrupt CAN0’s receive FIFO.
  • CAN0 should only receive frames from its own physical CAN bus.

Actual Behavior

When CAN1.write(msg) is executed:

  • CAN0 begins receiving frames with incorrect IDs.
  • The corrupted ID always matches the reply ID from the device connected to CAN1.
  • If the child device’s reply ID is changed (e.g., 0x022 → 0x025),
    the corrupted ID on CAN0 also changes to the same value.
  • Payload bytes also match the frames received on CAN1.

This proves that CAN1 RX/TX data is leaking into CAN0 RX FIFO.

If CAN1.write() is commented out, the issue disappears completely.


Corrupted RX log on CAN0 (Portenta C33)

Below is an example of the corrupted frames received on CAN0 when CAN1.write() is enabled.

  • The first frame ([021]) is correct and comes from the parent device.
  • Immediately after that, CAN0 starts receiving frames with ID = 0x25,
    even though 0x25 is the reply ID from the child device on CAN1,
    and no such frame exists on the CAN0 bus.
  • All corrupted frames have the same payload as the child device’s reply.
15:26:37.963 -> Start
15:26:37.963 -> Received msg = [021] (8) : CAFE0000540E0000   <-- correct (from parent)
15:26:37.963 -> ACK_code = 1
15:26:37.963 -> Received msg = [025] (8) : CAFE0000540E0000   <-- incorrect (should never appear on CAN0)
15:26:37.963 -> ACK_code = 1
15:26:37.963 -> Received msg = [025] (8) : CAFE0000540E0000
15:26:37.963 -> ACK_code = 1
15:26:37.997 -> Received msg = [025] (8) : CAFE0000540E0000
15:26:37.997 -> ACK_code = 1
15:26:37.997 -> Received msg = [025] (8) : CAFE0000540E0000
15:26:37.997 -> ACK_code = 1
15:26:37.997 -> Received msg = [025] (8) : CAFE0000540E0000
15:26:37.997 -> ACK_code = 1
15:26:37.997 -> Received msg = [025] (8) : CAFE0000540E0000
15:26:37.997 -> ACK_code = 1

Code

1. Parent device (UNO R4 Minima)

#include <Arduino_CAN.h>

static uint32_t const CAN_ID = 0x21;

unsigned long previousMillis = 0;
const long interval = 1000;

void setup()
{
  Serial.begin(115200);

  if (!CAN.begin(CanBitRate::BR_500k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
}

static uint32_t msg_cnt = 0;

void loop()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    uint8_t const msg_data[] = {0xCA,0xFE,0,0,0,0,0,0};
    memcpy((void *)(msg_data + 4), &msg_cnt, sizeof(msg_cnt));
    CanMsg const msg(CanStandardId(CAN_ID), sizeof(msg_data), msg_data);
    Serial.print("Sent msg = ");
    Serial.println(msg);

    int rc = CAN.write(msg);
    Serial.print("ACK_code = ");
    Serial.println(rc);

    msg_cnt++;
  }
}

2. Gateway device (Arduino Portenta C33)

#include <Arduino_CAN.h>

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

  if (!CAN.begin(CanBitRate::BR_500k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }

#if (PIN_CAN1_STBY >= 0)
  pinMode(PIN_CAN1_STBY, OUTPUT);
  digitalWrite(PIN_CAN1_STBY, LOW);
#endif

  if (!CAN1.begin(CanBitRate::BR_500k))
  {
    Serial.println("CAN1.begin(...) failed.");
    for (;;) {}
  }

  delay(5000);
  Serial.println("Start");
}

void loop()
{
  // CAN0 --> CAN1
  if (CAN.available())
  {
    CanMsg const msgR0 = CAN.read();
    Serial.print("Received msg = ");
    Serial.println(msgR0);
    
    int const rc = CAN1.write(msgR0);
    Serial.print("ACK_code = ");
    Serial.println(rc);
  }


  /*
  // CAN1 --> CAN0 (not used in this test)
  if (CAN1.available())
  {
    CanMsg const msgR1 = CAN1.read();
    Serial.println(msgR1);
    int const rc1 = CAN.write(msgR1);
    Serial.print("rc1 = ");
    Serial.println(rc1);
  }
  */
}

3. Child device (Arduino UNO R4 WiFi)

#include <Arduino_CAN.h>

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

  if (!CAN.begin(CanBitRate::BR_500k))
  {
    Serial.println("CAN.begin(...) failed.");
    for (;;) {}
  }
}

void loop()
{
  if (CAN.available())
  {
    CanMsg const rx = CAN.read(); // Read message
    
    CanMsg tx(CanStandardId(0x25), rx.data_length, rx.data);
    
    delayMicroseconds(500);
    int const rc = CAN.write(tx);
    Serial.print("Sent msg = ");
    Serial.println(tx);
    Serial.print("ACK_code = ");
    Serial.println(rc);
  }
  delay(1);
}

Request

Please investigate the cause of the message RAM overlap between CAN0 and CAN1
on the Portenta C33 (RA6M5), and fix the memory allocation so that
CAN1.write() does not corrupt CAN0’s RX FIFO.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: codeRelated to content of the project itselftype: imperfectionPerceived defect in any part of project

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions