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的功能框图如下:
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与对应的功能信号如下表所示:
在上述表格中,当选择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的底层操作函数。
- typedef struct _gpio_ctx_desc {
- struct _gpio_ctx_desc *next;
- void (*gpio_handler)(void *);
- void *arg;
- uint8_t gpioPin;
- uint8_t intCtrlMod;
- uint8_t intTrgMod;
- } gpio_ctx_t;
- int bl_gpio_enable_output(uint8_t pin, uint8_t pullup, uint8_t pulldown); // 设置GPIO为输出
- int bl_gpio_enable_input(uint8_t pin, uint8_t pullup, uint8_t pulldown); // 设置GPIO为输入
- int bl_gpio_output_set(uint8_t pin, uint8_t value); // 设置GPIO电平值,0表示低电平;1表示高电平
- int bl_gpio_input_get(uint8_t pin, uint8_t *value); // 读取GPIO电平值,0表示低电平;1表示高电平
- int bl_gpio_input_get_value(uint8_t pin);// 读取GPIO电平值,0表示低电平;1表示高电平
- int bl_gpio_int_clear(uint8_t gpioPin,uint8_t intClear);// 清除中断标志
- void bl_gpio_intmask(uint8_t gpiopin, uint8_t mask); // 中断掩码
- void bl_set_gpio_intmod(uint8_t gpioPin, uint8_t intCtrlMod, uint8_t intTrgMod); // 设置中断模式
- void bl_gpio_register(gpio_ctx_t *pstnode); // 注册gpio
复制代码 同时在bl iot sdk的系统抽象硬件层中进一步封装定义,如下:
bl iot sdk/components/platform/hosal/include/hosal gpio.h
该文件定义了在RTOS级对GPIO操作的硬件抽象层操作
- typedef struct hosal_gpio_ctx {
- struct hosal_gpio_ctx *next;
- hosal_gpio_irq_handler_t handle;
- void *arg;
- uint8_t pin;
- uint8_t intCtrlMod;
- uint8_t intTrigMod;
- }hosal_gpio_ctx_t;
- typedef struct {
- uint8_t port; /**< @brief gpio port */
- hosal_gpio_config_t config; /**< @brief gpio config */
- void *priv; /**< @brief priv data */
- } hosal_gpio_dev_t;
- int hosal_gpio_init(hosal_gpio_dev_t *gpio);
- int hosal_gpio_output_set(hosal_gpio_dev_t *gpio, uint8_t value);
- int hosal_gpio_input_get(hosal_gpio_dev_t *gpio, uint8_t *value);
- 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);
- int hosal_gpio_irq_mask(hosal_gpio_dev_t *gpio, uint8_t mask);
- 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输出
示例代码如下
- #include <stdio.h>
- #include <string.h>
- #include <FreeRTOS.h>
- #include <task.h>
- #include <bl_gpio.h>
- #define GPIO_LED_RED 0
- #define GPIO_LED_GREEN 1
- #define GPIO_LED_BLUE 2
- void blink_task(void *param){
- uint8_t r_value = 1;
- uint8_t g_value = 1;
- uint8_t b_value = 1;
- bl_gpio_enable_output(GPIO_LED_RED, 0, 0);
- bl_gpio_enable_output(GPIO_LED_GREEN, 0, 0);
- bl_gpio_enable_output(GPIO_LED_BLUE, 0, 0);
- while(1) {
- bl_gpio_output_set(GPIO_LED_RED, r_value);
- r_value = !r_value;
- vTaskDelay(200);
- bl_gpio_output_set(GPIO_LED_GREEN, g_value);
- g_value = !g_value;
- vTaskDelay(200);
- bl_gpio_output_set(GPIO_LED_BLUE, b_value);
- b_value = !b_value;
- vTaskDelay(200);
- }
- }
- void main(void)
- {
- xTaskCreate(blink_task, "blink_task", 1024, NULL, 15, NULL);
- }
复制代码 在示例代码中,我们定义了一个FreeRTOS任务blin_ktask,该任务执行LED的闪烁任务。在 blink_task 中,通过bl_gpio_enable_output 设置GPIO为输出模式,然后通过调用 bl_gpio_output_set 设置引脚的电平值。
2. GPIO输入
示例代码如下
- #include <stdio.h>
- #include <string.h>
- #include <FreeRTOS.h>
- #include <task.h>
- #include <bl_gpio.h>
- #include <stdio.h>
- #include <hosal_gpio.h>
- #include <hosal_dma.h>
- #include <blog.h>
- #include <stdbool.h>
- #define LED_PIN 0
- #define KEY_PIN 3
- #define TAG "gpio_exti"
- static bool led_state = false;
- static hosal_gpio_dev_t led;
- static hosal_gpio_dev_t key;
- static int32_t counter = 0;
- static void init_led(void) {
- led.port = LED_PIN;
- led.config = OUTPUT_OPEN_DRAIN_NO_PULL;
- hosal_gpio_init(&led);
- hosal_gpio_output_set(&led,0);
- printf("led inited\r\n");
- }
- static void init_key() {
- key.port = KEY_PIN;
- key.config = INPUT_PULL_UP;
- hosal_gpio_init(&key);
- printf("key inited\r\n");
- }
- void key_task(void* params) {
- printf("key task started\r\n");
- static uint8_t key_state = 0;
- while (true) {
- if (hosal_gpio_input_get(&key, &key_state) == 0) {
- if (key_state) {
- vTaskDelay(10 / portTICK_PERIOD_MS);
- if (hosal_gpio_input_get(&key, &key_state) == 0) {
- if (key_state) {
- hosal_gpio_output_set(&led, 1);
- printf("key pressed\r\n");
- }
- else {
- hosal_gpio_output_set(&led, 0);
- }
- }
- }
- }
- vTaskDelay(1 / portTICK_PERIOD_MS);
- }
- }
- void main(void) {
- init_led();
- init_key();
- xTaskCreate(key_task, "key_task", 1024, NULL, 15, NULL);
- }
复制代码 在示例代码中,我们使用了RTOS抽象层API。
首先,定义 hosal_gpio_devt实例,用于配置LED引脚和按键引脚。然后调用 hosal_gpio_init 函数初始化引脚配置,接通过调用hosal_gpio_input_get 函数来读取按键引脚的按键值,然后根据按键的电平值来通过调用 hosal_gpio_output_set 函数实现。设置LED引用的电平值.
3. GPIO中断
示例代码如下
- #include <stdio.h>
- #include <string.h>
- #include <FreeRTOS.h>
- #include <task.h>
- #include <bl_gpio.h>
- #include <stdio.h>
- #include <hosal_gpio.h>
- #include <hosal_dma.h>
- #include <blog.h>
- #include <stdbool.h>
- #define LED_PIN 3
- #define KEY_PIN 4
- #define TAG "gpio_exti"
- static bool led_state = false;
- static hosal_gpio_dev_t led;
- static hosal_gpio_dev_t key;
- static int32_t counter = 0;
- static void init_led(void) {
- led.port = LED_PIN;
- led.config = OUTPUT_OPEN_DRAIN_NO_PULL;
- hosal_gpio_init(&led);
- printf("led inited\r\n");
- }
- static void key_irq_callback(void* arg) {
- printf("key pressed:%d\r\n",counter++);
- led_state = !led_state;
- hosal_gpio_output_set(&led, led_state);
- }
- static void init_key() {
- key.port = KEY_PIN;
- key.config = INPUT_PULL_UP;
- hosal_gpio_init(&key);
- hosal_gpio_irq_set(&key, HOSAL_IRQ_TRIG_NEG_PULSE, key_irq_callback, NULL);
-
- printf("key inited\r\n");
- }
- void main(void) {
- init_led();
- init_key();
- }
复制代码 在示例代码中,LED引脚和按键引脚初始化与前面GPIO输入的步骤一样。在按键初引脚始化完成之后,通过调用 hosal_gpio_irq_set 来实现按键中断配置。
|
|