Trouble with Serial Interrupt

environment

Board used: NUCLEO-F303K8

Development Environment:VSCode + PlatformIO

situation

I’m using serial receive interrupt to receive MIDI and outputting the status via USB serial butg the code freezes very rarely.

When I investigated it, I found out that if a receive interrupt occurs during serial transmission, mbed stops.

I found the cause of the problem, but I can’t think of a specific way to deal with it.

Before and after the serial transmission.

void testSend(void){
    serial.attach(NULL,Serial::RxIrq);
    Sending process //----
    serial.attach(receiveFunction,Serial::TxIrq );
}

but it moves a little at first and then doesn’t work after that.

Also.

__disable_irq();
__enable_irq();

had the same result.

In this case, how can I get the serial receive interrupt to not freeze when it occurs during serial transmission? Is it possible to continue the process to the

For serial transmissions, we are not looking for that much real-time.

Sorry,English is not my mother tongue.

Hello Itsuki,

Maybe you can utilize Condition Variable rather than interrupts. For example:

#include "mbed.h"

#define BUFF_LEN    32

BufferedSerial      serial(STDIO_UART_TX, STDIO_UART_RX);
Mutex               mutex;
ConditionVariable   cond(mutex);

// These variables are protected by locking mutex
uint8_t             serBuff[BUFF_LEN];
ssize_t             dataLen;

void taskSend()
{
    mutex.lock();
    
    while (1) {

        printf("Send: Waiting for serial data\r\n");
        // Wait for a condition to change
        cond.wait();

        // serBuff and dataLen are safely accessible
        printf("Send: %d bytes are available in serBuff\r\n", dataLen);
        // Send data over USB
        printf("Send: Sending data over USB\r\n");
        // ...
    }
}

int main()
{
    Thread  thread;

    thread.start(taskSend);

    while (1) {
        if (serial.readable()) {
            mutex.lock();

            // Read serial (change the serBuff and dataLen variables)
            dataLen = serial.read(serBuff, BUFF_LEN);

            printf("Main: Serial data received\r\n");
            printf("Main: %d bytes are available in serBuff\r\n", dataLen);
            // Signal that serBuff and dataLen have changed
            cond.notify_all();
            mutex.unlock();
        }

        ThisThread::sleep_for(5);
    }
}

Best regards, Zoltan

1 Like

Hello Itsuki,

I’m very sorry, I didn’t notice that you need a solution for NUCLEO-F303K8 (thank you Jan for noticing me). Unfortunately, the NUCLEO-F303K8 doesn’t support Mbed OS 6 with RTOS (only bare-metal) so condition variable and threads cannot be implemented on your board :frowning:

Best regards, Zoltan

2 Likes

There is MUTEX GUARD in stdio.h library and Serial.
So you cant use any put / print /get function in ISR.

So you need to use Rawserial library.Here I attached simple but useful code to read and write data in 2 way communication on UART.
Please check , it may be useful !!!

NEVER USE LONG CODE INSIDE ISR – IT pause other process, IF POSSIBLE use only flag or semaphore or signals. :innocent:

LINK: SIMPLE UART COMMUNICATION

Thanks for showing me a solution.
However, I use a separate serial interface for sending and receiving.
And I used RawSerial instead of Serial,but mbed os hangs.

Can you please show your code ?
RawSerial allow you to use any of library function inside ISR, but as I said use only flag inside ISR, this is because OS pause other processes while handling ISR block.
I think your OS hang not because serial interface, there is something other cause

This is the code I’m using.
Using Serial Receive Interrupt in MIDI.h And sending text in main.cpp.

Even I changed the Serial to RawSerial in main.cpp, the result was not changed.

Hi ;
I have checked your code.
Are you facing any error or just getting no output ???

Hello Itsuki,

You handle serial interrupts in the midi::receiveMessage ISR:

void midi::receiveMessage(void) {
    uint8_t data = _serial.getc();
    if (messageBuffer.size() > receiveMessageBufferSize - 1)messageBuffer.clear();
    messageBuffer.push_back(data);
    return;
}

Inside this ISR you call the messageBuffer.clear() and messageBuffer.push_back(data) functions. Both of these functions include a while(true) endless loop:

...
if (isLocked) 
    while (true);
...

However, the isLocked variable can be set to true also outside the ISR, for example when you call the messageBuffer.pull() function. If that happens (isLocked = true) and a serial interrupt occurs the program inside the ISR enters the while(true) endless loop and hangs.

Best regards, Zoltan

Thanks,It works!!