Edit online

设计说明

4 Dec 2024
Read time: 4 minute(s)

源码说明

源代码位于 bsp/artinchip/

  • bsp/artinchip/drv/gpai/drv_gpai.c,GPAI Driver 层实现

  • bsp/artinchip/hal/gpai/hal_gpai.c,GPAI HAL 层实现

  • bsp/artinchip/include/hal/hal_gpai.h,GPAI HAL 层接口头文件

模块架构

GPAI 驱动 Driver 层采用 RT-Thread 的 ADC 设备驱动框架,如果只使用 HAL 层也可以支持 Baremetal 方式的应用场景。

sw_system20

关键流程设计

初始化流程

GPAI 驱动的初始化接口通过 INIT_DEVICE_EXPORT(drv_gpai_init) 完成,会通过调用 ADC 子系统的接口 rt_hw_adc_register() 注册一个 ADC 设备。

GPAI 控制器的初始化过程,主要步骤有:

  1. 初始化模块的 clk

  2. 注册中断

  3. 初始化默认参数

  4. 向设备框架中注册 ADC 设备

中断处理流程

GPAI 支持使用中断方式来读取数据,这样避免应用层的忙等待。


gpai_irq_flow.png

1. GPAI 非周期模式的数据采集流程
  • 对于非周期模式:当用户层触发 convert()接口,就会启动一次硬件去读数据

  • 当硬件准备好数据,会产生一个中断

  • 在中断处理函数中,用 INT Flag 来区分是哪个通道有数据,逐个通道扫描将数据读出,会缓存到一个全局变量中

  • 对于周期模式:GPAI 控制器会自动按给定周期产生一次数据中断

数据结构设计

  • struct aic_gpai_dev
    属于 Driver 层内部使用的数据结构,管理 GPAI 控制器的设备资源:
    struct aic_gpai_dev {
        struct rt_adc_device *dev;
        struct aic_gpai_ch *chan;
    };
  • struct aic_gpai_ch
    属于 HAL 层接口,记录单个 ADC 通道的配置信息:
    struct aic_gpai_ch {
        u8 id;
        u8 available;
        enum aic_gpai_mode mode;
        u32 smp_period;
        u16 latest_data;
        u8 fifo_depth;
        u8 fifo_thd;
    
        u8 hla_enable; // high-level alarm
        u8 lla_enable; // low-level alarm
        u16 hla_thd;
        u16 hla_rm_thd;
        u16 lla_thd;
        u16 lla_rm_thd;
    
        aicos_sem_t complete;
    };

Driver 层接口设计

以下接口是 GPAI 设备驱动框架的标准接口。
struct rt_adc_ops
{
    rt_err_t (*enabled)(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled);
    rt_err_t (*convert)(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value);
    rt_uint8_t (*get_resolution)(struct rt_adc_device *device);
    rt_int16_t (*get_vref) (struct rt_adc_device *device);
};
其中的 get_vref() 暂未支持。
1. drv_gpai_enabled
函数原型
rt_err_t drv_gpai_enabled(struct rt_adc_device *dev, rt_uint32_t ch, rt_bool_t enabled)
功能说明 使能一个 ADC 通道
参数定义
dev - 指向 ADC 设备
ch - 指定 ADC 通道的通道编号
enable - 使能
返回值 0,成功; < 0,失败
注意事项 -
2. drv_gpai_convert
函数原型
rt_err_t drv_gpai_convert(struct rt_adc_device *dev, rt_uint32_t ch, rt_uint32_t *value)
功能说明 读取一个 ADC 通道的当前数据
参数定义
dev - 指向 ADC 设备
ch - 指定 ADC 通道的通道编号
value - 用于保存返回的 ADC 数据
返回值 0,成功; < 0,失败
注意事项 -
3. drv_gpai_resolution
函数原型
rt_err_t drv_gpai_resolution(struct rt_adc_device *dev)
功能说明 获取 GPAI 控制器的采样精度
参数定义
dev - 指向 ADC 设备
返回值 12,表示 12bit 的采样精度
注意事项 -

HAL 层接口设计

HAL 层的函数接口声明存放在 hal_gpai.h 中,主要接口有:
void aich_gpai_enable(int enable);
void aich_gpai_ch_enable(u32 ch, int enable);
int aich_gpai_ch_init(struct aic_gpai_ch *chan, u32 pclk);

irqreturn_t aich_gpai_isr(int irq, void *arg);

int aich_gpai_read(struct aic_gpai_ch *chan, u32 *val, u32 timeout);
s32 aich_gpai_data2vol(u16 data);

struct aic_gpai_ch *hal_gpai_ch_is_valid(u32 ch);
void hal_gpai_set_ch_num(u32 num);

void aich_gpai_status_show(struct aic_gpai_ch *chan);

Demo

此 Demo 是 gpai 命令的部分代码(详见 drv_gpai.c),可以作为 GPAI 设备的使用参考:
u32 ch = 0;
struct rt_adc_device *dev = NULL;

dev = (struct rt_adc_device *)rt_device_find("gpai");
if (!dev) {
    LOG_E("Failed to open %s device\n", "gpai");
    return;
}
ret = rt_adc_enable(dev, ch);
if (!ret) {
    val = rt_adc_read(dev, ch);
    printf("GPAI ch%d: %d\n", ch, val);
}

rt_adc_disable(dev, ch);