Nucelo L432KC freeze

Hello,

I have a problem with the program freezing after several minutes of operation (1 min to 30 min approximately) on a Nucleo L432KC. The Nucleo communicates via the USB port with a computer on which a program in LabView runs.
This program sends data to each “M” request from the computer. if the computer detects a data format error or if it waits too long, it immediately sends an “R” request to obtain the same information (2 times if necessary). if the error persists the computer goes to the next point after a delay of 100ms. For a test I voluntarily removed a data to cause a data format error (7 data instead of 8), it was at this point that the problem appeared. What is amazing is that if I write 8 data from “M” and 7 data from “R” the reaction is the same as if I write 7 data from “M” and 8 data from “R”! And even more surprising: with 7 given instead of 8, if I comment out the line flipflop =! Flipflop; the program does not freeze!
I also had a Watchdog in place which worked with the typical endless loop errors but which proved to be ineffective against this freeze problem.
I simplified the code I anointed to this message and checked the problem with this code.

/* mbed test Program */

#include "mbed.h"


Serial port_USB(USBTX,USBRX); // tx, rx
Timer MyTimer;
DigitalOut myled(LED1);


//////////////////////////////////////////////////////////////////////////////
char tableau_de_reception[50];
unsigned short indice_tableau_reception;
float Marche = 0;
float Temps = 1;
int flipflop = 1;

//_____________________________________________________________________________
void reception_USB(void)
{
    char caractere_recu;
    caractere_recu=port_USB.getc();
    switch (caractere_recu) {
        case '0':
        case '1':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '-':
        case '.'://if i get a number
            tableau_de_reception[indice_tableau_reception]=caractere_recu;//I put the received character in an array
            indice_tableau_reception++;
            break;

        case 'M':
            Marche = 1;
            flipflop = !flipflop;
            Temps = MyTimer.read();
            port_USB.printf("%f ",Temps);
            port_USB.printf("%i ",flipflop);
            port_USB.printf("3 4 5 6 7 \n");
            break;
         
        case 'R':
            port_USB.printf("%f ",Temps);
            port_USB.printf("%i ",flipflop);
            port_USB.printf("3 4 5 6 7 8 \n");
            break;
         
        case '?':
            port_USB.printf("Mon_MBED\r\n");
            MyTimer.reset();
            break;
            
    }
}
//_____________________________________________________________________________
int main()
{
     port_USB.baud(115200);
     port_USB.attach(&reception_USB);//we define the USB link as an interruption procedure
    MyTimer.start();

    while(Marche==0) {
        myled = 1; // LED is ON
        wait(1.0);
        myled = 0; // LED is OFF
        wait(1.0);
    }
    while(1) {
        myled = 1; // LED is ON
        wait(0.1);
        myled = 0; // LED is OFF
        wait(0.1);
    }

}//main()

If someone understands something about this problem I am interested.
Marc.

Hi there,

I can not reproduce your issue, because the program freeze immediately after first command is received. Probably because I use a different version of the Mbed than you (copy &paste your code, Nucleo-L432KC, MbedOS 5.15). Maybe information what a version of the Mbed you use, would be necessary.

  • However, some variables are good to have declared as volatile. For example, your global float Marche and so on.
  • The Serial Api is not good to use with interrupts, the RawSerial is recommended instead. Or Unbufferedserial in the MbedOS 6.
  • I am not software engineer but I am sure about whole program operation in the interrupt context is not good solution. Especially using printf in the interrupt context is not good, because it is very slow function.
    You want to keep the interrupt hendler as short as possible!
  • The issue what freezes your program, seems to be a bad memory manipulation. You have a buffer with a specific size, but you increment a counter without an overflow protection of the buffer.

I think, you can use the RawSerial, read the byte from stream and set a flag. This flag you can processed in the main loop. Or if you want let the main loop for another operations, then use the RawSerial together with the EventQueue.

#include "mbed.h"

#define BMS 50 //buffer max size

EventQueue *queue;
RawSerial port_USB(USBTX,USBRX); // tx, rx
Timer MyTimer;
DigitalOut myled(LED1);


//////////////////////////////////////////////////////////////////////////////
char tableau_de_reception[BMS+1];
unsigned short indice_tableau_reception = 0;
volatile float Marche = 0;
float Temps = 1;
int flipflop = 1;

//_____________________________________________________________________________
void processing(char c){
    switch (c) {
        case '0':
        case '1':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '-':
        case '.'://if i get a number
            tableau_de_reception[indice_tableau_reception] = c;//I put the received character in an array
            port_USB.printf("count %d\n ",indice_tableau_reception);
            if (indice_tableau_reception >= BMS) indice_tableau_reception = 0; //overflow protection
            else indice_tableau_reception++;
            break;

        case 'M':
            Marche = 1;
            flipflop = !flipflop;
            Temps = MyTimer.read();
            port_USB.printf("%f ",Temps);
            port_USB.printf("%i ",flipflop);
            port_USB.printf("3 4 5 6 7 \n");
            break;
         
        case 'R':
            port_USB.printf("%f ",Temps);
            port_USB.printf("%i ",flipflop);
            port_USB.printf("3 4 5 6 7 8 \n");
            break;
         
        case '?':
            port_USB.printf("Mon_MBED\r\n");
            MyTimer.reset();
            break;
    }
}

void reception_USB(void){
    char caractere_recu;
    caractere_recu=port_USB.getc();
    queue->call(processing, caractere_recu);
}

//_____________________________________________________________________________
int main()
{
    queue = mbed_event_queue();
    port_USB.baud(115200);
    port_USB.attach(&reception_USB);//we define the USB link as an interruption procedure
    MyTimer.start();

    while(Marche==0) {
        myled = !myled;
        wait(1.0);
    }
    while(1) {
        myled = !myled;
        wait(0.1);

    }

}//main()

BR, Jan

hi JohnnyK,

Thank you for your very detailed answer.
Indeed I had not indicated my version of MBED, my apologies. I am using the obsolete version MBED 2. I have the impression that the online compilation MBED OS is much slower, but maybe I am doing it wrong?

Now I also tried my code with MBED OS 5.15, actually the program does not work anymore upon receipt of a request but the reaction of the Nucleo when it freezes is a little different: the LED flashes in a mode that is not found in the program while under MBED 2 the LED is frozen.

I will try to follow your advice: declaration of volatile variable when they are used in an interrupt, use of RawSerial, protect the buffers against overflows.
When you say “I am sure about whole program operation in the interrupt context is not good solution” I understand that slow procedures should not be used in interrupts, is that correct?

I cannot use EventQueue with MBED 2. The other option which consists in processing the arrival of the instructions which arrives on the USB-serial port in the main loop obliges to make it loop back more quickly.
In general it’s probably safer to use MBED OS. I will see if it is possible to have a faster compilation time.

Marc.

Hi Mark,

The compilation time takes so long because the source of the Mbed OS 5 (or 6) is very huge and all its files are precompiled even if you not use them. But that occurs only first time or when you make a bigger change like change to another version of the MbedOS and so on.
When you not need / not want to use the RTOS functionality, you can use the Mbed OS 5 (or 6) with bare metal profile. It is more economical (vs MbedOS 5-6) for board’s flash memory, It is similar like MbedOS2. Also the EvenQueue is possible to use under the bare metal profile, it can be enabled in mbed_app.json like the bare metal profile.

In the interrupt handler you want to do only really necessary steps, because during this time is the rest of program out, it can not operate until the interrupt handler not finish. That can cause losing a data or something similar.

BR, Jan

thank you for all your advice.
I will see to use Mbed OS with the bare metal profile. :slightly_smiling_face:
Marc.

Hi,
I tried your code using MBED-OS bare-metal but I get this compilation error message:
Error: Could not parse mbed app configuration from /tmp/chroots/ch-acd2575d-67f1-4804-aeac-19549d1d7a27/src/mbed_app.json
I have mi in mbed_app.json:
{ "requires": ["bare-metal"] }
Do you have an idea ?

Hi Mark,

If you copy my modification of your code with the eventqueue from above you need this, how i wrote.

{
“requires”: [“bare-metal”, “events” ,“rtos-api”]
}

BR, Jan

Thank you for your prompt response.
I then get this error message:
Error: Could not parse mbed app configuration from /tmp/chroots/ch-773c6ec2-bad7-42fb-b5f8-6237fc6557b3/src/mbed_app.json
Marc

that indicates that mbed_app.json is not a valid json file, so there must be some mistake like missing ‘,’ or bracket error.
In the documentation, you’ll find which API can be used in bare-metal, but its a teddious work to find all the requriments. I looked up in the source mbed_lib.json files, or is there a smarter way?

https://os.mbed.com/docs/mbed-os/v6.1/apis/index.html

Yep, I reproduce that when this " was changed with which was caused during copy&paste.

The example does not process the EventQueue, isn’t there missing a queue->dispatch() or ->dispatch_forever() ?

I don’t know but it was working when I did test it. I took it from Mbed’s example what is in the documentation of the EventQeueue (second example).

BR, Jan

yes, its ok, because it uses the existing queue in bare-metal. For the rtos, there can be many queues and then you need to dispatch the events.

there was indeed a “copy and paste” which must have gone wrong, look at the difference between these two lines at the level of “”:
“ Requires ”: [“ bare-metal ”,“ events ”,“ rtos-api ”]
" requires ": [" bare-metal "," events "]
I just noticed it.
The compilation works.
However, the program does not work as if there were no requests on the serial port (it’s the same if I add “rtos-api”).
Marc.

does the LabView program set the DTR signal on the serial line? The Mbed USBserial waits for an USB connect and then for a terminal_connect. That is detected by the DTR signal. Can you test with a terminal program where you can set this signal manually?

The LabView program does not use any flow control.
The program as it is written in my first post works … a few thousand iteration until the crash. And there is no DTR signal management.

The line queue-> call (processing, caractere_recu);
does not execute the processing () procedure.
I just tested with myled =! Myled;

this works with queue-> dispatch_forever (); in the main ()

on the other hand the instructions which follow queue-> dispatch_forever (); in the main () are not executed.
It is not essential, I just have to take it into account when writing the program.

I was confused by the USB, but you are using the Serial, so forget about the DTR.

Just looked up for this, with RTOS, a dedicated dispatch thread is created automatically. For bare-metal, the dispatch() is necessary.
But you can add a timeout in ms to the dispatch call, so you can use it instead of the wait(). But for a fast response, it should loop very fast.
You can put also other events into the queue. And also cyclic events with:

 queue.call_every(1000, printf, "called every 1 seconds\n");

Thank you for this advice.
On the other hand I have just noted that the program with the use of EventQueue has the same reaction, it crashes after a few thousand iteration.