4 years, 4 months ago.

K64 UART Interrupt Handler calls Mutex_Acquire

Trying to debug a problem where my UART Rx handler calls uart.getc() finally leading to HardFault_Handler() getting called everytime. Attached the error state from my Keil Debugger. /media/uploads/ykd/callstack.png .

I see that uart.getc() in my ISR routine calls serial_getc() which in turn calls serial_readable() , but the disassembly shows _mutex_acquire() getting called finally leading to HardFault_handler().

Below shows the stack trace indicating how _mutex_acquire() gets called

Stack trace mbed library with this snippet

                _do _fflush:
0x0000F444 E92D41F0  PUSH          {r4-r8,lr}
0x0000F448 4604      MOV           r4,r0
0x0000F44A F100074C  ADD           r7,r0,#0x4C
0x0000F44E 4638      MOV           r0,r7
0x0000F450 F7FEFE0B  BL.W          _mutex_acquire (0x0000E06A)   // -> mutex_acquire finally leads to HardFault
0x0000F454 68E0      LDR           r0,[r4,#0x0C]

0x00013010 B510      PUSH          {r4,lr}
0x00013012 4604      MOV           r4,r0
0x00013014 6940      LDR           r0,[r0,#0x14]
0x00013016 F7FCFA3A  BL.W          fflush (0x0000F48E)   // --> here the above fflush got called
0x0001301A 6960      LDR           r0,[r4,#0x14]
0x0001301C E8BD4010  POP           {r4,lr}

uint8_t byte = bt_uart.getc(); 
0x0000EA08 48BC      LDR           r0,[pc,#752]  ; @0x0000ECFC
0x0000EA0A 303C      ADDS          r0,r0,#0x3C
0x0000EA0C F004FB00  BL.W          _ZN4mbed6Stream4getcEv (0x00013010)    // --> here the above  Stream4getcEv
0x0000EA10 B2C4      UXTB          r4,r0

Attaching my ISR routine for reference

ISR routine snippet

void HostioUartRxIRQHandler(void)
    static uint8_t isRxBufferFull = 0;


    if(bt_uart.readable() && (isRxBufferFull == 0))

        uint8_t byte = bt_uart.getc();
		//some logic to copy above byte into global buffer

I am running the standard RTOS CMSIS-RTX .

Can someone help me as to why this is happening ?

Secondly it will be nice to know why calling the standard UART serial api getc() function is leading to mutex_acquire() call ? As far as I know it is not a good practice to call mutex_acquire in an ISR routine as mutex_acquire calls mutex_wait which may sleep.

- YK

1 Answer

4 years, 4 months ago.

Worse, mutex acquire will fail because it is not allowed in ISR context, which probably causes your hard fault. This is simply happening because the C stdio lib has this mutex acquire call, and mbed Serial used the stdio lib.

Solution is to switch from Serial to RawSerial. This allows for getc/putc directly via the device registers, and skips the entire stdio layer. So besides being faster it also works with interrupts + RTOS, which normal Serial does indeed not do.

Accepted Answer

thanks Erik, but then all mbed UART serial ISR routines must have faced this problem. I do not see this problem on the STM boards where when we call getc and I never used RawSerial there but the mbed Serial.

posted by yogesh kulkarni 07 Sep 2015

@ykd: Can you make a simple RTOS demo which would end up in the fault?

posted by Martin Kojtal 07 Sep 2015

@Yogesh, All mbed UART serial IRQ routines while also using RTOS suffer from this. It might be that it only happens when regular ARM instead of uARM lib is used, but that is something I haven't read about before! If thats the case, then STM ones might not have issues, since I believe for some reason they are all set at uARM (also don't know if thats still the case).

But in principle RawSerial was specifically introduced for your use case: Serial IRQs while using RTOS.

posted by Erik Olieman 07 Sep 2015

Hi Erik, Thank you for deeper clarification on this subject. Do you also recommend RawSerial (over Serial) in case of serial IRQs without RTOS? Cheers, Miloje

posted by Miloje Zecevic 08 Sep 2015

thanks Erik, you are very right. RawSerial did the trick and now there is no hardfault.

posted by yogesh kulkarni 08 Sep 2015

@Miloje: Serial can do everything, RawSerial has limitations (you can always manually program it, but it does not have the stdio connection Serial has, as random example: printf has been implemented, but not scanf. Also you cannot redirect a stdio stream to a RawSerial). The most used stuff is there (printf/putc/getc), it works with RTOS and it is faster/lighter than regular Serial.

So up to you what your requirements are :).

posted by Erik Olieman 08 Sep 2015

Thanks Erik! Cheers

posted by Miloje Zecevic 11 Sep 2015