Design a “CAN read” task (data producer), running in its own thread (waits for a CAN Rx event). When a “CAN read event” is triggered it reads the CAN message and puts it into a mail queue:
typedef struct
{
unsigned int id;
uint8_t tag;
float temp;
uint8_t mode;
uint8_t target;
} mail_t;
Mail<mail_t, 24> mail_box;
CAN can(PA_11, PA_12, 500000);
void taskCanRx(void)
{
CanMsg rxMsg;
while (1) {
eventFlags.wait_all(CAN_RX_INT_FLAG); // wait for CAN Rx interrupt
if (can.read(rxMsg)) {
mail_t* mail = mail_box.try_alloc(); // create a mail msg on the heap
if (mail != nullptr) {
mail->id = rxMsg.id; // set mail ID
switch (rxMsg.id) {
case (HEARTBEAT_RX + ID_NODE):
break;
case PDO_RX1 + ID_NODE:
rxMsg >> mail->target;
rxMsg >> mail->mode;
break;
...
}
mail_box.put(mail);
}
}
}
}
Setup a CAN data consumer called by the main thread
void getCanData()
{
mail_t* mail;
while (!mail_box.empty()) {
mail = mail_box.try_get(); // get a mail from the queue
if (mail != nullptr) {
switch (mail->id) {
case (HEARTBEAT_RX + ID_NODE):
ThisThread::sleep_for(5ms);
canBusConnected = publishHeartbeat(mail->tag);
break;
case (PDO_RX1 + ID_NODE):
relay[mail->tag].mode = mail->mode;
if (relay[mail->tag].target != mail->target) {
relay[mail->tag].target = mail->target;
relay[mail->tag].toggle = true;
}
break;
...
}
mail_box.free(mail); // remove mail from the heap
}
}
}
...
In the “main” function setup as many CAN filters as you can. This will reduce the rate of CAN Rx interrupts.
...
Thread threadCanRx(osPriorityHigh);
int main()
{
...
// Setup CAN filters
can.filter(HEARTBEAT_RX + ID_NODE, 0b11111111111, CANStandard, 0);
can.filter(PDO_RX1 + ID_NODE, 0b11111111111, CANStandard, 1);
...
// Start CAN receive thread
threadCanRx.start(callback(taskCanRx)); // canRx() waits for CAN Rx interrupt
// Attach CAN Rx ISR
can.attach(isrCanRx);
...
// The main thread
while(1) {
...
// Get data from the CAN Mail Queue
getCanData();
...
}
}