1.3. GPADC

SARADC是12 Bit ADC(A/D转换器),支持6bit/8bit/10bit/12bit数据位宽采样,该外设时钟最大不可超过12MHz,最小250KHz。

Note

该外设涉及的源码文件包括 gpadc.c,gpadc.h,gpadc_api.h。

1.3.1. GPADC相关宏配置

1.3.1.1. 数据采样位宽配置

GPADC持6bit/8bit/10bit/12bit数据位宽采样。

//ADC采样数据位宽
#define ADC_SEL_6_BIT   (0x0)
#define ADC_SEL_8_BIT   (0x1)
#define ADC_SEL_10_BIT  (0x2)
#define ADC_SEL_12_BIT  (0x3)
#define ADC_BIT_SEL         ADC_SEL_12_BIT //adc工作采样宽度

1.3.1.2. 时钟配置

GPADC时钟最大不可超过12MHz。

#define ADC_CLK                     (300000L) //非DNA单通道模式工作时钟
#define ADC_DMA_CONTI_CLK   (10000000L) //DMA单通道模式工作时钟

1.3.2. GPADC采集通道

GPADC采集通道包括普通IO通道,模拟ANA通道(含PMU等通道),差分DIFF通道。

enum AD_CH {
    //ANA通道(模拟通道只支持CPU采集,不支持DMA采集)
    AD_ANA_PMU_CH_VBG = (AD_PMU_TEST | ADC_PMU_CH_VBG),
    AD_ANA_PMU_CH_VP17,
    AD_ANA_PMU_CH_VLCD_DIV_4,
    AD_ANA_PMU_CH_AVDDR_DIV_2,
    AD_ANA_PMU_CH_VTEMP,
    AD_ANA_PMU_CH_VPWR_DIV_4,
    AD_ANA_PMU_CH_AVDDCP_DIV_4,
    AD_ANA_PMU_CH_AVDDCP_DIV_2,
    AD_ANA_PMU_CH_AVDDCP_VB17,
    AD_ANA_PMU_CH_DCVDD = (AD_PMU_TEST | ADC_PMU_CH_DCVDD),
    AD_ANA_PMU_CH_DVDD,
    AD_ANA_PMU_CH_WVDD = (AD_PMU_TEST | ADC_PMU_CH_WVDD),

    //IO通道(支持CPU采集和DMA采集)
    AD_CH_PA0 = (AD_IO_TEST | ADC_IO_CH_PA0),
    AD_CH_PA8,
    AD_CH_PA4,
    AD_CH_PA12,
    AD_CH_PA2,
    AD_CH_PA10,
    AD_CH_PA6,
    AD_CH_DM,
    AD_CH_PA1,
    AD_CH_PA9,
    AD_CH_PA5,
    AD_CH_DP,
    AD_CH_PA3,
    AD_CH_PA11,
    AD_CH_PA7,

    //DIFF通道(支持CPU采集和DMA采集)
    AD_DIFF_CH_SP_PA2_SN_PA3 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA2_SN_PA3),
    AD_DIFF_CH_SP_PA2_SN_PA4,
    AD_DIFF_CH_SP_PA2_SN_PA5,
    AD_DIFF_CH_SP_PA3_SN_PA2 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA3_SN_PA2),
    AD_DIFF_CH_SP_PA3_SN_PA4 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA3_SN_PA4),
    AD_DIFF_CH_SP_PA3_SN_PA5,
    AD_DIFF_CH_SP_PA4_SN_PA2 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA4_SN_PA2),
    AD_DIFF_CH_SP_PA4_SN_PA3,
    AD_DIFF_CH_SP_PA4_SN_PA5 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA4_SN_PA5),
    AD_DIFF_CH_SP_PA5_SN_PA2 = (AD_DIFF_TEST | ADC_DIFF_CH_SP_PA5_SN_PA2),
    AD_DIFF_CH_SP_PA5_SN_PA3,
    AD_DIFF_CH_SP_PA5_SN_PA4,
    AD_DIFF_CH_VB = (AD_DIFF_TEST | ADC_DIFF_CH_VB),
};

1.3.3. GPADC采集模式

GPADC采集模式包括CPU采集模式,CPU阻塞采集模式,DMA多通道采集模式和DMA单通道采集模式。

Note

ANA通道只能使用CPU模式采集。工作在DMA单通道采集模式时,CPU模式无法同时工作。

1.3.3.1. CPU采集模式

由CPU访问,逐次读取各通道电压值。

该模式接口介绍如下。

1.3.3.1.1. adc_add_sample_ch

添加ch到CPU采集模式ADC采集队列

原型:

void adc_add_sample_ch(enum AD_CH ch);
参数:

ch

ADC通道

返回值

通道ADC值

示例:

adc_add_sample_ch(AD_CH_PA0);

1.3.3.1.2. adc_remove_sample_ch

删除CPU采集模式ADC采集队列里的ch

原型:

void adc_remove_sample_ch(enum AD_CH ch);
参数:

ch

ADC通道

返回值

示例:

adc_remove_sample_ch(AD_CH_PA0);

1.3.3.2. CPU阻塞采集模式

由CPU访问,阻塞CPU采集模式,打断ADC转换队列,立即获取对应通道的ADC值或电压值。

该模式接口介绍如下。

1.3.3.2.1. adc_get_value_by_blocking

阻塞CPU模式采集,打断ADC转换队列,立即获取对应通道的ADC值,不支持中断调用

原型:

s16 adc_get_value_by_blocking(u32 ch, u8 times)
参数:

ch

ADC通道

times

采集次数

返回值

通道ADC值

示例:

adc_get_value_by_blocking(AD_CH_PA0, 8);

1.3.3.2.2. adc_get_voltage_by_blocking

阻塞CPU模式采集,打断ADC转换队列,立即获取对应通道的电压值,内部做了滤波取平均处理,不支持中断调用

原型:

s16 adc_get_voltage_by_blocking(u32 ch, u8 times)
参数:

ch

ADC通道

times

采集次数

返回值

通道电压

示例:

adc_get_voltage_by_blocking(AD_CH_PA0, 8);

1.3.3.3. DMA多通道采集模式

通过配置固定的采样率和通道数,使用DMA多通道采集模式自动读取通道电压值。 使用DMA多通道采集模式的同时,CPU采集模式也可以同时操作读取不同通道电压值,但需要做好采样时间分配。

1.3.3.3.1. adc_dma_add_sample_ch

添加ch到DMA多通道采集模式ADC采集队列。

原型:

void adc_dma_add_sample_ch(enum AD_CH ch);
参数:

ch

ADC通道

返回值

通道ADC值

示例:

adc_dma_add_sample_ch(AD_CH_PA0);

1.3.3.3.2. adc_dma_remove_sample_ch

删除DMA多通道采集模式ADC采集队列里的ch。

原型:

void adc_dma_remove_sample_ch(enum AD_CH ch);
参数:

ch

ADC通道

返回值

示例:

adc_dma_remove_sample_ch(AD_CH_PA0);

1.3.3.4. DMA单通道采集模式

1.3.3.4.1. adc_dma_enter_single_ch_sample

ADC进入DMA单通道连续采集模式(该模式下CPU模式采样无法进行)。 注意需要与adc_dma_exit_single_ch_sample()成对使用。 回调函数16bits的buf,有效数据为bit16~4,低4位无效,读取时需>>4。

原型:

void adc_dma_enter_single_ch_sample(enum AD_CH ch, void (*gpadc_dma_irq_callback)(u16 *buf, u32 len));
参数:

ch

ADC通道

gpadc_dma_irq_callback

DMA单通道中断回调函数

返回值

示例:

adc_dma_enter_single_ch_sample(AD_CH_PA0, callback_func);

1.3.3.4.2. adc_dma_exit_single_ch_sample

ADC退出DMA单通道连续采集模式(恢复DMA多通道模式采集和CPU模式采集)。 注意需要与adc_dma_enter_single_ch_sample()成对使用。

原型:

void adc_dma_exit_single_ch_sample(enum AD_CH ch);
参数:

ch

ADC通道

返回值

示例:

adc_dma_exit_single_ch_sample(AD_CH_PA0);

1.3.3.5. 公共API

1.3.3.5.1. adc_init

GPADC初始化。

原型:

void adc_init(void);
参数:

1.3.3.5.2. adc_get_value

获取对应通道的ADC值。需确保通道有存在于CPU或DMA的采集队列,否则需先通过adc_add_sample_ch/adc_dma_add_sample_ch注册通道。

原型:

s16 adc_get_value(enum AD_CH ch);
参数:

ch

ADC通道

返回值

通道ADC值

示例:

adc_get_value(AD_CH_PA0);

1.3.3.5.3. adc_get_voltage

获取对应通道的电压值。需确保通道有存在于CPU或DMA的采集队列,否则需先通过adc_add_sample_ch/adc_dma_add_sample_ch注册通道。

原型:

s32 adc_get_voltage(enum AD_CH ch);
参数:

ch

ADC通道

返回值

通道电压

示例:

adc_get_voltage(AD_CH_PA0);

1.3.4. GPADC使用示例demo

#include "gpadc_api.h"
#include "asm/clock.h"

void gpadc_cpu_mode_demo(void)
{
    printf("\n@_0 gpadc cpu mode demo test start\n");

    printf("@_0 cpu add ch PA5\n");
    adc_add_sample_ch(AD_CH_PA5);
    printf("@_0 cpu add ch VPWR\n");
    adc_add_sample_ch(AD_ANA_PMU_CH_VPWR_DIV_4);

    mdelay(10);

    printf("@_0 PA5 adc res: %d\n", adc_get_value(AD_CH_PA5));
    printf("@_0 PA5 voltage: %dmV\n", adc_get_voltage(AD_CH_PA5));

    printf("@_0 VPWR adc res: %d\n", adc_get_value(AD_ANA_PMU_CH_VPWR_DIV_4));
    printf("@_0 VPWR voltage: %dmV\n", adc_get_voltage(AD_ANA_PMU_CH_VPWR_DIV_4) * 4);

    printf("@_0 cpu remove ch PA5\n");
    adc_remove_sample_ch(AD_CH_PA5);
    printf("@_0 cpu remove ch VPWR\n");
    adc_remove_sample_ch(AD_ANA_PMU_CH_VPWR_DIV_4);
}

void gpadc_dma_mode_demo(void)
{
    printf("\n@_1 gpadc dma mode demo test start\n");

    printf("@_1 dma add ch PA5\n");
    adc_dma_add_sample_ch(AD_CH_PA5);
    printf("@_1 dma add ch DIFF SP_PA2_SN_PA3\n");
    adc_dma_add_sample_ch(AD_DIFF_CH_SP_PA2_SN_PA3);

    mdelay(10);

    printf("@_1 PA5 adc res: %d\n", adc_get_value(AD_CH_PA5));
    printf("@_1 PA5 voltage: %dmV\n", adc_get_voltage(AD_CH_PA5));

    printf("@_1 DIFF SP_PA2_SN_PA3 adc res: %d\n", adc_get_value(AD_DIFF_CH_SP_PA2_SN_PA3));
    printf("@_1 DIFF SP_PA2_SN_PA3 voltage: %dmV\n", adc_get_voltage(AD_DIFF_CH_SP_PA2_SN_PA3));

    printf("@_1 dma remove ch PA5\n");
    adc_dma_remove_sample_ch(AD_CH_PA5);
    printf("@_1 dma remove ch DIFF SP_PA2_SN_PA3\n");
    adc_dma_remove_sample_ch(AD_DIFF_CH_SP_PA2_SN_PA3);
}

void gpadc_blocking_mode_demo(void)
{
    printf("\n@_2 gpadc blocking mode demo test start\n");
    printf("@_2 PA8 adc res: %d\n", adc_get_value_by_blocking(AD_CH_PA8, 8));
    printf("@_2 PA8 voltage: %dmV\n", adc_get_voltage_by_blocking(AD_CH_PA8, 8));
}

void gpadc_dma_conti_mode_callback(u16 *buf, u32 len)
{
    /* printf("len: %d\n", len); */
}

void gpadc_dma_conti_mode_demo(void)
{
    printf("\n@_3 gpadc blocking mode demo test start\n");
    printf("@_3 enter sample DIFF SP_PA2_SN_PA3\n");
    adc_dma_enter_single_ch_sample(AD_DIFF_CH_SP_PA2_SN_PA3, gpadc_dma_conti_mode_callback);
    mdelay(1);
    printf("@_3 exit sample DIFF SP_PA2_SN_PA3\n");
    adc_dma_exit_single_ch_sample(AD_DIFF_CH_SP_PA2_SN_PA3);
}

//gpadc测试demo
void gpadc_test_demo(void)
{
    printf("\n***** GPADC module test begin *****\n");

    adc_init();

    //cpu模式测试
    gpadc_cpu_mode_demo();

    //dma模式测试
    gpadc_dma_mode_demo();

    //打断模式测试
    gpadc_blocking_mode_demo();

    //dma单通道测试
    gpadc_dma_conti_mode_demo();

    printf("\n***** GPADC module test end *****\n");
}