Nucleo -f429zi-144 with CAN communication

Hello All,

I’ve already tried this program with nucleo with it was already worked with me:

#include "mbed.h"
 
Ticker ticker;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
CAN can1(PB_8, PB_9);
CAN can2(PD_0, PD_1);
char counter = 0;
 
void send() {
    //printf("send()\n");
    if (can1.write(CANMessage(1337, &counter, 1))) {
        //printf("wloop()\n");
        counter++;
        printf("Message sent: %d\r\n", counter);
        wait(0.5);
    } 
    led1 = !led1;
}

int main() {
    //printf("main()\n");
    //wait(0.5);
    can1.frequency(250000);
    can2.frequency(250000);
    ticker.attach(&send, 1);
    CANMessage msg;
    while(1) {
        //printf("loop()\n");
        if (can2.read(msg)) {
            printf("Message received: %d\r\n", msg.data[0]);
            led2 = !led2;
            //wait(0.5);
        } 
    }
}

but it didn’t work.

I’m using the MCP2562 which already worked with LPC1768.

Please your advise as I looked in the other threads and they were saying about usint the event queue

Thank you for your help.
Nada

Hello Nada,

  • what version of MbedOS do you use or want to use?
  • what you mean with “but it didn’t work”? The code stucks or MbedOS crash?

From version 5.12 (If I remember) were implemented mutexes to all methods what read/write to/from a peripherals, like (Buffered)Serial, Can, I2C and so on. So it can not be called in ISR, the EventQeue it takes it out of Interrupt context to user context, that is why EventQeue was recommended.

CAN bus interrupt problem (MBED 5.15) - Mbed OS - Arm Mbed OS support forum

Examples are old (out of date) but with 5.15 they will be ok I think.
CAN_queue_test - Some test about how work with Queue. The target i… | Mbed
CANLoop_EventQueue - CAN-BUS loop back with EventQueue | Mbed

BR, Jan

1 Like

Also your pinout seems to be wrong

CAN can1(PB_8, PB_9);
CAN can2(PD_0, PD_1);

You have connected both CAN object to same peripheral CAN_1 - source.
So you need to change it to some pins what are for CAN_2. So PB_5 and PB_6 or PB_12 and PB_13 (care this one is also reserved).

BR, Jan

Hello Jan,

Thank you for your help and support.
I’m using MBED 5 and when I tried to see the output, The rprogram send only three message and I couldn’t see any message recieved.

I tried to use CAN1 and CAN 2 but it didn’t work as well.

I’m still trying and i will try the examples that you sent to me and I will keep you updated.

Also now I’m tryin to connect the nucleo with the LPC1768 through CAN.

Regards
Nada

The rprogram send only three message and I couldn’t see any message recieved.

That is usually because the messages were not delivered to any node. So you have wires badly connected, probably. So check if your wires are not crossed between Nucleo(CAN controller) and MCP(CAN transceiver) or check terminators are correctly connected.

BR, Jan

Thank you I will do that and let you know.

Regards
Nada

Hello Jan,

Thank you so much for your support . The programs that you sent are working.

I want to ask you if I can have can read in one thread and can write in another thread using mutex and memory pool

Regards
Nada

Thank you Jan .

I used event queue for both and it’s working. I will keep you updated in case I faced any issue later.

Regards
Nada

Dear Jan,

Sorry for bothering you again.

I have the below program with 4 threads, CAN read, CAN write, UDP client and UDP server.

#include "mbed.h"
#include "EthernetInterface.h"
 
#define ECHO_SERVER_PORT   11000

//Threads
Thread UDP_Client_Thread(osPriorityNormal, 2000);
Thread UDP_Server_Thread(osPriorityNormal, 2000);

Thread t;
Thread r;

CAN can2(PB_8, PB_9);
CAN can1(PB_5, PB_6);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
EventQueue queue_1(32 * EVENTS_EVENT_SIZE);

//Mutex

Mutex Network_Mutex;
Mutex RecIP_Mutex;
 
// Network interface
EthernetInterface net;
 
Serial pc(USBTX, USBRX);


// LEDs
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);


static const char* mbedIP = "192.168.220.45";  //IP 
static const char* mbedMask = "255.255.252.0";  // Mask
static const char* mbedGateway = "192.168.220.1";    //Gateway
 
static const char* recvIP = "192.168.220.100";

char counter = 0;
 
void send() {
    printf("send()\r\n");
    if(can1.write(CANMessage(1337, &counter, 1))) {
        counter++;
        printf("Message sent: %d\r\n", counter);
        led3 = !led3;
    } 
}

void receive()
{
      CANMessage msg;
   
        if(can2.read(msg)) 
        {
            printf("Message received: %d\r\n", msg.data[0]);
            led2 = !led2;
        } 
}
 

//////////////////////////////////////////////////////////////////////////////UDP_Server///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Server()
{
    

    UDPSocket server;
    Network_Mutex.lock();
    server.open(&net);
    Network_Mutex.unlock();
    server.bind(10110);
    SocketAddress sockAddr;
 while(true)
 {
    char buffer[256];
    pc.printf("\nWaiting for UDP packet...\r\n");
    int n = server.recvfrom(&sockAddr, buffer, sizeof(buffer));
    buffer[n] = '\0';
 
   // pc.printf("Received packet from: %s\n", sockAddr.get_ip_address());
    pc.printf("Packet contents : '%s'\r\n",buffer);
    //pc.printf("Sending Packet back to Client\n");
    server.sendto(sockAddr, buffer, n);
    
 }
    // Bring down the ethernet interface
    //net.disconnect();
    //pc.printf("Done\n");
}

//////////////////////////////////////////////////////////////////////////UDP_Client//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Client()
{
    
    //Buffer for output messages
        const char out_buffer[] = "very important data";
 
        //address of destination ip address and port
        RecIP_Mutex.lock();
        SocketAddress td_addr(recvIP, 11000);
        RecIP_Mutex.unlock();
        
        Network_Mutex.lock();
        UDPSocket td_sock(&net);
        Network_Mutex.unlock();
 
        // Loop to send data to Socket address "td_sock"
       while(true)
       {
            int ret = td_sock.sendto(td_addr, &out_buffer, sizeof(out_buffer));
            
         if(ret < 0)
         {
            Thread::wait(500);
         }
        }
}
 
// Socket demo
int main() {
 
    // Bring up the ethernet interface
    pc.baud(9600);
    //pc.printf("Ethernet socket example... \n");
    net.set_network(mbedIP, mbedMask, mbedGateway);// my device address
    can1.frequency(1000000); // set CAN bit rate to 1Mbps
    //can1.reset();
    can2.frequency(1000000); // set CAN bit rate to 1Mbps
    //can2.reset();
    if (0 != net.connect())
        {
            printf("Error connecting\n\r");
            // ThisThread::sleep_for(1000);
            return -1;
        }
        else
        {
            printf("Connected Ethernet \n\r");
            led1=!led1;

        }
        UDP_Server_Thread.start(UDP_Server);
        UDP_Client_Thread.start(UDP_Client);
        
        t.start(callback(&queue, &EventQueue::dispatch_forever)); 
        r.start(callback(&queue_1, &EventQueue::dispatch_forever)); 
        queue.call_every(500, send); 
        queue_1.call_every(500, receive);
        
        while(1)
        {
            ThisThread::sleep_for(500);
        }
}

At the beginning the program will be working fine then after a while the CAN stop working.

Please, your advice as I’m not sure that I’m using the event queue in a proper way.

Regards
Nada

Dear Nada,

  • CAN::reset() will reset the CAN controller to the default settings (500kHz?). So if you want to set the frequency to 1MHz, you must to do it after the reset call, not before.
  • I don’t think you need one EventQueue for each object. You can refer few tasks to one instance of EventQueue.
  • Your queue.call_every(500, send) is OK like that.
    On the other hand the queue_1.call_every(500, receive) is wrong. You can not timing the receiving of a message, the flow must be free.
    You have two options for receive a message:
    1. Polling - call the CAN::read() in a while loop (in the main or another thread) like is it in the official example
    2. Interrupts - CAN::attach() and use it like was descripted by Zoltan here and probably add this setting.

BTW, do you have already connected the Nucleo to the LPC or it is still loopback on one board?

BR, Jan

Hello Jan,

Thank you for your reply.

The nucleo still in the loopback and I’m planning to connect them and try them today. also I will be using the UDP client and server to send and receive the data with the CAN bus.

I will keep you updated in case i need anything.

If you have any suggestions to me please let me know.

Thank you again,

Regards
Nada

Hello Jan,

I tried the two methods for can read as illustrated in the following two programs:

Firts Option:

#include "mbed.h"
#include "EthernetInterface.h"
 
#define ECHO_SERVER_PORT   11000

//Threads
Thread UDP_Client_Thread(osPriorityNormal, 2000);
Thread UDP_Server_Thread(osPriorityNormal, 2000);

Thread t;
Thread r;

CAN can2(PB_8, PB_9);
CAN can1(PB_5, PB_6);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
EventQueue queue_1(32 * EVENTS_EVENT_SIZE);

//Mutex

Mutex Network_Mutex;
Mutex RecIP_Mutex;
 
// Network interface
EthernetInterface net;
 
Serial pc(USBTX, USBRX);


// LEDs
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);


static const char* mbedIP = "192.168.220.45";  //IP 
static const char* mbedMask = "255.255.252.0";  // Mask
static const char* mbedGateway = "192.168.220.1";    //Gateway
 
static const char* recvIP = "192.168.220.100";

char counter = 0;
 
void send() {
    printf("send()\r\n");
    if(can1.write(CANMessage(1337, &counter, 1))) {
        counter++;
        printf("Message sent: %d\r\n", counter);
        led3 = !led3;
    } 
}

void receive()
{
      CANMessage msg;
   while(true)
{
        if(can2.read(msg)) 
        {
            printf("Message received: %d\r\n", msg.data[0]);
            led2 = !led2;
        }
} 
}
 

//////////////////////////////////////////////////////////////////////////////UDP_Server///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Server()
{
    

    UDPSocket server;
    Network_Mutex.lock();
    server.open(&net);
    Network_Mutex.unlock();
    server.bind(10110);
    SocketAddress sockAddr;
 while(true)
 {
    char buffer[256];
    pc.printf("\nWaiting for UDP packet...\r\n");
    int n = server.recvfrom(&sockAddr, buffer, sizeof(buffer));
    buffer[n] = '\0';
 
   // pc.printf("Received packet from: %s\n", sockAddr.get_ip_address());
    pc.printf("Packet contents : '%s'\r\n",buffer);
    //pc.printf("Sending Packet back to Client\n");
    server.sendto(sockAddr, buffer, n);
    
 }
    // Bring down the ethernet interface
    //net.disconnect();
    //pc.printf("Done\n");
}

//////////////////////////////////////////////////////////////////////////UDP_Client//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Client()
{
    
    //Buffer for output messages
        const char out_buffer[] = "very important data";
 
        //address of destination ip address and port
        RecIP_Mutex.lock();
        SocketAddress td_addr(recvIP, 11000);
        RecIP_Mutex.unlock();
        
        Network_Mutex.lock();
        UDPSocket td_sock(&net);
        Network_Mutex.unlock();
 
        // Loop to send data to Socket address "td_sock"
       while(true)
       {
            int ret = td_sock.sendto(td_addr, &out_buffer, sizeof(out_buffer));
            
         if(ret < 0)
         {
            Thread::wait(500);
         }
        }
}
 
// Socket demo
int main() {
 
    // Bring up the ethernet interface
    pc.baud(9600);
    //pc.printf("Ethernet socket example... \n");
    net.set_network(mbedIP, mbedMask, mbedGateway);// my device address
    can1.frequency(1000000); // set CAN bit rate to 1Mbps
    can2.frequency(1000000); // set CAN bit rate to 1Mbps

    if (0 != net.connect())
        {
            printf("Error connecting\n\r");
            // ThisThread::sleep_for(1000);
            return -1;
        }
        else
        {
            printf("Connected Ethernet \n\r");
            led1=!led1;

        }
        UDP_Server_Thread.start(UDP_Server);
        UDP_Client_Thread.start(UDP_Client);
        
        t.start(callback(&queue, &EventQueue::dispatch_forever)); 
         queue.call_every(500, send); 
        r.start(receive); 
       
  
        
        while(1)
        {
            ThisThread::sleep_for(500);
        }
}

Second Option:

#include "mbed.h"
#include "EthernetInterface.h"
 
#define ECHO_SERVER_PORT   11000

//Threads
Thread UDP_Client_Thread(osPriorityNormal, 2000);
Thread UDP_Server_Thread(osPriorityNormal, 2000);

Thread t;
Thread r;

CAN can2(PB_8, PB_9);
CAN can1(PB_5, PB_6);
EventQueue queue(32 * EVENTS_EVENT_SIZE);
EventQueue queue_1(32 * EVENTS_EVENT_SIZE);

//Mutex

Mutex Network_Mutex;
Mutex RecIP_Mutex;
 
// Network interface
EthernetInterface net;
 
Serial pc(USBTX, USBRX);


// LEDs
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);


static const char* mbedIP = "192.168.220.45";  //IP 
static const char* mbedMask = "255.255.252.0";  // Mask
static const char* mbedGateway = "192.168.220.1";    //Gateway
 
static const char* recvIP = "192.168.220.100";

char counter = 0;
 
void send() {
    printf("send()\r\n");
    if(can1.write(CANMessage(1337, &counter, 1))) {
        counter++;
        printf("Message sent: %d\r\n", counter);
        led3 = !led3;
    } 
}

void receive()
{
      CANMessage msg;
   while(true)
{
        if(can2.read(msg)) 
        {
            printf("Message received: %d\r\n", msg.data[0]);
            led2 = !led2;
        }
} 
}
 

//////////////////////////////////////////////////////////////////////////////UDP_Server///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Server()
{
    

    UDPSocket server;
    Network_Mutex.lock();
    server.open(&net);
    Network_Mutex.unlock();
    server.bind(10110);
    SocketAddress sockAddr;
 while(true)
 {
    char buffer[256];
    pc.printf("\nWaiting for UDP packet...\r\n");
    int n = server.recvfrom(&sockAddr, buffer, sizeof(buffer));
    buffer[n] = '\0';
 
   // pc.printf("Received packet from: %s\n", sockAddr.get_ip_address());
    pc.printf("Packet contents : '%s'\r\n",buffer);
    //pc.printf("Sending Packet back to Client\n");
    server.sendto(sockAddr, buffer, n);
    
 }
    // Bring down the ethernet interface
    //net.disconnect();
    //pc.printf("Done\n");
}

//////////////////////////////////////////////////////////////////////////UDP_Client//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void UDP_Client()
{
    
    //Buffer for output messages
        const char out_buffer[] = "very important data";
 
        //address of destination ip address and port
        RecIP_Mutex.lock();
        SocketAddress td_addr(recvIP, 11000);
        RecIP_Mutex.unlock();
        
        Network_Mutex.lock();
        UDPSocket td_sock(&net);
        Network_Mutex.unlock();
 
        // Loop to send data to Socket address "td_sock"
       while(true)
       {
            int ret = td_sock.sendto(td_addr, &out_buffer, sizeof(out_buffer));
            
         if(ret < 0)
         {
            Thread::wait(500);
         }
        }
}
 
// Socket demo
int main() {
 
    // Bring up the ethernet interface
    pc.baud(9600);
    //pc.printf("Ethernet socket example... \n");
    net.set_network(mbedIP, mbedMask, mbedGateway);// my device address
    can1.frequency(1000000); // set CAN bit rate to 1Mbps
    can2.frequency(1000000); // set CAN bit rate to 1Mbps

    if (0 != net.connect())
        {
            printf("Error connecting\n\r");
            // ThisThread::sleep_for(1000);
            return -1;
        }
        else
        {
            printf("Connected Ethernet \n\r");
            led1=!led1;

        }
        UDP_Server_Thread.start(UDP_Server);
        UDP_Client_Thread.start(UDP_Client);
        
        t.start(callback(&queue, &EventQueue::dispatch_forever));
 queue.call_every(500, send); 
      r.start(callback(&queue, &EventQueue::dispatch_forever)); 
        
        can2.attach(queue.event(receive)); 
       
  
        
        while(1)
        {
            ThisThread::sleep_for(500);
        }
}

Both option didn’t work with me as the sending will send only 3 messages and stop and the receiving part not working.

I tried to put both of them in defferent threads but still.

Please your advise.

Regards
Nada

Hello Nada,

Firts Option: Ok for me. I tested it on my NucleoF429ZI with a self made CanBUS shield.
Second Option: Error Message: CMSIS-RTOS error: ISR Queue overflow. But that is nothing new.

BR, Jan

Is the CAN keep sending because it’s stop after a while.

Regards
Nada

Is the CAN keep sending because it’s stop after a while.

I do not know what you exactly mean with that.

However, how I wrote. Your first option it worked for me.
For connection you can check these links:

BR, Jan

Thank you so much Jan. I made it work yesterday with the LPC1768. and I used the same links.

I think I had some issue with the MBED os version. the old one is working fine for me.

The loopback is working for some time then sending and receiving stop but it’s fine as I will use diffrent devices.

I will keep you updated
Regards
Nada

Dear Jan,

After I made both the Nucleo and the LPC1768 to work with each other using CAN. Today I run the program again an I faced the fetal run time issue with the nucleo.

I don’t know if I should use the new MBED os library or I’m doing something wrone.

Both codes are as follow:

#include"mbed.h"
//Serial  pc(USBTX, USBRX);                                       //tx,rx for Tera Term output

DigitalOut led2(LED2);// status LED
DigitalOut led1(LED1);// status LED
DigitalOut led3(LED3);// status LED

CAN  can1(PB_8, PB_9);        // CAN interface

Thread CAN_Read;

Thread CAN_Send;

char counter =0;

void send()
{
       while(1)
   {
       //send  value  to  CAN  bus  AND  monitor  return value    to    check    if    CAN    message    was    sent successfully. If so display, increment and toggle.
       
       if(can1.write(CANMessage(1 ,&counter,1)))
       {
           printf("Message sent: %d\r\n",counter);//display
           counter++;                      //increment
           led1=!led1;                       //toggle status LEDelse
           //can1.reset();
        }
        wait(1);
    }
}


void receive()
{
    CANMessage msg;//create empty CAN message
    
    printf("read....\r\n");
    
    while(1)
    {
       if(can1.read(msg))    // if message is available, read Into msg
       {
           printf("Message received: %d\r\n" , msg.data[0]);           //display message  data
           
           led2 =  ! led2;        //toggle status LED
        }
    }
}

int main()
{
    can1.frequency(250000);
    
    printf("read....\r\n");
    
    CAN_Read.start(receive);
    CAN_Send.start(send);
    
    while(1)
    {
           
           led3 =  ! led3;        //toggle status LED
    }
}

the same for the LPC1768 after changing the CAN pins.

Sometimes also both boards stop sending and receiving mssages

Please, advise.

Regrads
Nada

Hello Nada,

from my experience, the fatal runtime error usually occurs during starting.
In my case:

  • Hold reset on both boards and then release both boards approx together. Result should be OK.
  • Hold reset on both boards and then release only one board, hold the second board until first board will not fail CAN::write. Result should be fatal runtime error.

I have only ST boards so I don’t know if it is normal for boards from another manufacturer.

Maybe someone else can share the experience with us.

BR, Jan

Thank you Jan,

I hope some one will share the experience.

Thank you again. I will try again.

Regards
Nada

Holding the reset button for both boards solving the issue Jan thank u. I hope I won’t recieve this error during the operation. I don’t want to hold the reset button each time as I will have other CAN devices.

Regards
Nada