当前位置: 首页 > article >正文

STM32F1 LL 库和HAL 库在GPIO 上的区别

区别

STM32F1 的LL 库在GPIO_PIN 定义上用了特别的处理,和HAL 库不一样,不能按HAL 库或标准库的惯例处理。LL 的GPIO 头文件中Pin 的定义如下:

/** @defgroup GPIO_LL_EC_PIN PIN
  * @{
  */
#define LL_GPIO_PIN_0                    ((GPIO_BSRR_BS0  << GPIO_PIN_MASK_POS) | 0x00000001U)  /*!< Select pin 0  */
#define LL_GPIO_PIN_1                    ((GPIO_BSRR_BS1  << GPIO_PIN_MASK_POS) | 0x00000002U)  /*!< Select pin 1  */
#define LL_GPIO_PIN_2                    ((GPIO_BSRR_BS2  << GPIO_PIN_MASK_POS) | 0x00000004U)  /*!< Select pin 2  */
#define LL_GPIO_PIN_3                    ((GPIO_BSRR_BS3  << GPIO_PIN_MASK_POS) | 0x00000008U)  /*!< Select pin 3  */
#define LL_GPIO_PIN_4                    ((GPIO_BSRR_BS4  << GPIO_PIN_MASK_POS) | 0x00000010U)  /*!< Select pin 4  */
#define LL_GPIO_PIN_5                    ((GPIO_BSRR_BS5  << GPIO_PIN_MASK_POS) | 0x00000020U)  /*!< Select pin 5  */
#define LL_GPIO_PIN_6                    ((GPIO_BSRR_BS6  << GPIO_PIN_MASK_POS) | 0x00000040U)  /*!< Select pin 6  */
#define LL_GPIO_PIN_7                    ((GPIO_BSRR_BS7  << GPIO_PIN_MASK_POS) | 0x00000080U)  /*!< Select pin 7  */
#define LL_GPIO_PIN_8                    ((GPIO_BSRR_BS8  << GPIO_PIN_MASK_POS) | 0x04000001U)  /*!< Select pin 8  */
// ...

而HAL 库的定义是:

/** @defgroup GPIO_pins_define GPIO pins define
  * @{
  */
#define GPIO_PIN_0                 ((uint16_t)0x0001)  /* Pin 0 selected    */
#define GPIO_PIN_1                 ((uint16_t)0x0002)  /* Pin 1 selected    */
#define GPIO_PIN_2                 ((uint16_t)0x0004)  /* Pin 2 selected    */
#define GPIO_PIN_3                 ((uint16_t)0x0008)  /* Pin 3 selected    */
#define GPIO_PIN_4                 ((uint16_t)0x0010)  /* Pin 4 selected    */
#define GPIO_PIN_5                 ((uint16_t)0x0020)  /* Pin 5 selected    */
#define GPIO_PIN_6                 ((uint16_t)0x0040)  /* Pin 6 selected    */

// ...

HAL 库的Pin 定义就是简单的pin maskGPIO_PIN_N = 0x1 << N,和GPIO 里ODR,IDR 等寄存器的操作对应,而LL 库把pin mask 左移了八位,然后在低8 位和高8 位附加了其他信息。

所以,首先,HAL 的pin_maskuint16_t,而LL 要用uint32_t。如果自己写了函数接收Pin 作为参数,LL 库的类型可能会不匹配。其次,使用LL 库的Pin 定义时,需要一些额外处理,比如LL 里面给引脚设置高电平的函数:

__STATIC_INLINE void LL_GPIO_SetOutputPin(GPIO_TypeDef *GPIOx, uint32_t PinMask)
{
  WRITE_REG(GPIOx->BSRR, (PinMask >> GPIO_PIN_MASK_POS) & 0x0000FFFFU);
}

给BSRR 赋值之前,先要把Pin 右移8 位,也就是把pin mask 挪回去,还要把高8 位的东西去掉。对比HAL 库的写引脚电平函数:

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  assert_param(IS_GPIO_PIN_ACTION(PinState));

  if (PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRR = (uint32_t)GPIO_Pin;
  }
  else
  {
    GPIOx->BRR = (uint32_t)GPIO_Pin;
  }
}

直接用Pin 给BSRR 赋值,不需要额外处理。另外,STM32F0 的LL 库也是没有额外处理的:

__STATIC_INLINE void LL_GPIO_SetOutputPin(GPIO_TypeDef *GPIOx, uint32_t PinMask)
{
  WRITE_REG(GPIOx->BSRR, PinMask);
}

没去细究pin_mask 里附加的那些东西有什么用,估计是和F1 系列特殊的GPIO 模式寄存器有关。F0 和F4 系列GPIO 寄存器把输出模式、速度、上下拉之类的配置都用单独的寄存器实现,而F1 系列是全部塞进CRH 和CRL 寄存器里,各个模式之间相互耦合,某一个寄存器位的含义取决于其他寄存器位的值;这就给驱动代码编写造成了麻烦,比如,没办法临时将输出切换成输入,而不修改原来配置的输出速度。

影响

如果实际代码中,调用写GPIO 引脚函数时用的参数都是常量,比如:

#define LED_PIN    LL_GPIO_PIN_0
#define LED_PORT   GPIOB

// ...

// 拉高LED 引脚
LL_GPIO_SetOutputPin(LED_PORT, LED_PIN);

这种情况编译器有可能把右移和位运算都优化省略掉,变成常量操作。但是如果引脚参数不是常量,而是用变量传入的,比如结构体:

typedef struct {
	GPIO_TypeDef *port;
	uint32_t pin_mask;
} PinType;

// 多个引脚放进一个数组
const PinType pins[] = {{GPIOB, LL_GPIO_PIN_0}, {GPIOB, LL_GPIO_PIN_1}, {GPIOB, LL_GPIO_PIN_2}};

void 拉高所有引脚() {
	for(int i = 0; i< 3; ++i) {
		LL_GPIO_SetOutputPin(pins[i].port, pins[i].pin_mask);
	}
}

此时,对LL 函数的调用难以被优化,引脚操作的效率有所降低。当然效率低一点还是其次,重点是我的代码不兼容STM32F1 的LL 库这种引脚定义ヽ(≧□≦)ノ。除了STM32F1,其他单片机的库代码基本都是HAL 库那样定义的,所以我就默认pin mask 可以用(0x1 << N) 这种方式生成,然而拿这种pin mask 去调用LL 库的函数是没效果的。总之,建议别用STM32F1 的LL 库,实在用不了HAL,GPIO 操作很简单,就自己写点寄存器代码喽。


http://www.kler.cn/a/384129.html

相关文章:

  • 热门开源项目推荐
  • API网关如何在iPaaS平台中助企业构建安全高效的API生态体系
  • 【MacOS实操】如何基于SSH连接远程linux服务器
  • 在docker中搭建redis哨兵环境
  • MySQL45讲 第十一讲 怎么给字符串字段加索引?
  • 提升网站安全性 HTTPS的重要性与应用指南
  • 从0开始学习机器学习--Day13--神经网络如何处理复杂非线性函数
  • 【JavaEE】常见锁策略、CAS
  • python --03 (数据类型)
  • 【持续更新】【NLP项目】【自然语言处理】智能聊天机器人——“有问必答”【Chatbot】第2章、《模式一:问候模式》
  • Qt——窗口
  • 阿里云 DataWorks 正式支持 SelectDB Apache Doris 数据源,实现 MySQL 整库实时同步
  • Golang | Leetcode Golang题解之第542题01矩阵
  • Spring Boot 与 Vue 共筑航空机票预定卓越平台
  • Docker LLama-Factory vLLM 快速部署Meta-Llama-3.1-70B-Instruct
  • 银行卡二要素核验 API 对接说明
  • uniapp 实现瀑布流
  • LSTM+LightGBM+Catboost的stacking融合模型
  • Pr 视频过渡:沉浸式视频 - VR 默比乌斯缩放
  • 网络安全从入门到精通(特别篇II):应急响应之DDOS处置流程
  • ArcGIS地理空间平台 manager 任意文件读取漏洞复现
  • [C语言]strstr函数的使用和模拟实现
  • 《Java 实现堆排序:深入理解与代码剖析》
  • 如何选择适合的AWS EC2实例类型
  • VMWareTools安装及文件无法拖拽解决方案
  • SpringBoot之定时任务