From ae7697e63edaa4af8a2266b03150f30da8ada3de Mon Sep 17 00:00:00 2001 From: kurisaw <2053731441@qq.com> Date: Thu, 15 May 2025 18:19:20 +0800 Subject: [PATCH] bsp: ab32vg1 board support gpio interrupt --- bsp/bluetrum/libraries/hal_drivers/drv_gpio.c | 221 +++++++++++++++++- bsp/bluetrum/libraries/hal_drivers/drv_gpio.h | 25 ++ .../hal_libraries/bmsis/include/ab32vg1.h | 1 + 3 files changed, 239 insertions(+), 8 deletions(-) diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_gpio.c b/bsp/bluetrum/libraries/hal_drivers/drv_gpio.c index 5cf0a72aa57..9fb13071c12 100644 --- a/bsp/bluetrum/libraries/hal_drivers/drv_gpio.c +++ b/bsp/bluetrum/libraries/hal_drivers/drv_gpio.c @@ -6,6 +6,7 @@ * Change Logs: * Date Author Notes * 2020-11-19 greedyhao first version + * 2025-05-15 kurisaW support gpio interrupt */ #include "drv_gpio.h" @@ -40,6 +41,9 @@ static const hal_sfr_t port_sfr[] = GPIOF_BASE, }; +static struct ab32_pin_irq pin_irq_table[8] = {0}; // For WAKEUP_CRICUIT_0 to _7 +static rt_mq_t gpio_irq_mq = RT_NULL; + static rt_uint8_t _pin_port(rt_uint32_t pin) { rt_uint8_t port = 0; @@ -99,7 +103,7 @@ static rt_base_t ab32_pin_get(const char *name) return pin; } -static void ab32_pin_write(rt_device_t dev, rt_base_t pin, rt_uint8_t value) +static void ab32_pin_write(rt_device_t dev, rt_base_t pin, rt_base_t value) { rt_uint8_t port = PIN_PORT(pin); rt_uint8_t gpio_pin = pin - port_table[port].total_pin; @@ -147,22 +151,223 @@ static void ab32_pin_mode(rt_device_t dev, rt_base_t pin, rt_uint8_t mode) hal_gpio_init(PORT_SFR(port), &gpio_init); } -static rt_err_t ab32_pin_attach_irq(struct rt_device *device, rt_base_t pin, - rt_uint8_t mode, void (*hdr)(void *args), void *args) +static rt_err_t get_port_pin(rt_base_t pin, rt_uint8_t *port, rt_uint8_t *hw_pin) +{ + rt_uint8_t i; + for (i = 0; i < sizeof(port_table) / sizeof(port_table[0]); i++) + { + if (pin >= port_table[i].total_pin && + pin < port_table[i].total_pin + port_table[i].delta_pin) + { + *port = i; + *hw_pin = pin - port_table[i].total_pin + port_table[i].start_pin; + return RT_EOK; + } + } + return -RT_EINVAL; +} + +static rt_int32_t get_wakeup_circuit(rt_base_t pin) +{ + /* Special interrupt pins */ + if (pin == PIN_NUM(0, 7)) return WAKEUP_CRICUIT_0; // PA7 + if (pin == PIN_NUM(1, 1)) return WAKEUP_CRICUIT_1; // PB1 + if (pin == PIN_NUM(1, 2)) return WAKEUP_CRICUIT_2; // PB2 + if (pin == PIN_NUM(1, 3)) return WAKEUP_CRICUIT_3; // PB3 + if (pin == PIN_NUM(1, 4)) return WAKEUP_CRICUIT_4; // PB4 + /* WAKEUP_CRICUIT_5 is for RTC (WKO), assuming not a GPIO pin */ + /* Other pins use WAKEUP_CRICUIT_6 (falling) or WAKEUP_CRICUIT_7 (rising) */ + return -1; // Will be handled in attach_irq based on mode +} + +static rt_uint32_t get_edge_select_bit(rt_uint8_t circuit) +{ + switch (circuit) + { + case WAKEUP_CRICUIT_0: return WAKEUP_EDGE_SELECT_0; + case WAKEUP_CRICUIT_1: return WAKEUP_EDGE_SELECT_1; + case WAKEUP_CRICUIT_2: return WAKEUP_EDGE_SELECT_2; + case WAKEUP_CRICUIT_3: return WAKEUP_EDGE_SELECT_3; + case WAKEUP_CRICUIT_4: return WAKEUP_EDGE_SELECT_4; + case WAKEUP_CRICUIT_5: return WAKEUP_EDGE_SELECT_5; + case WAKEUP_CRICUIT_6: return WAKEUP_EDGE_SELECT_6; + case WAKEUP_CRICUIT_7: return WAKEUP_EDGE_SELECT_7; + default: return 0; + } +} + +void __attribute__((section(".irq.gpio"))) ab32_pin_irq_handler(void *args) +{ + rt_interrupt_enter(); + rt_uint32_t pending = WKUPEDG; + rt_uint8_t circuit = 0; + + for (circuit = 0; circuit <= WAKEUP_CRICUIT_7; circuit++) + { + if (pending & (BIT(circuit) << WAKEUP_INT_ENABLE)) + { + /* clear pending interrupt */ + WKUPCPND = (BIT(circuit) << WAKEUP_INT_ENABLE); + rt_mq_send(gpio_irq_mq, &circuit, sizeof(circuit)); + } + } + rt_interrupt_leave(); +} + +static void ab32_pin_irq_thread(void *parameter) { - return -RT_ERROR; + rt_uint8_t circuit; + while (1) + { + if (rt_mq_recv(gpio_irq_mq, &circuit, sizeof(circuit), RT_WAITING_FOREVER) == RT_EOK) + { + if (circuit <= WAKEUP_CRICUIT_7 && pin_irq_table[circuit].hdr) + { + pin_irq_table[circuit].hdr(pin_irq_table[circuit].args); + } + } + } } -static rt_err_t ab32_pin_dettach_irq(struct rt_device *device, rt_base_t pin) +static rt_err_t ab32_pin_attach_irq(struct rt_device *device, rt_int32_t pin, + rt_uint32_t mode, void (*hdr)(void *args), void *args) { - return -RT_ERROR; + rt_uint8_t port, hw_pin; + rt_int32_t circuit; + uint8_t pin_mode; + + if (get_port_pin(pin, &port, &hw_pin) != RT_EOK) + { + return -RT_EINVAL; + } + + circuit = get_wakeup_circuit(pin); + if(circuit == -1) + { + circuit = (mode == PIN_IRQ_MODE_FALLING) ? WAKEUP_CRICUIT_6 : WAKEUP_CRICUIT_7; + } + + /* store handler and arguments */ + pin_irq_table[circuit].hdr = hdr; + pin_irq_table[circuit].args = args; + + /* The interrupt source in the port is: Port_intsrc = {PG[4:0], PF[5:0], PE[7:0], PB[4:0], PA[7:0]}. */ + /* Such as:the interrupt source number of PA0 is 0, interrupt source number of PG4 is 31. */ + PORTINTEN |= BIT(pin); // Enable interrupt + PORTINTEDG |= BIT(pin); // Edge trigger + + return RT_EOK; +} + +static rt_err_t ab32_pin_dettach_irq(struct rt_device *device, rt_int32_t pin) +{ + rt_uint8_t port, hw_pin; + rt_int32_t circuit; + + if (get_port_pin(pin, &port, &hw_pin) != RT_EOK) + { + return -RT_EINVAL; + } + + circuit = get_wakeup_circuit(pin); + if (circuit < 0) + { + /* assume previously assigned to WAKEUP_CRICUIT_6 or _7 */ + /* check both circuits for handler */ + if (pin_irq_table[WAKEUP_CRICUIT_6].hdr) + circuit = WAKEUP_CRICUIT_6; + else if (pin_irq_table[WAKEUP_CRICUIT_7].hdr) + circuit = WAKEUP_CRICUIT_7; + else + return RT_EOK; + } + + PORTINTEN &= ~BIT(circuit); + WKUPCON &= ~BIT(circuit); + WKUPCPND = BIT(get_edge_select_bit(circuit)); + + /* clear handler */ + pin_irq_table[circuit].hdr = RT_NULL; + pin_irq_table[circuit].args = RT_NULL; + + return RT_EOK; } static rt_err_t ab32_pin_irq_enable(struct rt_device *device, rt_base_t pin, - rt_uint8_t enabled) + rt_uint32_t enabled) { - return -RT_ERROR; + rt_uint8_t port, hw_pin; + rt_int32_t circuit; + + if (get_port_pin(pin, &port, &hw_pin) != RT_EOK) + { + return -RT_EINVAL; + } + + circuit = get_wakeup_circuit(pin); + if (circuit < 0) + { + if (pin_irq_table[WAKEUP_CRICUIT_6].hdr) + { + circuit = WAKEUP_CRICUIT_6; + } + else if (pin_irq_table[WAKEUP_CRICUIT_7].hdr) + { + circuit = WAKEUP_CRICUIT_7; + } + else + return -RT_EINVAL; + } + + rt_uint32_t edge_bit = get_edge_select_bit(circuit); + + if (enabled == RT_TRUE) + { + WKUPEDG = BIT(circuit) | BIT(edge_bit); + WKUPCON = BIT(circuit) | BIT(WAKEUP_INT_ENABLE); + + WKUPCPND = BIT(circuit); + + /* install interrupt handler */ + rt_hw_interrupt_install(IRQ_GPIO_IRQ, ab32_pin_irq_handler, RT_NULL, "gpio_isr"); + rt_hw_irq_enable(IRQ_GPIO_IRQ); + } + else + { + /* disable interrupt */ + WKUPCON &= ~BIT(circuit); + } + + return RT_EOK; +} + +static int ab32_pin_irq_init(void) +{ + gpio_irq_mq = rt_mq_create("gpio_irq", sizeof(rt_uint8_t), 128, RT_IPC_FLAG_FIFO); + if (gpio_irq_mq == RT_NULL) + { + return -RT_ENOMEM; + } + + rt_thread_t tid = rt_thread_create("gpio_irq", + ab32_pin_irq_thread, + RT_NULL, + 512, + 15, + 5); + if (tid != RT_NULL) + { + rt_thread_startup(tid); + } + else + { + rt_mq_delete(gpio_irq_mq); + return -RT_ENOMEM; + } + + return RT_EOK; } +INIT_PREV_EXPORT(ab32_pin_irq_init); const static struct rt_pin_ops _ab32_pin_ops = { diff --git a/bsp/bluetrum/libraries/hal_drivers/drv_gpio.h b/bsp/bluetrum/libraries/hal_drivers/drv_gpio.h index 55cf2efc005..4745498bda3 100644 --- a/bsp/bluetrum/libraries/hal_drivers/drv_gpio.h +++ b/bsp/bluetrum/libraries/hal_drivers/drv_gpio.h @@ -20,6 +20,31 @@ #define __AB32_GET_PIN_E(PIN) 13 + PIN #define __AB32_GET_PIN_F(PIN) 21 + PIN +#define WAKEUP_INT_ENABLE 16 +#define WAKEUP_CRICUIT_0 0 // PA7 +#define WAKEUP_CRICUIT_1 1 // PB1 +#define WAKEUP_CRICUIT_2 2 // PB2 +#define WAKEUP_CRICUIT_3 3 // PB3 +#define WAKEUP_CRICUIT_4 4 // PB4 +#define WAKEUP_CRICUIT_5 5 // WKO (RTC) +#define WAKEUP_CRICUIT_6 6 // Falling edge for other GPIOs +#define WAKEUP_CRICUIT_7 7 // Rising edge for other GPIOs +#define WAKEUP_EDGE_SELECT_0 16 +#define WAKEUP_EDGE_SELECT_1 17 +#define WAKEUP_EDGE_SELECT_2 18 +#define WAKEUP_EDGE_SELECT_3 19 +#define WAKEUP_EDGE_SELECT_4 20 +#define WAKEUP_EDGE_SELECT_5 21 +#define WAKEUP_EDGE_SELECT_6 22 +#define WAKEUP_EDGE_SELECT_7 23 + +/* structure to store IRQ handler and arguments per pin */ +struct ab32_pin_irq +{ + void (*hdr)(void *args); + void *args; +}; + int rt_hw_pin_init(void); #endif // DRV_GPIO_H__ diff --git a/bsp/bluetrum/libraries/hal_libraries/bmsis/include/ab32vg1.h b/bsp/bluetrum/libraries/hal_libraries/bmsis/include/ab32vg1.h index c436572b349..591d2d0728f 100644 --- a/bsp/bluetrum/libraries/hal_libraries/bmsis/include/ab32vg1.h +++ b/bsp/bluetrum/libraries/hal_libraries/bmsis/include/ab32vg1.h @@ -30,6 +30,7 @@ typedef enum IRQ_HSUART_VECTOR = 15, IRQ_RTC_VECTOR = 16, /*!< RTC, LVD and WDT Interrupt */ IRQ_I2S_VECTOR = 17, + IRQ_GPIO_IRQ = 18, IRQ_TOTAL_NUM = 23, } irq_type; #endif // __ASSEMBLER__