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设备详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 永磁同步电机三相等效电路图_同步电动机原
- 下一篇: CString,string,char*