当前位置:网站首页>2.1 rtthread pin设备详解
2.1 rtthread pin设备详解
2022-07-06 03:20:00 【rou252051452】
目录
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为默认推挽输出,不上下拉,输出速度HIGH
GPIO_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);
}
#else
if ((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);
}
#endif
rt_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);
}
}
边栏推荐
- 手写数据库客户端
- 八道超经典指针面试题(三千字详解)
- Arabellacpc 2019 (supplementary question)
- Performance test method of bank core business system
- Pytorch基础——(1)张量(tensor)的初始化
- BUUCTF刷题笔记——[极客大挑战 2019]EasySQL 1
- Derivation of anti Park transform and anti Clarke transform formulas for motor control
- 1.16 - 校验码
- Handwriting database client
- IPv6 jobs
猜你喜欢
C # create self host webservice
JS regular filtering and adding image prefixes in rich text
[ruoyi] enable Mini navigation bar
Who is the winner of PTA
Reverse repackaging of wechat applet
IPv6 comprehensive experiment
Remote Sensing Image Super-resolution and Object Detection: Benchmark and State of the Art
深入探究指针及指针类型
Python implementation of maddpg - (1) openai maddpg environment configuration
Pytorch基础——(1)张量(tensor)的初始化
随机推荐
手写数据库客户端
Self made CA certificate and SSL certificate using OpenSSL
ASU & OSU | model based regularized off-line meta reinforcement learning
Linear programming matlab
Map sorts according to the key value (ascending plus descending)
Problems encountered in 2022 work IV
NR modulation 1
3857 Mercator coordinate system converted to 4326 (WGS84) longitude and latitude coordinates
jsscript
Pytorch load data
Buuctf question brushing notes - [geek challenge 2019] easysql 1
【Rust 笔记】18-宏
Handwriting database client
遥感图像超分辨率论文推荐
Linear regression and logistic regression
The real machine cannot access the shooting range of the virtual machine, and the real machine cannot Ping the virtual machine
Derivation of anti Park transform and anti Clarke transform formulas for motor control
SWC介绍
Research on cooperative control of industrial robots
February 14, 2022 Daily: Google long article summarizes the experience of building four generations of TPU