【Ai-WB2入门篇】GPIO使用

[复制链接]
查看1011 | 回复7 | 2024-8-27 14:29:50 | 显示全部楼层 |阅读模式
Ai-WB2(BL602)的GLB(Global Register)是芯片通用全局设定模块,主要包含了时钟管理、复位管理、总线管理、内存管理以及GPIO管理等功能。
本文将介绍如何使用Ai-WB2的GPIO管理功能,包含GPIO输入、GPI0输出以及GPIO中断。
一:GPIO介绍
通用型之输入输出(General-purpose inputoutput,通常称为GPIO),GPIO管理功能提供GPIO控制寄存器,实现软件对 GPIO 属性的配置,使用户能够方便地操作 GPIO。每个GPIO可以配置为输入、输出和可选功能三种模式。在每个模式下(除模拟可选功能),提供设置上拉,下拉,浮空三种端口状态,此外GPIO还提供中断功能,可以配置为上升沿触发,下降沿触发或者高电平/低电平触发。

Ai-WB2的 GPI0主要特点如下:

    · 可以配置为普通输入输出功能,该模式下可以设定上拉,下拉或者浮空输入输出
    · 可以配置为可选功能,搭配外设功能使用,该模式下亦可以设定上拉,下拉,在使用模拟功能时,必须设置为浮空
    · 可以设置驱动能力,以提供更大的输出电流
    · 可以设置施密特触发器功能,提供简单硬件防抖功能


每个GPIO可以通过软件配置为:
    · 高阻输入
    · 上拉输入
    · 下拉输入
    · 上拉中断输入
    · 下拉中断输入
    · 高阻中断输入
    · 上拉输出
    · 下拉输出
    · 高阻输出
    · 模拟输入可选功能
    · 模拟输出可选功能
    · 数字可选功能

GPIO的功能框图如下:
3.png

GPIO可以设定的功能包括:

    · Flash/QSPI:设定GPIO为QSPI功能,可以连接Flash,作为程序存储/运行介质
    · SPI:设定GPIO为SPI功能
    · 12C:设定GPI0为I2C功能
    · UART:设定GPIO为UART功能
    · PWM:设定GPIO为PWM功能
    · ANA:设定GPI0为Analog功能
    · SWGPIO:设定GPI0为通用I0功能
    · JTAG:设定GPIO为JTAG功能


每个GPIO基本上都可以选择上述可选功能,当选择某个可选功能时,GPI0与对应的功能信号如下表所示:
1.png

在上述表格中,当选择UARI功能时,只是选择JUARI的一个信号,开没有指定该引脚的县体切能比是UARX认是UARLRX),认需要通过UART SIGX SEL(X=0-7)进一步选择具体的UART信号及对应的功能。每一个UART SIGX SEL可以选择的信号包括:

    · 0:UARTO RTS
    · 1:UARTO CTS
    · 2:UARTO TXD
    · 3:UARTO RXD
    · 4:UART1 RTS
    · 5:UART1 CTS
    · 6:UART1 TXD
    · 7:UART1 RXD


以GPIO0为例,当fun sel选择UART的时候,GPIO0选择的是UART_SIG0,在默认情况下UART_SIGO_SEL的值是0,也就是UARTO_RTS,即GPIO是UARTO_RTS功能。如果应用程序想把GPIO作为UART1_TXD.那只要把UART_SIGO_SEL设置为6,那么GPIO0的功能就是UART1_TXD。

GPIO输出设置
通过设定func_sel为SWGPIO,GPIO可以作为普通GPIO的输入输出,将IE设置为0,OE设置为1,就可以将GPIO配置为输出功能,输出的数值通过GPIO_O寄存器组设定。当GPIO_O对应bit设置为0时,GPIO输出低电平,当GPIO_O对应bit设置为1时,GPIO输出高电平。可以通过DRV控制位设置输出能力。

GPIO输入设置
通过设定func_sel为SWGPIO,将IE设置为1,0E设置为0,就可以将GPIO配置为输入功能,可以通过SMT控制位设置是否使能施密特触发器,通过PD,PU控制位设置上拉下拉属性。外部输入的数值,可以通过读取GPIO_I寄存器对应的bit获取到。

GPIO可选功能设置
通过设定func_sel为对应的外设功能,可以实现GPIO与外设的连接,实现外设的输入输出,从GPIO的基础功能框图可以看出,当选择可选功能时,需要将IE设置为1,OE设置为0,也就是断开普通GPIO的输出控制功能。这样,对于固定输入功能的外设,外设的OE信号始终为0,从而实现输入功能;对于固定输出的外设,其OE信号始终为1,从而实现输出是被外设控制,而此时的输入信号就是输出信号但是不会被正在输出的外设采集;当外设既需要输入又要输出时,通过控制外设OE信号就可以实现输入输出。

GPI0中断设置
要使用GPIO的中断功能,需要先将GPIO设置为输入模式,中断触发模式通过GPIO_INT_MODE_SET寄存器组进行设定。可以设定的中断模式包括:

· 上升沿触发中断
· 下降沿触发中断
· 高电平触发中断
· 低电平触发中断


每个GPIO都可以设定为中断功能,是否使能某个GPIO中断可以通过GPIO_INT_MASK寄存器进行设定,中断产生时,在中断函数中可以通过GPIO_ INT_STAT寄存器获取到产生中断的GPIO引脚号,同时可以通过GPIO_INT_CLR清除掉对应的中断信号。
二:GPIO管理相关API介绍
BL602的GPIO管理相关的底层定义,在如下文件中定义:
bl iot sdk/components/platform/soc/bl602/b1602 std/bl602 std/StdDriver/inc/bl602 gpio.h
该文件主要定义了BL602的GPIO编号、GPIO模式以及GPIO功能。
BL602的GPIO管理相关高级API定义,在如下文件中定义
bl iot sdk/components/platform/hosal/bl602 hal/bl gpio.h
该文件定义了GPIO的底层操作函数。
  1. typedef struct _gpio_ctx_desc {
  2.     struct _gpio_ctx_desc *next;
  3.     void (*gpio_handler)(void *);
  4.     void *arg;

  5.     uint8_t gpioPin;
  6.     uint8_t intCtrlMod;
  7.     uint8_t intTrgMod;
  8. } gpio_ctx_t;

  9. int bl_gpio_enable_output(uint8_t pin, uint8_t pullup, uint8_t pulldown); // 设置GPIO为输出
  10. int bl_gpio_enable_input(uint8_t pin, uint8_t pullup, uint8_t pulldown); // 设置GPIO为输入
  11. int bl_gpio_output_set(uint8_t pin, uint8_t value); // 设置GPIO电平值,0表示低电平;1表示高电平
  12. int bl_gpio_input_get(uint8_t pin, uint8_t *value); // 读取GPIO电平值,0表示低电平;1表示高电平
  13. int bl_gpio_input_get_value(uint8_t pin);// 读取GPIO电平值,0表示低电平;1表示高电平
  14. int bl_gpio_int_clear(uint8_t gpioPin,uint8_t intClear);// 清除中断标志
  15. void bl_gpio_intmask(uint8_t gpiopin, uint8_t mask); // 中断掩码
  16. void bl_set_gpio_intmod(uint8_t gpioPin, uint8_t intCtrlMod, uint8_t intTrgMod); // 设置中断模式
  17. void bl_gpio_register(gpio_ctx_t *pstnode); // 注册gpio
复制代码
同时在bl iot sdk的系统抽象硬件层中进一步封装定义,如下:
bl iot sdk/components/platform/hosal/include/hosal gpio.h
该文件定义了在RTOS级对GPIO操作的硬件抽象层操作
  1. typedef struct hosal_gpio_ctx {
  2.     struct hosal_gpio_ctx *next;
  3.     hosal_gpio_irq_handler_t handle;
  4.     void *arg;
  5.     uint8_t pin;
  6.     uint8_t intCtrlMod;
  7.     uint8_t intTrigMod;
  8. }hosal_gpio_ctx_t;

  9. typedef struct {
  10.     uint8_t        port;         /**< @brief gpio port */
  11.     hosal_gpio_config_t  config; /**< @brief gpio config */
  12.     void          *priv;         /**< @brief priv data */
  13. } hosal_gpio_dev_t;

  14. int hosal_gpio_init(hosal_gpio_dev_t *gpio);
  15. int hosal_gpio_output_set(hosal_gpio_dev_t *gpio, uint8_t value);
  16. int hosal_gpio_input_get(hosal_gpio_dev_t *gpio, uint8_t *value);
  17. int hosal_gpio_irq_set(hosal_gpio_dev_t *gpio, hosal_gpio_irq_trigger_t trigger_type, hosal_gpio_irq_handler_t handler, void *arg);
  18. int hosal_gpio_irq_mask(hosal_gpio_dev_t *gpio, uint8_t mask);
  19. int hosal_gpio_finalize(hosal_gpio_dev_t *gpio);
复制代码
三:硬件准备
本次示例将使用到如下硬件:
    · Ai-WB2-32S开发板
    · RGB LED
    · 470欧姆电阻
    · 按键
    · 连接线
    · 面板包板

四:软件准备
在前面的文章中,我们详细介绍了如何搭建Ai-WB2的开发环境:
搭建windows+eclipse环境
五:代码实现
下面将以LED和按键输入为例,介绍如何使用Ai-WB2的GPIO输入、输出以及中断功能。
1. GPIO输出
示例代码如下
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <FreeRTOS.h>
  4. #include <task.h>
  5. #include <bl_gpio.h>

  6. #define GPIO_LED_RED   0
  7. #define GPIO_LED_GREEN  1
  8. #define GPIO_LED_BLUE   2

  9. void blink_task(void *param){
  10.     uint8_t r_value = 1;
  11.     uint8_t g_value = 1;
  12.     uint8_t b_value = 1;
  13.     bl_gpio_enable_output(GPIO_LED_RED, 0, 0);
  14.     bl_gpio_enable_output(GPIO_LED_GREEN, 0, 0);
  15.     bl_gpio_enable_output(GPIO_LED_BLUE, 0, 0);
  16.     while(1) {
  17.         bl_gpio_output_set(GPIO_LED_RED, r_value);
  18.         r_value = !r_value;
  19.         vTaskDelay(200);

  20.         bl_gpio_output_set(GPIO_LED_GREEN, g_value);
  21.         g_value = !g_value;
  22.         vTaskDelay(200);

  23.         bl_gpio_output_set(GPIO_LED_BLUE, b_value);
  24.         b_value = !b_value;
  25.         vTaskDelay(200);
  26.     }
  27. }

  28. void main(void)
  29. {
  30.     xTaskCreate(blink_task, "blink_task", 1024, NULL, 15, NULL);
  31. }
复制代码
在示例代码中,我们定义了一个FreeRTOS任务blin_ktask,该任务执行LED的闪烁任务。在 blink_task 中,通过bl_gpio_enable_output 设置GPIO为输出模式,然后通过调用 bl_gpio_output_set 设置引脚的电平值。
2. GPIO输入
示例代码如下
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <FreeRTOS.h>
  4. #include <task.h>
  5. #include <bl_gpio.h>
  6. #include <stdio.h>
  7. #include <hosal_gpio.h>
  8. #include <hosal_dma.h>
  9. #include <blog.h>
  10. #include <stdbool.h>

  11. #define LED_PIN 0
  12. #define KEY_PIN 3

  13. #define TAG "gpio_exti"

  14. static bool led_state = false;
  15. static hosal_gpio_dev_t led;
  16. static hosal_gpio_dev_t key;
  17. static int32_t counter = 0;

  18. static void init_led(void) {
  19.     led.port = LED_PIN;
  20.     led.config = OUTPUT_OPEN_DRAIN_NO_PULL;
  21.     hosal_gpio_init(&led);
  22.     hosal_gpio_output_set(&led,0);
  23.     printf("led inited\r\n");
  24. }

  25. static void init_key() {
  26.     key.port = KEY_PIN;
  27.     key.config = INPUT_PULL_UP;
  28.     hosal_gpio_init(&key);
  29.     printf("key inited\r\n");
  30. }

  31. void key_task(void* params) {
  32.     printf("key task started\r\n");
  33.     static uint8_t key_state = 0;
  34.     while (true) {
  35.         if (hosal_gpio_input_get(&key, &key_state) == 0) {
  36.             if (key_state) {
  37.                 vTaskDelay(10 / portTICK_PERIOD_MS);
  38.                 if (hosal_gpio_input_get(&key, &key_state) == 0) {
  39.                     if (key_state) {
  40.                         hosal_gpio_output_set(&led, 1);
  41.                         printf("key pressed\r\n");
  42.                     }
  43.                     else {
  44.                         hosal_gpio_output_set(&led, 0);
  45.                     }
  46.                 }
  47.             }
  48.         }
  49.         vTaskDelay(1 / portTICK_PERIOD_MS);
  50.     }
  51. }

  52. void main(void) {
  53.     init_led();
  54.     init_key();
  55.     xTaskCreate(key_task, "key_task", 1024, NULL, 15, NULL);
  56. }
复制代码
在示例代码中,我们使用了RTOS抽象层API。
首先,定义 hosal_gpio_devt实例,用于配置LED引脚和按键引脚。然后调用 hosal_gpio_init 函数初始化引脚配置,接通过调用hosal_gpio_input_get 函数来读取按键引脚的按键值,然后根据按键的电平值来通过调用 hosal_gpio_output_set 函数实现。设置LED引用的电平值.
3. GPIO中断
示例代码如下
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <FreeRTOS.h>
  4. #include <task.h>
  5. #include <bl_gpio.h>
  6. #include <stdio.h>
  7. #include <hosal_gpio.h>
  8. #include <hosal_dma.h>
  9. #include <blog.h>
  10. #include <stdbool.h>

  11. #define LED_PIN 3
  12. #define KEY_PIN 4

  13. #define TAG "gpio_exti"

  14. static bool led_state = false;
  15. static hosal_gpio_dev_t led;
  16. static hosal_gpio_dev_t key;
  17. static int32_t counter = 0;
  18. static void init_led(void) {
  19.     led.port = LED_PIN;
  20.     led.config = OUTPUT_OPEN_DRAIN_NO_PULL;
  21.     hosal_gpio_init(&led);
  22.     printf("led inited\r\n");
  23. }

  24. static void key_irq_callback(void* arg) {
  25.     printf("key pressed:%d\r\n",counter++);
  26.     led_state = !led_state;
  27.     hosal_gpio_output_set(&led, led_state);
  28. }

  29. static void init_key() {
  30.     key.port = KEY_PIN;
  31.     key.config = INPUT_PULL_UP;
  32.     hosal_gpio_init(&key);

  33.     hosal_gpio_irq_set(&key, HOSAL_IRQ_TRIG_NEG_PULSE, key_irq_callback, NULL);
  34.    
  35.     printf("key inited\r\n");
  36. }

  37. void main(void) {
  38.     init_led();
  39.     init_key();
  40. }
复制代码
在示例代码中,LED引脚和按键引脚初始化与前面GPIO输入的步骤一样。在按键初引脚始化完成之后,通过调用 hosal_gpio_irq_set
实现按键中断配置。
用心做好保姆工作
回复

使用道具 举报

妖猊 | 2024-8-27 14:31:16 | 显示全部楼层
看完了, 表示我学会了
回复 支持 反对

使用道具 举报

bzhou830 | 2024-8-27 15:24:04 | 显示全部楼层
写得很好,点灯会了
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

WangChong | 2024-8-27 16:49:09 | 显示全部楼层
园长 出个WIFI的
回复 支持 反对

使用道具 举报

爱笑 | 2024-8-27 16:52:00 | 显示全部楼层

没问题~都会出的
用心做好保姆工作
回复 支持 反对

使用道具 举报

WT_0213 | 2024-8-28 08:43:32 | 显示全部楼层
园长的园快变成程序员的员了
回复 支持 反对

使用道具 举报

IBelieve | 2024-8-28 11:19:10 | 显示全部楼层
写得很好,点灯会了
回复 支持 反对

使用道具 举报

djy876 | 2024-9-2 09:09:06 | 显示全部楼层
学习打卡,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则