Example using STM32F103 HAL_UART receive and transmit

Hi. I’m new to FreeRTOS. Since timing conditions and real time responsitivity were becoming crucial I turned to be using FreeRTOS.
I managed to setup a very rudimentary program for an STM32F103 (blue pill) under STM32CubeIDE.

Now I’m seeking for a code example that allows for reading one character from a UART Rx register and write it out to the same UART Tx register.

Is there a collection a sample code available somewhere? Thanks in advance.


Christoph

The simplest way to do that wouldn’t use FreeRTOS at all, but just an ISR.

The demo program provided with FreeRTOS do have code that has the ISR put the receive character into a Queue, and then a task read from the Queue, put it into another Queue and activate a transmit function.

Note, all the ISR part of that code will be VERY processor specific.

Queue is exactly what I’m aiming at. Other tasks like reading out ADC data continuously will have to be implemented also. I was fed up with all these delays() and timing constraints. Two UARTs will be acting later in the solution.

In a first consideration I thought not to use IRs at all. A task could polll the receive status bit and when there is no character available it just idles. When a character is available, it reads it and puts it in a ringbuffer. Another task looks whether tail != head (overflow conditions have to be processed) and gets the character, processes it and puts it into the Tx register. Tx empty bit must be polled and task could be released, when Tx busy.

NO. Do not have tasks poll and idle loop, that is the way to RTOS madness.

The whole concept of an RTOS is that tasks only run when they have work to do, at which point they automatically start (in priority order) and this requires ISR to be doing the work and triggering notifications.

The polling method basically just makes your whole program just one big loop task. Checking operations in order.

By default, the stm32 hal does not use the FreeRTOS vTaskDelay() function and instead busy-waits in it’s API. For better performance, make sure to define the HAL_Delay function in a way which yields time back to the rtos.

You can also reference the uart implementation in the STM32U5 reference integration for an example of an interrupt driven UART approach with the STM32 HAL.

The STM32 HAL library isn’t really good to use with FreeRTOS, or possibly in. production code in general. It is a nice convent library to get you started and lock yourself into the STM products.

@Krischu Let me know if any issues remain, or if the answers thus far have been sufficient.

Thanks. I will give that above posted example code a try.

@richard-damon: years ago I read a book titled “Minicomputer Systems” by Richard D. Eckhouse, containing a small Real Time Operating System written in PDP-11 assembler. It was called a “cooperative” OS, which means it gave control to the scheduler when a task had nothing to do. So when the UART read flag was tested “not set” it passed along to “PAUSE”. (this all provided my memory stilll serves) :slight_smile: That’s why I had this idea of not using IRs. Maybe it’s different in RTOS. Tasks in RTOS are bound in a tight loop that is only interrupted by the scheduler and the next task can only get started after a time interval that corresponds to the interrupt tick time, right? What is this “granularity” in RTOS?

I tried to incorporate that cli_uart_drv.c example into my project. But it doesn’t compile.
I’m getting:

10:08:39 **** Build of configuration Debug for project NewFreeRTOS ****
make -j7 all 
...
10:20:51 **** Incremental Build of configuration Debug for project NewFreeRTOS ****
make -j7 all 
arm-none-eabi-gcc "../Core/Src/cli_uart_drv.c" -mcpu=cortex-m3 -std=gnu11 -g3 -DDEBUG -DUSE_HAL_DRIVER -DSTM32F103xB -c -I../Core/Inc -I../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy -I../Drivers/STM32F1xx_HAL_Driver/Inc -I../Drivers/CMSIS/Device/ST/STM32F1xx/Include -I../Drivers/CMSIS/Include -I../Middlewares/Third_Party/FreeRTOS/Source/include -I../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM3 -I../Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2 -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -fcyclomatic-complexity -MMD -MP -MF"Core/Src/cli_uart_drv.d" -MT"Core/Src/cli_uart_drv.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Core/Src/cli_uart_drv.o"
../Core/Src/cli_uart_drv.c:63:11: error: 'UART_InitTypeDef' has no member named 'OneBitSampling'; did you mean 'OverSampling'?
   63 |     .Init.OneBitSampling         = UART_ONE_BIT_SAMPLE_DISABLE,
      |           ^~~~~~~~~~~~~~
      |           OverSampling
../Core/Src/cli_uart_drv.c:63:36: error: 'UART_ONE_BIT_SAMPLE_DISABLE' undeclared here (not in a function); did you mean 'UART_ONE_BIT_SAMPLE_DISABLED'?
   63 |     .Init.OneBitSampling         = UART_ONE_BIT_SAMPLE_DISABLE,
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                    UART_ONE_BIT_SAMPLE_DISABLED
../Core/Src/cli_uart_drv.c:64:11: error: 'UART_InitTypeDef' has no member named 'ClockPrescaler'
   64 |     .Init.ClockPrescaler         = UART_PRESCALER_DIV1,
      |           ^~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:64:36: error: 'UART_PRESCALER_DIV1' undeclared here (not in a function); did you mean 'TIM_ETRPRESCALER_DIV1'?
   64 |     .Init.ClockPrescaler         = UART_PRESCALER_DIV1,
      |                                    ^~~~~~~~~~~~~~~~~~~
      |                                    TIM_ETRPRESCALER_DIV1
../Core/Src/cli_uart_drv.c:65:6: error: 'UART_HandleTypeDef' {aka 'struct __UART_HandleTypeDef'} has no member named 'AdvancedInit'
   65 |     .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT,
      |      ^~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:65:36: error: 'UART_ADVFEATURE_NO_INIT' undeclared here (not in a function)
   65 |     .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT,
      |                                    ^~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c: In function 'vUart1MspInitCallback':
../Core/Src/cli_uart_drv.c:83:43: error: 'RCC_PERIPHCLK_USART1' undeclared (first use in this function); did you mean 'RCC_PERIPHCLK_USB'?
   83 |         xClockInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
      |                                           ^~~~~~~~~~~~~~~~~~~~
      |                                           RCC_PERIPHCLK_USB
../Core/Src/cli_uart_drv.c:83:43: note: each undeclared identifier is reported only once for each function it appears in
../Core/Src/cli_uart_drv.c:84:20: error: 'RCC_PeriphCLKInitTypeDef' has no member named 'Usart1ClockSelection'; did you mean 'UsbClockSelection'?
   84 |         xClockInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
      |                    ^~~~~~~~~~~~~~~~~~~~
      |                    UsbClockSelection
../Core/Src/cli_uart_drv.c:84:43: error: 'RCC_USART1CLKSOURCE_PCLK2' undeclared (first use in this function); did you mean 'RCC_LPTIM1CLKSOURCE_PCLK'?
   84 |         xClockInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~
      |                                           RCC_LPTIM1CLKSOURCE_PCLK
../Core/Src/cli_uart_drv.c:106:24: error: 'GPIO_InitTypeDef' has no member named 'Alternate'
  106 |         GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
      |                        ^
../Core/Src/cli_uart_drv.c:106:37: error: 'GPIO_AF7_USART1' undeclared (first use in this function)
  106 |         GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
      |                                     ^~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c: In function 'vInitUartEarly':
../Core/Src/cli_uart_drv.c:143:14: warning: implicit declaration of function 'HAL_UART_RegisterCallback'; did you mean 'HAL_DMA_RegisterCallback'? [-Wimplicit-function-declaration]
  143 |     ( void ) HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_MSPINIT_CB_ID, vUart1MspInitCallback );
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~
      |              HAL_DMA_RegisterCallback
../Core/Src/cli_uart_drv.c:143:58: error: 'HAL_UART_MSPINIT_CB_ID' undeclared (first use in this function)
  143 |     ( void ) HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_MSPINIT_CB_ID, vUart1MspInitCallback );
      |                                                          ^~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:144:58: error: 'HAL_UART_MSPDEINIT_CB_ID' undeclared (first use in this function)
  144 |     ( void ) HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_MSPDEINIT_CB_ID, vUart1MspDeInitCallback );
      |                                                          ^~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c: In function 'xInitConsoleUart':
../Core/Src/cli_uart_drv.c:162:61: error: 'HAL_UART_MSPINIT_CB_ID' undeclared (first use in this function)
  162 |     xHalRslt |= HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_MSPINIT_CB_ID, vUart1MspInitCallback );
      |                                                             ^~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:163:61: error: 'HAL_UART_MSPDEINIT_CB_ID' undeclared (first use in this function)
  163 |     xHalRslt |= HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_MSPDEINIT_CB_ID, vUart1MspDeInitCallback );
      |                                                             ^~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:174:65: error: 'HAL_UART_TX_COMPLETE_CB_ID' undeclared (first use in this function)
  174 |         xHalRslt |= HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_TX_COMPLETE_CB_ID, txCompleteCallback );
      |                                                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:176:65: error: 'HAL_UART_ERROR_CB_ID' undeclared (first use in this function); did you mean 'HAL_UART_ERROR_FE'?
  176 |         xHalRslt |= HAL_UART_RegisterCallback( &xConsoleHandle, HAL_UART_ERROR_CB_ID, rxErrorCallback );
      |                                                                 ^~~~~~~~~~~~~~~~~~~~
      |                                                                 HAL_UART_ERROR_FE
../Core/Src/cli_uart_drv.c:177:21: warning: implicit declaration of function 'HAL_UART_RegisterRxEventCallback'; did you mean 'HAL_UARTEx_RxEventCallback'? [-Wimplicit-function-declaration]
  177 |         xHalRslt |= HAL_UART_RegisterRxEventCallback( &xConsoleHandle, rxEventCallback );
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                     HAL_UARTEx_RxEventCallback
../Core/Src/cli_uart_drv.c:183:21: warning: implicit declaration of function 'HAL_UARTEx_SetTxFifoThreshold' [-Wimplicit-function-declaration]
  183 |         xHalRslt |= HAL_UARTEx_SetTxFifoThreshold( &xConsoleHandle, UART_TXFIFO_THRESHOLD_8_8 );
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:183:69: error: 'UART_TXFIFO_THRESHOLD_8_8' undeclared (first use in this function)
  183 |         xHalRslt |= HAL_UARTEx_SetTxFifoThreshold( &xConsoleHandle, UART_TXFIFO_THRESHOLD_8_8 );
      |                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:188:21: warning: implicit declaration of function 'HAL_UARTEx_SetRxFifoThreshold' [-Wimplicit-function-declaration]
  188 |         xHalRslt |= HAL_UARTEx_SetRxFifoThreshold( &xConsoleHandle, UART_RXFIFO_THRESHOLD_8_8 );
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:188:69: error: 'UART_RXFIFO_THRESHOLD_8_8' undeclared (first use in this function)
  188 |         xHalRslt |= HAL_UARTEx_SetRxFifoThreshold( &xConsoleHandle, UART_RXFIFO_THRESHOLD_8_8 );
      |                                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c:194:21: warning: implicit declaration of function 'HAL_UARTEx_EnableFifoMode' [-Wimplicit-function-declaration]
  194 |         xHalRslt |= HAL_UARTEx_EnableFifoMode( &xConsoleHandle );
      |                     ^~~~~~~~~~~~~~~~~~~~~~~~~
../Core/Src/cli_uart_drv.c: In function 'rxErrorCallback':
../Core/Src/cli_uart_drv.c:224:14: warning: implicit declaration of function 'xTaskNotifyIndexedFromISR'; did you mean 'xTaskNotifyAndQueryFromISR'? [-Wimplicit-function-declaration]
  224 |     ( void ) xTaskNotifyIndexedFromISR( xRxThreadHandle,
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~
      |              xTaskNotifyAndQueryFromISR
../Core/Src/cli_uart_drv.c: In function 'vRxThread':
../Core/Src/cli_uart_drv.c:295:13: warning: implicit declaration of function 'xTaskNotifyWaitIndexed'; did you mean 'xTaskNotifyWait'? [-Wimplicit-function-declaration]
  295 |         if( xTaskNotifyWaitIndexed( 1, 0, 0xFFFFFFFF, &ulNotifyValue, pdMS_TO_TICKS( 30 ) ) == pdTRUE )
      |             ^~~~~~~~~~~~~~~~~~~~~~
      |             xTaskNotifyWait
../Core/Src/cli_uart_drv.c: In function 'txCompleteCallback':
../Core/Src/cli_uart_drv.c:329:14: warning: implicit declaration of function 'vTaskNotifyGiveIndexedFromISR'; did you mean 'vTaskNotifyGiveFromISR'? [-Wimplicit-function-declaration]
  329 |     ( void ) vTaskNotifyGiveIndexedFromISR( xTxThreadHandle, 1, &xHigherPriorityTaskWoken );
      |              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |              vTaskNotifyGiveFromISR
../Core/Src/cli_uart_drv.c: In function 'vTxThread':
../Core/Src/cli_uart_drv.c:405:22: warning: implicit declaration of function 'xTaskNotifyStateClearIndexed'; did you mean 'xTaskNotifyStateClear'? [-Wimplicit-function-declaration]
  405 |             ( void ) xTaskNotifyStateClearIndexed( NULL, 1 );
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                      xTaskNotifyStateClear
../Core/Src/cli_uart_drv.c:412:26: warning: implicit declaration of function 'ulTaskNotifyTakeIndexed'; did you mean 'ulTaskNotifyTake'? [-Wimplicit-function-declaration]
  412 |                 ( void ) ulTaskNotifyTakeIndexed( 1, pdTRUE, portMAX_DELAY );
      |                          ^~~~~~~~~~~~~~~~~~~~~~~
      |                          ulTaskNotifyTake
make: *** [Core/Src/subdir.mk:43: Core/Src/cli_uart_drv.o] Error 1
"make -j7 all" terminated with exit code 2. Build might be incomplete.

10:20:52 Build Failed. 20 errors, 10 warnings. (took 1s.174ms)


Sorry for posting this long error list. But examples that don’t compile are not so pleasant :slight_smile:

A “Cooperative OS” is different than a “Real-Time OS”, A Cooperative OS just needs to give tasks the ability to show they are idle and try to keep the processor busy so everything gets done.

The “Real-TIme” part means that it wants to help get vital tasks done quickly on schedule, and giveng only the left over time to less important tasks. This is what needs the data from the ISRs, so it can know what tasks are actually able to run and schedule them appropiately.

Indeed. It’s not an isolated example. I meant it more as a reference rather than something to be used as-is.

The key takeaway is suggesting that you can use a FreeRTOS Stream Buffer on the RX and TX sides to buffer data for transmission by ISRs while your task has yielded time back to the scheduler.

FreeRTOS Stream Buffers are lighter weight compared to Queues and allow send/receiving multiple characters in a single call.