Overview of HAL drivers
The HAL drivers were designed to offer a rich set of APIs and to interact easily with the application upper layers.
Each driver consists of a set of functions covering the most common peripheral features.
The development of each driver is driven by a common API which standardizes the driver structure, the functions and the parameter names.
The HAL drivers consist of a set of driver modules, each module being linked to a standalone peripheral.
However, in some cases, the module is linked to a peripheral functional mode.
As an example, several modules exist for the USART peripheral:
UART driver module,
USART driver module,
SMARTCARD driver module and
IRDA driver module.
The HAL main features are the following:
Cross-family portable set of APIs covering the common peripheral features as well as extension APIs in case of specific peripheral features.
Three API programming models: polling, interrupt and DMA.
APIs are RTOS compliant:
Fully reentrant APIs
Systematic usage of timeouts in polling mode.
Peripheral multi-instance support allowing concurrent API calls for multiple instances of a given peripheral (USART1, USART2...)
All HAL APIs implement user-callback functions mechanism:
Peripheral Init/DeInit HAL APIs can call user-callback functions to perform peripheral system level Initialization/De-Initialization (clock, GPIOs, interrupt, DMA)
Peripherals interrupt events
Error events.
Object locking mechanism: safe hardware access to prevent multiple spurious accesses to shared resources.
Timeout used for all blocking processes: the timeout can be a simple counter or a timebase.
2.1 HAL and user-application files
2.1.1 HAL driver files
A HAL drivers are composed of the following set of files: Table 2: HAL drivers files
2.1.2 User-application files
The minimum files required to build an application using the HAL are listed in the table below: Table 3: User-application files
The STM32Cube package comes with ready-to-use project templates, one for each supported board.
Each project contains the files listed above and a preconfigured project for the supported toolchains.
Each project template provides empty main loop function and can be used as a starting point to get familiar with project settings for STM32Cube.
Their characteristics are the following:
It contains sources of HAL, CMSIS and BSP drivers which are the minimal components to develop a code on a given board.
It contains the include paths for all the firmware components.
It defines the STM32 device supported, and allows to configure the CMSIS and HAL drivers accordingly.
It provides ready to use user files preconfigured as defined below:
HAL is initialized
SysTick ISR implemented for HAL_Delay()
System clock configured with the maximum frequency of the device
If an existing project is copied to another location, then include paths must be updated.
2.2 HAL data structures
Each HAL driver can contain the following data structures:
Peripheral handle structures
Initialization and configuration structures
Specific process structures.
2.2.1 Peripheral handle structures
The APIs have a modular generic multi-instance architecture that allows working with several IP instances simultaneously.
PPP_HandleTypeDef *handle is the main structure that is implemented in the HAL drivers.
It handles the peripheral/module configuration and registers and embeds all the structures and variables needed to follow the peripheral device flow.
The peripheral handle is used for the following purposes:
Multi instance support: each peripheral/module instance has its own handle. As a result instance resources are independent.
Peripheral process intercommunication: the handle is used to manage shared data resources between the process routines.
Example: global pointers, DMA handles, state machine.
Storage : this handle is used also to manage global variables within a given HAL driver.
An example of peripheral structure is shown below:
typedef struct { USART_TypeDef *Instance; /* USART registers base address */ USART_InitTypeDef Init; /* Usart communication parameters */ uint8_t *pTxBuffPtr;/* Pointer to Usart Tx transfer Buffer */ uint16_t TxXferSize; /* Usart Tx Transfer size */ __IO uint16_t TxXferCount;/* Usart Tx Transfer Counter */ uint8_t *pRxBuffPtr;/* Pointer to Usart Rx transfer Buffer */ uint16_t RxXferSize; /* Usart Rx Transfer size */ __IO uint16_t RxXferCount; /* Usart Rx Transfer Counter */ DMA_HandleTypeDef *hdmatx; /* Usart Tx DMA Handle parameters */ DMA_HandleTypeDef *hdmarx; /* Usart Rx DMA Handle parameters */ HAL_LockTypeDef Lock; /* Locking object */ __IO HAL_USART_StateTypeDef State; /* Usart communication state */ __IO HAL_USART_ErrorTypeDef ErrorCode;/* USART Error code */ }USART_HandleTypeDef;
1) The multi-instance feature implies that all the APIs used in the application are re-entrant
and avoid using global variables because subroutines can fail to be reentrant
if they rely on a global variable to remain unchanged but that variable is modified
when the subroutine is recursively invoked.
For this reason, the following rules are respected:
Re-entrant code does not hold any static (or global) non-constant data:
reentrant functions can work with global data. For example, a re-entrant interrupt service routine can grab a piece of hardware status to work with
(e.g. serial port read buffer) which is not only global, but volatile. Still, typical use of static variables and global data is not advised,
in the sense that only atomic read-modify-write instructions should be used in these variables.
It should not be possible for an interrupt or signal to occur during the execution of such an instruction.
Reentrant code does not modify its own code.
2) When a peripheral can manage several processes simultaneously using the DMA (full duplex case),
the DMA interface handle for each process is added in the PPP_HandleTypeDef.
3) For the shared and system peripherals, no handle or instance object is used.
The peripherals concerned by this exception are the following:
GPIO
SYSTICK
NVIC
PWR
RCC
FLASH.
2.2.2 Initialization and configuration structure
These structures are defined in the generic driver header file when it is common to all part numbers.
When they can change from one part number to another, the structures are defined in the extension header file for each part number.
typedef struct { uint32_t BaudRate; /*!< This member configures the UART communication baudrate.*/ uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received in a frame.*/ uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.*/ uint32_t Parity; /*!< Specifies the parity mode. */ uint32_t Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or disabled.*/ uint32_t HwFlowCtl; /*!< Specifies wether the hardware flow control mode is enabled or disabled.*/ uint32_t OverSampling; /*!< Specifies wether the Over sampling 8 is enabled or disabled, to achieve higher speed (up to fPCLK/8).*/ }UART_InitTypeDef;
The config structure is used to initialize the sub-modules or sub-instances. See below example:
HAL_ADC_ConfigChannel (ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
2.2.3 Specific process structures
The specific process structures are used for specific process (common APIs).
They are defined in the generic driver header file.
Example:
HAL_PPP_Process (PPP_HandleTypeDef* hadc,PPP_ProcessConfig* sConfig)
2.3 API classification
The HAL APIs are classified into three categories:
Generic APIs: common generic APIs applying to all STM32 devices.
These APIs are consequently present in the generic HAL drivers files of all STM32 microcontrollers.
HAL_StatusTypeDef HAL_ADC_Init(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_DeInit(ADC_HandleTypeDef *hadc);
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc); void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc);
Extension APIs: This set of API is divided into two sub-categories :
Family specific APIs: APIs applying to a given family. They are located in the extension HAL driver file (see example below related to the ADC).
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc, uint32_t SingleDiff);
uint32_t HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef* hadc, uint32_t SingleDiff);
Device part number specific APIs:
These APIs are implemented in the extension file and delimited by specific define statements relative to a given part number.
#if defined(STM32F756xx) HAL_StatusTypeDef HAL_HASHEx_SHA224_Accumulate(HASH_HandleTypeDef *hhash, uint8_t *pInBuffer, uint32_t Size); #endif /* STM32F756xx */
The data structure related to the specific APIs is delimited by the device part number define statement. It is located in the corresponding extension header C file.
The following table summarizes the location of the different categories of HAL APIs in the driver files. Table 4: APis classification
Notes: (1)
In some cases, the implementation for a specific device part number may change .
In this case the generic API is declared as weak function in the extension file.
The API is implemented again to overwrite the default function
Family specific APIs are only related to a given family.
This means that if a specific API is implemented in another family, and the arguments of this latter family are different,
additional structures and arguments might need to be added.
The IRQ handlers are used for common and family specific processes.
2.5 HAL drivers rules
2.5.1 HAL API naming rules
The following naming rules are used in HAL drivers: Table 6: HAL API naming rules
The PPP prefix refers to the peripheral functional mode and not to the peripheral itself.
For example, if the USART, PPP can be USART, IRDA, UART or SMARTCARD depending on the peripheral mode.
The constants used in one file are defined within this file.
A constant used in several files is defined in a header file. All constants are written in uppercase, except for peripheral driver function parameters.
typedef variable names should be suffixed with _TypeDef.
Registers are considered as constants. In most cases, their name is in uppercase and uses the same acronyms as in thestm32f7xx reference manuals.
Peripheral registers are declared in the PPP_TypeDef structure (e.g. ADC_TypeDef)
in stm32f7xxx.h header file.stm32f7xxx.h corresponds to stm32f756xx.h, stm32f746xx.h and stm32f745xx.h.
Peripheral function names are prefixed by HAL_, then the corresponding peripheral acronym in uppercase followed by an underscore.
The first letter of each word is in uppercase (e.g. HAL_UART_Transmit()).
Only one underscore is allowed in a function name to separate the peripheral acronym from the rest of the function name.
The structure containing the PPP peripheral initialization parameters are named PPP_InitTypeDef (e.g. ADC_InitTypeDef).
The structure containing the Specific configuration parameters for the PPP peripheral are named PPP_xxxxConfTypeDef (e.g. ADC_ChannelConfTypeDef).
Peripheral handle structures are named PPP_HandleTypedef (e.g DMA_HandleTypeDef)
The functions used to initialize the PPP peripheral according to parameters specified in PPP_InitTypeDef are named HAL_PPP_Init (e.g. HAL_TIM_Init()).
The functions used to reset the PPP peripheral registers to their default values are named PPP_DeInit, e.g. TIM_DeInit.
The MODE suffix refers to the process mode, which can be polling, interrupt or DMA.
As an example, when the DMA is used in addition to the native resources, the function should be called: HAL_PPP_Function_DMA ().
The Feature prefix should refer to the new feature. Example: HAL_ADC_Start() refers to the injection mode
2.5.2 HAL general naming rules
For the shared and system peripherals, no handle or instance object is used. This rule applies to the following peripherals:
GPIO
SYSTICK
NVIC
RCC
FLASH.
Example: The HAL_GPIO_Init() requires only the GPIO address and its configuration parameters.
HAL_StatusTypeDef HAL_GPIO_Init (GPIO_TypeDef* GPIOx, GPIO_InitTypeDef *Init) { /*GPIO Initialization body */ }
2.5.3 HAL interrupt handler and callback functions
Besides the APIs, HAL peripheral drivers include:
HAL_PPP_IRQHandler() peripheral interrupt handler that should be called from stm32f7xx_it.c
User callback functions The user callback functions are defined as empty functions with “weak” attribute.
They have to be defined in the user code. There are three types of user callbacks functions:
Peripheral system level initialization/ de-Initialization callbacks: HAL_PPP_MspInit() and HAL_PPP_MspDeInit
Process complete callbacks : HAL_PPP_ProcessCpltCallback()
Error callback: HAL_PPP_ErrorCallback().
Table 8: Callback functions
2.6 HAL generic APIs
The generic APIs provide common generic functions applying to all STM32 devices. They are composed of four APIs groups:
Initialization and de-initialization functions: HAL_PPP_Init(), HAL_PPP_DeInit()
IO operation functions: HAL_PPP_Read(), HAL_PPP_Write(),HAL_PPP_Transmit(), HAL_PPP_Receive()
Control functions: HAL_PPP_Set (), HAL_PPP_Get ().
State and Errors functions: HAL_PPP_GetState (), HAL_PPP_GetError ().
For some peripheral/module drivers, these groups are modified depending on the peripheral/module implementation.
Example: in the timer driver, the API grouping is based on timer features (PWM, OC, IC...).
The initialization and de-initialization functions allow initializing a peripheral and configuring the low-level resources,
mainly clocks, GPIO, alternate functions (AF) and possibly DMA and interrupts.
The HAL_DeInit()function restores the peripheral default state, frees the low-level resources and removes any direct dependency with the hardware.
The IO operation functions perform a row access to the peripheral payload data in write and read modes.
The control functions are used to change dynamically the peripheral configuration and set another operating mode.
The peripheral state and errors functions allow retrieving in runtime the peripheral and data flow states, and identifying the type of errors that occurred.
The example below is based on the ADC peripheral. The list of generic APIs is not exhaustive. It is only given as an example.
2.7 HAL extension APIs
2.7.1 HAL extension model overview
The extension APIs provide specific functions or overwrite modified APIs for a specific family (series) or specific part number within the same family.
The extension model consists of an additional file, stm32f7xx_hal_ppp_ex.c,
that includes all the specific functions and define statements (stm32f7xx_hal_ppp_ex.h) for a given part number.
Below an example based on the ADC peripheral: Table 10: HAL extension APIs
2.8 File inclusion model
The header of the common HAL driver file (stm32f7xx_hal.h) includes the common configurations or the whole HAL library.
It is the only header file that is included in the user sources and the HAL C sources files to be able to use the HAL resources.
Figure 6: File inclusion model
HAL usage models
The following figure shows the typical use of the HAL driver and the interaction between the application user, the HAL driver and the interrupts.
The functions implemented in the HAL driver are shown in green, the functions called from interrupt handlers in dotted lines,
and the msp functions implemented in the user application in red.
Non-dotted lines represent the interactions between the user application functions.
Basically, the HAL driver APIs are called from user files and optionally from interrupt handlers file
when the APIs based on the DMA or the PPP peripheral dedicated interrupts are used.
When DMA or PPP peripheral interrupts are used, the PPP process complete callbacks are called
to inform the user about the process completion in real-time event mode (interrupts).
Note that the same process completion callbacks are used for DMA in interrupt mode.