Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 213 additions & 8 deletions bsp/bluetrum/libraries/hal_drivers/drv_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 =
{
Expand Down
25 changes: 25 additions & 0 deletions bsp/bluetrum/libraries/hal_drivers/drv_gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down