Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
PIN_GPIO通用驱动
个人对pin设备驱动的理解
发布于 2021-08-31 18:09:19 浏览:1712
订阅该版
阅读多个BSP对PIN驱动的实现,个人觉得实现pin驱动可以归纳成两个关键问题: 1. **如何将rt-thread中的编号pin与实际的管脚对应起来?** 2. **如何将rt-thread中的编号pin绑定芯片的外部中断(EXTI)?** 第一个问题影响着以下的接口函数: ~~~c void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode); void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value); int (*pin_read)(struct rt_device *device, rt_base_t pin); rt_base_t (*pin_get)(const char *name); ~~~ 第二个问题影响以下的接口函数: ~~~c rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args); rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin); rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled); ~~~ 事实上,如果不使用pin的中断触发处理,不实现第二个问题也是可以的,按我自己的经验,pin用的最多的地方就是模拟i2c和spi的cs管脚。 好,回归到第一个问题上,学过数据库的基本上弄过XX管理系统,然后数据库建立一堆表。rt-thread中的pin如何和实际的管脚对应起来呢,以下三个关键字段: * rt_base_t pin * GPIO_TypeDef* GPIOx * rt_uint16_t GPIO_Pin rt-thread的pin编号,芯片厂商的驱动库的GPIO端口(A,B,..)和管脚GPIO_Pin(0~15),这样就相当于建立了一个表。到此,熟悉数据库封装接口的轻车熟路了,从表建立实体对象,以及一系列的操作。 以我移植的ch32f103c8为例,建立一张pin info表,具有以下的字段: * pin * gpio_pin * portsource * pinsource * gpio 构建的对象: ~~~c struct pin_info { rt_base_t pin; rt_uint32_t gpio_pin; rt_uint32_t portsource; rt_uint32_t pinsource; GPIO_TypeDef *gpio; }; ~~~ 表有了,那数据从哪来呢? 看ch32f103的datasheet关于GPIO描述, "系统提供了 4 组 GPIO 端口,共 51 个 GPIO 引脚。" 通常是16管脚一组GPIO, 16 x 3 + 3 = GPIOA(0~15), GPIOB(0~15), GPIOC(0~15), GPIOD(0~2) | pin | gpio_pin | portsource | pinsource| gpio| |----|----|----|----|----| |0|GPIO_Pin_0|GPIO_PortSourceGPIOA|GPIO_PinSource0|GPIOA |1|GPIO_Pin_1|GPIO_PortSourceGPIOA|GPIO_PinSource1|GPIOA |2|GPIO_Pin_2|GPIO_PortSourceGPIOA|GPIO_PinSource2|GPIOA |3|GPIO_Pin_3|GPIO_PortSourceGPIOA|GPIO_PinSource3|GPIOA |4|GPIO_Pin_4|GPIO_PortSourceGPIOA|GPIO_PinSource4|GPIOA |5|GPIO_Pin_5|GPIO_PortSourceGPIOA|GPIO_PinSource5|GPIOA |6|GPIO_Pin_6|GPIO_PortSourceGPIOA|GPIO_PinSource6|GPIOA |7|GPIO_Pin_7|GPIO_PortSourceGPIOA|GPIO_PinSource7|GPIOA |8|GPIO_Pin_8|GPIO_PortSourceGPIOA|GPIO_PinSource8|GPIOA |9|GPIO_Pin_9|GPIO_PortSourceGPIOA|GPIO_PinSource9|GPIOA |10|GPIO_Pin_10|GPIO_PortSourceGPIOA|GPIO_PinSource10|GPIOA |11|GPIO_Pin_11|GPIO_PortSourceGPIOA|GPIO_PinSource11|GPIOA |12|GPIO_Pin_12|GPIO_PortSourceGPIOA|GPIO_PinSource12|GPIOA |13|GPIO_Pin_13|GPIO_PortSourceGPIOA|GPIO_PinSource13|GPIOA |14|GPIO_Pin_14|GPIO_PortSourceGPIOA|GPIO_PinSource14|GPIOA |15|GPIO_Pin_15|GPIO_PortSourceGPIOA|GPIO_PinSource15|GPIOA |16|GPIO_Pin_0|GPIO_PortSourceGPIOB|GPIO_PinSource0|GPIOB |17|GPIO_Pin_1|GPIO_PortSourceGPIOB|GPIO_PinSource1|GPIOB 这样一堆数据就给它一个数组装着,我习惯叫它为list: ~~~c static const struct pin_info pin_info_list[] ~~~ 录入方式在C语言就对应着这样的一个宏操作 ~~~c #define ASSIGN_PIN(pin, group, gpio_pin) \ { \ pin, GPIO_Pin_##gpio_pin, GPIO_PortSourceGPIO##group, GPIO_PinSource##gpio_pin, GPIO##group \ } #define NOT_USE_PIN \ { \ -1, 0, 0, 0, 0 \ } ~~~ 一看到list之类的,基本上会涉及增删改查,像这样写死的数据那就只能查查数据的操作了: ~~~c static const struct pin_info *pin_info_list_find(rt_base_t pin) { const struct pin_info *item = RT_NULL; if ((pin != -1) && (pin < ITEM_NUM(pin_info_list))) { item = pin_info_list[pin].pin == -1 ? RT_NULL : &pin_info_list[pin]; } return item; } static rt_base_t pin_info_list_find_pin(rt_uint16_t portsource, rt_uint16_t pinsource) { rt_base_t pin = -1; int index; for (index = 0; index < ITEM_NUM(pin_info_list); index++) { if (pin_info_list[index].portsource == portsource && pin_info_list[index].pinsource == pinsource) { pin = pin_info_list[index].pin; break; } } return pin; } ~~~ 第一个问题就解决好了。 ~~~c void ch32f1_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode) { const struct pin_info *item; GPIO_InitTypeDef gpio_initstruct; item = pin_info_list_find(pin); if (item == RT_NULL) { return; } ......... void ch32f1_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value) { const struct pin_info *item; item = pin_info_list_find(pin); if (item == RT_NULL) { return; } GPIO_WriteBit(item->gpio, item->gpio_pin, (BitAction)value); } int ch32f1_pin_read(rt_device_t dev, rt_base_t pin) { const struct pin_info *item; item = pin_info_list_find(pin); if (item == RT_NULL) { return PIN_LOW; } return GPIO_ReadInputDataBit(item->gpio, item->gpio_pin); } ~~~ 现在开始解决第二个问题,看看rt-thread的一个pin中断处理handler对象 ~~~c struct rt_pin_irq_hdr { rt_int16_t pin; rt_uint16_t mode; void (*hdr)(void *args); void *args; }; ~~~ 这里面有个pin,前面已经解决第一个问题,有了这个pin,操作实际管脚没啥问题。同样,把rt_pin_irq_hdr展开得到一些字段,加上一条外部中断线字段,不就可以了么。这个pin看起来像不像表的“外键”? 构建一个表exti_line_irq的字段: * nvic_priority * nvic_subpriority * exit_line * irqn * use * pin * mode * hdr * args | nvic_priority | nvic_subpriority | exit_line | irqn | use | pin | mode | hdr | args | | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | |5|0|EXTI_Line0|EXTI0_IRQn|0|-1|null|null|null| |5|0|EXTI_Line1|EXTI1_IRQn|0|-1|null|null|null| |5|0|EXTI_Line2|EXTI2_IRQn|0|-1|null|null|null| 这样理解可以,但写的时候既然有rt_pin_irq_hdr这个那就可以构建这样的对象: ~~~c struct exti_line_irq { rt_uint16_t nvic_priority; rt_uint16_t nvic_subpriority; rt_uint32_t exit_line; IRQn_Type irqn; int use; struct rt_pin_irq_hdr bind_irq_hdr; }; ~~~ 给它一个数组装着: ~~~c static struct exti_line_irq exti_line_irq_list[] ~~~ 当然也就有对其的增删改查,额,只有一个查的操作: ~~~c static struct exti_line_irq *exti_line_irq_list_find(rt_int16_t pin) { struct exti_line_irq *item = RT_NULL; int index; for (index = 0; index < ITEM_NUM(exti_line_irq_list); index++) { if (exti_line_irq_list[index].bind_irq_hdr.pin == pin) { item = &exti_line_irq_list[index]; break; } } return item; } ~~~ 填入/删除“外键”,完成绑定/取消绑定 ~~~c static rt_err_t exti_line_irq_list_bind(struct rt_pin_irq_hdr *irq_hdr) { rt_err_t ret = RT_EFULL; rt_base_t level; struct exti_line_irq *item; int index; for (index = 0; index < ITEM_NUM(exti_line_irq_list); index++) { if (exti_line_irq_list[index].bind_irq_hdr.pin == -1 && exti_line_irq_list[index].use != -1) { item = &exti_line_irq_list[index]; break; } } if (item != RT_NULL) { level = rt_hw_interrupt_disable(); item->bind_irq_hdr.pin = irq_hdr->pin; item->bind_irq_hdr.mode = irq_hdr->mode; item->bind_irq_hdr.hdr = irq_hdr->hdr; item->bind_irq_hdr.args = irq_hdr->args; rt_hw_interrupt_enable(level); ret = RT_EOK; } return ret; } static rt_err_t exti_line_irq_list_unbind(rt_int16_t pin) { rt_err_t ret = RT_EEMPTY; rt_base_t level; struct exti_line_irq *item; item = exti_line_irq_list_find(pin); if (item != RT_NULL) { level = rt_hw_interrupt_disable(); item->bind_irq_hdr.pin = -1; rt_hw_interrupt_enable(level); ret = RT_EOK; } return ret; } ~~~ 第二个问题影响的接口函数也就解决了 ~~~c rt_err_t ch32f1_pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args) { struct rt_pin_irq_hdr bind_item; bind_item.pin = pin; bind_item.mode = mode; bind_item.hdr = hdr; bind_item.args = args; return exti_line_irq_list_bind(&bind_item); } rt_err_t ch32f1_pin_detach_irq(struct rt_device *device, rt_int32_t pin) { return exti_line_irq_list_unbind(pin); } rt_err_t ch32f1_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled) { struct exti_line_irq *find; const struct pin_info *item; rt_base_t level; EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; find = exti_line_irq_list_find(pin); if (find == RT_NULL) return RT_EINVAL; item = pin_info_list_find(pin); if (item == RT_NULL) return RT_EINVAL; if (enabled == PIN_IRQ_ENABLE) { level = rt_hw_interrupt_disable(); GPIO_EXTILineConfig(item->portsource, item->pinsource); EXTI_InitStructure.EXTI_Line = find->exit_line; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; .... ~~~ * 接口pin_get 为什么pin_info有portsource, pinsource呢? 除了用于GPIO_EXTILineConfig(item->portsource, item->pinsource)外, 投机取巧用portsource, pinsource值实现pin_get接口 ~~~c /* GPIO_Port_Sources */ #define GPIO_PortSourceGPIOA ((uint8_t)0x00) #define GPIO_PortSourceGPIOB ((uint8_t)0x01) #define GPIO_PortSourceGPIOC ((uint8_t)0x02) #define GPIO_PortSourceGPIOD ((uint8_t)0x03) #define GPIO_PortSourceGPIOE ((uint8_t)0x04) #define GPIO_PortSourceGPIOF ((uint8_t)0x05) #define GPIO_PortSourceGPIOG ((uint8_t)0x06) /* GPIO_Pin_sources */ #define GPIO_PinSource0 ((uint8_t)0x00) #define GPIO_PinSource1 ((uint8_t)0x01) ... ~~~ ~~~c /*PX.XX*/ rt_base_t ch32f1_pin_get(const char *name) { rt_uint16_t portsource, pinsource; int sz; sz = rt_strlen(name); if (sz == 4) { portsource = name[1] - 0x41; pinsource = name[3] - 0x30; return pin_info_list_find_pin(portsource, pinsource); } if (sz == 5) { portsource = name[1]; pinsource = (name[3] - 0x30) * 10 + (name[4] - 0x30); return pin_info_list_find_pin(portsource, pinsource); } return -1; } ~~~~ 至此,接口已实现好,其实只要知道问题就好解决了。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
charlown.cai
这家伙很懒,什么也没写!
文章
4
回答
53
被采纳
0
关注TA
发私信
相关文章
1
PIN绑定引脚中断回调函数没有反应
2
rtthread PIN设备
3
关于引脚宏定义的一些疑惑
4
关于gpio引脚实在不懂了,求大家帮助
5
GET_PIN(A, 1) 提示 'A' 未定义
6
关于4.0.2版本中STM32的PIN设备外部中断的相关问题
7
自己按照官方手册 在drv_gpio.c里面找不到PIN脚信息
8
关于多个PIN设备同时读写的问题
9
翻车在一个GPIO上 开启pin中断 导致程序卡死
10
外部中断回调函数执行问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
10
个答案
3
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
lizimu
2
篇文章
9
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部