rtthread 驱动开发的两种情况
rtthread studio 自动生成
由 RT Thread Studio 自动生成,无需修改任何文件或者简单定义几个宏即可直接使用的驱动,如 GPIO,UART,I2C,SPI,SDIO 和 ETH 等。
使用 RT-Thread Studio 新建完整版工程时,用户不需要修改任何代码
使用hal库实现
没有对接到设备驱动框架,可直接使用 HAL 库函数进行开发的驱动,如 DAC,FSMC 等。
使用rtthread studio自动生成的外设驱动
注:增加修改外设通过RT-Thread Setting和 board.h文件进行配置。配置完成烧写运行均可通过list_device命令进行查看外设驱动是否已经注册。
gpio外设
使用 PIN 驱动需要使用 GET_PIN 获取相应的引脚编号,获取到引脚编号后,可使用 rt_pin_write 等函数来操作引脚。 例如,stm32l475-atk-pandora 开发板的 LED 所接的引脚为 PE7,所以修改为
#define LED0_PIN GET_PIN(E, //GPIO PORT
7) //GPIO PIN
USART外设
由于rtthread 默认启用了uart外设进行debug输出;默认使用 UART1 进行输出,若要修改为串口 2 (TX->PA2、RX->PA3)进行输出,则在 board.h 中定义宏 BSP_USING_UART2,并将串口 2 对应的引脚信息修改为实际所使用的引脚即可
新增串口只需要在 board.h 文件中定义相关串口的宏定义 BSP_USING_UARTx 及修改引脚信息即可,新增串口的步骤总结如下
1、新增对应串口的宏定义,如 BSP_USING_UART1、BSP_USING_UART2等。
2、修改串口 TX/RX 所使用的端口,如 “PA9”、"PA10"等。
3、基于修改控制台章节新增串口 1 的示例如下
#define BSP_USING_UART1
#define BSP_UART1_TX_PIN "PA9"
#define BSP_UART1_RX_PIN "PA10"
#define BSP_USING_UART2
#define BSP_UART2_TX_PIN "PA2"
#define BSP_UART2_RX_PIN "PA3"
如果需要使用串口 DMA 只需要在 board.h 文件中定义如下宏即可。
#define BSP_UARTx_RX_USING_DMA
#define BSP_UARTx_TX_USING_DMA
UARTx 表示的是哪个串口需要使用 DMA,使用的是 DMA 的发送还是接收功能。
I2C外设
软件I2C,在 board.h 文件中定义软件 I2C 相关的宏
#define BSP_USING_I2C1 /* 使用 I2C1 总线 */
#define BSP_I2C1_SCL_PIN GET_PIN(C, 1) /* SCL -> PC1 */
#define BSP_I2C1_SDA_PIN GET_PIN(D, 6) /* SDA -> PD6 */
SPI外设
在 board.h 文件中定义 SPI 总线相关的宏,本例中使用 SPI3 总线,只需定义如下宏即可
#define BSP_USING_SPI3
在 stm32xxxx_hal_config.h 文件中打开对 SPI 的支持,也就是取消掉 HAL_SPI_MODULE_ENABLED 这个宏定义的注释,如下所示:
#define HAL_SPI_MODULE_ENABLED
定义了 BSP_USING_SPI3 宏之后,drv_spi.c 文件就会参与编译,该文件只是配置了 SPI 的工作方式和传输函数,具体 SPI 外设的时钟和引脚的初始化需要借助 STM32CubeMx 生成的代码。
例如 stm32l475-atk-pandora 开发板的 SPI3 外设连接了一个 LCD 屏幕,所以需要将 CubeMx 生成的 SPI3 的初始化代码(一般在 stm32_xxxx_hal_msp.c 文件中)复制到自己工程的 board.c 文件的末尾,使之参与编译
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance == SPI3)
{
/* USER CODE BEGIN SPI3_MspInit 0 */
/* USER CODE END SPI3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI3 GPIO Configuration
PC11 ------> SPI3_MISO
PB3 (JTDO-TRACESWO) ------> SPI3_SCK
PB5 ------> SPI3_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN SPI3_MspInit 1 */
/* USER CODE END SPI3_MspInit 1 */
}
}
如果需要注册更多的 SPI 总线设备,只需参考 board.h 文件中 SPI 相关的宏定义并拷贝引脚初始化函数即可。
ETH外设
ETH 设备驱动的开发可总结为如下:
1、新建 RT-Thread 完整版项目
2、board.h中定义 BSP_USING_ETH 和 PHY 相关的宏
3、board.c中初始化 ETH 相关的引脚和时钟
4、stm32xxxx_hal_config.h中打开 HAL 库函数对 ETH 的支持
5、board.c 中实现自己的 PHY 复位函数
6、配置 lwIP 协议栈
定位到工程文件 board.h 中 ETH 配置说明部分,按照注释部分的说明分别定义 BSP_USING_ETH 和 PHY 相关的宏,本例中使用板载以太网 PHY 芯片为 LAN8720A, 所以 ETH 相关的宏定义如下 :
#define BSP_USING_ETH
#ifdef BSP_USING_ETH
#define PHY_USING_LAN8720A
#endif
定义了 BSP_USING_ETH 宏之后,drv_eth.c 文件就会参与编译,该文件只是配置了 ETH 的工作方式和传输函数等,具体 ETH 外设的时钟和引脚的初始化需要借助 STM32CubeMx 生成的代码。
将 STM32CubeMx 工具生成的 ETH 引脚和时钟初始化代码(一般在 stm32_xxxx_hal_msp.c 文件中)复制到自己工程的 board.c 文件的末尾,使之参与编译,如下所示:
void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(heth->Instance==ETH)
{
/* USER CODE BEGIN ETH_MspInit 0 */
/* USER CODE END ETH_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_ETH_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PG11 ------> ETH_TX_EN
PG13 ------> ETH_TXD0
PG14 ------> ETH_TXD1
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* USER CODE BEGIN ETH_MspInit 1 */
/* USER CODE END ETH_MspInit 1 */
}
}
在 stm32_xxxx_hal_config.h 文件中打开对 ETH 的支持,也就是取消掉 HAL_ETH_MODULE_ENABLED 这个宏定义的注释,如下所示:
#define HAL_ETH_MODULE_ENABLED
实现PHY复位函数:
在 drv_eth.c 文件中会调用 phy_reset 函数,该函数需要根据自己的实际情况进行实现,本例中 PHY 的复位引脚接在了 PD3 引脚,所以复位函数的实现如下所示 :
#include <rtdevice.h>
#define RESET_IO GET_PIN(D, 3)
void phy_reset(void)
{
rt_pin_mode(RESET_IO, PIN_MODE_OUTPUT);
rt_pin_write(RESET_IO, PIN_HIGH);
rt_thread_mdelay(50);
rt_pin_write(RESET_IO, PIN_LOW);
rt_thread_mdelay(50);
rt_pin_write(RESET_IO, PIN_HIGH);
}
配置 lwIP 协议栈
打开 RT-Thread Settings 文件,在图形化配置界面中左键单击 lwIP 图标即可打开 lwIP 协议栈的支持(组件开启,相应的图标会高亮)。
使用hal库实现外设驱动
1、使用 RT-Thread Studio 新建 RT-Thread 工程
2、使用 STM32CubeMx 配置外设和系统时钟
3、复制 stm32xxxx_hal_msp.c 函数
4、修改 stm32xxxx_hal_config.h 文件,打开相应外设支持。
5、替换 board.c 文件中时钟配置函数
6、使用外设
使用cubemx新建目标板卡工程
将 CubeMx 生成的代码 stm32l4xx_hal_msp.c 函数复制到 RT-Thread Studio 生成的工程中,并参与工程编译。复制完成后的结果如下图所示
由于我们并没有使用 CubeMx 生成的工程,所以这里需要将 stm32l4xx_hal_msp.c 文件中 #include “main.h” 替换为 #include “board.h”。
打开 HAL 库配置文件对应外设的支持宏
需要在 stm32l4xx_hal_config.h 文件使能相关外设模块
使用hal库在rtthread编写外设功能代码
void adc_init(void)
{
}