本文转载自《安富莱STM32-V7开发板用户手册,含BSP驱动包设计(V3.0)》

初学者重要提示

对于一些常用的函数,大家一定要熟练的掌握都实现了什么功能,比如 HAL_InitHAL_RCC_OscConfigHAL_RCC_ClockConfig 等。最好的办法是把这些函数的源码读一遍

哪些是必备的 API

这里我们通过一个简单的初始化流程来了解 STM32H7 的工程模板所必备的库文件和 API:

  • 第 1 步: 系统上电复位, 进入启动文件 startup_stm32h743xx.s, 在这个文件里面执行复位中断服务

程序。

  • 在复位中断服务程序里面执行函数 SystemInit,此函数在文件 system_stm32h7xx.c 里面。
  • 之后是调用编译器封装好的函数,比如用于 MDK 的启动文件是调用 __main, 最终进入到 main

函数。

  • 第 2 步:进入到 main 函数就可以开始用户应用程序编程了。 在这个函数里面要做几个重要的初始化,

依次是:

  • MPU 初始化,需要用到库文件 stm32h7xx_hal_cortex.cstm32h7xx_hal_cortex.h
  • Cache 初始化,需要用到 core_cm7.h 文件。
  • HAL 库初始化函数 HAL_Init,需要用到文件 stm32h7xx_hal.c
  • 系统时钟初始化, 需要用到库文件 stm32h7xx_hal_rcc.c

前面的两步完成后,就可以开始做用户需要的按键、 串口等方面的初始化和应用代码的实现了。 这里
把我们需要学习的几个库文件整理出来,依次有:

  • startup_stm32h743xx.s
  • system_stm32h7xx.c
  • stm32h7xx_hal.c
  • stm32h7xx_hal_cortex.c
  • stm32h7xx_hal_rcc.c
  • core_cm7.h

/todo 看能不能将所有文件的相关说明都整合到一起
其中 startup_stm32h743xx.s 和 system_stm32h7xx.c 已经在第 13 章为大家讲解过,这里不再赘述。
而 MPU 和 Cache 涉及到的文件 core_cm7.h 在第 23 和 24 章为大家讲解。本章教程重点为大家讲解文
件 stm32h7xx_hal.c、 stm32h7xx_hal_cortex.c 和 sm32h7xx_hal_rcc.c。

源文件 stm32h7xx_hal.c

这个文件比较杂,像基准电压大小配置, EXTI 配置, IO 补偿配置等都在这个文件里面设置。学习这
个文件注意事项:

  • HAL 库中各个外设驱动里面的延迟实现是基于此文件提供的时间基准,而这个时间基准既可以使用滴

答定时器实现也可以使用通用的定时器实现,默认情况下是用的滴答定时器。/todo 这里的滴答定时器是指?

  • 函数 HAL_Init 里面会调用时间基准初始化函数 HAL_InitTick,而调用函数 HAL_RCC_ClockConfig

也会调用时间基准初始化函数 HAL_InitTick

  • 如果在中断服务程序里面调用延迟函数HAL_Delay 要特别注意,因为这个函数的时间基准是基于滴

答定时器或者其他通用定时器实现, 实现方式是滴答定时器或者其他通用定时器里面做了个变量计数。
如此一来,结果是显而易见的,如果其他中断服务程序调用了此函数,且中断优先级高于滴答定时器,
会导致滴答定时器中断服务程序一直得不到执行,从而卡死在里面。所以滴答定时器的中断优先级一
定要比它们高

函数 HAL_Init

函数原型:

  1. HAL_StatusTypeDef HAL_Init(void)
  2. {
  3. /* 设置中断优先级分组 */
  4. HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
  5. /* 使用滴答定时器做为默认时基,配置为 1ms 滴答,另外系统上电后默认使用的 HIS 时钟 */
  6. if(HAL_InitTick(TICK_INT_PRIORITY) != HAL_OK)
  7. {
  8. return HAL_ERROR;
  9. }
  10. /* 初始化底层硬件 */
  11. HAL_MspInit();
  12. /* 返回函数状态 */
  13. return HAL_OK;
  14. }

函数描述:
此函数用于初始化 HAL 库,此函数主要实现如下功能:

  • 设置 NVIC 优先级分组是 4。
  • 设置滴答定时器的每 1ms 中断一次。
  • HAL 库不像之前的标准库,在系统启动函数 SystemInit 里面做了 RCC 初始化, HAL 库是没有做的

所以进入到 main 函数后,系统还在用内部高速时钟 HSI,对于 H7 来说, HSI 主频是 64MHz。

  • 函数 HAL_Init 里面调用的 HAL_MspInit 一般在文件 stm32h7xx_hal_msp.c 里面做具体实现,主要

用于底层初始化。当前此函数也在文件 stm32h7xx_hal.c 里面,只是做了弱定义。
函数参数:

  • 返回值, 返回 HAL_ERROR 表示参数错误, HAL_OK 表示发送成功, HAL_BUSY 表示忙,正在使用

中。

注意事项:
1. 必须在 main 函数里面优先调用此函数。
2. 用户务必保证每 1ms 一次滴答中断。
3. 关于优先级分组的设置可以看第 21 章节。/todo 相关内容学完21章节后补充过来

使用举例:
此函数的使用比较简单,上电后优先调用即可。

函数 HAL_DeInit

函数原型:

  1. HAL_StatusTypeDef HAL_DeInit(void)
  2. {
  3. /* 复位所有外设 */__set_PRIMASK
  4. __HAL_RCC_AHB3_FORCE_RESET();
  5. __HAL_RCC_AHB3_RELEASE_RESET();
  6. /* 省略未写 */
  7. __HAL_RCC_APB4_FORCE_RESET();
  8. __HAL_RCC_APB4_RELEASE_RESET();
  9. /* 复位底层硬件初始化 */
  10. HAL_MspDeInit();
  11. /* 返回值 */
  12. return HAL_OK;
  13. }

函数描述:
此函数用于复位 HAL 库和滴答时钟。

  • 复位了 AHB1,2,3,4 的时钟以及 APB1L, APB1H, APB2,3,4 的时钟。
  • 函数 HAL_DeInit 里面调用的 HAL_MspDeInit 一般在文件 stm32h7xx_hal_msp.c 里面做具体实现,

主要用于底层初始化,跟函数 HAL_Init 里面调用的 HAL_MspInit 是一对。当前此函数也在文件stm32h7xx_hal.c 里面,只是做了弱定义。

使用举例:
此函数的使用比较简单, 需要调用的时候直接调用即可。/todo 什么时候需要调用这个?

函数 HAL_InitTick

函数原型:

  1. __weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
  2. {
  3. /* Configure the SysTick to have interrupt in 1ms time basis*/
  4. if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) > 0U)
  5. {
  6. return HAL_ERROR;
  7. }
  8. /* Configure the SysTick IRQ priority */
  9. if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  10. {
  11. HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
  12. uwTickPrio = TickPriority;
  13. }
  14. else
  15. {
  16. return HAL_ERROR;
  17. }
  18. /* Return function status */
  19. return HAL_OK;
  20. }

函数描述:
此函数用于初始化滴答时钟, 此函数相关问题如下:

  • 此函数有个前缀 __weak ,表示弱定义,用户可以重定义。
  • 此函数用于初始化滴答时钟 1ms 中断一次,并且为滴答中断配置一个用户指定的优先级。
  • 此函数由 HAL_Init 调用,或者任何其它地方调用函数 HAL_RCC_ClockConfig 配置 RCC 的时候也会

调用 HAL_InitTick

  • 调用基于此函数实现的 HAL_Delay 要特别注意,因为这个函数的时间基准是基于滴答定时器或者其他通用定时器实现,实现方式是滴答定时器或者其他通用定时器里面做了个变量计数。如此一来,结果是显而易见的,如果其他中断服务程序调用了此函数,且中断优先级高于滴答定时器,会导致滴答定时器中断服务程序一直得不到执行,从而卡死在里面。所以滴答定时器的中断优先级一定要比它们高。

函数参数:

  • 形参 TickPriority 用于设置滴答定时器优先级。
  • 返回值, 返回 HAL_ERROR 表示参数错误, HAL_OK 表示发送成功, HAL_BUSY 表示忙,正在使用

中。

使用举例:
此函数由 HAL_Init 调用, 无需用户操作, 除非需要重定义。

Systick 的相关函数

调用了函数 HAL_Init 后, Systick 相关的函数就可以使用了。这些函数如下:

  1. __weak void HAL_IncTick(void)
  2. __weak uint32_t HAL_GetTick(void)
  3. uint32_t HAL_GetTickPrio(void)
  4. HAL_StatusTypeDef HAL_SetTickFreq(HAL_TickFreqTypeDef Freq)
  5. HAL_TickFreqTypeDef HAL_GetTickFreq(void)
  6. __weak void HAL_Delay(uint32_t Delay)
  7. __weak void HAL_SuspendTick(void)
  8. __weak void HAL_ResumeTick(void)

函数描述:
这些函数就比较简单了, 下面把这些函数实现的功能做个简单的说明:

  • 函数 HAL_IncTick 在滴答定时器中断里面被调用,实现一个简单的计数功能,因为一般滴答定时器中

断都是配置的 1ms,所以计数全局变量 uwTick 每毫秒加 1。

  • 函数 HAL_GetTick 用于获取全局变量 uwTick 当前的计数。
  • 函数 HAL_GetTickPrio 用于获取滴答时钟优先级。
  • 函数 HAL_SetTickFreqHAL_GetTickFreq 是一对, 前者用于设置滴答中断频率, 后再用于获取滴答中断频率。
  • 函数 HAL_Delay 用于阻塞式延迟,默认单位是 ms。
  • 函数 HAL_SuspendTickHAL_ResumeTick 是一对, 前者用于挂起滴答定时器, 后者用于恢复。

注意事项:

  • 函数有个前缀__weak ,表示弱定义,用户可以重定义。

使用举例:
这些函数都比较简单,这里就不举例了。 需要的时候,直接调用即可。

函数 HAL_SYSCFG_VREFBUF_VoltageScalingConfig

函数原型:
void HAL_SYSCFG_VREFBUF_VoltageScalingConfig(uint32_t VoltageScaling)
函数描述:
此函数用于配置 STM32H7 内部电压基准大小。

  • 当形参 VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE0 时

输出基准是 2.048 V,条件是 VDDA >= 2.4V。

  • 当形参 VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE1 时

输出基准是 2.5 V,条件是 VDDA >= 2.8V。

  • 当形参 VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE2 时

输出基准是 1.5 V,条件是 VDDA >= 1.8V。

  • 当形参 VoltageScaling = SYSCFG_VREFBUF_VOLTAGE_SCALE3 时

输出基准是 1.8 V,条件是 VDDA >= 2.1V。

H7 自带电压基准相关函数

函数原型:

  1. void HAL_SYSCFG_VREFBUF_HighImpedanceConfig(uint32_t Mode)
  2. void HAL_SYSCFG_VREFBUF_TrimmingConfig(uint32_t TrimmingValue)
  3. HAL_StatusTypeDef HAL_SYSCFG_EnableVREFBUF(void)
  4. void HAL_SYSCFG_DisableVREFBUF(void)

函数描述:

  • 函数 HAL_SYSCFG_VREFBUF_HighImpedanceConfig

    1. 此函数用于配置 STM32H7 内部电压基准是否在芯片内部与 VREF+引脚接通。
    • 形参为 SYSCFG_VREFBUF_HIGH_IMPEDANCE_DISABLE 时,表示导通。
    • 形参为 SYSCFG_VREFBUF_HIGH_IMPEDANCE_ENABLE 时,表示高阻,即不导通。
  • 函数 HAL_SYSCFG_VREFBUF_TrimmingConfig
    此函数用于内部电压基准的校准调节。
  • 函数 HAL_SYSCFG_EnableVREFBUFHAL_SYSCFG_DisableVREFBUF 是一对, 分别用于内部电
    压参考基准的禁止和使能。

    函数 HAL_SYSCFG_AnalogSwitchConfig

    函数原型:
    void HAL_SYSCFG_AnalogSwitchConfig(uint32_t SYSCFG_AnalogSwitch , uint32_t SYSCFG_SwitchState )
    函数描述:
    引脚 PA0, PA1, PC2, PC3 用于 ADC 时,还有一组对应的可选引脚 PA0_C, PA1_C, PC2_C 和
    PC3_C。此函数的作用就是切换可选引脚。

    BOOST 的使能和禁止(用于 ADC)

    函数原型:
    void HAL_SYSCFG_EnableBOOST(void)
    void HAL_SYSCFG_DisableBOOST(void)

函数描述:
这两个函数用于使能或者禁止 Booster。如果使能了 booster 的话,在供电电压低于 2.7V 时,可以
减少模拟开关总的谐波失真,这样的话,模拟开关的性能跟正常供电电压时的全范围测量一样

函数 HAL_SYSCFG_CM7BootAddConfig

函数原型:
void HAL_SYSCFG_CM7BootAddConfig(uint32_t BootRegister, uint32_t BootAddress)
函数描述:
用于配置 BOOT = 0 或者 BOOT = 1 时的启动地址,详情可以看第 13 章的 13.4 小节。

IO 补偿相关函数

函数原型:
void HAL_EnableCompensationCell(void)
void HAL_DisableCompensationCell(void)
void HAL_SYSCFG_EnableIOSpeedOptimize(void)
void HAL_SYSCFG_DisableIOSpeedOptimize(void)
void HAL_SYSCFG_CompensationCodeSelect(uint32_t SYSCFG_CompCode)
void HAL_SYSCFG_CompensationCodeConfig(uint32_t SYSCFG_PMOSCode, uint32_t SYSCFG_NMOSCode )

函数描述:

  • 函数 HAL_EnableCompensationCellHAL_DisableCompensationCell 分别用于使能或者禁止 IO 补偿,只有在供电电压范围是 2.4V 到 3.6V 之间时,使用此功能才有意义。
  • 函数 HAL_SYSCFG_EnableIOSpeedOptimizeHAL_SYSCFG_DisableIOSpeedOptimize 分别用于优化 IO 速度或者禁止优化,不过仅在供电电压低于 2.5V 时可用,高于 2.5V 是不可以使用的,另外使用这个功能的前提是用户使能了 PRODUCT_BELOW_25V(是可选字节配置选项里面的一个 bit) 。
  • 函数 HAL_SYSCFG_CompensationCodeSelect IO 补偿单元的选择, 函数形参可以是 SYSCFG_CELL_CODE,即寄存器 SYSCFG_CCVR,也可以是 SYSCFG_REGISTER_CODE,即寄存器 SYSCFG_CCCR
  • 函数 HAL_SYSCFG_CompensationCodeConfig 用于设置 GPIO 内部构造中 NMOS 和 PMOS 的补偿值,两个形参的范围都是 0-15。根据用户调用函数 HAL_SYSCFG_CompensationCodeSelect 选择的寄存器,这里仅有一个形参的设置是有效的。

    低功耗和 EXTI 相关函数

    低功耗和 EXTI 相关的函数暂时不做讲解,后面章节用到时候再说明。