How to read serial port in RTOS?

27 Nov 2012

Hi All! I'm using RTOS and still vainly seeking a solution to the problem with the serial port.

Based on testing of many different variations I've come to the following code:

#include "mbed.h"
#include "rtos.h"
DigitalOut    led1(LED1);
DigitalOut    led2(LED2);
DigitalOut    led3(LED3);
Serial        pc(USBTX, USBRX);
Thread        *RX_THREAD_POINTER;


// Rx Interupt Routine
void Rx_interrupt(void){
    uint32_t RBR = LPC_UART0->RBR;        // reset RBR interrupt flag
    (*RX_THREAD_POINTER).signal_set(0x1); // dereference of RX_THREAD_POINTER
}


// Read received chars from serial port
void rx_thread(void const *argument){
    while (true) {
        // Signal flags that are reported as event are automatically cleared.
        Thread::signal_wait(0x1);
        while (pc.readable()) { // Serial port 'pc' is never readable. Why?
          led3=!led3;           // LED never lights..
          pc.putc(pc.getc());   // Input buffer of serial port 'pc' is empty. Why?
        }
        led2=!led2;
    }
}


int main(){
    Thread t_rx(rx_thread);
    RX_THREAD_POINTER = &t_rx;  // Set thread pointer as globally-accessible 
    t_rx.set_priority(osPriorityHigh);
    pc.attach(&Rx_interrupt, RxIrq);
    pc.printf("Start\r\n");
    while(true){
        led1=!led1;
        Thread::wait(1000);
    }
}

Rx interrupt is generated reliably, but condition "pc.readable()" is never TRUE, and the "pc.getc()" does not return any data.

Why? Where is my mistake?

Please suggest me another solution!

Thank You all! Vladimir

LPC1768, mbed library revision 47, rtos revision 8

28 Nov 2012

SOLVED !

#include "mbed.h"
#include "rtos.h"
DigitalOut    led1(LED1);
DigitalOut    led2(LED2);
Serial        pc(USBTX, USBRX);
Thread        *RX_THREAD_POINTER;

// Rx Interupt routine
void Rx_interrupt(void){
    LPC_UART0->IER = 0;                   // Disable Rx interrupt
    (*RX_THREAD_POINTER).signal_set(0x1); // dereference of RX_THREAD_POINTER
}


// Read received chars from UART
void rx_thread(void const *argument){
    while (true) {
        // Signal flags that are reported as event are automatically cleared.
        Thread::signal_wait(0x1);
        while (pc.readable()) {
          pc.putc(pc.getc());             // read data from UART
          led2=!led2;
        }
        LPC_UART0->IER = 1;               // Enable Rx interrupt
    }
}


int main(){
    Thread t_rx(rx_thread);
    RX_THREAD_POINTER = &t_rx;  // Set thread pointer as globally-accessible 
    t_rx.set_priority(osPriorityHigh);
    pc.attach(&Rx_interrupt, RxIrq);
    pc.printf("\r\nStart\r\n");
    while(true){
        led1=!led1;
        Thread::wait(1000);
    }
}
28 Nov 2012

Thank for sharing

15 Mar 2013

I think you can use

pc.attach(NULL, RxIrq);

in place of

LPC_UART0->IER = 0;

to disable to the interrupt.

Re-enable using

pc.attach(&Rx_interrupt, RxIrq);

in place of

LPC_UART0->IER = 1;

Makes it more intuitive. Any thoughts / concerns on that as an approach?

12 Apr 2013

There can be an issue with the use of getc in conjunction with the RTOS even for this approach. I have adapted my approach to the one below:

#include "mbed.h"
#include "UART_RTOS_Interrupt.h"

/****** PUT IN HEADER FILE: UART_RTOS_Interrupt.h  *************
#define   UART_RTOS_Interrupt_buffer_SIZE   32    // <---- set to desired size

void Standard_UART_Interrupt(void);
void Setup_CHOSEN_UART(int baud_rate);
char UART_RTOS_getc(void);
int UART_RTOS_putc(char c);
int UART_RTOS_printf(char* input_string);
****************************************************************/

char UART_RTOS_Interrupt_buffer[UART_RTOS_Interrupt_buffer_SIZE] = "";
int UART_RTOS_Interrupt_buffer_position = 0;

Serial CHOSEN_UART(p28,p27);   // <----- tx,rx, UART2

void Standard_UART_Interrupt(void) {
    char c;
    
    if(CHOSEN_UART.readable()) {
            //c = CHOSEN_UART.getc();
            c = (char)LPC_UART2->RBR;     // <----- IMPORTANT: LPC_UARTx must be set to correct UART (UART0 = USB, UART1 = p13/14, UART2 = p27/28, UART3 = p9/10).
            if(UART_RTOS_Interrupt_buffer_position < UART_RTOS_Interrupt_buffer_SIZE - 1) {
                UART_RTOS_Interrupt_buffer[UART_RTOS_Interrupt_buffer_position] = c;
                UART_RTOS_Interrupt_buffer_position++;
            }
    }
}

void Setup_CHOSEN_UART(int baud_rate) {
    CHOSEN_UART.baud(baud_rate);
    UART_RTOS_Interrupt_buffer_position = 0;
    CHOSEN_UART.attach(&Standard_UART_Interrupt, CHOSEN_UART.RxIrq);    // Recv interrupt handler
    printf("UART RTOS Interrupt Buffer Size: %d\n", UART_RTOS_Interrupt_buffer_SIZE);     // <----- May wish to disable
}

char UART_RTOS_getc(void) {
    int a;
    char c;
    
    while(!UART_RTOS_Interrupt_buffer_position);    //blocking just like getc
    
    CHOSEN_UART.attach(NULL, CHOSEN_UART.RxIrq);    // Recv interrupt handler  --  Have to stop interrupt from firing during this manipulation
    
    c = UART_RTOS_Interrupt_buffer[0];
    for(a = 1; a <= UART_RTOS_Interrupt_buffer_position - 1; a++) {
        UART_RTOS_Interrupt_buffer[a - 1] = UART_RTOS_Interrupt_buffer[a];
    }
    UART_RTOS_Interrupt_buffer[UART_RTOS_Interrupt_buffer_position - 1] = '\0';
    UART_RTOS_Interrupt_buffer_position--;
    
    CHOSEN_UART.attach(&Standard_UART_Interrupt, CHOSEN_UART.RxIrq);    // Recv interrupt handler
     
    return c;
}

int UART_RTOS_putc(char c) {
    CHOSEN_UART.putc(c);
    return 1;
}

int UART_RTOS_printf(char* input_string) {
    CHOSEN_UART.printf(input_string);
    return 1;
}

Using getc with this can cause it to hang (seems like readable returns 1, but getc then blocks forever).

13 May 2013

Hi All, I am looking for the best approach to read/write Serial with RTOS. Are there any official serial library for RTOS? I have seen "Buffered Serial with RTOS" : http://mbed.org/users/tylerjw/notebook/buffered-serial-with-rtos/ thanks to Tyler Weaver.

I am a bit confused which way to choose. I would like to use official supported library if there is.

Thanks!

20 Jul 2015

For anyone who encounters this problem on the K64F (or any other platform), beware of differing symbols. I had a problem similar to Vladimir's, and I solved it by finding the appropriate data structure for my platform in the veritable maze of header files. Specifically the UART_Type structure defined in the MK64F12.h file. In my case, the solution was to replace the getc call with a direct load from the specific UART's Data register:

K64F Solution

void rxHook ( void )
{
    if (pc.readable())
    {
        // Replace this:
        // char c = serialPort.getc();
        // With this:
        char c = UART3->D;
        // note: Replace UART3 with whatever UART you are using.
        // in a real implementation, one would then probably put c into some buffer...
    }
}

I hope this helps to prevent poor souls like me from spending far too much time sifting through the mbed source code.

24 Aug 2015

Thank you Zachary. Very much appreciated.

Zachary Polikarpus wrote:

For anyone who encounters this problem on the K64F (or any other platform), beware of differing symbols. I had a problem similar to Vladimir's, and I solved it by finding the appropriate data structure for my platform in the veritable maze of header files. Specifically the UART_Type structure defined in the MK64F12.h file. In my case, the solution was to replace the getc call with a direct load from the specific UART's Data register:

K64F Solution

void rxHook ( void )
{
    if (pc.readable())
    {
        // Replace this:
        // char c = serialPort.getc();
        // With this:
        char c = UART3->D;
        // note: Replace UART3 with whatever UART you are using.
        // in a real implementation, one would then probably put c into some buffer...
    }
}

I hope this helps to prevent poor souls like me from spending far too much time sifting through the mbed source code.