当前文档版本为 v0.9.0,您可以访问当前页面的 开发中 版本以获取最近可能的更新。

Driver: ADC

1 功能概述

本文档的例程演示外设模块 ADC 单次转换及多次转换功能,并演示从 ADC 采样值反推输入电压的方法。

DMA 功能参考第 6 小节。

2 环境要求

  • PAN1080 EVB 一块 (需确保核心板 SoC 为校准后的芯片)

  • USB-TypeC 线一条(用于供电和查看串口打印 Log)

  • 万用表 一块

  • 硬件接线:

    • 使用USB线,将 PC USB 与 EVB USB-TypeC(USB->UART)相连

    • 根据 EVB 核心板芯片的封装不同,使用杜邦线将 EVB 底板上的:

      • TX0 与 P00 相连, RX0 与 P01 相连(若 EVB 板芯片为 QFN32 或 LQFP64 封装)

      • TX0 与 P30 相连, RX0 与 P31 相连(若 EVB 板芯片为 QFN48 封装)

    • 使用跳线帽将 EVB 底板左上角的 ADC 与 P20 (ADC_Channel_6) 相连

  • PC 软件: 串口调试助手(UartAssist)或终端工具(SecureCRT),波特率921600

3 编译和烧录

例程位置:

  1. zephyr\samples_panchip\drivers\adc (Zephyr ADC Sample)

  2. zephyr\samples_panchip\drivers\adc_hal_api (ADC HAL API Sample)

使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍

4 演示说明 (Zephyr ADC Sample)

  1. 使用万用表,测量 EVB 板 ADC 引脚的电压,调节可调电阻 R_ADJ 的阻值,将 ADC 引脚电压调整至 1.2v 以内 (如 850mV)

  2. 执行例程,串口打印如下 Log:

    Try to load HW calibration data.. DONE.
    - Chip Type         : 0x80
    - Chip CP Version   : None
    - Chip FT Version   : 7
    - Chip MAC Address  : D0000C0507EA
    - Chip Flash UID    : 9429050C014491089429050C01449108
    - Chip Flash Size   : 512 KB
    *** Booting Zephyr OS build zephyr-v2.7.0-1346-g181eea9cf7ca  ***
    adc-vbg voltage: 1201 mV
    
    sample one time:
    adc sampling data: 0xb6e
    The ADC sample code is 2926
    The voltage value calculated with ideal formula is 857 mV
    The voltage value calculated with fitting formula is 846 mV
    The voltage value calculated with fitting formula2 is 845 mV
    
    sample ten times:
    adc sampling data: 0xb7c
    adc sampling data: 0xb77
    adc sampling data: 0xb84
    adc sampling data: 0xb74
    adc sampling data: 0xb64
    adc sampling data: 0xb73
    adc sampling data: 0xb78
    adc sampling data: 0xb70
    adc sampling data: 0xb80
    adc sampling data: 0xb7c
    The processed ADC sample code is 2935
    The voltage value calculated with ideal formula is 860 mV
    The voltage value calculated with fitting formula is 849 mV
    The voltage value calculated with fitting formula2 is 848 mV
    
    Done.
    

4.1 ADC 通道配置

配置 ADC 通道参数,主要有两个参数可调:

  1. adc_channel_cfg.reference: ADC 参考电压,有 2 个可选值:

    • ADC_REF_VDD_1_2: 参考电压为 ADC 内部 1.2v VBG

    • ADC_REF_VDD_1: 参考电压为 SoC VDD (VBAT, 通常为 3.3v)

  2. adc_channel_cfg.channel_id: ADC 采样通道,可选值为 0 ~ 7,分别表示通道 1 ~ 通道 7

static const struct adc_channel_cfg m_channel_cfg = {
	.gain             = ADC_GAIN_1,
	.reference        = ADC_REF_VDD_1_2,
	.acquisition_time = ADC_ACQ_TIME_DEFAULT,
	.channel_id       = ADC_CHANNEL_ID,
};

4.2 ADC 单次转换功能

  1. 配置adc序列信息并adc初始化。

    const struct adc_sequence sequence = {
        .channels = BIT(ADC_CHANNEL_ID),				/*通道选择*/
        .buffer = m_sample_buffer,						/*结果缓存buffer*/
        .buffer_size = sizeof(m_sample_buffer),			/*buffer大小,不能小于次数*/
        .resolution = ADC_RESOLUTION,					/*我们固定为12bit adc*/
    };
    
    const struct device *adc_dev = init_adc();	/*初始化adc模块*/
    
    if (!adc_dev) {
        return -ENODEV;
    }
    
  2. 读取adc转换值。

    ret = adc_read(adc_dev, &sequence);	/*读取adc转换的code*/
    if (ret != 0) {
        printk("adc_read() failed with code %d\n", ret);
    }
    printk("adc sampling data: 0x%x\n", m_sample_buffer[0]); /*打印获取code*/
    
  3. 软件分别通过理想公式和拟合公式推算 ADC 采样电压,并将其打印出来:

    voltage_with_ideal_formula = ADC_REF_VOLTAGE * adc_code / 4096;
    printk("The voltage value calculated with ideal formula is %d mV\n", voltage_with_ideal_formula);
    
    voltage_with_fitting_formula = ADC_OutputVoltage(ADC, adc_code) / 1000;
    printk("The voltage value calculated with fitting formula is %d mV\n", voltage_with_fitting_formula);
    
    if (otp.m.ft_version >= 7) {
    	voltage_with_fitting_formula2 = ADC_OutputVoltageRefVbgPiecewise(ADC, adc_code) / 1000;
    	printk("The voltage value calculated with fitting formula2 is %d mV\n\n", voltage_with_fitting_formula2);
    }
    

    上述 3 种计算方法中:

    • voltage_with_ideal_formula 为使用理想公式计算的结果

    • voltage_with_fitting_formula 为使用最小二乘法拟合的直线公式计算的结果

    • voltage_with_fitting_formula2 为使用分段拟合的直线公式计算的结果

    :一般来说,理想公式计算结果最不准确,最小二乘法拟合的直线公式与分段拟合的直线公式计算的结果更准确,实际项目中推荐使用最小二乘法拟合的直线公式,计算速度会比较快。

  4. 观察计算结果是否与实际输入电压一致

4.3 ADC 多次转换功能

  1. 配置adc序列信息并adc初始化。

    const struct adc_sequence_options options = {
        .callback        = repeated_samplings_callback,	/*中断回调函数*/
        .extra_samplings = ADC_BUFFER_SIZE / 2,			/*转换次数*/
        .interval_us     = 0,							/*间隔时间*/
        .user_data       = user_data,					/*用户数据*/
    };
    
    const struct adc_sequence sequence = {
        .options     = &options,						/*增加附加序列信息*/
        .channels = BIT(ADC_CHANNEL_ID),				/*通道选择*/
        .buffer = m_sample_buffer,						/*结果缓存buffer*/
        .buffer_size = sizeof(m_sample_buffer),			/*buffer大小,不能小于次数*/
        .resolution = ADC_RESOLUTION,					/*我们固定为12bit adc*/
    };
    
    const struct device *adc_dev = init_adc();	/*初始化adc模块*/
    
    if (!adc_dev) {
        return -ENODEV;
    }
    
  2. 设置回调函数

    static enum adc_action repeated_samplings_callback(const struct device *dev,
    						   const struct adc_sequence *sequence,
    						   uint16_t sampling_index)
    {
    	++m_samplings_done;
    	if (m_samplings_done == 1U) {
    		/* After first sampling continue normally. */
    		return ADC_ACTION_CONTINUE;
    	} else {
    		/*
    		 * The second sampling is repeated 9 times (the samples are
    		 * written in the same place), then the sequence is finished
    		 * prematurely.
    		 */
    		if (m_samplings_done < ADC_BUFFER_SIZE / 2) {
                /*这里选择continue,code会依次存放在buffer中*/
                /*如果选择repeat,那么只会存放在buffer的固定第二个数据中*/
    			return ADC_ACTION_CONTINUE;
    		} else {
    			convert_finish = true;
    			return ADC_ACTION_FINISH;
    		}
    	}
    }
    
  3. 读取adc转换值并计算平均值。

    ret = adc_read(adc_dev, &sequence);	/*读取adc转换的code*/
    if (ret != 0) {
        printk("adc_read() failed with code %d\n", ret);
    }
    
    for (uint8_t i = 0; i < ADC_BUFFER_SIZE / 2; i++) {
        avg_code += m_sample_buffer[i];
        printk("adc sampling data: 0x%x\n", m_sample_buffer[i]);
    }
    
  4. 软件分别通过理想公式和拟合公式推算 ADC 采样电压,并将其打印出来:

    voltage_with_ideal_formula = ADC_REF_VOLTAGE * adc_code / 4096;
    printk("The voltage value calculated with ideal formula is %d mV\n", voltage_with_ideal_formula);
    
    voltage_with_fitting_formula = ADC_OutputVoltage(ADC, adc_code) / 1000;
    printk("The voltage value calculated with fitting formula is %d mV\n", voltage_with_fitting_formula);
    
    if (otp.m.ft_version >= 7) {
    	voltage_with_fitting_formula2 = ADC_OutputVoltageRefVbgPiecewise(ADC, adc_code) / 1000;
    	printk("The voltage value calculated with fitting formula2 is %d mV\n\n", voltage_with_fitting_formula2);
    }
    

    上述 3 种计算方法中:

    • voltage_with_ideal_formula 为使用理想公式计算的结果

    • voltage_with_fitting_formula 为使用最小二乘法拟合的直线公式计算的结果

    • voltage_with_fitting_formula2 为使用分段拟合的直线公式计算的结果

    :一般来说,理想公式计算结果最不准确,最小二乘法拟合的直线公式与分段拟合的直线公式计算的结果更准确,实际项目中推荐使用最小二乘法拟合的直线公式,计算速度会比较快。

  5. 观察计算结果是否与实际输入电压一致

    本次演示 ADC 实际输入电压为 850 mV,由前面的串口打印 Log 可知:

    • 单次 ADC 采样:

      • 使用理想公式计算的 ADC 输入电压为 857 mV

      • 使用最小二乘法拟合的直线公式计算的 ADC 输入电压为 846 mV

      • 使用分段拟合的直线公式计算的 ADC 输入电压为 845 mV

    • 多次 ADC 采样(10次)取平均:

      • 使用理想公式计算的 ADC 输入电压为 860 mV

      • 使用最小二乘法拟合的直线公式计算的 ADC 输入电压为 849 mV

      • 使用分段拟合的直线公式计算的 ADC 输入电压为 848 mV

5 演示说明 (ADC HAL API Sample)

  1. 使用万用表,测量 EVB 板 ADC 引脚的电压,调节可调电阻 R_ADJ 的阻值,将 ADC 引脚电压调整至 1.2v 以内 (如 850mV)

  2. 执行例程,串口打印如下 Log:

    Try to load HW calibration data.. DONE.
    - Chip Type         : 0x80
    - Chip CP Version   : None
    - Chip FT Version   : 7
    - Chip MAC Address  : D0000C0507EA
    - Chip Flash UID    : 9429050C014491089429050C01449108
    - Chip Flash Size   : 512 KB
    *** Booting Zephyr OS build zephyr-v2.7.0-1346-g181eea9cf7ca  ***
    adc-vbg voltage: 1201 mV
    ---------------- Measure round 0 ----------------
    ADC sampling data:
    2897 2911 2919 2926 2928 2928 2928 2928 2928 2928
    2929 2929 2932 2934 2934 2937 2940 2941 2944 3200
    The processed ADC sample code is 2929
    The voltage value calculated with ideal formula is 858 mV
    The voltage value calculated with fitting formula is 847 mV
    The voltage value calculated with fitting formula2 is 846 mV
    
    ---------------- Measure round 1 ----------------
    ADC sampling data:
    2920 2928 2928 2928 2928 2929 2932 2933 2936 2940
    2940 2942 2944 2944 2944 2945 2945 2950 2960 2980
    The processed ADC sample code is 2940
    The voltage value calculated with ideal formula is 862 mV
    The voltage value calculated with fitting formula is 850 mV
    The voltage value calculated with fitting formula2 is 849 mV
    
    ---------------- Measure round 2 ----------------
    ADC sampling data:
    2914 2920 2921 2921 2928 2928 2928 2930 2931 2936
    2937 2939 2940 2944 2944 2944 2944 2944 2946 2951
    The processed ADC sample code is 2937
    The voltage value calculated with ideal formula is 861 mV
    The voltage value calculated with fitting formula is 849 mV
    The voltage value calculated with fitting formula2 is 848 mV
    
    ---------------- Measure round 3 ----------------
    ADC sampling data:
    2928 2928 2928 2928 2929 2929 2931 2936 2936 2936
    2936 2936 2937 2940 2944 2944 2945 2951 2958 3004
    The processed ADC sample code is 2936
    The voltage value calculated with ideal formula is 860 mV
    The voltage value calculated with fitting formula is 849 mV
    The voltage value calculated with fitting formula2 is 848 mV
    
    ---------------- Measure round 4 ----------------
    ADC sampling data:
    2896 2915 2928 2928 2928 2928 2929 2931 2932 2932
    2933 2934 2935 2937 2944 2944 2944 2952 2976 3005
    The processed ADC sample code is 2933
    The voltage value calculated with ideal formula is 859 mV
    The voltage value calculated with fitting formula is 848 mV
    The voltage value calculated with fitting formula2 is 847 mV
    
    Done.
    
  3. 本次演示 ADC 实际输入电压为 850 mV,由上述串口打印 Log 可知:

    • 使用 ADC 采样 5 轮,每轮采样 20 次,取采样值的中位数

      • 使用理想公式计算的 ADC 输入电压依次为:858 mV、862 mV、861 mV、860 mV、859 mV

      • 使用最小二乘法拟合的直线公式计算的 ADC 输入电压依次为:847 mV、850 mV、849 mV、849 mV、848 mV

      • 使用分段拟合的直线公式计算的 ADC 输入电压依次为:846 mV、849 mV、848 mV、848 mV、847 mV

注:本例程的 ADC 软件操作流程请参考工程代码中的相关注释。

6 开发说明

  1. 为使用 ADC 计算电压准确,请确保当前的芯片为校准后的芯片,且芯片的 FT 版本号最好大于或等于 7,可根据芯片上电后的串口 Log 判断:

    Try to load HW calibration data.. DONE.
    - Chip Type         : 0x80
    - Chip CP Version   : None
    - Chip FT Version   : 7
    

    上述 Log 即表示当前芯片为校准后的芯片,FT Version 为 7;另外,若芯片的 FT Version 小于 7,ADC也是可以正常使用的,只是计算准确度可能会稍微差一些。

  2. 当使用 Zephyr ADC Driver 时,需要在prj.conf文件中添加 “CONFIG_ADC=y” 以启用 ADC 模块;而当直接使用 ADC HAL Driver时,无需执行此步骤

  3. ADC 初始化代码执行完成后,应当延时一段时间后再执行采样操作,以确保 ADC 硬件模块处于稳定状态

  4. 应用中可能会需要使用分压电阻将待测电压分压至 ADC 采样电压范围内(0 ~ 1.2v),而为了减少电路漏电,可能会需要使用较大的电阻,但是,过大的分压电阻可能导致 ADC 采样抖动较大,解决的方法一方面可以在 ADC 输入引脚处增加电容,另一方面要采用稍小一些的分压电阻,这里我们推荐总电阻不要超过 1MΩ,例如使用 ADC 测量典型的锂电池电压(4.2v),分压电阻可采用 1/4 分压的方式,可分别使用一个 250KΩ 和 一个 750KΩ 的电阻,将电池电压分压至 1.1v 以内, 由分压电路产生的漏电流为 4.2v / 1MΩ = 4.2 uA

7 ADC DMA配置说明

ADC DMA 例程位于:zephyr\samples_panchip\drivers\adc_dma

  • CONFIG_ADC_PANCHIP_DMA=y

    该配置使能 ADC DMA feature。

  • CONFIG_ADC_PANCHIP_DMA_TIMEOUT=1000

    该配置为ADC DMA读取一次时的超时时间,单位为ms。

  • ADC配置注意点 需要确认extra_samplings+1等于实际采样的次数,否则采样次数不对会导致不会触发DMA中断,从而导致ADC DMA read超时。

8 RAM/Flash资源使用情况

Memory region         Used Size  Region Size  %age Used
FLASH:       24924 B       256 KB      9.51%
SRAM:         5728 B        64 KB      8.74%

9 Adc全功能测试case

Adc全功能测试case及测试流程请参考文档:03_MCU/mcu_samples_doc/PAN1080 ADC例程说明.pdf