跳转至

ADCLP使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 09/06/2024
    1.1
  • 完善硬件功能和FAQ描述
  • 04/14/2025
    1.2
  • 增加IIO接口说明,更新头文件函数说明
  • 09/02/2025

    1. 概述

    逐次逼近型模数转换器(Successive Approximation ADC)采用的是一种反馈比较型电路结构。实现方式简要概述为:取一个数字量加到DAC上,可得到一个对应的输出模拟电压,将这个模拟电压和输入的模拟电压信号相比较,如果两者不相等,则调整所取的数字量,直到两个模拟电压相等为止,最后所取的这个数字量就是所求的转换结果。

    2. 关键字说明

    • ADCLP

      Analog-to-digital converter Low Precision,低精度(10bit)模数转换器

    • ADCMP

      Analog-to-digital converter Medium Precision,中精度(12bit)模数转换器

    • upper/lower bound

      ADCLP可设置外部输入电压数字量的上下限,超出范围则触发中断

    • 基准电压

      用于模数转换计算时使用的参考电压,也是最大量程,若基准电压设定为1.8v,当外部输入电压>=1.8v时,数字量达到最大值1023

    3. 功能描述

    3.1. 硬件功能说明

    • SAR ADCLP共计5个Channel可支持外部输入电压的模数转换

    • 采样精度为10bit,因此获取到的寄存器数值范围在0~0x3ff之间

    • 支持两个档位的基准电压(即满量程)切换,分别为1.8V和1.0V

    • 支持外部输入电压的阈值设定

    • 采样频率 = 12Mhz / 104 = 115384hz(相当于硬件上每点的采样间隔为8667ns)

    3.2. 计算说明

    SAR ADCLP的主要功能是将模拟信号转换为相应的数字信号,即可以将输入电压转换为数字量存储于寄存器中,通过公式计算出输入电压,

    计算公式:电压 = ( 寄存器数值 / 满量程 )* 基准电压

    即如果读到的数值是0x1D2,可得电压为0x1D2/0x3FF *1.8=0.82v左右

    4. 硬件连接介绍

    如下图,可将外部电压接入引脚PAD_SAR_GPIO0~PAD_SAR_GPIO4

    5. Uboot用法介绍

    5.1. Uboot Config配置

    查看Kconfig可以看到支持ADCLP需要配置CONFIG_SGS_ADCLP、CONFIG_ADC、CONFIG_CMD_ADC,其中开启CONFIG_CMD_ADC需要先配置CONFIG_DM_REGULATOR

    1. CONFIG_SGS_ADCLP=y

    2. CONFIG_ADC=y

    3. CONFIG_DM_REGULATOR=y

    4. CONFIG_CMD_ADC=y

    5.2. DTS配置

    SAR ADCLP的DTS配置只需要在chipname.dtsi中配置如下信息:

    adclp: adclp {
        compatible = "sgs,adclp";
        reg = <0x1F002800 0x200>;
        chan-num = <5>;
        ref-voltage = <1800>;
        status = "okay";
    };
    

    SAR ADCLP DTS配置说明:

    属性 描述 设定值 备注
    compatible 匹配驱动进行驱动注册 "sgs,adclp" 禁止修改
    reg 设定寄存器bank地址 <0x1F002800 0x200> 禁止修改
    chan-num 设定支持的通道数量 5 禁止修改
    ref-voltage 设定基准电压档位 以mv为单位,可选1800和1000 可根据需要修改
    status 选择是否使能驱动 "okay" or "disable" 可根据需要修改

    5.3. Uboot cmd参数说明及使用实例

    命令行输入adc:

    ①adc list → 可查看sar adclp是否有绑定

    ②adc info adclp → 可查看sar adclp支持的channel数量及data精度

    如下图,目前支持的channel数量为5(注意区分mask为0x1f),最大data值为0x3ff

    ③adc single adclp [channel] → 可查看具体某个channel的data

    如下图,channel 0的数值为605

    根据公式:电压 = ( data / 0x3ff)* 基准电压

    此时电压为605 / 1023 * 1.8 V = 1.065V

    ④adc scan adclp [channel mask] → 可查看多个channel的data

    adc scan adclp :查看所有channel的data

    adc scan adclp 0x3:查看channel 0和channel 1的data

    5.4. 非DM Regulator框架下的使用方法

    为了提供更高程度的定制化功能,adclp驱动可以选择不对接DM Regulator框架,直接通过API调用实现ADC采样的功能,仅需设定CONFIG和调用头文件里的API。

    5.4.1. CONFIG配置

    • CONFIG_ADC=n

    • CONFIG_SGS_ADCLP=y

    5.4.2. API说明

    参考头文件drivers/sgs_common/include/drv_adclp.h

    enum adclp_vdd_type
    {
        ADCLP_VDD_CPU = 0,
        ADCLP_VDD_DLA,
        ADCLP_VDD_MIU,
        ADCLP_VDD_CORE,
        ADCLP_VDD_NODIE,
        ADCLP_VSS,
    };
    
    s32 drv_adclp_enable(u8 channel, u8 enable);
    s32 drv_adclp_vdd_data(u8 channel, u16 *data, enum adclp_vdd_type type);
    s32 drv_adclp_sample_data(u8 channel, u16 *data);
    
    5.4.2.1. drv_adclp_enable
    • 目的

      使能指定通道的采样功能

    • 语法

      s32 drv_adclp_enable(u8 channel, u8 enable);
      
    • 参数

      参数名称 描述
      channel 采样通道
      enable 使能与否
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败
    5.4.2.2. drv_adclp_vdd_data
    • 目的

      获取指定通道(仅持支持channel=8)的VDD采样结果

    • 语法

      s32 drv_adclp_vdd_data(u8 channel, u16 *data, enum adclp_vdd_type type);
      
    • 参数

      参数名称 描述
      channel 采样通道(仅持支持channel=8),内部直联,PIN脚无需外接负载
      data VDD_CPU、VDD_CORE等ADC采样结果
      type VDD_CPU、VDD_DLA、VDD_MIU、VDD_CORE
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败
    5.4.2.3. drv_adclp_sample_data
    • 目的

      获取指定通道的输入电压转换后的数字量

    • 语法

      s32 drv_adclp_sample_data(u8 channel, u16 *data)
      
    • 参数

      参数名称 描述
      channel 采样通道
      data 采样数据
    • 返回值

      返回值 描述
      0 成功
      EINVAL 失败

    5.4.3. DEMO

    #include <command.h>
    #include <common.h>
    #include <drv_adclp.h>
    
    int do_adclp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
    {
        int   ret;
        char *cmd;
        u16 * data;
        u8    enable;
        u8    channel;
    
        cmd = argv[1];
        if (strcmp(cmd, "init") == 0)
        {
            if (argc != 4)
            {
                printf("adclp init [channel] [enable]\r\n");
                return CMD_RET_USAGE;
            }
    
            channel = (int)simple_strtoul(argv[2], NULL, 10);
            enable  = (int)simple_strtoul(argv[3], NULL, 10);
    
            ret = drv_adclp_enable(channel, enable);
            if (ret)
            {
                return CMD_RET_USAGE;
            }
        }
        else if (strcmp(cmd, "vdd") == 0)
        {
            if (argc != 3)
            {
                printf("adclp vdd [channel] \r\n");
                return CMD_RET_USAGE;
            }
    
            channel = (int)simple_strtoul(argv[2], NULL, 10);
    
            ret = drv_adclp_vdd_data(channel, data, ADCLP_VDD_CPU);
            if (ret)
            {
                return CMD_RET_USAGE;
            }
            printf("adclp channel[%d] data[%hu]\r\n", channel, *data);
        }
        else if (strcmp(cmd, "sample") == 0)
        {
            if (argc != 3)
            {
                printf("adclp sample [channel] \r\n");
                return CMD_RET_USAGE;
            }
    
            channel = (int)simple_strtoul(argv[2], NULL, 10);
    
            ret = drv_adclp_sample_data(channel, data);
            if (ret)
            {
                return CMD_RET_USAGE;
            }
            printf("adclp channel[%d] data[%d]\r\n", channel, *data);
        }
        else
        {
            printf("adclp command error\r\n");
            return CMD_RET_USAGE;
        }
    
        return 0;
    }
    
    static char adclp_help_text[] =
        "\n"
        "adclp init   [channel] [enable] \n"
        "adclp vdd    [channel]\n"
        "adclp sample [channel]\n";
    
    U_BOOT_CMD(adclp, CONFIG_SYS_MAXARGS, 1, do_adclp, "adclp test", adclp_help_text);
    

    6. Kernel用法介绍

    6.1. Kernel Config配置

    SAR ADCLP关联的驱动模块Config:

    • CONFIG_IIO

    SAR ADCLP驱动enable需要选择如下配置:

    Device Drivers --->
    
        [*] Sgs SoC platform drivers --->
    
            <*> Sgs ADCLP driver
    

    6.2. DTS配置

    SAR ADCLP的DTS配置只需要在chipname.dtsi中配置如下信息:

    adclp0: adclp0@1f002800 {
        compatible = "sgs,adclp";
        interrupts=<GIC_SPI INT_IRQ_SAR_ADC_WAKEUP IRQ_TYPE_LEVEL_HIGH>;
        reg = <0x0 0x1F002800 0x200>;
        clocks = <&CLK_sar>;
        interrupt-enable;
        channel = <0>;
        scope = <0>;
        ref-voltage = <1800>;
        upper-bound = <0x3FF>;
        lower-bound = <0>;
        #io-channel-cells = <0>;
        status = "ok";
    };
    
    属性 描述 设定值 备注
    compatible 匹配驱动进行驱动注册 "sgs,adclp" 禁止修改
    interrupts 设定中断 禁止修改
    reg 设定寄存器bank地址 0x1F002800 禁止修改
    clocks 设定时钟源 &CLK_sar 不需要更改
    interrupt-enable 使能中断 bool类型,注释即disable 可根据需要修改
    channel 设定通道 0~4 不需要更改
    scope 设定作用域 作为测量外部输入电压的通道, scope都为0 可根据需要修改
    ref-voltage 设定基准电压档位 以mv为单位,可选1800和1000 可根据需要修改
    upper-bound 设定阈值上限电压 0~0x3FF,使能中断有效 可根据需要修改
    lower-bound 设定阈值下限电压 0~0x3FF,使能中断有效 可根据需要修改
    status 是否使能驱动 "ok" or "disable" 可根据需要修改

    6.3. Padmux配置

    SAR-ADCLP无需进行padmux的配置,原理图上的PIN脚会默认配置为ADC采样功能,但是padmux.dtsi中如果将SAR_GPIO引脚配置为GPIO MODE,那么ADC功能将失效

    6.4. 模块使用介绍

    6.4.1. SYSFS接口说明

    1. 进入SAR ADCLP采样的通道Channel 0

      cd /sys/class/sgs/adclp0/
      
    2. 设定SAR ADCLP0的阈值(不设定阈值也不影响采样)

      echo 800 400 > /sys/class/sgs/adclp0/threshold
      (第一个参数800是阈值上限,第二个参数400是阈值下限,即adc code在400~800的阈值范围内判断为安全,超出范围会触发中断,可以参考kernel/drivers/sgs_common/adc/ut/lnx/adclp_lnx_ut.c中的写法,这里只起了参数设定的作用,中断callback需要程序实现,因此验证SYSFS接口也可不用设置此参数)
      
    3. 使能SAR ADCLP0

      echo 1 > enable
      
    4. 获取SAR ADCLP0采样后的数字量

      cat /sys/class/sgs/adclp0/value
      

    6.4.2. IIO接口说明

    1. 进入ADCLP通道的IIO入口

      cd /sys/bus/iio/devices/iio:adclp0  //通道0的入口
      cd /sys/bus/iio/devices/iio:vdd-mux //VDD通道入口
      cd /sys/bus/iio/devices/iio:tsensor //Tsensor通道入口
      
    2. 设定VDD或者Tsensor的类型(仅支持iio:vdd-mux和iio:tsensor)

      echo N > in_voltage_phase //N为adclp_vdd_type或者adclp_tsensor_type
      
    3. 使能通道

      echo 1 > in_voltage_en
      
    4. 获取该通道的adc code

      cat in_voltage_raw
      
    5. 获取该通道的计算比例因子

      in_voltage_scale
      

    实际电压 = in_voltage_raw的值 * in_voltage_scale的值

    6.4.3. Ioctl接口说明

    头文件<drv_adclp.h>位于kernel/drivers/sgs_common/include目录下,

    • IOCTL_ADCLP_SET_BOUND

      设定采样电压阈值

    • IOCTL_ADCLP_READ_VALUE

      获取电压转换后的数字量

    struct adclp_bound
    {
        u16 upper_bound;
        u16 lower_bound;
    };
    
    #define ADCLP_IOC_MAXNR        1
    #define ADCLP_IOC_MAGIC        'a'
    #define IOCTL_ADCLP_SET_BOUND  _IO(ADCLP_IOC_MAGIC, 0)
    #define IOCTL_ADCLP_READ_VALUE _IO(ADCLP_IOC_MAGIC, 1)
    

    6.5. Sample Code

    6.5.1 Ioctl

    源码位于kernel/drivers/sgs_common/adc/ut/lnx/adclp_lnx_ut.c

    #include <fcntl.h>
    #include <stdio.h>
    #include <errno.h>
    #include <signal.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <limits.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <drv_adclp.h>
    
    void sample_warn(int num)
    {
        printf("adclp data exceeding the threshold\n");
    }
    
    int get_parameter(u16 *para, const char *str)
    {
        long  value  = 0;
        char *endptr = NULL;
    
        errno = 0;
        value = strtol(str, &endptr, 0);
    
        if (errno == ERANGE)
        {
            fprintf(stderr, "Error: parameter '%s' out of range [%ld, %ld]\n", str, LONG_MIN, LONG_MAX);
            return -ERANGE;
        }
        if (endptr == str)
        {
            fprintf(stderr, "Error: parameter '%s' not a valid number\n", str);
            return -EINVAL;
        }
        if (*endptr != '\0')
        {
            fprintf(stderr, "Warning: parameter '%s' contains extra characters '%s'\n", str, endptr);
        }
    
        if (value > UINT_MAX)
        {
            fprintf(stderr, "Error: value %ld greater than [%u]\n", value, UINT_MAX);
            return -EINVAL;
        }
    
        *para = (u16)value;
    
        return 0;
    }
    
    int main(int argc, char **argv)
    {
        int                i;
        int                fd;
        int                ret;
        char               cmd;
        int                flags;
        u16                value;
        u16                channel;
        u16                upper_bd;
        u16                lower_bd;
        u16                chan_num;
        char               path[64];
        struct adclp_bound adclp_bd;
    
        if (argc < 2)
        {
            printf("format: adclp_lnx_ut once [channel] <upper> <lower>\n");
            printf("format: adclp_lnx_ut scan [chan num]\n");
            return -1;
        }
    
        if (!strcmp(argv[1], "once"))
        {
            if (argc == 3)
            {
                ret = get_parameter(&channel, argv[2]);
                if (ret < 0)
                {
                    return ret;
                }
            }
            else if (argc == 5)
            {
                ret = get_parameter(&channel, argv[2]);
                if (ret < 0)
                {
                    return ret;
                }
    
                ret = get_parameter(&upper_bd, argv[3]);
                if (ret < 0)
                {
                    return ret;
                }
                adclp_bd.upper_bound = (u16)upper_bd;
    
                ret = get_parameter(&lower_bd, argv[4]);
                if (ret < 0)
                {
                    return ret;
                }
                adclp_bd.lower_bound = (u16)lower_bd;
            }
            else
            {
                printf("format: adclp_lnx_ut once [channel] <upper> <lower>\n");
                return -1;
            }
    
            snprintf(path, sizeof(path), "/dev/adclp%u", channel);
            fd = open((const char *)(char *)path, O_RDWR);
            if (fd < 0)
            {
                printf("open device fail\n");
                return -1;
            }
    
            if (argc == 5)
            {
                ioctl(fd, IOCTL_ADCLP_SET_BOUND, &adclp_bd);
            }
    
            signal(SIGIO, sample_warn);
    
            fcntl(fd, F_SETOWN, getpid());
            flags = fcntl(fd, F_GETFL);
            fcntl(fd, F_SETFL, flags | FASYNC);
    
            while (1)
            {
                cmd = getchar();
                if (cmd == 'q' || cmd == 'Q')
                {
                    break;
                }
    
                ioctl(fd, IOCTL_ADCLP_READ_VALUE, &value);
                printf("adclp%u data[%hu]\n", channel, value);
            }
    
            close(fd);
        }
        else if (!strcmp(argv[1], "scan"))
        {
            if (argc == 3)
            {
                ret = get_parameter(&chan_num, argv[2]);
                if (ret < 0)
                {
                    return ret;
                }
            }
            else
            {
                printf("format: adclp_lnx_ut scan [chan num]\n");
                return -1;
            }
    
            for (i = 0; i < chan_num; i++)
            {
                snprintf(path, sizeof(path), "/dev/adclp%u", i);
                fd = open((const char *)(char *)path, O_RDWR);
                if (fd < 0)
                {
                    printf("open device fail\n");
                    continue;
                }
    
                ioctl(fd, IOCTL_ADCLP_READ_VALUE, &value);
                printf("adclp%u data[%hu]\n", i, value);
                close(fd);
            }
        }
        else
        {
            printf("format: adclp_lnx_ut once [channel] <upper> <lower>\n");
            printf("format: adclp_lnx_ut scan [chan num]\n");
            return -1;
        }
    
        return 0;
    }
    

    6.5.2 Kernel Mode

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/platform_device.h>
    #include <linux/of.h>
    #include <drv_adclp.h>
    
    static adclp_cb_t cb_t[4];
    
    int adclp_get_data2(u8 channel)
    {
        u16 data;
    
        drv_adclp_sample_data(channel, &data);
        printk("%s adclp test chan[%d], data[%hu]\n", __func__, channel, data);
    
        return 0;
    }
    
    int adclp_get_data1(u8 channel)
    {
        u16 data;
    
        drv_adclp_sample_data(channel, &data);
        printk("%s adclp test chan[%d], data[%hu]\n", __func__, channel, data);
    
        return 0;
    }
    
    static int __init adclp_test_init(void)
    {
        int ret;
    
        cb_t[0] = adclp_get_data1;
        ret = drv_adclp_register_callback(0, cb_t[0]);
        if (ret)
        {
            printk("adclp ch0-0 register callback fail\n");
            return ret;
        }
    
        cb_t[1] = adclp_get_data2;
        ret = drv_adclp_register_callback(0, cb_t[1]);
        if (ret)
        {
            printk("adclp ch0-1 register callback fail\n");
            return ret;
        }
    
        cb_t[2] = adclp_get_data1;
        ret = drv_adclp_register_callback(1, cb_t[2]);
        if (ret)
        {
            printk("adclp ch1-0 register callback fail\n");
            return ret;
        }
    
        cb_t[3] = adclp_get_data2;
        ret = drv_adclp_register_callback(1, cb_t[3]);
        if (ret)
        {
            printk("adclp ch1-1 register callback fail\n");
            return ret;
        }
    
        ret = drv_adclp_set_bound(0, 800, 600);
        if (ret)
        {
            printk("adclp ch0 set bound fail\n");
            return ret;
        }
    
        ret = drv_adclp_set_bound(1, 1000, 600);
        if (ret)
        {
            printk("adclp ch1 set bound fail\n");
            return ret;
        }
    
        drv_adclp_enable(0, 1);
        drv_adclp_enable(1, 1);
    
        return 0;
    }
    
    static void __exit adclp_test_exit(void)
    {
        drv_adclp_enable(0, 0);
        drv_adclp_enable(1, 0);
    
        drv_adclp_unregister_callback(0, cb_t[0]);
        drv_adclp_unregister_callback(0, cb_t[1]);
        drv_adclp_unregister_callback(1, cb_t[2]);
        drv_adclp_unregister_callback(1, cb_t[3]);
    }
    
    module_init(adclp_test_init);
    module_exit(adclp_test_exit);
    

    7. API参考

    API可参考位于kernel/drivers/sgs_common/include目录下的头文件<drv_adclp.h>

    enum adclp_vdd_type
    {
        ADCLP_VDD_CPU = 0,
        ADCLP_VDD_DLA,
        ADCLP_VDD_MIU,
        ADCLP_VDD_CORE,
        ADCLP_VDD_NODIE,
        ADCLP_VSS,
    };
    
    enum adclp_tsensor_type
    {
        ADCLP_TSNR_SAR = 0,
        ADCLP_TSNR_CPU,
        ADCLP_TSNR_DLA,
        ADCLP_TSNR_CORE,
    };
    
    typedef s32 (*adclp_cb_t)(u8 channel);
    
    //该功能模块提供以下内核态接口:
    s32 drv_adclp_enable(u8 channel, u8 enable);
    s32 drv_adclp_set_bound(u8 channel, u16 upper_bound, u16 lower_bound);
    s32 drv_adclp_vdd_data(enum adclp_vdd_type type, u16 *data);
    s32 drv_adclp_tsensor_data(enum adclp_tsensor_type type, u16 *data);
    s32 drv_adclp_sample_data(u8 channel, u16 *data);
    s32 drv_adclp_register_callback(u8 channel, adclp_cb_t cb_t);
    s32 drv_adclp_unregister_callback(u8 channel, adclp_cb_t cb_t);
    

    drv_adclp_enable

    • 目的

      使能指定通道的采样功能

    • 语法

      s32 drv_adclp_enable(u8 channel, u8 enable);
      
    • 参数

      参数名称 描述
      channel 采样通道
      enable 使能与否
    • 返回值

      返回值 描述
      0 成功
      -EINVAL 通道不支持

    drv_adclp_set_bound

    • 目的

      设定指定通道的阈值

    • 语法

      s32 drv_adclp_set_bound(u8 channel, u16 upper_bound, u16 lower_bound)
      
    • 参数

      参数名称 描述
      channel 采样通道
      upper_bound 阈值上限
      lower_bound 阈值下限
    • 返回值

      返回值 描述
      0 成功
      -EINVAL 通道不支持

    drv_adclp_vdd_data

    • 目的

      获取不同VDD类型的的adc code,无需外接输入电压,adc code值取决于adclp_vdd_type传入的类型

    • 语法

      s32 drv_adclp_vdd_data(enum adclp_vdd_type type, u16 *data)
      
    • 参数

      参数名称 描述
      type VDD类型
      data 获取采样结果的指针地址
    • 返回值

      返回值 描述
      0 设定成功
      -EINVAL 通道不支持

    drv_adclp_tsensor_data

    • 目的

      获取不同tsensor类型的的adc code,无需外接输入电压,adc code值取决于adclp_tsensor_type传入的类型

    • 语法

      s32 drv_adclp_tsensor_data(enum adclp_tsensor_type type, u16 *data)
      
    • 参数

      参数名称 描述
      type tsensor类型
      data 获取采样结果的指针地址
    • 返回值

      返回值 描述
      0 设定成功
      -EINVAL 通道不支持

    drv_adclp_sample_data

    • 目的

      获取指定通道的外部输入电压数字量

    • 语法

      s32 drv_adclp_sample_data(u8 channel, u16 *data)
      
    • 参数

      参数名称 描述
      channel 采样通道
      data 获取采样结果的指针地址
    • 返回值

      返回值 描述
      0 成功
      -EINVAL 通道不支持

    drv_adclp_register_callback

    • 目的

      注册指定通道的回调函数(同一通道支持注册多个回调函数),当采样结果超出阈值后可在回调函数里作出相应的处理

    • 语法

      s32 drv_adclp_register_callback(u8 channel, adclp_cb_t cb_t)
      
    • 参数

      参数名称 描述
      channel 采样通道
      cb_t 函数指针
    • 返回值

      返回值 描述
      0 注册成功
      -EINVAL 注册失败

    drv_adclp_unregister_callback

    • 目的

      释放指定通道的回调函数和注册时申请的内存

    • 语法

      s32 drv_adclp_unregister_callback(u8 channel, adclp_cb_t cb_t)
      
    • 参数

      参数名称 描述
      channel 采样通道
      cb_t 函数指针
    • 返回值

      返回值 描述
      0 取消注册成功
      -EINVAL 取消注册失败

    8. FAQ

    Q1:SAR ADCLP接口不存在

    1. 检查DTS ADCLP节点的status是否为ok

    2. 检查kernel config是否配置,详见[6.1. Kernel Config配置]

    Q2:外部输入电压变化,SAR ADCLP采样数据没有变化

    1. 当PIN脚处于GPIO MODE时,采样数据不会变化,可读取寄存器的数值判断PIN脚是否被切为GPIO MODE:

      0x14 0x11 BIT0-BIT5:
      BIT0~BIT5的每个BIT对应一个通道,当value=0时,该通道PIN脚处于GPIO MODE,当value=1时,该通道PIN脚处于ADC MODE,比如BIT0=0时,通道0处于GPIO MODE,BIT1=1时,通道1处于ADC MODE
      
      0x14 0x11 BIT8-BIT13:
      BIT8~BIT13的每个BIT对应一个通道,前提条件是PIN脚已处于GPIO MODE,当value=0时,PIN脚切换为output,当value=1时,PIN脚切换为input
      
      0x14 0x12 BIT0-BIT5:
      BIT0~BIT5的每个BIT对应一个通道,前提条件是PIN脚已处于GPIO MODE并且设定为ouput,当value=0时,该通道PIN脚切换为低电平,当value=1时,该通道PIN脚切换为高电平
      
      例如:riu_r 0x14 0x11
      返回值:0x3F3F -> 全部通道为ADC MODE
      返回值:0x3E3E -> 通道0为GPIO MODE,其余通道为ADC MODE
      返回值:0x0000 -> 全部通道为GPIO MODE且切换为output
      
    2. 当PIN脚寄存器设定非GPIO MODE时,采样数据仍然没有变化,可将PIN脚设为GPIO MODE并进行output high/low的试验,如果PIN脚电平无法拉高拉低则可判断为硬件问题

    Q3:第一次或者前几次采样数据与实际输入电压偏差大

    此问题大概率与采样时机有关,可通过操作GPIO作为触发源,获取每次采样时元件的电压情况,

    如下图所示,触发ADC采样前,GPIO从高电平切换为低电平,ADC采样时机刚好处于电压的下降过程,并不是在电压稳定时去采样,因此被判定为采样异常,此时需要等元件稳定时再去采样