1、LL驱动程序概述
LL驱动程序旨在提供快速、轻量级、面向专家的层,它比 HAL 更接近硬件。与 HAL 相反,LL API 不适用于以下外设:不需要代码优化的外设,软件配置复杂的外设,复杂的上层堆栈(如 USB)的外设。
LL 驱动程序特征:
一组初始化函数,用于根据数据结构中指定的参数初始化外设主要功能
一组初始化函数,用于用每个字段的重置值填充初始化数据结构
执行外设去初始化的函数(外设寄存器恢复为默认值)
一组内联函数,用于直接和原子寄存器访问
完全独立于 HAL,因为 LL 驱动程序可以在独立模式下使用(无 HAL 驱动程序)或混合模式(有 HAL 驱动程序)
完全覆盖了支持的外设功能。
LL驱动程序根据 STM32 外设的可用功能提供硬件服务。这些服务完全反映了硬件功能,并提供必须按照微控制器系列参考手册中描述的编程模型调用的一次性操作。因此, LL 服务不实现任何处理,也不需要任何额外的内存资源来保存其状态、计数器或数据指针:所有操作都是通过更改相关的外设寄存器内容来执行的。
2、LL驱动程序文件
LL驱动程序是围绕头文件/C 文件(每个支持的外设一个)和五个头文件构建的,用于一些系统和 Cortex 相关功能。
stm32f1xx_ll_bus.h //这是用于内核总线控制和外设时钟激活和停用的 h 源文件 示例: LL_AHB2_GRP1_EnableClock
stm32f1xx_ll_ppp.h/.c //stm32f1xx_ll_ppp.c 提供外设初始化功能,如 LL_PPP_Init()、LL_PPP_StructInit()、LL_PPP_DeInit()。所有其他 API 都在 stm32f1xx_ll_ppp.h 文件中定义。底层 PPP 驱动程序是一个独立的模块。要使用它,应用程序必须将其包含在 stm32f1xx_ll_ppp.h 文件中。
stm32f1xx_ll_cortex.h //Cortex-M 相关的寄存器操作 API,包括 Systick、低功耗 (LL_SYSTICK_xxxxx LL_LPM_xxxxx “低功耗模式” ...)
stm32f1xx_ll_utils.h/.c //本文件涵盖通用 API: • 读取设备唯一 ID 和电子签名 • 时基和延迟管理 • 系统时钟配置。
stm32f1xx_ll_system.h //系统相关操作。示例:LL_SYSCFG_xxx、LL_DBGMCU_xxx 和 LL_FLASH_xxx 以及 LL_VREFBUF_xxx
stm32_assert_template.h //模板文件,允许定义启用运行时检查时使用的assert_param 宏。仅当在独立模式下使用 LL 驱动程序时(无需调用 HAL API),才需要此文件。应将其复制到应用程序文件夹并重命名为 stm32_assert.h。
没有 LL 驱动程序的配置文件。
LL文件位于同一 HAL 驱动程序文件夹中。通常,LL驱动程序仅包括 STM32 CMSIS 设备文件。
#include "stm32yyxx.h"
应用程序文件必须仅包含使用的LL驱动程序头文件。
3、LL API 及命名规则
3.1、外设初始化函数
LL 驱动程序提供三组初始化函数。它们在 stm32f1xx_ll_ppp.c 文件中定义:
• 根据数据结构中指定的参数初始化外设主要特征的函数
• 一组用于用每个字段的重置值填充初始化数据结构的函数
• 外设去初始化函数(外设寄存器恢复为默认值)
这些 LL 初始化函数和相关资源的定义(结构、术语和 原型)由编译开关 USE_FULL_LL_DRIVER开启。要使用这些函数,必须将此开关添加到 toolchain 编译器预处理器中或在 LL 驱动程序之前处理的任何通用头文件中。下表显示了为所有支持的外设提供的常用功能列表:
ErrorStatus LL_PPP_Init (PPP_TypeDef* PPPx, LL_PPP_InitTypeDef* PPP_InitStruct)
根据 PPP_InitStruct 中指定的参数初始化外设主要功能。例:LL_USART_Init(USART_TypeDef *USARTx, LL_USART_InitTypeDef *USART_InitStruct)
void LL_PPP_StructInit (LL_PPP_InitTypeDef* PPP_InitStruct)
使用其默认值填充每个 PPP_InitStruct 成员。例:LL_USART_StructInit(LL_USART_InitTypeDef *USART_InitStruct)
ErrorStatus LL_PPP_DeInit (PPP_TypeDef* PPPx)
取消初始化外设寄存器,即将它们恢复到其默认 reset 值。例:LL_USART_DeInit(USART_TypeDef *USARTx)
3.1.1.、运行时检查
与 HAL 驱动程序一样,LL 初始化函数通过检查所有 LL 驱动程序函数的输入值来实现运行时故障检测。有关更多详细信息,请参阅前文12.4.3 运行时检查。在独立模式下使用 LL 驱动程序时(不调用 HAL 函数),需要执行以下操作才能使用运行时检查:1. 将 stm32_assert_template.h 复制到应用程序文件夹,并将其重命名为 stm32_assert.h。此文件定义启用运行时检查时使用的 assert_param 宏。2. 将 stm32_assert.h 文件包含在应用程序主头文件中。3. 在 toolchain 编译器预处理器或在 stm32_assert.h 驱动程序之前处理的任何通用头文件中添加 USE_FULL_ASSERT 编译开关。注: 运行时检查不适用于 LL 内联函数。
3.2、外设寄存器级配置函数
除了外设初始化函数之外,LL 驱动程序还提供了一组内联函数,用于直接原子寄存器访问。其格式如下:
__STATIC_INLINE return_type LL_PPP_Function (PPPx_TypeDef *PPPx, args)
(1)“函数”命名根据操作类别进行定义:
特定中断、DMA 请求和状态标志管理:在中断和状态寄存器上设置/获取/清除/启用/禁用标志。
LL_PPP_{_CATEGORY}_ActionItem_BITNAME
LL_PPP{_CATEGORY}_IsItem_BITNAME_Action
例如:
LL_RCC_IsActiveFlag_LSIRDY
LL_RCC_IsActiveFlag_FWRST()
LL_ADC_ClearFlag_EOC(ADC1)
LL_DMA_ClearFlag_TCx(DMA_TypeDef* DMAx)
Flag
Get LL_PPP_IsActiveFlag_BITNAME
Clear LL_PPP_ClearFlag_BITNAME
Interrupts
Enable LL_PPP_EnableIT_BITNAME
Disable LL_PPP_DisableIT_BITNAME
Get LL_PPP_IsEnabledIT_BITNAME
DMA
Enable LL_PPP_EnableDMAReq_BITNAME
Disable LL_PPP_DisableDMAReq_BITNAME
Get LL_PPP_IsEnabledDMAReq_BITNAME
BITNAME 是指产品线参考手册中描述的外设寄存器位名称。
(2)外设时钟激活/停用管理:启用/禁用/重置外设时钟
LL_BUS_GRPx_ActionClock{Mode}
• LL_AHB2_GRP1_EnableClock (LL_AHB2_GRP1_PERIPH_GPIOA | LL_AHB2_GRP1_PERIPH_GPIOB)
• LL_APB1_GRP1_EnableClockSleep (LL_APB1_GRP1_PERIPH_DAC1)
'x' 对应于组索引,指的是给定总线上修改后的 register 的索引。'bus' 对应于总线名称。
(3)外设激活/停用管理 : 启用/禁用外设或激活/停用特定外设功能
LL_PPP{_CATEGORY}_Action{Item}
LL_PPP{_CATEGORY}_IsItemAction
• LL_ADC_Enable ()
• LL_ADC_StartCalibration();
• LL_ADC_IsCalibrationOnGoing;
• LL_RCC_HSI_Enable ()
• LL_RCC_HSI_IsReady()
(4)外设配置管理 : 设置/获取外设的配置设置
LL_PPP{_CATEGORY}_Set{ or Get}ConfigItem
例如:LL_USART_SetBaudRate (USART2, Clock, LL_USART_BAUDRATE_9600)
(5)外设寄存器管理:写入/读取寄存器/重新运行 DMA 相对寄存器地址的内容
LL_PPP_WriteReg(__INSTANCE__, __REG__, __VALUE__)
LL_PPP_ReadReg(__INSTANCE__, __REG__)
LL_PPP_DMA_GetRegAddr (PPP_TypeDef *PPPx,{Sub Instance if any ex: Channel} , {uint32_t Propriety})
Propriety 是用于标识 DMA 传输方向或数据寄存器类型的变量。
4、HAL 和 LL 的联合使用
LL API 设计为在独立模式下使用或与 HAL 结合使用。它们不能自动与同一外设实例的 HAL 一起使用。如果您将 LL API 用于特定实例,则仍可以对其他实例使用 HAL API。请注意,LL API 可能会覆盖某些寄存器,这些寄存器的内容在反映在HAL 句柄中。
4.1、独立模式下使用的LL驱动程序
LL API 可以在不调用 HAL 驱动程序服务的情况下使用。只需在应用程序文件中包含 stm32f1xx_ll_ppp.h 即可完成此操作。通过执行与相应产品线参考手册中编程模型推荐的序列相同的序列来调用给定外设的 LL API。在这种情况下,可以从工作区中删除与所用外设关联的 HAL 驱动程序。但是,STM32CubeF1 框架的使用方式应与 HAL 驱动程序相同,这意味着应始终使用系统文件、启动文件和 CMSIS。注意:当包含 BSP 驱动程序时,与 BSP 函数驱动程序关联的已使用 HAL 驱动程序应包含在工作区中,即使它们未被应用程序层使用。
4.2、LL API 和 HAL 驱动程序的混合使用
在这种情况下,LL API 与 HAL 驱动程序结合使用,以实现基于直接和寄存器级别的操作。允许混合使用,但应考虑一些因素:
• 建议避免为给定的外设实例同时使用 HAL API 和低层 API 的组合。如果是这种情况,则应相应地更新 HAL PPP 句柄结构中的一个或多个私有字段。
• 对于不更改 handle 字段(包括初始化结构)的操作和进程,HAL 驱动程序 API 和LL服务可以一起用于同一外设实例。
• LL驱动程序可以不受任何限制地与所有不基于句柄对象(RCC、通用 HAL、闪存和 GPIO)的 HAL 驱动程序一起使用。stm32f1 固件包中提供了几个示例,说明如何在同一应用程序中使用 HAL 和 LL(请参阅Examples_MIX项目)。
注意:
1. 当 HAL Init/DeInit API 未使用并被LL宏替换时,不会调用 InitMsp()函数,MSP 初始化应在用户应用程序中完成。
2. 当不使用流程 API 并通过LL API 执行相应功能时,不调用回调,后处理或错误管理应由用户应用程序完成。
3. 当使用 LL API 进行流程操作时,IRQ 处理程序 HAL API 无法调用,IRQ 应由用户应用程序实现。每个 LL 驱动程序都实现了读取和清除相关中断标志所需的宏。