1

Hi I'm using STM32G070 nucleo board and I was trying to learn how to use UART with interrupts. I made a simple led blinking program in the main and in the interrupt handler there is a simple echo program. The echo works fine but the led blinking never starts.

Below is my code:

//while loop for led blinking
while(1)
    {
        
        GPIOA->BSRR     |= (GPIO_BSRR_BS5);
        //delaySys is a blocking delay function that takes milli seconds as input
        delaySys(1000);
        GPIOA->BSRR     &=~(GPIO_BSRR_BS5);
        GPIOA->BSRR     |= (GPIO_BSRR_BR5);
        delaySys(1000);
        
    }
    

Next is my interrupt handler

void USART2_IRQHandler()
{
    
    if((USART2->ISR) & (USART_ISR_RXNE_RXFNE))
        {
            
            USART2->TDR = USART2->RDR;
            while(!((USART2->ISR) & (USART_ISR_TC)))
                ;
            NVIC_ClearPendingIRQ(USART2_IRQn);
            
        }
        
    if(((USART2->ISR) & (USART_ISR_TXE_TXFNF)))
    {
        
        //TRANSMISSION COMPLETE
        
        
    }
    
}
  • I don't have a STM, but do work with MSP432. Your loop `while(!((USART2->ISR) & (USART_ISR_TC)));` looks like it would create a race condition where `USART2_IRQHandler()` can be invoked again before the loop completes. At least with the MSP the UART interrupt is triggered for each character received -- so double check whether the STM is the same – David C. Rankin Apr 08 '22 at 05:13
  • My idea to wait there was to ensure the program waits till the transmission is complete. I tried commenting the line to see what happens but the result is same as before. I'm sure something is making the interrupt to be called again and again but can't figure out what exactly – plantPlanter Apr 08 '22 at 05:49

2 Answers2

1

If you expect a subsequent stream of bytes from the UART, it might sometimes be justified to hang in the ISR and poll, until you got the expected amount. However, the rest of the program will hang up and wait while you do.

You shouldn't need to call NVIC_ClearPendingIRQ from inside the ISR, because the flag causing the interrupt should be cleared automatically, typically by reading it followed by a data register access or such. Check the UART part of the manual for register descriptions.

A better but more complex way to deal with UART rx interrupts without stalling is to use DMA. I think most STM32 should have support for this, but I'm not sure.

Looking at your blinking code however, it's problematic:

    // light up 1000ms
    GPIOA->BSRR     |= (GPIO_BSRR_BS5);
    delaySys(1000);

    // lights off
    GPIOA->BSRR     &=~(GPIO_BSRR_BS5); 

    // light up some other LED? NOTE: BR5 not BS5
    GPIOA->BSRR     |= (GPIO_BSRR_BR5);
    delaySys(1000);

This can do one of two things:

  • If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are the same bit masks, then it lits up the LED approximately 1000ms and turns it off for approximately 50-100ns. The LED stays lit around 99.99% of the time.
  • If GPIO_BSRR_BS5 and GPIO_BSRR_BR5 are different bit masks, then one LED will blink with 1000ms duty cycle and another stay lit 100% of the time.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thank you for the answer. I'll try to implement this with DMA and see if it arrives on the same issue. However for the led blink part BS5 reset and BR5 set is intentional as the reference manual says "If both BSx and BRx are set, BSx has priority". BS is to set a bit and BR is for clearing a bit. You need to write 1 in BS5 to set and 1 in BR5 to clear the bit – plantPlanter Apr 08 '22 at 06:50
  • @plantPlanter If so the `GPIOA->BSRR &=~(GPIO_BSRR_BS5); ` part is superfluous. – Lundin Apr 08 '22 at 07:25
1

Okay I did fix the problem somehow. I had enabled the interrupt for tx before but when I have disabled it, everything works fine. Seems like Tx was sending an interrupt request and was competing with main.

  • 1
    Glad you stuck to it and got it going. Microcrontrollers can be a whole new world of programming as they are each hardware specific and the libraries are unique. With the TI MSP, the "driverlib" support library provides a convenient (relatively reasonably documented in comments) library for interacting with the hardware on and above the register/address/bit-level interface. (which looks similar to what `NVIC_ClearPendingIRQ()` would have come from). Good luck with your coding. – David C. Rankin Apr 08 '22 at 19:37