diff --git a/bsp/k230/drivers/interdrv/gpio/SConscript b/bsp/k230/drivers/interdrv/gpio/SConscript new file mode 100644 index 00000000000..483a61fc820 --- /dev/null +++ b/bsp/k230/drivers/interdrv/gpio/SConscript @@ -0,0 +1,11 @@ +# RT-Thread building script for component + +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('GPIO', src, depend = [], CPPPATH = CPPPATH) + +Return('group') diff --git a/bsp/k230/drivers/interdrv/gpio/drv_gpio.c b/bsp/k230/drivers/interdrv/gpio/drv_gpio.c new file mode 100644 index 00000000000..2185418aea0 --- /dev/null +++ b/bsp/k230/drivers/interdrv/gpio/drv_gpio.c @@ -0,0 +1,400 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include "ioremap.h" +#include "drv_gpio.h" +#include "drv_hardlock.h" +#include "board.h" +#include +#include +#include +#include + +#define DBG_TAG "GPIO" +#ifdef RT_DEBUG +#define DBG_LVL DBG_LOG +#else +#define DBG_LVL DBG_WARNING +#endif +#define DBG_COLOR + +struct kd_gpio_device { + struct rt_device dev; + void* base[2]; + int hardlock; +}; + +static struct kd_gpio_device gpio_dev; + +static struct +{ + void (*hdr)(void* args); + void* args; + gpio_pin_edge_t edge; + int debounce; + struct rt_work debounce_work; + struct rt_work send_sig_work; + struct rt_lwp* lwp; + int lwp_ref_cnt; + int signo; + void* sigval; +} irq_table[GPIO_MAX_NUM]; + +static void kd_gpio_reg_writel(void* reg, rt_size_t offset, rt_uint32_t value) +{ + while (0 != kd_hardlock_lock(gpio_dev.hardlock)) + ; + rt_uint32_t val = readl(reg); + val &= ~(1 << offset); + val |= (value << offset); + writel(val, reg); + kd_hardlock_unlock(gpio_dev.hardlock); +} + +static rt_uint32_t kd_gpio_reg_readl(void* reg, rt_size_t offset) +{ + rt_uint32_t val = readl(reg); + return (val & (1 << offset)) >> offset; +} + +static int check_pin_valid(rt_base_t pin) +{ + if ((rt_uint16_t)pin < 0 || (rt_uint16_t)pin > GPIO_MAX_NUM) + { + LOG_E("pin %d is not valid\n", pin); + return -RT_EINVAL; + } + return pin; +} + +rt_err_t kd_pin_mode(rt_base_t pin, rt_base_t mode) +{ + void* reg; + uint32_t dir; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + + switch (mode) + { + case GPIO_DM_INPUT: + dir = 0; + break; + case GPIO_DM_OUTPUT: + dir = 1; + break; + default: + LOG_E("GPIO drive mode is not supported."); + return -RT_EINVAL; + } + + if (pin < 32) + { + reg = gpio_dev.base[0] + DIRECTION; + } else { + pin -= 32; + if (pin < 32) + { + reg = gpio_dev.base[1] + DIRECTION; + } else { + reg = gpio_dev.base[1] + DIRECTION + DIRECTION_STRIDE; + pin -= 32; + } + } + + kd_gpio_reg_writel(reg, pin, dir); + + return RT_EOK; +} + +int kd_pin_mode_get(rt_base_t pin) +{ + void* reg; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + + if (pin < 32) + { + reg = gpio_dev.base[0] + DIRECTION; + } else { + pin -= 32; + if (pin < 32) + { + reg = gpio_dev.base[1] + DIRECTION; + } else { + reg = gpio_dev.base[1] + DIRECTION + DIRECTION_STRIDE; + pin -= 32; + } + } + + return kd_gpio_reg_readl(reg, pin) ? GPIO_DM_OUTPUT : GPIO_DM_INPUT; +} + +rt_err_t kd_pin_write(rt_base_t pin, rt_base_t value) +{ + void* reg; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + + if (pin < 32) + { + reg = gpio_dev.base[0] + DATA_OUTPUT; + } else { + pin -= 32; + if (pin < 32) + { + reg = gpio_dev.base[1] + DATA_OUTPUT; + } else { + reg = gpio_dev.base[1] + DATA_OUTPUT + DATA_INPUT_STRIDE; + pin -= 32; + } + } + + kd_gpio_reg_writel(reg, pin, value ? GPIO_PV_HIGH : GPIO_PV_LOW); + + return RT_EOK; +} + +int kd_pin_read(rt_base_t pin) +{ + void* reg; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + + if (pin < 32) + { + reg = gpio_dev.base[0] + DATA_INPUT; + } else { + pin -= 32; + if (pin < 32) + { + reg = gpio_dev.base[1] + DATA_INPUT; + } else { + reg = gpio_dev.base[1] + DATA_INPUT + DATA_INPUT_STRIDE; + pin -= 32; + } + } + + return kd_gpio_reg_readl(reg, pin) ? GPIO_PV_HIGH : GPIO_PV_LOW; +} + +static int kd_set_pin_edge(rt_int32_t pin, gpio_pin_edge_t edge) +{ + void* reg; + + reg = gpio_dev.base[pin >> 5]; + pin = pin & 0x1f; + + switch (edge) + { + case GPIO_PE_RISING: + kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x1); + kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x1); + kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0); + break; + case GPIO_PE_FALLING: + kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x1); + kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x0); + kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0); + break; + case GPIO_PE_BOTH: + kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x1); + break; + case GPIO_PE_LOW: + kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x0); + kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x0); + kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0); + break; + case GPIO_PE_HIGH: + kd_gpio_reg_writel(reg + INT_TYPE_LEVEL, pin, 0x0); + kd_gpio_reg_writel(reg + INT_POLARITY, pin, 0x1); + kd_gpio_reg_writel(reg + INT_BOTHEDGE, pin, 0x0); + break; + default: + break; + } + + kd_gpio_reg_writel(reg + INT_ENABLE, pin, 0x1); + + return RT_EOK; +} + +static void debounce_work(struct rt_work* work, void* param) +{ + void* reg; + rt_size_t pin = (rt_size_t)param; + + reg = gpio_dev.base[pin >> 5]; + pin = pin & 0x1f; + + rt_base_t level = rt_hw_interrupt_disable(); + kd_gpio_reg_writel(reg + INT_MASK, pin, 0x0); + rt_hw_interrupt_enable(level); +} + +static void pin_irq(int vector, void* param) +{ + void* reg; + long pin = vector - IRQN_GPIO0_INTERRUPT; + gpio_pin_edge_t edge = irq_table[pin].edge; + long pin_offset; + + reg = gpio_dev.base[pin >> 5]; + pin_offset = pin & 0x1f; + + switch (edge) + { + case GPIO_PE_RISING: + case GPIO_PE_FALLING: + case GPIO_PE_BOTH: + kd_gpio_reg_writel(reg + INT_CLEAR, pin_offset, 0x1); + break; + case GPIO_PE_LOW: + case GPIO_PE_HIGH: + kd_gpio_reg_writel(reg + INT_MASK, pin_offset, 0x1); + rt_work_init(&irq_table[pin].debounce_work, debounce_work, (void *)pin); + rt_work_submit(&irq_table[pin].debounce_work, irq_table[pin].debounce); + break; + default: + break; + } + + if (irq_table[pin].hdr) + irq_table[pin].hdr(irq_table[pin].args); +} + +static void gpio_irq_to_user(void* args) +{ +} + +rt_err_t kd_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode, void (*hdr)(void* args), void* args) +{ + char irq_name[10]; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + if (pin >= GPIO_IRQ_MAX_NUM) + { + LOG_E("pin %d not support interrupt", pin); + return -RT_EINVAL; + } + + irq_table[pin].hdr = hdr; + irq_table[pin].args = args; + if (hdr != gpio_irq_to_user) + { + irq_table[pin].lwp = NULL; + irq_table[pin].lwp_ref_cnt = 0; + } + + if (mode < 0 || mode > 4) + return -RT_EINVAL; + irq_table[pin].edge = mode; + irq_table[pin].debounce = rt_tick_from_millisecond(10); + + kd_set_pin_edge(pin, irq_table[pin].edge); + rt_snprintf(irq_name, sizeof irq_name, "pin%d", pin); + rt_hw_interrupt_install(IRQN_GPIO0_INTERRUPT + pin, pin_irq, RT_NULL, irq_name); + + return RT_EOK; +} + +rt_err_t kd_pin_detach_irq(rt_int32_t pin) +{ + void* reg; + + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + if (pin >= GPIO_IRQ_MAX_NUM) + { + LOG_E("pin %d not support interrupt", pin); + return -RT_EINVAL; + } + + irq_table[pin].hdr = RT_NULL; + irq_table[pin].args = RT_NULL; + irq_table[pin].lwp = NULL; + irq_table[pin].lwp_ref_cnt = 0; + irq_table[pin].signo = 0; + irq_table[pin].sigval = 0; + + reg = gpio_dev.base[pin >> 5]; + pin = pin & 0x1f; + kd_gpio_reg_writel(reg + INT_ENABLE, pin, 0x0); + + return RT_EOK; +} + +rt_err_t kd_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled) +{ + if (check_pin_valid(pin) < 0) + return -RT_EINVAL; + if (pin >= GPIO_IRQ_MAX_NUM) + { + LOG_E("pin %d not support interrupt", pin); + return -RT_EINVAL; + } + + if (enabled) + rt_hw_interrupt_umask(IRQN_GPIO0_INTERRUPT + pin); + else + rt_hw_interrupt_mask(IRQN_GPIO0_INTERRUPT + pin); + + return RT_EOK; +} + +int rt_hw_gpio_init(void) +{ + rt_err_t ret; + + gpio_dev.base[0] = rt_ioremap((void*)GPIO0_BASE_ADDR, GPIO0_IO_SIZE); + gpio_dev.base[1] = rt_ioremap((void*)GPIO1_BASE_ADDR, GPIO1_IO_SIZE); + + if (kd_request_lock(HARDLOCK_GPIO)) + { + rt_kprintf("fail to request hardlock-%d\n", HARDLOCK_GPIO); + return -RT_ERROR; + } + gpio_dev.hardlock = HARDLOCK_GPIO; + + ret = rt_device_register(&gpio_dev.dev, "gpio", RT_DEVICE_FLAG_RDWR); + + return ret; +} +INIT_BOARD_EXPORT(rt_hw_gpio_init); \ No newline at end of file diff --git a/bsp/k230/drivers/interdrv/gpio/drv_gpio.h b/bsp/k230/drivers/interdrv/gpio/drv_gpio.h new file mode 100644 index 00000000000..8441a7ec7b6 --- /dev/null +++ b/bsp/k230/drivers/interdrv/gpio/drv_gpio.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 2006-2025, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef DRV_GPIO_H__ +#define DRV_GPIO_H__ + +#define GPIO_IRQ_MAX_NUM (64) +#define GPIO_MAX_NUM (64+8) +#define IRQN_GPIO0_INTERRUPT 32 + +/* k230 gpio register table */ +#define DATA_OUTPUT 0x0 +#define DIRECTION 0x04 +#define DATA_SOURCE 0x08 +#define INT_ENABLE 0x30 +#define INT_MASK 0x34 +#define INT_TYPE_LEVEL 0x38 +#define INT_POLARITY 0x3c +#define INT_STATUS 0x40 +#define INT_STATUS_RAW 0x44 +#define INT_DEBOUNCE 0x48 +#define INT_CLEAR 0x4c +#define DATA_INPUT 0x50 +#define VER_ID_CODE 0x64 +#define INT_BOTHEDGE 0x68 + +#define DATA_INPUT_STRIDE 0x04 /* register stride 32 bits */ +#define DATA_OUTPUT_STRIDE 0x0c /* register stride 3*32 bits */ +#define DIRECTION_STRIDE 0x0c /* register stride 3*32 bits, */ + +#define KD_GPIO_HIGH 1 +#define KD_GPIO_LOW 0 +#define KD_GPIO_IRQ_DISABLE 0x00 +#define KD_GPIO_IRQ_ENABLE 0x01 + +/* ioctl */ + +#define KD_GPIO_DM_OUTPUT _IOW('G', 0, int) +#define KD_GPIO_DM_INPUT _IOW('G', 1, int) +#define KD_GPIO_DM_INPUT_PULL_UP _IOW('G', 2, int) +#define KD_GPIO_DM_INPUT_PULL_DOWN _IOW('G', 3, int) +#define KD_GPIO_WRITE_LOW _IOW('G', 4, int) +#define KD_GPIO_WRITE_HIGH _IOW('G', 5, int) + +#define KD_GPIO_PE_RISING _IOW('G', 7, int) +#define KD_GPIO_PE_FALLING _IOW('G', 8, int) +#define KD_GPIO_PE_BOTH _IOW('G', 9, int) +#define KD_GPIO_PE_HIGH _IOW('G', 10, int) +#define KD_GPIO_PE_LOW _IOW('G', 11, int) + +#define KD_GPIO_READ_VALUE _IOW('G', 12, int) + +#define KD_GPIO_SET_MODE _IOW('G', 20, int) +#define KD_GPIO_GET_MODE _IOWR('G', 21, int) +#define KD_GPIO_SET_VALUE _IOW('G', 22, int) +#define KD_GPIO_GET_VALUE _IOWR('G', 23, int) +#define KD_GPIO_SET_IRQ _IOW('G', 24, int) +#define KD_GPIO_GET_IRQ _IOWR('G', 25, int) + +typedef enum _gpio_pin_edge +{ + GPIO_PE_RISING, + GPIO_PE_FALLING, + GPIO_PE_BOTH, + GPIO_PE_HIGH, + GPIO_PE_LOW, +} gpio_pin_edge_t; + +typedef enum _gpio_drive_mode +{ + GPIO_DM_OUTPUT, + GPIO_DM_INPUT, + GPIO_DM_INPUT_PULL_UP, + GPIO_DM_INPUT_PULL_DOWN, +} gpio_drive_mode_t; + +typedef enum _gpio_pin_value +{ + GPIO_PV_LOW, + GPIO_PV_HIGH +} gpio_pin_value_t; + +typedef struct { + rt_uint16_t pin; + rt_uint16_t value; +} gpio_cfg_t; + +typedef struct { + rt_uint16_t pin; + rt_uint8_t enable; + rt_uint8_t mode; + rt_uint16_t debounce; + rt_uint8_t signo; + void *sigval; +} gpio_irqcfg_t; + +rt_err_t kd_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled); +rt_err_t kd_pin_detach_irq(rt_int32_t pin); +rt_err_t kd_pin_attach_irq(rt_int32_t pin,rt_uint32_t mode, void (*hdr)(void *args), void *args); +rt_err_t kd_pin_write(rt_base_t pin, rt_base_t value); +rt_err_t kd_pin_mode(rt_base_t pin, rt_base_t mode); +int kd_pin_read(rt_base_t pin); + +#endif \ No newline at end of file diff --git a/bsp/k230/drivers/utest/SConscript b/bsp/k230/drivers/utest/SConscript index b5c8e2ed55e..e2daadae5af 100644 --- a/bsp/k230/drivers/utest/SConscript +++ b/bsp/k230/drivers/utest/SConscript @@ -3,6 +3,8 @@ from building import * src = [] if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('BSP_UTEST_DRIVERS'): + src += ['test_gpio.c'] + src += ['test_gpio_irq.c'] if GetDepend('BSP_USING_TIMERS'): src += ['test_timer.c'] diff --git a/bsp/k230/drivers/utest/test_gpio.c b/bsp/k230/drivers/utest/test_gpio.c new file mode 100644 index 00000000000..de8a9c83438 --- /dev/null +++ b/bsp/k230/drivers/utest/test_gpio.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + */ + +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + + /* + * 本测试用例演示基于 01Studio Canmv-K230 开发板测试 gpio 的基本输入和输出功能。其中 + * gpio_led_flashing 演示 LED 的跑马灯功能。LED 采用开发板上的 LED2(连接 LED_GPIO52)。 + * gpio_io 演示用杜邦线将 40Pin GPIO 中的 GPIO33 和 GPIO32 连接起来,GPIO33 配 + * 置为输出,GPIO32 配置为输入。分别用 GPIO33 产生输出给 GPIO32 读取并检查是否 + * 和预期的输出一致。 + */ +#include +#include +#include +#include +#include +#include "board.h" +#include "drv_pinctrl.h" +#include "drv_gpio.h" +#include "utest.h" + +#define LED_PIN_NUM 52 + +#define OUT_PIN_NUM 33 +#define IN_PIN_NUM 32 + +static void gpio_led_flashing(void) +{ + int cnt = 5; + + /* Use default pinmux function */ + kd_pin_mode(LED_PIN_NUM, GPIO_DM_OUTPUT); + + while(cnt--) + { + LOG_I("led ON"); + kd_pin_write(LED_PIN_NUM, GPIO_PV_HIGH); + rt_thread_mdelay(1000); + + LOG_I("led OFF"); + kd_pin_write(LED_PIN_NUM, GPIO_PV_LOW); + rt_thread_mdelay(1000); + } +} + +static void gpio_io(void) +{ + int cnt = 5; + int level = 0xff; + + rt_uint32_t val; + + /* Set pinmux function */ + k230_pinctrl_set_function(IN_PIN_NUM, IOMUX_FUNC1); + k230_pinctrl_set_ie(IN_PIN_NUM, 1); + k230_pinctrl_set_oe(IN_PIN_NUM, 0); + + k230_pinctrl_set_function(OUT_PIN_NUM, IOMUX_FUNC1); + k230_pinctrl_set_ie(OUT_PIN_NUM, 0); + k230_pinctrl_set_oe(OUT_PIN_NUM, 1); + + /* Set GPIO mode */ + kd_pin_mode(OUT_PIN_NUM, GPIO_DM_OUTPUT); + kd_pin_mode(IN_PIN_NUM, GPIO_DM_INPUT); + + while(cnt--) + { + kd_pin_write(OUT_PIN_NUM, GPIO_PV_LOW); + level = kd_pin_read(IN_PIN_NUM); + LOG_I("--> %d", level); + uassert_int_equal(level, GPIO_PV_LOW); + + kd_pin_write(OUT_PIN_NUM, GPIO_PV_HIGH); + level = kd_pin_read(IN_PIN_NUM); + LOG_I("--> %d", level); + uassert_int_equal(level, GPIO_PV_HIGH); + + rt_thread_mdelay(500); + } +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(gpio_led_flashing); + UTEST_UNIT_RUN(gpio_io); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +UTEST_TC_EXPORT(testcase, "gpio", utest_tc_init, utest_tc_cleanup, 100); \ No newline at end of file diff --git a/bsp/k230/drivers/utest/test_gpio_irq.c b/bsp/k230/drivers/utest/test_gpio_irq.c new file mode 100644 index 00000000000..759166ca896 --- /dev/null +++ b/bsp/k230/drivers/utest/test_gpio_irq.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2022, Canaan Bright Sight Co., Ltd + * + * All enquiries to https://www.canaan-creative.com/ + */ + +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + + /* + * 本测试用例演示基于 01Studio Canmv-K230 开发板测试 gpio 的中断检测功能。其中 + * 采用开发板上的按键 S3 以及其连接的 KEY_GPIO21 作为中断输入 + * 在中断处理函数中控制 LED 的状态。LED2 采用开发板上的 LED2(连接 LED_GPIO52)。 + * gpio_falling_edge_trigger_irq 将按键 S3 的中断触发方式设置为下降沿触发,测试 + * 时应该会观察到在每次按下 S3 时收到中断。 + * gpio_rising_edge_trigger_irq 将按键 S3 的中断触发方式设置为上升沿触发,测试 + * 时应该会观察到在每次松开 S3 时收到中断。 + * gpio_both_edge_trigger_irq 将按键 S3 的中断触发方式设置为双边沿触发。测试时 + * 应该会观察到在每次按下或松开 S3 时都会收到中断。 + */ +#include +#include +#include +#include +#include "drv_gpio.h" +#include "utest.h" + +#define LED_PIN_NUM 52 +#define KEY_PIN_NUM 21 + +/* It is best to use an even number, especially for testing both edges triggering. */ +#define MAX_LOOP_COUNT 6 +static volatile int cnt; + +#define LED_ON 1 +#define LED_OFF 0 +static volatile int led_status; + +static void led_on(void) +{ + LOG_W("led ON\n"); + kd_pin_write(LED_PIN_NUM, GPIO_PV_HIGH); + led_status = LED_ON; +} + +static void led_off(void) +{ + LOG_W("led OFF\n"); + kd_pin_write(LED_PIN_NUM, GPIO_PV_LOW); + led_status = LED_OFF; +} + +void key_irq(void *args) +{ + LOG_I("---> IRQ: %d\n", ++cnt); + if(LED_OFF == led_status) + led_on(); + else + led_off(); +} + +static void gpio_falling_edge_trigger_irq(void) +{ + cnt = 0; + + /* Use default pinmux function */ + kd_pin_mode(LED_PIN_NUM, GPIO_DM_OUTPUT); + led_off(); + + /* Use default pinmux function */ + kd_pin_mode(KEY_PIN_NUM, GPIO_DM_INPUT); + kd_pin_attach_irq(KEY_PIN_NUM, GPIO_PE_FALLING, key_irq, RT_NULL); + kd_pin_irq_enable(KEY_PIN_NUM, KD_GPIO_IRQ_ENABLE); + + while (cnt < MAX_LOOP_COUNT); + kd_pin_detach_irq(KEY_PIN_NUM); +} + +static void gpio_rising_edge_trigger_irq(void) +{ + cnt = 0; + + /* Use default pinmux function */ + kd_pin_mode(LED_PIN_NUM, GPIO_DM_OUTPUT); + led_off(); + + /* Use default pinmux function */ + kd_pin_mode(KEY_PIN_NUM, GPIO_DM_INPUT); + kd_pin_attach_irq(KEY_PIN_NUM, GPIO_PE_RISING, key_irq, RT_NULL); + kd_pin_irq_enable(KEY_PIN_NUM, KD_GPIO_IRQ_ENABLE); + + while (cnt < MAX_LOOP_COUNT); + kd_pin_detach_irq(KEY_PIN_NUM); +} + +static void gpio_both_edge_trigger_irq(void) +{ + cnt = 0; + + /* Use default pinmux function */ + kd_pin_mode(LED_PIN_NUM, GPIO_DM_OUTPUT); + led_off(); + + /* Use default pinmux function */ + kd_pin_mode(KEY_PIN_NUM, GPIO_DM_INPUT); + kd_pin_attach_irq(KEY_PIN_NUM, GPIO_PE_BOTH, key_irq, RT_NULL); + kd_pin_irq_enable(KEY_PIN_NUM, KD_GPIO_IRQ_ENABLE); + + while (cnt < MAX_LOOP_COUNT); + kd_pin_detach_irq(KEY_PIN_NUM); +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(gpio_falling_edge_trigger_irq); + UTEST_UNIT_RUN(gpio_rising_edge_trigger_irq); + UTEST_UNIT_RUN(gpio_both_edge_trigger_irq); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +UTEST_TC_EXPORT(testcase, "gpio_irq", utest_tc_init, utest_tc_cleanup, 100); \ No newline at end of file