2.1 rtthread pin设备详解
目录
1、PIN设备说明
2、PIN设备的初始化及注册
3、PIN设备的操作
3.1 获取管脚编号的实现
3.1.1使用API
3.1.2使用宏定义
3.1.3查看驱动文件
3.2 设置引脚模式
3.3 输出控制
3.4 输入获取
3.5 中断回调的绑定
3.6 中断回调的解绑
3.7 中断的使能和禁用
3.8 中断回调函数的实现
1、PIN设备说明
rtthread通过pin.c和pin.h两个文件进行pin设备的管理。通过pin.h中的结构体rt_device_pin进行pin设备的定义,pin设备继承自设备基类rt_device,rt_device继承自rt_object基类,继承关系如下
PIN设备通过结构体的定义实现了对rt_device设备基类的继承,结构体中的成员rt_pin_ops来实现pin设备的具体操作实现。
struct rt_device_pin
{struct rt_device parent;const struct rt_pin_ops *ops;
};
struct rt_pin_ops
{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_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);rt_base_t (*pin_get)(const char *name);
};
2、PIN设备的初始化及注册
启动阶段rtthread会根据是否进行了RT_USING_PIN定义,在hw_board_init函数中进行pin设备的初始化,在rt_hw-pin_init函数中首先进行了时钟的初始化,最终调用函数rt_device_pin_register来实现STM32的IO和pin设备的关联及设备的挂载。
/*
进行PIN设备的结构体定义
*/
static struct rt_device_pin _hw_pin; int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data)
{/*PIN设备的父设备,设备基类的类型进行定义,定义为RT_Device_Class_Miscellaneous,杂类*/_hw_pin.parent.type = RT_Device_Class_Miscellaneous;/*收发回调函数为空*/_hw_pin.parent.rx_indicate = RT_NULL;_hw_pin.parent.tx_complete = RT_NULL;/*设备基类的初始化灯相关函数指针赋值。*/
#ifdef RT_USING_DEVICE_OPS_hw_pin.parent.ops = &pin_ops;
#else_hw_pin.parent.init = RT_NULL;_hw_pin.parent.open = RT_NULL;_hw_pin.parent.close = RT_NULL;_hw_pin.parent.read = _pin_read;_hw_pin.parent.write = _pin_write;_hw_pin.parent.control = _pin_control;
#endif/*PIN设备ops,即STM32的具体实现方式进行赋值。*/_hw_pin.ops = ops;_hw_pin.parent.user_data = user_data;/*设备注册*//* register a character device */rt_device_register(&_hw_pin.parent, name, RT_DEVICE_FLAG_RDWR);return 0;
}
rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL)中参数_stm32_pin_ops为rt_pin_ops,具体定义内容如下,实现了GPIO的模式配置,输入输出控制,中断控制和管脚查找等功能在STM32下得具体实现方式函数指针的定义。
const static struct rt_pin_ops _stm32_pin_ops =
{stm32_pin_mode,stm32_pin_write,stm32_pin_read,stm32_pin_attach_irq,stm32_pin_dettach_irq,stm32_pin_irq_enable,stm32_pin_get,
};
3、PIN设备的操作
PIN设备对外提供如下接口函数
函数 | 描述 |
---|---|
rt_pin_get() | 获取引脚编号 |
rt_pin_mode() | 设置引脚模式 |
rt_pin_write() | 设置引脚电平 |
rt_pin_read() | 读取引脚电平 |
rt_pin_attach_irq() | 绑定引脚中断回调函数 |
rt_pin_irq_enable() | 使能引脚中断 |
rt_pin_detach_irq() | 脱离引脚中断回调函数 |
3.1 获取管脚编号的实现
RT-Thread 提供的引脚编号需要和芯片的引脚号区分开来,它们并不是同一个概念,引脚编号由 PIN 设备驱动程序定义,和具体的芯片相关。管脚序号是后续其他输入输出中断函数实现的一个重要参数。STM32的驱动中对GPIOA(0-15)到GPIOx(0-15)进行了按顺序的编号操作。
RTT官方文档描述针对STM32的GPIO驱动drv_gpio.c中针对管脚编号提供了三种方式进行实现:
3.1.1使用API
此处需要注意
旧版本的drv_gpio.c文件在_stm32_pin_ops 中并没有定义函数stm32_pin_get,的实现,所以旧版本的驱动无法使用API获取到管脚编号。新建工程时,系统使用的驱动任为旧版本的
gpio驱动所以需要更新,可以从gitee进行文件下载bsp/stm32/libraries/HAL_Drivers/drv_gpio.c · RT-Thread/rt-thread - Gitee.com。具体实现方式函数如下
/*根据输入字符串的端口号A-Z,转换为数值0-25根据输入字符串的管脚号0-15,转换为数值0-15将两者结合端口号为高位,管脚号为地位
*/
static rt_base_t stm32_pin_get(const char *name)
{rt_base_t pin = 0;int hw_port_num, hw_pin_num = 0;int i, name_len;name_len = rt_strlen(name); if ((name_len < 4) || (name_len >= 6)) //进行字符串长度验证PA.0 PA.15 最短4,最长5{return -RT_EINVAL;}if ((name[0] != 'P') || (name[2] != '.')) //字符串第一个必须为P 第三个必须为.{return -RT_EINVAL;}if ((name[1] >= 'A') && (name[1] <= 'Z')) //端口范围在A-Z{hw_port_num = (int)(name[1] - 'A'); //端口编号计算,A-Z转换为0-25}else{return -RT_EINVAL;}for (i = 3; i < name_len; i++) //根据字符串的第4个进行编号转换PA.0=0 PA.15 = 15{hw_pin_num *= 10;hw_pin_num += name[i] - '0';}pin = PIN_NUM(hw_port_num, hw_pin_num); //进行最后引脚编号的处理return pin;
}
最终调用宏定义如下来进行引脚编号的获取
#define PIN_NUM(port, no) (((((port) & 0xFu) << 4) | ((no) & 0xFu)))
测算结果如下表,后续IO以此类推
name | port | no | result | name | port | no | result |
PA.0 | 0 | 0 | 0 | PB.0 | 1 | 0 | 16 |
PA.1 | 0 | 1 | 1 | PB.1 | 1 | 1 | 17 |
PA.2 | 0 | 2 | 2 | PB.2 | 1 | 2 | 18 |
PA.3 | 0 | 3 | 3 | PB.3 | 1 | 3 | 19 |
PA.4 | 0 | 4 | 4 | PB.4 | 1 | 4 | 20 |
PA.5 | 0 | 5 | 5 | PB.5 | 1 | 5 | 21 |
PA.6 | 0 | 6 | 6 | PB.6 | 1 | 6 | 22 |
PA.7 | 0 | 7 | 7 | PB.7 | 1 | 7 | 23 |
PA.8 | 0 | 8 | 8 | PB.8 | 1 | 8 | 24 |
PA.9 | 0 | 9 | 9 | PB.9 | 1 | 9 | 25 |
PA.10 | 0 | 10 | 10 | PB.10 | 1 | 10 | 26 |
PA.11 | 0 | 11 | 11 | PB.11 | 1 | 11 | 27 |
PA.12 | 0 | 12 | 12 | PB.12 | 1 | 12 | 28 |
PA.13 | 0 | 13 | 13 | PB.13 | 1 | 13 | 29 |
PA.14 | 0 | 14 | 14 | PB.14 | 1 | 14 | 30 |
PA.15 | 0 | 15 | 15 | PB.15 | 1 | 15 | 31 |
3.1.2使用宏定义
针对STM32,RTT提供了宏定义GET_PIN来进行管脚编号的获取,再未更新drv_gpio驱动前,该定义再drv_common.h中进行了定义,更新驱动后在drv_gpio.h中也进行了定义,两者定义相同。内容如下。
//drv_common.h中的宏定义
#define __STM32_PORT(port) GPIO##port##_BASE
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)//drv_gpio.h中的宏定义
#define __STM32_PORT(port) GPIO##port##_BASE#if defined(SOC_SERIES_STM32MP1)
#define GET_PIN(PORTx,PIN) (GPIO##PORTx == GPIOZ) ? (176 + PIN) : ((rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x1000UL) )) + PIN))
#else
#define GET_PIN(PORTx,PIN) (rt_base_t)((16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) )) + PIN)
#endif
如上图,对GET_PIN宏定义进行了重复定义,可以看出drv_gpio.h中对宏定义进行了预编译,包含了STM32MP1的支持。
全局搜索GET_PIN的使用情况如下
board.h、drv_gpio.h和drv_usart.c中均进行了drv_common.h的包含。仅在drv_gpio.c文件中进行了drv_gpio.h的包含。所以我们可以将drv_gpio.h中关于GET_PIN的相关宏定义进行删除(不涉及STM32MP1的使用)。来保证宏定义的唯一性。
宏定义根据参数portx进行管脚端口的地址获取,将A-Z分别转换为0-25。参数PIN为端口下得具体IO。最终转换结果为端口序号*16+IO编号。与API转换结果相同。
宏定义 | PORTx | 16 * ( ((rt_base_t)__STM32_PORT(PORTx) - (rt_base_t)GPIOA_BASE)/(0x0400UL) ) | PIN | result | |
GET_PIN(A, 0) | GPIOA_BASE | D3_AHB1PERIPH_BASE + 0x0000UL | 0 | 0 | 0 |
GET_PIN(A, 1) | GPIOA_BASE | D3_AHB1PERIPH_BASE + 0x0000UL | 0 | 0 | 0 |
GET_PIN(A, 2) | GPIOA_BASE | D3_AHB1PERIPH_BASE + 0x0000UL | 0 | 0 | 0 |
GET_PIN(A, 3) | GPIOA_BASE | D3_AHB1PERIPH_BASE + 0x0000UL | 0 | 0 | 0 |
GET_PIN(B, 0) | GPIOB_BASE | D3_AHB1PERIPH_BASE + 0x0400UL | 1 | 0 | 16 |
GET_PIN(B, 1) | GPIOB_BASE | D3_AHB1PERIPH_BASE + 0x0400UL | 1 | 1 | 17 |
GET_PIN(B, 2) | GPIOB_BASE | D3_AHB1PERIPH_BASE + 0x0400UL | 1 | 2 | 18 |
3.1.3查看驱动文件
旧版本的drv_gpio驱动提供了管脚与编号的对应定义,可以通过查看直接进行管脚序号的定义。
新版本驱动更新了管脚编号识别逻辑,不在提供该驱动文件查看的方式。
3.2 设置引脚模式
rtt通过rt_pin_mode进行管脚模式的配置
void rt_pin_mode(rt_base_t pin, rt_base_t mode)
{RT_ASSERT(_hw_pin.ops != RT_NULL);_hw_pin.ops->pin_mode(&_hw_pin.parent, pin, mode);
}
最终调用的函数为pin设备类的ops下的pin_mode函数,在初始阶段该函数指针设置为了stm32_pin_mode,具体实现如下
/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin))) 转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu)) 转换为0-15来进行序号识别 2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static void stm32_pin_mode(rt_device_t dev, rt_base_t pin, rt_base_t mode)
{GPIO_InitTypeDef GPIO_InitStruct;//验证端口是否大于最大端口,是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return;}//配置端口IO为默认推挽输出,不上下拉,输出速度HIGHGPIO_InitStruct.Pin = PIN_STPIN(pin);GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;//根据实际传入参数的模式来进行配置if (mode == PIN_MODE_OUTPUT){/* output setting */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;}else if (mode == PIN_MODE_INPUT){/* input setting: not pull. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;}else if (mode == PIN_MODE_INPUT_PULLUP){/* input setting: pull up. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLUP;}else if (mode == PIN_MODE_INPUT_PULLDOWN){/* input setting: pull down. */GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_PULLDOWN;}else if (mode == PIN_MODE_OUTPUT_OD){/* output setting: od. */GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_NOPULL;}//调用库函数进行初始化HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);
}
3.3 输出控制
rtt通过rt_pin_write进行管脚模式的配置。
void rt_pin_write(rt_base_t pin, rt_base_t value)
{RT_ASSERT(_hw_pin.ops != RT_NULL);_hw_pin.ops->pin_write(&_hw_pin.parent, pin, value);
}
最终调用的函数为pin设备类的ops下的pin_write函数,在初始阶段该函数指针设置为了stm32_pin_write,具体实现如下
/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin))) 转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu)) 转换为0-15来进行序号识别 2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static void stm32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value)
{GPIO_TypeDef *gpio_port;uint16_t gpio_pin;if (PIN_PORT(pin) < PIN_STPORT_MAX){//获取端口gpio_port = PIN_STPORT(pin);//获取IO编号gpio_pin = PIN_STPIN(pin);//库函数输出HAL_GPIO_WritePin(gpio_port, gpio_pin, (GPIO_PinState)value);}
}
3.4 输入获取
rtt通过rt_pin_read进行管脚模式的配置。
int rt_pin_read(rt_base_t pin)
{RT_ASSERT(_hw_pin.ops != RT_NULL);return _hw_pin.ops->pin_read(&_hw_pin.parent, pin);
}
最终调用的函数为pin设备类的ops下的pin_read函数,在初始阶段该函数指针设置为了stm32_pin_read,具体实现如下
/*1、管脚序号的识别通过宏定义#define PIN_STPIN(pin) ((uint16_t)(1u << PIN_NO(pin))) 转换为位信息#define PIN_NO(pin) ((uint8_t)((pin) & 0xFu)) 转换为0-15来进行序号识别 2、端口识别#define PIN_STPORT(pin) ((GPIO_TypeDef *)(GPIOA_BASE + (0x400u * PIN_PORT(pin))))来进行引脚编号到端口结构体地址的转换。3、最终调用库函数进行GPIO的配置。
*/
static int stm32_pin_read(rt_device_t dev, rt_base_t pin)
{GPIO_TypeDef *gpio_port;uint16_t gpio_pin;int value = PIN_LOW;if (PIN_PORT(pin) < PIN_STPORT_MAX){gpio_port = PIN_STPORT(pin);gpio_pin = PIN_STPIN(pin);value = HAL_GPIO_ReadPin(gpio_port, gpio_pin);}return value;
}
3.5 中断回调的绑定
rtt通过rt_pin_attach_irq进行中断回调的绑定。
rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode,void (*hdr)(void *args), void *args)
{RT_ASSERT(_hw_pin.ops != RT_NULL);if(_hw_pin.ops->pin_attach_irq){return _hw_pin.ops->pin_attach_irq(&_hw_pin.parent, pin, mode, hdr, args);}return -RT_ENOSYS;
}
最终调用的函数为pin设备类的ops下的pin_attach_irq函数,在初始阶段该函数指针设置为了stm32_pin_attach_irq,具体实现如下
/*该函数不进行底层STM32的外部中断的实际操作。进行了pin设备的中断相关结构体赋值。
*/
static rt_err_t stm32_pin_attach_irq(struct rt_device *device, rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void *args), void *args)
{rt_base_t level;rt_int32_t irqindex = -1;//识别端口号是否正确if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}/*进行中断序号的识别1、通过管脚序号进行了中断序号的识别,首先通过PIN_STDPIN进行了位的转换2、通过函数bit2bitno实现了位序号的识别。3、实际可以通过PIN_NO来替代上述流程来进行识别*/irqindex = bit2bitno(PIN_STPIN(pin));/*判断中断序号是否合法*/if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}/*进行pin设备的中断模式和回调函数的赋值*/level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == pin &&pin_irq_hdr_tab[irqindex].hdr == hdr &&pin_irq_hdr_tab[irqindex].mode == mode &&pin_irq_hdr_tab[irqindex].args == args){rt_hw_interrupt_enable(level);return RT_EOK;}if (pin_irq_hdr_tab[irqindex].pin != -1){rt_hw_interrupt_enable(level);return RT_EBUSY;}pin_irq_hdr_tab[irqindex].pin = pin;pin_irq_hdr_tab[irqindex].hdr = hdr;pin_irq_hdr_tab[irqindex].mode = mode;pin_irq_hdr_tab[irqindex].args = args;rt_hw_interrupt_enable(level);return RT_EOK;
}
3.6 中断回调的解绑
rtt通过rt_pin_detach_irq进行管脚模式的配置。
rt_err_t rt_pin_detach_irq(rt_int32_t pin)
{RT_ASSERT(_hw_pin.ops != RT_NULL);if(_hw_pin.ops->pin_detach_irq){return _hw_pin.ops->pin_detach_irq(&_hw_pin.parent, pin);}return -RT_ENOSYS;
}
最终调用的函数为pin设备类的ops下的pin_detach_irq函数,在初始阶段该函数指针设置为了stm32_pin_dettach_irq,具体实现如下
static rt_err_t stm32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin)
{rt_base_t level;rt_int32_t irqindex = -1;//识别输入端口是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}/*进行中断序号的识别1、通过管脚序号进行了中断序号的识别,首先通过PIN_STDPIN进行了位的转换2、通过函数bit2bitno实现了位序号的识别。3、实际可以通过PIN_NO来替代上述流程来进行识别*/irqindex = bit2bitno(PIN_STPIN(pin));/*判断中断序号是否合法*/if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}/*中断模式和中断管脚回调函数的复位*/level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == -1){rt_hw_interrupt_enable(level);return RT_EOK;}pin_irq_hdr_tab[irqindex].pin = -1;pin_irq_hdr_tab[irqindex].hdr = RT_NULL;pin_irq_hdr_tab[irqindex].mode = 0;pin_irq_hdr_tab[irqindex].args = RT_NULL;rt_hw_interrupt_enable(level);return RT_EOK;
}
3.7 中断的使能和禁用
rtt通过rt_pin_irq_enable进行管脚模式的配置。
rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled)
{RT_ASSERT(_hw_pin.ops != RT_NULL);if(_hw_pin.ops->pin_irq_enable){return _hw_pin.ops->pin_irq_enable(&_hw_pin.parent, pin, enabled);}return -RT_ENOSYS;
}
最终调用的函数为pin设备类的ops下的pin_irq_enable函数,在初始阶段该函数指针设置为了stm32_pin_irq_enable,具体实现如下
static rt_err_t stm32_pin_irq_enable(struct rt_device *device, rt_base_t pin,rt_uint32_t enabled)
{const struct pin_irq_map *irqmap;rt_base_t level;rt_int32_t irqindex = -1;GPIO_InitTypeDef GPIO_InitStruct;//识别IO是否合法if (PIN_PORT(pin) >= PIN_STPORT_MAX){return -RT_ENOSYS;}//使能中断if (enabled == PIN_IRQ_ENABLE){//获取判断中断序号是否合法irqindex = bit2bitno(PIN_STPIN(pin));if (irqindex < 0 || irqindex >= ITEM_NUM(pin_irq_map)){return RT_ENOSYS;}level = rt_hw_interrupt_disable();if (pin_irq_hdr_tab[irqindex].pin == -1){rt_hw_interrupt_enable(level);return RT_ENOSYS;}//查表获取中断序号对应的内容irqmap = &pin_irq_map[irqindex];/*中断具体配置*/GPIO_InitStruct.Pin = PIN_STPIN(pin);GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;switch (pin_irq_hdr_tab[irqindex].mode){case PIN_IRQ_MODE_RISING:GPIO_InitStruct.Pull = GPIO_PULLDOWN;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;break;case PIN_IRQ_MODE_FALLING:GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;break;case PIN_IRQ_MODE_RISING_FALLING:GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;break;}HAL_GPIO_Init(PIN_STPORT(pin), &GPIO_InitStruct);//设置中断优先级HAL_NVIC_SetPriority(irqmap->irqno, 5, 0);HAL_NVIC_EnableIRQ(irqmap->irqno);pin_irq_enable_mask |= irqmap->pinbit;rt_hw_interrupt_enable(level);}//禁用中断else if (enabled == PIN_IRQ_DISABLE){irqmap = get_pin_irq_map(PIN_STPIN(pin));if (irqmap == RT_NULL){return RT_ENOSYS;}level = rt_hw_interrupt_disable();//复位管脚HAL_GPIO_DeInit(PIN_STPORT(pin), PIN_STPIN(pin));pin_irq_enable_mask &= ~irqmap->pinbit;
#if defined(SOC_SERIES_STM32F0) || defined(SOC_SERIES_STM32G0)if ((irqmap->pinbit >= GPIO_PIN_0) && (irqmap->pinbit <= GPIO_PIN_1)){if (!(pin_irq_enable_mask & (GPIO_PIN_0 | GPIO_PIN_1))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_2) && (irqmap->pinbit <= GPIO_PIN_3)){if (!(pin_irq_enable_mask & (GPIO_PIN_2 | GPIO_PIN_3))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_4) && (irqmap->pinbit <= GPIO_PIN_15)){if (!(pin_irq_enable_mask & (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else{HAL_NVIC_DisableIRQ(irqmap->irqno);}
#elseif ((irqmap->pinbit >= GPIO_PIN_5) && (irqmap->pinbit <= GPIO_PIN_9)){if (!(pin_irq_enable_mask & (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else if ((irqmap->pinbit >= GPIO_PIN_10) && (irqmap->pinbit <= GPIO_PIN_15)){if (!(pin_irq_enable_mask & (GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15))){HAL_NVIC_DisableIRQ(irqmap->irqno);}}else{HAL_NVIC_DisableIRQ(irqmap->irqno);}
#endifrt_hw_interrupt_enable(level);}else{return -RT_ENOSYS;}return RT_EOK;
}
3.8 中断回调函数的实现
在使能了外部中断后,STM32的底层在中断触发后会进行中断函数的调用如下函数。
- EXTI0_IRQHandler~EXTI4_IRQHandler
- EXTI9_5_IRQHandler
- EXTI15_10_IRQHandler
函数内部调用为HAL_GPIO_EXTI_IRQHandler。在该函数内部最终调用了回调函数HAL_GPIO_EXTI_Callback来进行回调函数的实现。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{pin_irq_hdr(bit2bitno(GPIO_Pin));
}
如上回调函数调用了pin_irq_hdr进行了与pin设备所绑定的回调函数的关联。
rt_inline void pin_irq_hdr(int irqno)
{if (pin_irq_hdr_tab[irqno].hdr){pin_irq_hdr_tab[irqno].hdr(pin_irq_hdr_tab[irqno].args);}
}
2.1 rtthread pin设备详解相关推荐
- RT-Thread pin设备驱动代码结构剖析
硬件测试平台:正点原子潘多拉STM32L4开发板 OS内核版本:4.0.0 注意:下面的示例代码是从原子提供的例程中摘录,因此可能与最新的RT-Thread源码有出入(因为RT-Thread源码在不断 ...
- RT-Thread Pin设备驱动API应用介绍
概要 本文主要涉及Pin驱动相关的API接口的简要介绍及使用示例,有兴趣深入了解Pin驱动程序框架可参考:RT-Thread pin设备驱动代码结构剖析 PIN设备的操作方法 应用程序通过RT-Thr ...
- 如何用树莓派连接语音模块,红外模块来控制红外设备详解
如何用树莓派连接语音模块,红外模块来控制红外设备详解 1.硬件设备 2.软件准备 3.解码 1.红外解码流程 1.连接红外设备(与TTL串口相连) 2.获取开关红外电器的码 4.我们使用树莓派如何和W ...
- OSI七层参考模型及其协议和各层设备详解
引言 我们在学习计算机网络的时候,都会接触到网络的分层模型,那么,这个分层模型是怎么来的呢? 本次博客,张大帅比将写出自己对于这个网络分层模型的详细理解 分层模型的理解 a.为什么需要分层,分层的作用 ...
- 芯片读取设备详解+U盘芯片flash读取分析实录_一篇看够
当我们在分析 IOT 设备,如智能摄像头.智能门锁.智能路由器等等产品时,采用传统的安全检测手段,如对 APP 的逆向.云端服务器的渗透测试.产品通信的抓包等方式可以获得部分的信息,但如果需要深入分析 ...
- 鸿蒙最新功能及承载设备详解:HarmonyOS 2及华为全场景新品发布会全纪录
6月2日,华为联手CSDN直播了"HarmonyOS 2及华为全场景新品发布会",老猿全程观看直播,并进行了回看,力争将发布会的核心内容在本文中概要性地呈现. 一.一生万物 万物归 ...
- RT-Thread记录(十三、I/O 设备模型之PIN设备)
讲完UART设备之后,我们已经熟悉RT-Thread I/O 设备模型了,回头看看基本的 PIN 设备. 目录 前言 一.PIN 设备模型解析 1.1 初识 GPIO 操作函数 1.2 PIN 设备框 ...
- RT-Thread学习笔记——PIN 设备
前言 本文主要学习RT-Thread的设备驱动框架之PIN 设备,这里以及后面更新的博客内容将不会详细介绍I/O 设备模型,当学习PIN 设备以及其他设备需要对I/O 设备模型有所了解,请和我一样刚学 ...
- c++获取串口设备名称_RTThread PIN设备学习笔记
前面我们学习了RTT的UART设备的使用,不得不说真的超级给力呀,不到100行秒杀任何MCU最原始的串口编程模式,不得不感叹RTT发展如此强大,文章链接: RT-Thread UART设备驱动框架初体 ...
最新文章
- HR问:“你能熬夜吗?”,你会如何回答?
- ORACLE 分区表 PARTITION table
- 数据可视化 -- Python
- flink streamGraph生成
- 自然语言处理项目之新闻主题分类Python实现
- linux纯文字界面,Linux入门 Part1: 使用控制台(1)-纯文本界面
- 中位数和顺序统计量(第9章)
- Pc端微信加群的测试用例
- cout输出精确小数点
- ubuntu安装cuda11.2
- vue省市区三级联动(行政区划代码)
- jQuery版本低引起的漏洞——CVE-2020-11022/CVE-2020-11023
- 分享一份软件测试面试指南
- 微信小程序python选择题_微信小程序头脑风暴2答题辅助
- 环保数采仪环境污染在线监控设备 上传监控平台
- 数据挖掘十大算法(九):朴素贝叶斯原理、实例与Python实现
- 微软数据中心将到南非!AWS也将要跟进
- 使用手机号登录、注册、重置密码
- 自定义输入矩阵,顺时针输出或顺时针旋转后输出
- 文案是否有违禁词查询