How HAL_UART_Transmit_IT manages sending data on serial on the STM32F091VB
Asked Answered
V

1

5

I'm trying to understand how the STM32F091VB manages the send of data via serial protocol with the function HAL_UART_Transmit_IT()

At the moment I've a function called in the main() that creates the packet and send it via serial; it is something like this:

tx1[0] = STX;    
tx1[1] = 0xFF;
tx1[2] = 0x80;
tx1[3] = 0x80;

DE_TAST_HIGH;
HAL_UART_Transmit_IT(&huart3, tx1, 8);

Now, the data I'm sending is quite small so the code run pretty fast and I'm trying to understand what's going to happen if I try to send a huge packet via serial protocol.

For istance, if my tx1[] is 100byte the HAL_UART_Transmit_IT() function block the CPU waiting while the full packet is sent to the serial port or it works more like a separate process where I tell the micro to send that packet and, while sending it it also process the remaining part of my code/main function?

I've tried to search on the micro datasheet to see if there was something about this process but I had no luck. I've read the stm32f0xx_hal_uart.c and it confirms that it is sent via interrupt in a non blocking mode but I would like to have some more in depth documentation about it

Verina answered 28/4, 2022 at 9:13 Comment(6)
What more information would you need? It's non-blocking interrupt based. It will send a byte when it's ready, otherwise will execute you main loop. For detailed description of the interrupt registers etc. have a look at the "Reference Manual" (what ST calls them) their "Datasheet" just says "yup, this has a UART interface". For software handling of those interrupts, you need to look at the HAL manual or the code itself. I'd suggest single stepping through the ISR and checking out when things get sent and where you end up afterwards.Deryl
@Deryl so it is not some kind of "multi thread/multi processor"?! When the micro is ready to trasmit jump from the main to the actual sending section of the code and back when it's over?Verina
It's a small ST MC, there is no multithreding. And yes, that is how interrupts work. There should also be a blocking UART_Transmit() (without the _IT at the end). Have a look at this to see the difference between blocking and non-blocking send.Deryl
@Verina multithreading is not magic, if you are programming bare metal than there is no multithreading/parallelism by default and everything you do run within the same thread. Interrupts are the base for context switch but that's the maximum you can get.Trinette
@Deryl gotcha, that's what I needed to knowVerina
@Verina by the way, I discourage using the HAL library to understand how microcontrollers work, as it is unnecessary convoluted. You can use the micro specific ARM libraries and learn from there. HAL have surely their reasons to exist, but learning isn't one of them.Trinette
T
8

First of all you need to understand how the HAL_UART_Transmit_IT is meant to be used. We can get some help from STM FAQ.

interrupt mode.

The function is "non blocking" because when you call it it will do some configuration of the interrupts and then return. The buffer will not be transmitted during the call to your function, instead the heavy lifting is deferred to a later stage.

We can further have a look at the source code, to get a proof from what I said (note I kept only the juicy parts).

Blocking

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint16_t* tmp;
  uint32_t tickstart = 0U;
  
    // [ ... ]

    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
    while(huart->TxXferCount > 0U)
    {

        // [ ... ]
        // This is were the actual HW regs are accessed, starting the transfer
        huart->Instance->DR = (*pData++ & (uint8_t)0xFF);
      } 
    }
    
    // [ ... ]

  return HAL_OK
}

Non Blocking

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{

    
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;

    /* Enable the UART Transmit data register empty Interrupt */
    // This is the only part were HW regs are accessed. What is happening here??
    SET_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
    
    return HAL_OK;

}

The _IT function only activates one interrupt, based also on the datasheet:

enter image description here

enter image description here

This means we will receive an interrupt whenever the TX buffer is free. Who is actually sending the data then?

With the help of the FAQs and reading the source code, we find that void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) does something like this:

/* UART in mode Transmitter ------------------------------------------------*/
   if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
   {
     UART_Transmit_IT(huart);
     return;
   }

Which in turn calls the UART_Transmit_IT

 static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
 {
   uint16_t* tmp;
   
   /* Check that a Tx process is ongoing */
   if(huart->gState == HAL_UART_STATE_BUSY_TX)
   {

       huart->Instance->DR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);
 
     if(--huart->TxXferCount == 0U)
     {
       /* Disable the UART Transmit Complete Interrupt */
       CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE);
 
       /* Enable the UART Transmit Complete Interrupt */    
       SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
     }
     return HAL_OK;
   }
   else
   {
     return HAL_BUSY;
   }
 }

This function transmits only one byte! It then decrements the counter for the transmission (remember, all the information was set into the uart handler) and if it reaches 0, finally the complete interrupt is called.

Interrupts

Note that StmCube does the peripheral initialization and interrupt linking for you, but if you program from scratch you need to remember to write and register UART_IRQ_Handler

You can find here the code navigator to review my snippets and investigate further.

Trinette answered 28/4, 2022 at 10:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.