-
Notifications
You must be signed in to change notification settings - Fork 14
ChibiOS HAL代码编写指南
内容部分来源于playembedded网站,获取详细信息请登录:https://www.playembedded.org/blog/chibioshal-design-an-object-oriented-approach
ChibiOS HAL库架构 通过ChibiOS-HAL库架构可知,HAL库由用户顶层调用相关外设驱动(PAL,串口,CAN等),并由外设驱动调用底层驱动。
在ChibiOS-HAL中,GPIO外设由PAL(Port Abstraction Layer, 端口抽象层)驱动。使用C++ wrapper并配置完成工程之后,我们可以使用如下代码:
#include "hal.h" /*HAL库头文件*/
#inlcude "ch.hpp" /*ChibiOS头文件*/
int main(){
halInit(); /*HAL库初始化*/
chibios_rt::System::init(); /*ChibiOS系统初始化*/
}
其中当我们开启了hal_init()之后,系统会自动执行pal_init()的PAL初始化函数,因此无需在main函数中添加。
接下来我们介绍几个PAL的API。在PAL中, Port代表端口,即GPIOA,GPIOB等等,PAD代表引脚,例如1,2,3,4 ……
palSetPadMode(port,pad,mode); /*GPIO引脚模式设置,如推挽输出*/
palSetPad(port,pad); /*GPIO引脚电平置高电平*/
palClearPad(port,pad); /*GPIO引脚电平置低电平*/
palTogglePad(port,pad); /*GPIO引脚电平反转*/
其中,port参数可以填写GPIOx,例如GPIO1,GPIO2,GPIO3……
pad参数填写数字即可。
mode可以填写的内容一共有若干种,具体可以查阅源代码,最常用的是推挽输出模式:PAL_MODE_OUTPUT_PUSHPULL
讲到串口驱动,我们不得不首先提及一下HAL库外设的状态机(以SPI为例)。 HAL库状态机 要启动一个HAL库外设,我们先要对我们的外设进行初始化。比如串口驱动是Serial Driver,简写作sd。但是当我们在halconf.h中打开了串口驱动相关的宏,hal_init()中就已经调用了sdInit()函数。因此我们要做的无非就是调用sdStart()函数。我们来看一下sdStart的定义:
msg_t sdStart(SerialDriver *sdp, const SerialConfig *config); 在ChibiOS移植的过程中,我们会修改hal_conf.h和mcu_conf.h这个头文件。在hal_conf.h中修改一个宏HAL_USE_SERIAL为TRUE,那么我们就在HAL中使用了串口。由于我使用的开发板的串口是USART1,所以在 mcu_conf.h中我将STM32_SERIAL_USE_USART1这个宏改为TRUE。阅读源码,这时候条件编译选项会把一个SerialDriver类型的驱动器SD1编译进去。因此,需要向sdStart中的第一个参数传入指向这个驱动器的指针,&SD1。第二个参数是配置结构体,该结构体会进一步配置USART对应的寄存器。如果输入NULL就会使用默认结构体。该串口的默认波特率为38400。
下面的代码展示了一个串口打印的程序,每隔500ms就会向串口打印 "Hello"。
#include "ch.hpp"
#include "hal.h"
#include "hal_serial.h"
#include "chprintf.h"
int main(){
halInit();
chibios_rt::System::init();
sdStart(&SD1, NULL); /* default baud rate 38400 */
while(1){
chprintf((BaseSequentialStream*)&SD1,"Hello\r\n");
chThdSleepMilliseconds(500); /* 500 ms delay*/
}
}
接下来将以Can驱动器为例,讲解配置结构体的配置方法。
int main(){
halInit();
chibios_rt::System::init();
CANConfig can_cfg = {
CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
CAN_BTR_SJW(0) | CAN_BTR_TS2(3) |
CAN_BTR_TS1(8) | CAN_BTR_BRP(2)
};
canStart(&CAND1, &can_cfg);
}
代码定义了一个CanConfig配置结构体。以下是CANConfig在"hal_can.h"中的定义:
typedef struct hal_can_config {
/**
* @brief CAN MCR register initialization data.
* @note Some bits in this register are enforced by the driver regardless
* their status in this field.
*/
uint32_t mcr;
/**
* @brief CAN BTR register initialization data.
* @note Some bits in this register are enforced by the driver regardless
* their status in this field.
*/
uint32_t btr;
} CANConfig;
该结构体有两个方法,第一个方法是MCR寄存器,第二个方法是BTR寄存器。CAN_MCR_ABOM等宏定义,有些是ST官方的宏定义,表示寄存器特定的位。而用位操作“|”运算符,则可以将所有不同位置上的1连接在一起。
这是STM32F4中文参考手册中提供的寄存器信息:
STM32F4中文参考手册,CAN的MCR寄存器 在官方提供的库文件中(stm32f4xx.h),CAN_MCR_ABOM的定义为:
#define CAN_MCR_ABOM ((uint16_t)0x0040) /*!<Automatic Bus-Off Management */
也就是说这个数字的二进制表示中的第六位是1。可以看到,ABOM值正好是MCR寄存器的第六位。那么把这个宏和其他的宏用位运算或连接在一起,可以最终达成配置寄存器的目的。
STM32F4对ABOM位的描述 当我们将这个宏给或运算进去,相当于将这位置为1,即一旦监测到 128 次连续 11 个隐性位,即通过硬件自动退出总线关闭状态。
如果我们使用Clion界面看这些代码,因为有自动提示功能,我们可以更方便地看到MCR和BTR寄存器的信息。
具体该使用哪些宏,我们可以查询CAN的工作原理以及STM32参考手册。CAN驱动启动之后,我们就可以调用更多CAN的API了,不再赘述,相关内容查询Documentation和源代码。对于上述串口的配置也是类似,请大家自行捣鼓。
Feb 11th, 2023 by Wu Feiyang, First Version
- 基础知识
- 基础配置
- 进阶与参考