mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-12-05 23:22:43 +00:00
bsp: ab32vg1 board support gpio interrupt (#10280)
This commit is contained in:
@@ -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,23 +151,224 @@ 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,
|
static rt_err_t get_port_pin(rt_base_t pin, rt_uint8_t *port, rt_uint8_t *hw_pin)
|
||||||
rt_uint8_t mode, void (*hdr)(void *args), void *args)
|
|
||||||
{
|
{
|
||||||
return -RT_ERROR;
|
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_err_t ab32_pin_dettach_irq(struct rt_device *device, rt_base_t pin)
|
static rt_int32_t get_wakeup_circuit(rt_base_t pin)
|
||||||
{
|
{
|
||||||
return -RT_ERROR;
|
/* 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)
|
||||||
|
{
|
||||||
|
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_attach_irq(struct rt_device *device, rt_int32_t pin,
|
||||||
|
rt_uint32_t mode, void (*hdr)(void *args), void *args)
|
||||||
|
{
|
||||||
|
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 =
|
||||||
{
|
{
|
||||||
ab32_pin_mode,
|
ab32_pin_mode,
|
||||||
|
|||||||
@@ -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__
|
||||||
|
|||||||
@@ -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__
|
||||||
|
|||||||
Reference in New Issue
Block a user