打印
[应用相关]

HAL驱动程序概述

[复制链接]
678|41
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xiaoqi000|  楼主 | 2024-3-31 22:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
HAL库文件结构:
HAL驱动文件:

外设驱动API文件和头文件:包含了常见主要的通用API,其中ppp表示外设名称,如adc、usart、gpio、irda等;

       stm32f0xx_hal_ppp.c
       stm32f0xx_hal_ppp.h
外设驱动扩展API文件和头文件:包含指定的API和内部不同实现以覆盖通用API的新定义API接口函数,其中ppp表示外设名称;

       stm32xx_hal_ppp_ex.c
       stm32xx_hal_ppp_ex.h
初始化HAL库文件、包含DBGMCU(调试接口)、Remap(重映射)和SysTick的TimeDelay;

       stm32xx_hal.c
       stm32xx_hal.h
自带的相应库函数例子:包含相应外设的初始化和去初始化;

       stm32xx_hal_msp_template.c
       stm32xx_hal_conf_template.h
通用HAL资源定义:包含通用定义声明、枚举、结构和宏定义;

       stm32xx_hal_def.h


使用特权

评论回复
沙发
xiaoqi000|  楼主 | 2024-3-31 22:14 | 只看该作者
用户应用文件:

用于在main函数前初始化系统时钟,包含SystermInit()函数,但不会在StartUp时配置相同时钟(与标准库不同的地方);

       system_stm32f0xx.c
包含reset handler处理函数、中断向量、并允许调整堆栈大小:

       startup_stm32f0xx.s
EWARM工具链文件,用以调整堆栈大小以适应应用程序的要求;

       stm32f0xx_flash.icf
用户自定义外设初始化文件:包括初始化和去初始化,包含主例程和回调;

       stm32f0xx_hal_msp.c
用户自定义驱动文件:允许用户自定义HAL驱动,可以使用默认配置而无需修改;

       stm32f0xx_hal_conf.h
异常处理和外设中断服务文件:会在SysTick_Handler()函数中反复调用HAL_IncTick()以实现延时;

       stm32f0xx_it.c/.h
主函数:调用HAL_Init()函数、在Debug模式下使用的assert_failed()时间检测函数、系统时钟配置函数、外设HAL初始化和应用代码;

       main.c/.h


通过STM32CubeMX配置的工程,已经默认做好如下的配置:

       HAL初始化完成;
       SysTick中断服务实现HAL_Delay()延时功能;
       系统时钟配置为器件最大频率的时钟;

使用特权

评论回复
板凳
xiaoqi000|  楼主 | 2024-3-31 22:15 | 只看该作者
HAL数据结构:
每一个HAL驱动都遵循以下数据结构:

       外设句柄结构Peripheral handle structures
       初始化和配置结构Initialization and configuration structures
       特殊的过程结构Specific process structures


Peripheral handle structures:
       PPP_HandlerTypeDef *handler是HAL驱动程序中实现的主要结构;它处理外设模块配置、注册、嵌入外围设备所需要的所有结构和变量;

       该句柄结构主要用于:

可以初始化多个实例(可以使用相同的结构定义和配置多个相同外设,如USART1、USART2、USART3),使每个初始化的外设都有相同的完整的结构;
外围进程互通,管理进程之间的共享数据资源,如全局变量、DMA句柄结构、状态机;
存储,用于管理对应的初始化HAL外设驱动程序中的全局变量;

使用特权

评论回复
地板
xiaoqi000|  楼主 | 2024-3-31 22:15 | 只看该作者
外设句柄结构举例:

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;


多实例特性意味着应用程序的所有API都是可重入的,因此会避免使用全局变量,当子例程递归调用时,如果子例程依赖全局变量保持不变但是该变量在循环调用时发生改变,则可能会造成子例程无法重入;

使用特权

评论回复
5
xiaoqi000|  楼主 | 2024-3-31 22:15 | 只看该作者
因此要遵守:

    可重入代码区域不应包含任何静态或全局的非常量数据,可重入函数则可以使用全局数据;例如在整个中断服务函数中使用硬件状态全局变量,会造成硬件状态的易失性;使用静态全局变量期间不应发生中断或其他的信号响应,并因尽量只应用在对其本身读-修改-写的过程中;

    可重入代码不会修改自己的代码;

当外设使用DMA全双工同时管理多个外设时,每个进程的DMA接口句柄都会更新对应的外设PPP_HandleTypeDef;即每个可以使用DMA的外设句柄handler中都包含了DMA_HandleTypeDef;

对于共享(所有外设和系统配置都可以使用的)和系统外围设备,没有句柄或实例对象;包括GPIO、SYSTICK、NVIC、PWR、RCC、FLASH;

外设句柄结构的定义:在外设驱动头文件stm32f0xx_hal_ppp.h中定义;其名称通常都是PPP_HandleTypeDef;

  这些结构通常都是用来初始化子模块和子实例;

特定的进程结构:具体的流程结构使用特定的流程(通用API),通常也是定义在外设驱动头文件中;

使用特权

评论回复
6
xiaoqi000|  楼主 | 2024-3-31 22:18 | 只看该作者
API分类:
通用API,存在于所有通用的HAL驱动程序中;

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);

使用特权

评论回复
7
xiaoqi000|  楼主 | 2024-3-31 22:18 | 只看该作者
扩展API,存在于扩展外设库文件中,有两类;

       第一种是同于特定系列的扩展API;

HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc, uint32_t SingleDiff);
uint32_t HAL_ADCEx_Calibration_GetValue(ADC_HandleTypeDef* hadc, uint32_t SingleDiff);
       第二种是用于特定型号的API;

#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) ||
defined(STM32F078xx) || \
defined(STM32F091xC) || defined(STM32F098xx)
#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || */
/* STM32F091xC || STM32F098xx */

使用特权

评论回复
8
xiaoqi000|  楼主 | 2024-3-31 22:18 | 只看该作者
HAL驱动规则:
HAL_API命名规则:下面这个表可以仔细看看;



其中PPP是外设模式,而不是指外设本身;

       MODE指的是过程模式,是轮循、中断或DMA模式;

       FEATURE指的是实现功能,如Start、Stop;



HAL通用命名规则:

以下外围设备其初始化不需要提供句柄handler和实例对象instance object;GPIO、SYSTICK、NVIC、RCC、FLASH

处理中断和特定时钟配置的宏在每个外设/模块驱动头文件中定义;

使用特权

评论回复
9
xiaoqi000|  楼主 | 2024-3-31 22:18 | 只看该作者
NVIC和SYSTICK是ARMCortex的两个核心功能,与这些功能相关的API位于stm32f0xx_hal_cortex.c中;

从寄存器中读取状态位或标志时,它由位移值构成,且通常返回的宽度为32位;

在初始化HAL_PPP_Init() 的API中,Init函数在修改句柄字段之前会检查句柄PPP_HandleTypeDef内容是否为空;

HAL_PPP_Init(PPP_HandleTypeDef)
if(hppp == NULL)
{
return HAL_ERROR;
}
宏定义分为两类:

       条件宏定义;

#define ABS(x) (((x) > 0) ? (x) : -(x))
       伪代码宏(多指令宏);

#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD_, __DMA_HANDLE_) \
do{ \
(__HANDLE__)->__PPP_DMA_FIELD_ = &(__DMA_HANDLE_); \
(__DMA_HANDLE_).Parent = (__HANDLE__); \
} while(0)

使用特权

评论回复
10
xiaoqi000|  楼主 | 2024-3-31 22:19 | 只看该作者
HAL中断处理程序和回调函数

除了API,HAL外设驱动还包含:

HAL_PPP_IRQHandler()外设中断处理函数;

       用户定义回调函数,系统默认的回调函数定义为weak属性,一旦用户自己定义了回调函数会覆盖系统默认的回调函数;



有三种类型的回调函数:

       外围系统初始化/去初始化回调:HAL_PPP_MspInit()、HAL_PPP_MspDeInit();

       处理完整进程的回调函数:HAL_PPP_ProcessCpltCallback;

       错误处理回调函数:HAL_PPP_ErrorCallback;



使用特权

评论回复
11
xiaoqi000|  楼主 | 2024-3-31 22:22 | 只看该作者
HAL通用APIs:
通用的API由四个方面组成:

       初始化和去初始化:

HAL_PPP_Init(), HAL_PPP_DeInit()
       IO操作来对外围设备进行有效的数据访问:

HAL_PPP_Read(), HAL_PPP_Write(),HAL_PPP_Transmit(), HAL_PPP_Receive()
       控制操作来动态更改外设配置和其他操作模式:

HAL_PPP_Set (), HAL_PPP_Get ()
       状态和错误处理来检索外围和数据流状态,并识别发生的错误:

HAL_PPP_GetState (), HAL_PPP_GetError ()

使用特权

评论回复
12
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
HAL扩展APIs:
扩展API通常是特定系列或同一系列中特定功能或覆盖已修改的API,扩展功能通常由stm32f0xx_hal_ppp_ex.c/h文件构成;

HAL程序由五种不同的方式处理特定的IP功能:

添加部分特定的功能:将新的API添加到stm32f0xx_hal_ppp_ex.c扩展文件中,并命名为HAL_PPPEx_Function();
添加一系列的功能:操作同添加部分特定功能相似;
添加新的外围设备:在stm32f0xx_hal_newppp.c中添加新的可用外围设备,同时在stm32f0xx_hal_conf.h中包含这个新外围设备的宏;
#define HAL_NEWPPP_MODULE_ENABLED

使用特权

评论回复
13
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
更新已有的通用API:想要覆盖一个在stm32f0xx_hal_ppp.c中已经存在的API函数,则在stm32f0xx_hal_ppp_ex.c扩展文件中使用相同名称的定义,因为通用API定义位weak,所以编译器将通过新定义的函数覆盖原始例程;
升级已存在的数据结构:通过采用不同的器件宏定义来重新定义数据结构PPP_InitTypeDef;
#if defined (STM32F072xB)
typedef struct
{
  (…)
}PPP_InitTypeDef;
#endif /* STM32F072xB */

使用特权

评论回复
14
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
文件包含模型:
在这其中stm32f0xx_hal.h是连接整个HAL库源和用户源的唯一头文件;

其中文件包含关系如下图所示:其基本的包含关系是

HAL库文件或main文件—stm32f0xx_hal.h—stm32f0xx_hal_conf.h—HAL库头文件



由于相应的外设功能需要在外设模块选择中添加相应的功能宏,在配置文件stm32f0xx_hal_conf.h中可以找到;

使用特权

评论回复
15
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
HAL共有配置:
HALStatus:除了布尔函数和IRQ处理程序,几乎所有的HAL_API都使用HAL状态,它返回当前API操作的状态;

Typedef enum
{
HAL_OK = 0x00,
HAL_ERROR = 0x01,
HAL_BUSY = 0x02,
HAL_TIMEOUT = 0x03
} HAL_StatusTypeDef;
HALLocked:锁定状态防止意外的共享数据修改和读写;

typedef enum
{
HAL_UNLOCKED = 0x00, /*!<Resources unlocked */
HAL_LOCKED = 0x01 /*!< Resources locked */
} HAL_LockTypeDef;
除了共有的资源,stm32f0xx_hal_def.h文件还调用CMSIS库中的stm32f0xx.h文件来获取所有外设的数据结构和地址映射:

       外设寄存器和位定义的声明;

       用于访问外设寄存器硬件的宏(读写寄存器.etc);

使用特权

评论回复
16
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
CommonMarco:

  NULL和HAL_MAX_DELAY宏定义;
#define HAL_MAX_DELAY 0xFFFFFFFF
       将PPP外设链接到DMA结构指针的宏:__HAL_LINKDMA();
#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD_, __DMA_HANDLE_) \
do{ \
(__HANDLE__)->__PPP_DMA_FIELD_ = &(__DMA_HANDLE_); \
(__DMA_HANDLE_).Parent = (__HANDLE__); \
} while(0)
  

使用特权

评论回复
17
xiaoqi000|  楼主 | 2024-3-31 22:23 | 只看该作者
HAL配置:
配置文件stm32f0xx_hal_conf.h允许用户自定义配置参数和定义;

示例配置文件stm32f0xx_hal_conf_template.h中开启了所有的HAL库定义,并将时钟配置为最大时钟数值;



使用特权

评论回复
18
xiaoqi000|  楼主 | 2024-3-31 22:24 | 只看该作者
HAL外围设备处理:
时钟Clock:
两个主要的功能配置时钟:

HAL_RCC_OscConfig (RCC_OscInitTypeDef *RCC_OscInitStruct)

       用来配置和使能时钟源,如HSE、HSI、LSE、LSI、PLL;

HAL_RCC_ClockConfig (RCC_ClkInitTypeDef *RCC_ClkInitStruct, uint32_t FLatency)

       用来选择SystemClock系统时钟、配置AHB和APB时钟分频、配置Flash等待状态的数量、HCLK时钟更改时更新SysTick配置;



某些外设时钟不是从SystemClock系统时钟中派生的(USB、RTC),这种情况下,时钟配置由stm32f0xx_hal_rcc_ex.c中定义的扩展API执行:

       HAL_RCCEx_PeriphCLKConfig(RCC_PeriphCLKInitTypeDef *PeriphClkInit)



提供额外的RCC_HAL驱动程序功能:

       HAL_RCC_DeInit()时钟去启动功能,将时钟配置返回到复位状态;

       获取时钟功能,并允许检索各种时钟配置(system clock、HCLK、PCLKn);

       MCO和CSS配置功能;

使用特权

评论回复
19
xiaoqi000|  楼主 | 2024-3-31 22:24 | 只看该作者
在stm32f0xx_hal_rcc.h和stm32f0xx_hal_rcc_ex.h中定义了一组宏;它们允许在RCC块寄存器上执行基本操作,例如外设时钟门控/复位控制:

__PPP_CLK_ENABLE/__PPP_CLK_DISABLE to enable/disable the peripheral clock
__PPP_FORCE_RESET/__PPP_RELEASE_RESET to force/release peripheral reset
__PPP_CLK_SLEEP_ENABLE/__PPP_CLK_SLEEP_DISABLE to enable/disable the
peripheral clock during low power (Sleep) mode.

使用特权

评论回复
20
xiaoqi000|  楼主 | 2024-3-31 22:24 | 只看该作者
GPIOs:
GPIO HAL API主要包含:

  HAL_GPIO_Init()/HAL_GPIO_DeInit()

  HAL_GPIO_ReadPin()/HAL_GPIO_WritePin()

  HAL_GPIO_TogglePin ()



除了标准GPIO模式(输入、输出、模拟)外,引脚模式还可以配置成带有中断IT和事件生成EVENT的EXTI模式;

     此模式需要从stm32f0xx_it.c中调用HAL_GPIO_EXTI_IRQHandler()并实现回调函数HAL_GPIO_EXTI_Callback();



下表是介绍了GPIO_InitTypeDef结构可以配置的参数列表:





可以参考GPIO的一些基础配置:

配置GPIO为输出PP模式,控制LED灯;

GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

45

主题

671

帖子

0

粉丝