Enabling serial RX interrupt collides with RTOS

28 Dec 2012

Hello,

1st this post is a follow-up on the question I asked here: http://mbed.org/questions/195/Enabling-serial-RX-interrupt-breaks-Ethe/

So what I've done so far to figure out what is wrong: Upgraded the firmware to include the debug option and installed keil. Created a test program to see where the whole process fails.

Import programRTOSTest

A test program to see why the RTOS doesn't like to play with the serial interrupt.

Connected the debugger and waited for the freeze of the controller.

So far I found that the controller really crashes since after the interrupt the debugger ends here

HardFault_Handler:
0x000020EA E7FE      B        HardFault_Handler (0x000020EA)

The other thing I noticed is that everything keeps on running happy as long as there is no serial data incoming.

Just before the controller goes to the HardFault_Handler this is the last code ran:

   170: __attribute__((used)) void _mutex_acquire (OS_ID *mutex) { 
   171:   /* Acquire a system mutex, lock stdlib resources. */ 
0x00001C56 B510      PUSH     {r4,lr}
0x00001C58 4604      MOV      r4,r0
   172:   if (runtask_id ()) { 
   173:     /* RTX running, acquire a mutex. */ 
0x00001C5A F7FEFC60  BL.W     rt_tsk_self (0x0000051E)
0x00001C5E 2800      CMP      r0,#0x00
0x00001C60 D005      BEQ      0x00001C6E
   174:     mutex_wait (*mutex); 
   175:   } 
0x00001C62 F64F71FF  MOVW     r1,#0xFFFF
0x00001C66 F8DFC038  LDR.W    r12,[pc,#56]  ; @0x00001CA2
0x00001C6A 6820      LDR      r0,[r4,#0x00]
0x00001C6C DF00      SVC      0x00

This is the "mbed-rtos\rtx\RTX_CM_lib.h" file starting from line 181.

The last line that is executed before the hardfault is 0x00001C6C.

Since all this stuff is WAY over my head I'm hoping you can help me with this and we can kill this bug.

31 Dec 2012

Just looking at your code and the debug output it is locking up when it tries to acquire a system mutex (stdlib), this happens when you call pc.printf(...). If you remove all of the printf pc.printf functions from your serial interrupt and just flash an led or something to indicate that you got there does it work? I'll try it in a bit and see if I can figure it out. Also, I'd make your buffer position variable volitile, that way if the interrupt happens while it is being updated it will finish being updated before the interrupt.

I think the reason this happens is when you include the RTOS you are no longer able to use standard library functions inside interrupts, see the RTOS handbook page.

31 Dec 2012

Got it working... here is the code:

#include "mbed.h"

#define DEBUG

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
Serial probe(p9,p10);

Serial testOut(p13,p14); // p13 wired to p10 for test

#ifdef DEBUG
Serial pc(USBTX,USBRX);
#endif

char serialBuffer[256];
unsigned char serialBufferLoc = 0;

void rxInterrupt(void){
    NVIC_DisableIRQ(UART3_IRQn);
    uint32_t IRR3 = LPC_UART3->IIR;
    led2=!led2;
    serialBuffer[serialBufferLoc] = LPC_UART3->RBR;

#ifdef DEBUG
    //pc.putc(serialBuffer[serialBufferLoc]);
    led3 = !led3;
#endif

    if (serialBuffer[serialBufferLoc] == 0x0A) {
        //pc.printf("cr found\r\n");
        led4 = !led4;
    }

    serialBufferLoc++;
    NVIC_EnableIRQ(UART3_IRQn);
}

void serialProbeInit(void){
    probe.baud(9600);
    probe.format(8,Serial::None,1);
    probe.attach(&rxInterrupt,Serial::RxIrq);
}

#ifdef DEBUG
void serialPcInit(void){
    pc.baud(115200);
    pc.format(8,Serial::None,1);
}
#endif

int main(){
    serialProbeInit();
#ifdef DEBUG
    serialPcInit();
    pc.printf("Comtest, MBED started\r\n");
#endif    

    testOut.baud(9600);
    testOut.format(8,Serial::None,1);
    char outCharacter = 0x00;
    
    while(1){
        outCharacter = (outCharacter + 1) & 0x0F; // circulate through values 0x00 and 0x0F
        testOut.putc(outCharacter);
        pc.printf("%0x\r\n", outCharacter);
        led1 = 1;
        wait(0.2);
        led1 = 0;
        led2 = 0;
        wait(0.2);
    }
}
31 Dec 2012

Ok, thanks for the info so far.

I'll try tomorrow if it wants to work. (But I assume it will)

Anyway thanks so far and best wishes for 2013. I'll make an post as soon as I tryed it.

06 Jan 2013

That took a little longer than expected but I just tested some more and (with thanks to Tyler Weaver) solved the problem.

The full (working) code can be found here: (same location as above)

Import programRTOSTest

A test program to see why the RTOS doesn't like to play with the serial interrupt.

(If you use the history the differences can be found)

To sum it up: In order to read and/or write in the serial interrupt with the RTOS library imported DON'T use the standard functions.
To read a character use:
<input data> = LPC_UARTx->RBR;
instead of:
<input data> = object.getc();

To write a character use: LPC_UARTx->RBR = <output data>;
instead of:
object.putc(<output data>);

The x in LPC_UARTx->RBR has to be replaced by 0 to 3 depending on the UART used. (see table below)

PinsUART
USBTX,USBRX0
p13,p141
p28,p272
p9,p103

(from http://mbed.org/users/tylerjw/notebook/buffered-serial-with-rtos/)

Hope someone else can use this as well.

29 Apr 2014

It's working fine for me so far with the UART2 (p27,28) as you told us i just modified the "x" in each "UARTx... " and it worked. So thx a lot !!! It's perfect

To go further i wanted to use string type. So I tried to use string type like :

str [ locBuffer ] = LPC_UART2->RBR;

But when i tried to screen str on a 2*16 LCD i just have "||||||||" which appears after sending "Qqqq" on the UART for example.

My code :

For (count=0;count<4;count++) {lcd.locate(count,0); lcd.printf("%s",str[count]);}

I'm a beginner so i don't really understand why a tab of char works and not a string. May i do an error. Let's continu to explore Mbed's possibilities !

Thx again.

29 Apr 2014

FYI this is outdated: The current solution is to replace Serial with RawSerial. This has some limitations, but it does allow you to getc() from an interrupt while using RTOS.

29 Apr 2014

Erik - wrote:

Ok nice ! I try this solution in a minute. thx