Browse Source

bsp: ab32vg1 board support gpio interrupt (#10280)

Yuqiang Wang 1 month ago
parent
commit
05699d63d5

+ 213 - 8
bsp/bluetrum/libraries/hal_drivers/drv_gpio.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Change Logs:
  * Date           Author            Notes
  * Date           Author            Notes
  * 2020-11-19     greedyhao         first version
  * 2020-11-19     greedyhao         first version
+ * 2025-05-15     kurisaW           support gpio interrupt
  */
  */
 
 
 #include "drv_gpio.h"
 #include "drv_gpio.h"
@@ -40,6 +41,9 @@ static const hal_sfr_t port_sfr[] =
     GPIOF_BASE,
     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)
 static rt_uint8_t _pin_port(rt_uint32_t pin)
 {
 {
     rt_uint8_t port = 0;
     rt_uint8_t port = 0;
@@ -99,7 +103,7 @@ static rt_base_t ab32_pin_get(const char *name)
     return pin;
     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 port = PIN_PORT(pin);
     rt_uint8_t gpio_pin  = pin - port_table[port].total_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);
     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,
 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 =
 const static struct rt_pin_ops _ab32_pin_ops =
 {
 {

+ 25 - 0
bsp/bluetrum/libraries/hal_drivers/drv_gpio.h

@@ -20,6 +20,31 @@
 #define __AB32_GET_PIN_E(PIN)  13 + PIN
 #define __AB32_GET_PIN_E(PIN)  13 + PIN
 #define __AB32_GET_PIN_F(PIN)  21 + 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);
 int rt_hw_pin_init(void);
 
 
 #endif // DRV_GPIO_H__
 #endif // DRV_GPIO_H__

+ 1 - 0
bsp/bluetrum/libraries/hal_libraries/bmsis/include/ab32vg1.h

@@ -30,6 +30,7 @@ typedef enum
     IRQ_HSUART_VECTOR               = 15,
     IRQ_HSUART_VECTOR               = 15,
     IRQ_RTC_VECTOR                  = 16,   /*!< RTC, LVD and WDT Interrupt         */
     IRQ_RTC_VECTOR                  = 16,   /*!< RTC, LVD and WDT Interrupt         */
     IRQ_I2S_VECTOR                  = 17,
     IRQ_I2S_VECTOR                  = 17,
+    IRQ_GPIO_IRQ                    = 18,
     IRQ_TOTAL_NUM                   = 23,
     IRQ_TOTAL_NUM                   = 23,
 } irq_type;
 } irq_type;
 #endif // __ASSEMBLER__
 #endif // __ASSEMBLER__