本文首先介绍LHAL库的概念,继而使用小安排的GPIO外设。并使用raspberry pi pico作为逻辑分析仪来对GPIO的输出做采样捕获验证。

1. LHAL库外设

博流的LHAL库驱动外设进行了统一的封装。下列表格则是从SDK文档中摘取出来,列举出来小安排使用的BL616芯片外设的在LHAL库中的支持。 其中: √表示已支持,×表示未支持,-表示该芯片没有该外设

parameter BL616/BL618
ADC
CAM ×
CKS
DAC
DMA
EFUSE
EMAC
FLASH
GPIO
I2C
IR
MJPEG
PWM_v1 -
PWM_v2
RTC
SEC_AES
SEC_SHA
SEC_TRNG
SEC_PKA
SPI
TIMER
UART
USB_v1 -
USB_v2
WDG

上述表格中的所有外设都是使用同一个结构体对其进行配置的:

struct bflb_device_s {
  const char *name;             //外设名称
  uint32_t reg_base;            //外设寄存器基地址
  uint8_t irq_num;              //外设中断号
  uint8_t idx;                  //外设 id,例如 UART0、UART1
  uint8_t sub_idx;              //外设子id,例如 DMA0_CH0、DMA0_CH1
  uint8_t dev_type;             //外设类型
  void *user_data;              //用户数据
};

或者外设对象提供了两个方法: 1.通过外设名称获取

struct bflb_device_s *bflb_device_get_by_name(const char *name) 

2.通过外设类型和外设id获取

struct bflb_device_s *bflb_device_get_by_id(uint8_t type, uint8_t idx)

这两个函数的实现可以在aithinker_Ai-M6X_SDK\drivers\lhal\config\bl616\device_table.c中找到,如下图所示:

image-20231013091526370

2. GPIO配置

有了上面的基础了解之后我们大概就清楚了,如果想要使用gpio外设,那么首先我们就需要get到gpio设备。随后就是用get到的设备进行初始化。sdk中提供的初始化的函数定义如下:

void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset);
  • 第一个参数就是前面我们通过get得到的gpio设备;
  • 第二个参数是对应到硬件上的端口号;
  • 第三个参数是将这个pin设置成具体的模式和功能(包括gpio mode、gpio function、gpio pupd、gpio smt、gpio drive)。这些设置可以通过位或的方式进行设置。下列是从sdk中摘录的具体的每个域的设置参数。
// gpio mode
#define GPIO_INPUT      (0 << GPIO_MODE_SHIFT) /* Input Enable */
#define GPIO_OUTPUT     (1 << GPIO_MODE_SHIFT) /* Output Enable */
#define GPIO_ANALOG     (2 << GPIO_MODE_SHIFT) /* Analog Enable */
#define GPIO_ALTERNATE  (3 << GPIO_MODE_SHIFT) /* Alternate Enable */

// gpio pupd
#define GPIO_FLOAT      (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
#define GPIO_PULLUP     (1 << GPIO_PUPD_SHIFT) /* Pull-up */
#define GPIO_PULLDOWN   (2 << GPIO_PUPD_SHIFT) /* Pull-down */

// gpio smt
#define GPIO_SMT_DIS   (0 << GPIO_SMT_SHIFT)
#define GPIO_SMT_EN    (1 << GPIO_SMT_SHIFT)

// gpio drive
#define GPIO_DRV_0     (0 << GPIO_DRV_SHIFT)
#define GPIO_DRV_1     (1 << GPIO_DRV_SHIFT)
#define GPIO_DRV_2     (2 << GPIO_DRV_SHIFT)
#define GPIO_DRV_3     (3 << GPIO_DRV_SHIFT)

// gpio init trig mode
#define GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE 0
#define GPIO_INT_TRIG_MODE_SYNC_RISING_EDGE  1
#define GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL    2
#define GPIO_INT_TRIG_MODE_SYNC_HIGH_LEVEL   3
#define GPIO_INT_TRIG_MODE_SYNC_FALLING_RISING_EDGE 4
#define GPIO_INT_TRIG_MODE_ASYNC_FALLING_EDGE       8
#define GPIO_INT_TRIG_MODE_ASYNC_RISING_EDGE        9
#define GPIO_INT_TRIG_MODE_ASYNC_LOW_LEVEL          10
#define GPIO_INT_TRIG_MODE_ASYNC_HIGH_LEVEL         11

// gpio uart function
#define GPIO_UART_FUNC_UART0_RTS 0
#define GPIO_UART_FUNC_UART0_CTS 1
#define GPIO_UART_FUNC_UART0_TX  2
#define GPIO_UART_FUNC_UART0_RX  3
#define GPIO_UART_FUNC_UART1_RTS 4
#define GPIO_UART_FUNC_UART1_CTS 5
#define GPIO_UART_FUNC_UART1_TX  6
#define GPIO_UART_FUNC_UART1_RX  7

顺便看看和初始化相关的几个函数

void bflb_gpio_deinit(struct bflb_device_s *dev, uint8_t pin);  //反初始化,相当于回到init之前的状态。io设置为浮空
void bflb_gpio_set(struct bflb_device_s *dev, uint8_t pin);     //设置为高电平
void bflb_gpio_reset(struct bflb_device_s *dev, uint8_t pin);   //设置为低电平
bool bflb_gpio_read(struct bflb_device_s *dev, uint8_t pin);    //读取io电平

3. GPIO配置示例

现在我们就来找一个io对其进行配置,让其间歇性的输出高低电平。随后使用逻辑分析仪来验证我们程序是否正常。 找到小安派的原理图,我们看看IO0是否引出了。 image-20231013094019743 从上图中看到IO0对应对应原理图中标号为I2C_SCL_TOP的网络,我们直接在原理图文件里面搜索,可以找到在J9这个连接件上是接着I2C_SCL_TOP的。 image-20231013094124445 那对应在板子的哪个位置呢?我们再来打开小安派的PCB文件,为了方便查看,先移除掉覆铜。这就看到了这个I2C_SCL_TOP对应在板子上的位置了。 image-20231013094559600 很幸运,这个接口是可以连接的。那么我们就直接使用IO0进行配置了。

#include "bflb_gpio.h"
#include "bflb_mtimer.h"
#include "board.h"

struct bflb_device_s *gpio;

#define gpio_test GPIO_PIN_0

int main(void)
{
    board_init();
    
    //获取gpio设备
    gpio = bflb_device_get_by_name("gpio"); 

    //配置io 0 为上拉 输出
    bflb_gpio_init(gpio, gpio_test, GPIO_OUTPUT | GPIO_PULLUP);

    while (1) 
    {
        bflb_gpio_set(gpio, gpio_test);   // 拉高
        bflb_mtimer_delay_ms(100);        // 延时100ms
        bflb_gpio_reset(gpio, gpio_test); // 拉低
        bflb_mtimer_delay_ms(100);
    }
}

将上述代码编译烧录到小安派。接下来就使用rp2040做的逻辑分析仪来测量IO0的输出。

4. 使用逻辑分析仪验证

树莓派pico烧入逻辑分析仪固件,插入到电脑上。配置好plusview。(这个过程不详述。)

将pico的gnd和GP2分别和小安派的GND和I2C_SCL_TOP连接。

image-20231013101450021

运行逻辑分析仪,就可以抓到如下的波形:

image-20231013101217814

从波形中可以看到,电平变化的间隔正好是100ms和我们的程序中的是完全一致的。

至此,gpio功能我们就了解了。