STM32 NucleoH7 Dev Board with FreeRTOS + CMSIS

I was following along the article about running the STM32 NucleoH7 with FreeRTOS and CMSIS: Intrduction to FreeRTOS It looks like the CMSIS provides an API to FreeRTOS, and to certain board functions, but I don’t see an API for reading the onboard ADCs, for example. Am I missing something in the CMSIS software, or does CMSIS not provide an API for the ADCs, DAC, etc?


Hello @gerry.mletzko,

Looks like the article you linked to is utilizing a NucleoL4 board (the Nucleo-L476RG to be specific) rather than an H7 board. It doesn’t really matter though, because the answer that follows applies to both. I just want to make sure we’re on the same page.

The CMSIS library is a more generic API that abstracts operations applicable to any MCU utilizing an Arm Cortex-M or Cortex-A processor. The peripherals surrounding the core in a particular MCU are implemented by the chip vendor (STMicroelectronics in this case) and thus are not generally supported by CMSIS. Looking at the structure of the various CMSIS components below, we see the oddball category called Peripheral HAL (Hardware Abstraction Layer) that interfaces with specialized peripherals (i.e., the ADC, DAC, timers, etc.). This HAL library will be supplied by the chip vendor. Note that while a CMSIS-Driver component does exist for interfacing with common communication peripherals (e.g., USART, SPI, USB), it does not appear to be supported by ST.

If you are using STM32CubeIDE to create and develop your project (as is done in the article you linked to), the STM32 HAL for your selected MCU should automatically be downloaded, included in your project, and available for you to use in your code. Shawn Hymel has another article, Getting Started with STM32 - Working with ADC and DMA, as an example of using the HAL to get samples from the ADC peripheral. Note that you can also download the ST MCU package separately as a zip file (the STM32CubeL4 package, for example) and explore all of the available drivers and example projects manually. If you do so and navigate to STM32Cube_FW_L4_V1.17.2\Projects\NUCLEO-L476RG\Examples\DAC, you will find two example projects in which the HAL is used to interface with the DAC peripheral.


Hello Gerry,

Let’s explore the STM32 HAL (Hardware Abstraction Layer) with a bit more depth.

As a starting point it’s useful to contrast the STM32 HAL with the well-known Arduino environment. In both cases abstraction is given high priority. Here the term abstraction allows you to move across different physical hardware with the same family without changing your code. For example, in Arduino the digitalWrite(pin, value ) function will work on every single Arduino from the classic UNO to the newest 32-bit Arduino. Likewise the SMT32 HAL command HAL_GPIO_WritePin(port, pin, value) will be the same across members of the STM32 family.

This abstraction is highly desirable as it reduces the amount of work required to understand and then attempt to manipulate the chip specific peripherals.

Stepping back, we need to realize that the STM32 is no Arduino. The most powerful members of the STM32 family have a rich and complex set of peripherals and consequently require an equally complex HAL. As of this writing, the HAL user manual UM1884 is 2604 pages long. This massive document will tell you everything you want to know about configuring the uC peripherals. However, it’s a bit of a learning curve if you are just getting started.

May I recommend you start your exploration using the Code Configurator Tool located within the STM32CubeID. This is a graphical tool that allows you to set individual functions for your chosen uC. For example, here is the window for the ADC.


At this point you may be asking what this graphical display has to do with HAL.

It provides working examples!

When you tell the tool to save your configuration it will automatically generate code in the main.c function. This code is built on top of HAL. Here is an example of the computer generated code:

/** Configure Regular Channel
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {

Observe that the HAL_ADC_ConfigChannel( ) function is passes a structure containing the appropriate configuration fields. This is a typical HAL operation. I would also argue it’s one of the impediments to getting started with the STM32 and HAL.

As we conclude, let me leave you with this code that I use from within main( ) to retrieve the ADC values:

	HAL_ADC_Start(&hadc1);// Blocking ADC conversion    ***** 12-bit ADC 
	HAL_ADC_PollForConversion(&hadc1, 100);
	int ADCVal6 = HAL_ADC_GetValue(&hadc1);

	HAL_ADC_PollForConversion(&hadc1, 100);
	int ADCVal8 = HAL_ADC_GetValue(&hadc1);

Best wishes in your exploration of FreeRTOS. It’s an impressive piece of code.