7 months, 2 weeks ago.

Reading serial from a new thread in RTOS?

I would like to have an interrupt which then starts up a thread which then reads from serial input, but it outputs the following error:

++ MbedOS Error Info ++ Error Status: 0x80020126 Code: 294 Module: 2 Error Message: CMSIS-RTOS error: ISR Queue overflow Location: 0x4CBB Error Value: 0x2 Current Thread: rtx_idle Id: 0x1000037C Entry: 0x5689 StackSize: 0x200 StackMem: 0x10000408 SP: 0x10007F70 For more info, visit: https://armmbed.github.io/mbedos-error/?error=0x80020126 MbedOS Error Info

Here is my code:

include the mbed library with this snippet

#include "mbed.h"

Thread ISRthread(osPriorityAboveNormal);
osThreadId ISRthreadId;

RawSerial pc(USBTX, USBRX);
Mutex serial_mutex;

DigitalOut myled(LED1);

void newInput();
void ISR_thread();

int main() {
    
   ISRthread.start(callback(ISR_thread));
   pc.attach(&newInput);          //interrupt to catch input
   
    while(1) {
        myled = 1;
        osDelay(1000);       
        myled = 0;
        osDelay(1000);
    }
}


void newInput() {
    osSignalSet(ISRthreadId,0x01);
}


void ISR_thread() {
    ISRthreadId = osThreadGetId();
    for(;;) {
        osSignalWait(0x01, osWaitForever);
        serial_mutex.lock();
        while (pc.readable()) {
            pc.getc();
        }
        serial_mutex.unlock();
    }
}

I'm using OS5. Any way to make this work? I've tried to use LPC_UART0->RBR instead of getc() but found no luck.

I'm working on an LPC1768.

Comment on this question

1 Answer

7 months, 2 weeks ago.

Hello W K,

  • The 'serial received' interrupt flag shall be cleared in the newInput ISR. Otherwise the ISR is kept triggered forever. This is usually done by reading from the receive register. Another method is to detach the ISR in the ISR and re-attach it in the tread when you finish reading.
  • Since both readable() and getc() lock the Mutex as their fist action you don't have to do it in your code

#include "mbed.h"

Thread      ISRthread(osPriorityAboveNormal);
osThreadId  ISRthreadId;

RawSerial   pc(USBTX, USBRX);
Mutex       serial_mutex;

DigitalOut  myled(LED1);

void        newInput();
void        ISR_thread();

int main(void)
{
    ISRthread.start(callback(ISR_thread));
    pc.attach(newInput);   //interrupt to catch input
    while (true) {
        myled = 1;
        osDelay(1000);
        myled = 0;
        osDelay(1000);
    }
}

void newInput()
{
    pc.attach(NULL);    //detach the ISR to prevent recursive calls
    osSignalSet(ISRthreadId, 0x01);
}

void ISR_thread()
{
    ISRthreadId = osThreadGetId();

    for (;;) {
        osSignalWait(0x01, osWaitForever);
//        serial_mutex.lock();
        while (pc.readable()) {
            pc.getc();
        }
//        serial_mutex.unlock();
        pc.attach(newInput);    // re-attach the ISR
    }
}

Thank you for sharing this info https://os.mbed.com/questions/4878/what-exactly-are-signals/#.

Thank you this worked really well.

posted by L B 07 Mar 2019

This solution is even better because the ISR is very short and there is no buffer:

#include "mbed.h"
 
class Comm : public Thread
{
    RawSerial         _pc;
    bool              _RUN;
    volatile bool     newChar;
 
    void serialISR()
    {
        _pc.attach(NULL);   // detaching ISR prevents being called again and again
        newChar = true; 
    }
 
    void commInFn()
    {
        while (_RUN) {
            if (newChar) {
                newChar = false;
                while (_pc.readable())
                    _pc.putc(_pc.getc());
                _pc.attach(callback(this, &Comm::serialISR));   // re-attach ISR
            }
        }
    }
 
public:
    Comm() : _pc(USBTX, USBRX), _RUN(0), newChar(false), Thread(osPriorityAboveNormal, 1024)
    {
        _pc.printf("Welcome.\r\n");
    }
 
    void start_comm()
    {
        _RUN = true;
        _pc.attach(callback(this, &Comm::serialISR));
        start(callback(this, &Comm::commInFn)); // reattach ISR
    }
};
 
//Main
int main()
{
    Comm comm_plz;
    
    comm_plz.start_comm();
 
    while (1) { }
}
posted by Zoltan Hudak 13 Mar 2019

Hi , Thanks for solution interrupt in thread.

i just want to clarify about 'osSignalWait(0x01, osWaitForever);'. is it automatically clear the 0x01 flag ?.

posted by Ibn Hidayat 27 Sep 2019

Hello Ibn,

Yes, osSignalWait(0x01, osWaitForever) automatically clears the 0x01 flag because the osFlagsNoClear option is not used when it calls the osThreadFlagsWait function:

cmsis_os1.c

// ...

os_InRegs osEvent osSignalWait (int32_t signals, uint32_t millisec) {
  osEvent  event;
  uint32_t flags;

  if (signals != 0) {
    flags = osThreadFlagsWait((uint32_t)signals, osFlagsWaitAll, millisec);
  } else {
    flags = osThreadFlagsWait(SignalMask, osFlagsWaitAny, millisec);
  }

// ...
}

options for the osThreadFlagsWait:

cmsis_os2.h

// ...

#define osFlagsWaitAny        0x00000000U ///< Wait for any flag (default).
#define osFlagsWaitAll        0x00000001U ///< Wait for all flags.
#define osFlagsNoClear        0x00000002U ///< Do not clear flags which have been specified to wait for.

// ...
posted by Zoltan Hudak 27 Sep 2019

Thanks for the answer :).

posted by Ibn Hidayat 27 Sep 2019