Cyphal CAN on Teensy4.1

Summary of the Issue:

Hello! I’m working on building a custom sensor node that operates with CyphalCAN. I’m using a Teensy 4.1 microcontroller for this purpose. I’m developing it using Arduino libraries within the platformIO environment.

Code Snippet:

c++Copy code

#include <FlexCAN_T4.h>
#include <Arduino.h>
#include <107-Arduino-Cyphal.h>
// #include <107-Arduino-Cyphal-Support.h>
// #include <107-Arduino-littlefs.h>
// #include <EEPROM.h>

#define NUM_TX_MAILBOXES 2
#define NUM_RX_MAILBOXES 6

// static littlefs::Filesystem filesystem(filesystem_config);

// cyphal::support::platform::storage::littlefs::KeyValueStorage kv_storage(filesystem);

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> port_;

void onReceive(const CAN_message_t &rec);
uavcan::node::ExecuteCommand::Response_1_1 onExecuteCommand_1_1_Request_Received(uavcan::node::ExecuteCommand::Request_1_1 const &req);

void can_setup()
{
    port_.begin();
    port_.setBaudRate(1000000);
    port_.setClock(CLK_60MHz);
    port_.setMaxMB(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES);
    for (int i = 0; i < NUM_RX_MAILBOXES; i++)
    {
        port_.setMB((FLEXCAN_MAILBOX)i, RX, EXT);
    }
    for (int i = NUM_RX_MAILBOXES; i < (NUM_TX_MAILBOXES + NUM_RX_MAILBOXES); i++)
    {
        port_.setMB((FLEXCAN_MAILBOX)i, TX, EXT);
    }
    port_.setMBFilter(REJECT_ALL);
    port_.enableMBInterrupts();
    port_.onReceive(MB0, onReceive);
}

void can_setFilter(CanardFilter filter)
{
    port_.setMBUserFilter(MB0, filter.extended_can_id, filter.extended_mask);
    port_.mailboxStatus();
}

void can_loop()
{
    port_.events();
}

CAN_message_t convert(CanardFrame const &frame)
{
    CAN_message_t ret;
    ret.flags.extended = true;
    ret.id = frame.extended_can_id;
    ret.len = frame.payload_size;
    std::memcpy(ret.buf, frame.payload, frame.payload_size);
    // Serial.write((std::to_string(frame.payload_size) + "\r\n").c_str());
    return ret;
}

CanardFrame convert(const CAN_message_t &frame)
{
    CanardFrame ret;
    ret.extended_can_id = frame.id;
    ret.payload_size = frame.len;
    std::memcpy(ret.payload, frame.buf, frame.len);
    return ret;
}

bool can_write(CanardFrame const &frame)
{
    port_.write(convert(frame));
    return true;
}

CanardPortID port_id_ = 0x40;
CanardNodeID node_id_ = 0x44;
static cyphal::Node::Heap<cyphal::Node::DEFAULT_O1HEAP_SIZE> node_heap_;
static cyphal::Node node_(node_heap_.data(), node_heap_.size(), micros, [](CanardFrame const &frame)
                          { return can_write(frame); });
cyphal::Publisher<uavcan::node::Heartbeat_1_0> heartbeat_pub_ = node_.create_publisher<uavcan::node::Heartbeat_1_0>(1 * 1000 * 1000UL);
cyphal::Publisher<uavcan::si::unit::angle::Scalar_1_0> data_pub_ = cyphal::Publisher<uavcan::si::unit::angle::Scalar_1_0>(node_.create_publisher<uavcan::si::unit::angle::Scalar_1_0>(port_id_, 1 * 1000 * 1000UL));

cyphal::ServiceServer execute_command_srv_ = node_.create_service_server<uavcan::node::ExecuteCommand::Request_1_1, uavcan::node::ExecuteCommand::Response_1_1>(2 * 1000 * 1000UL, onExecuteCommand_1_1_Request_Received);

uint64_t prev_heartbeat_{};
uint64_t prev_data_{};
auto registry_ = node_.create_registry();
const auto node_id_ptr = registry_->expose("cyphal.node.id", {true}, node_id_);
const auto node_desp_ptr = registry_->route("cyphal.node.description", {true}, []()
                                { return "GYRO Sensor"; });
const auto pub_id_ptr = registry_->expose("cyphal.pub.data_pub_.id", {true}, port_id_);
const auto pub_type_ptr = registry_->route("cyphal.pub.data_pub_.type", {true}, []()
                                { return "uavcan.si.unit.angle.Scalar.1.0"; });

void node_setup()
{
    node_.setNodeId(node_id_);
    static const cyphal::NodeInfo node_info_ = (node_.create_node_info(1, 0, 1, 0, 0, 1, 0, std::array<uint8_t, 16>{1}, "node_name"));
    can_setup();
    CanardFilter const CAN_FILTER_SERVICES = canardMakeFilterForServices(node_id_);
    can_setFilter(CAN_FILTER_SERVICES);
    Serial.write("SensorNode\r\n");
}

void node_loop()
{
    can_loop();

    node_.spinSome();

    unsigned long const now = millis();

    if ((now - prev_heartbeat_) > 1000)
    {
        prev_heartbeat_ = now;
        uavcan::node::Heartbeat_1_0 msg;
        msg.uptime = millis() / 1000;
        msg.health.value = uavcan::node::Health_1_0::NOMINAL;
        msg.mode.value = uavcan::node::Mode_1_0::OPERATIONAL;
        msg.vendor_specific_status_code = 0;
        (*heartbeat_pub_).publish(msg);
    }

    if ((now - prev_data_) > 100)
    {
        prev_data_ = now;
        uavcan::si::unit::angle::Scalar_1_0 msg;
        msg.radian = 0.5;
        (*data_pub_).publish(msg);
    }
}

CanardFrame frame;

void onReceive(const CAN_message_t &rec)
{
    Serial.write("onRceive");
    frame = convert(rec);
    node_.onCanFrameReceived(frame);
    Serial.write("onRceive");
}
uavcan::node::ExecuteCommand::Response_1_1 onExecuteCommand_1_1_Request_Received(uavcan::node::ExecuteCommand::Request_1_1 const &req)
{
    uavcan::node::ExecuteCommand::Response_1_1 rsp;
    rsp.status = uavcan::node::ExecuteCommand::Response_1_1::STATUS_SUCCESS;
    Serial.write("Service");
    return rsp;
};

void setup()
{
    Serial.begin(115200);
    delay(500);
    Serial.write("Start");
    node_setup();
}

void loop()
{
    node_loop();
}

Problem Description:

I’ve been attempting to verify if the cyphal Node is functioning on Yukon. However, when I attempted to check this by inserting node_.onCanFrameReceived(frame); within the onReceive function, the entire microcontroller crashes.

When running only the publisher without the sensor node receiving any CAN messages or being connected to Yukon, I didn’t encounter any issues with the microcontroller crashing.

I missed convert function. Thank you.

1 Like