Skip to main content
arnold_w
Senior II
December 31, 2016
Question

A few questions on goto-statements, encapsulation, etc

  • December 31, 2016
  • 3 replies
  • 1173 views
Posted on December 31, 2016 at 23:25

I am working with the STM32F405 microcontroller and I am trying to have a software UART use the same interrupt line (

EXTI15_10_IRQn) as other interrupts (for example, button press interrupts). In a perfect world, my code would look something like this:

void EXTI15_10_IRQHandler(void) {

    clearInterruptFlag();

    if (EXTI->PR & 0x0400) {

        receiveUARTbyte();

    } else if (

EXTI->PR & 0x0800) {

       handleButtonPress();

    } else if (

EXTI->PR & 0x1000) {

        handleOtherExternalInterrupt();

    }

}

However, I need to run the UART at a high speed (115200 Baud) and the system clock at a low speed (to save power). This means I can't use the stack in the interrupt routine, because pushing stuff onto the stack will make me miss the first UART-bit. So, instead of a calling a function, I need to do something else. We all learned in school that we should try to encapsulate our code as much as possible and that's why I don't want a full software UART implementation inside the interrupt routine. I could create a software interrupt (NVIC->STIR) to a dummy interrupt (with more urgent priority than

EXTI15_10_IRQn

) to transfer control to my UART.c file, but isn't there a lot of overhead associated with that? Could I use a goto instead? If so, can I use a goto without locking my

receiveUARTbyte

() function to a specific address? In other works, can I goto a 'global' goto-label somehow? Other thoughts about solving this and at the same time having well-encapsulated code (except using macros)?

    This topic has been closed for replies.

    3 replies

    Seb
    ST Employee
    December 31, 2015
    Posted on January 01, 2017 at 00:38

    For a sw uart, a better way would be to use a timer and its input capture and output compare to generate precise timing and less time critical. You would have a bit time say 9 us to save the rx edge timestamp. Need more hw assist? Use dma on timer capture.

    Good luck!

    arnold_w
    arnold_wAuthor
    Senior II
    January 1, 2016
    Posted on January 01, 2017 at 03:10

    Thanks for your replies.

    Clive One, I don't know what LR and auto variables are. Are you saying I should declare my receiveUARTbyte,

    handleButtonPress and 

    handleOtherExternalInterrupt

     functions as inline and avoid stack variables inside them and then I can feel confident I will sample the first bit as soon as physically possible?

    You are correct about the mutuality, I guess it should look something like this instead:

    static uint32_t EXTI_PR_temp;    // Use static variable instead of stack variable to avoid spending time pushing the stack.

    void EXTI15_10_IRQHandler(void) {

        // Handle time critical interrupt first 

        if (EXTI->PR & 0x0400) {

            receiveUARTbyte();     // Handle UART packet as soon as possible

            while (

    EXTI->PR

    0x0400) {     

    // Clear interrupt flag for UART receive

                EXTI->PR

    0x0400;

            }

        }

        

        // Handle the not so time critical interrupts

        EXTI_PR_temp = 

    EXTI->PR;

        while (

    EXTI->PR

    &

    EXTI_PR_temp

    )

    ) {     

    // Clear interrupt flags for non-timing critical interrupts

            EXTI->PR

    EXTI_PR_temp

    ;

        }

        if (

    EXTI_PR_temp

     & 0x0800) {

           handleButtonPress();   

        if (

    EXTI_PR_temp

     & 0x1000) {

            handleOtherExternalInterrupt();

        }

    }

    Seb Marsanne, the thing is, we want to use low power mode (i.e. turning off the system clock) and as I understand it it's not possible to wake the microcontroller through an input capture interrupt. So, the plan it so send one wake-up byte to turn on the clock and then send the 'real' packet.

    Tesla DeLorean
    Guru
    January 1, 2016
    Posted on January 01, 2017 at 16:38

    https://en.wikipedia.org/wiki/Automatic_variable

     

    https://en.wikipedia.org/wiki/Link_register

     

    The interrupt already eats 12 cycles just entering, allocating stack space entering scope is 1 cycle, and isn't significantly impacted by the size of the allocation. If you call other functions, LR must be stacked.

    EXTI->PR

    =

    0x0400; // not

    EXTI->PR

    0x0400; and not clear on the value of looping

    I'm not sure why using a local copy of the status bit helps. The bigger issue is perhaps that the interrupt doesn't reenter, so when it is in the lower priority service routines it blocks response to the primary. You could perhaps flags those and defer them to a handler that can be preempted.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Tesla DeLorean
    Guru
    December 31, 2016
    Posted on December 31, 2016 at 23:59

    Well the non macro method is __INLINE, see core_cm4.h

    I'm not sure goto is any more efficient than a branch or function call. The lack of function calls within a function will mean it doesn't need to push LR.

    In terms of local/auto variables what kills you is initialization. ie for a table of CRC constants, use 'static const' so the thing isn't allocated and copied at each entry.

    I will note that interrupts are not mutually exclusive, so I'd avoid the if-then-else-if type construct.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..