One Shot Mode - Polling Mode

该示例通过使用 ADC 单次采样模式进行电压检测。

该示例通过轮询 ADC_INT_ONE_SHOT_DONE 中断的方式进行 ADC 采样。当检测到采样完成时,读取 ADC FIFO 内的采样数据 raw data 并进行电压转换计算。

该示例中可通过配置宏 ADC_MODE_DIVIDE_OR_BYPASS 选择 ADC 的电压采样范围。

环境需求

该示例支持以下开发套件:

开发套件

Hardware Platforms

Board Name

RTL8752H HDK

RTL8752H EVB

更多信息请参考 快速入门

硬件连线

连接 P2_7 至外部电压输入。

配置选项

该示例可配置的宏如下:

  1. ADC_MODE_DIVIDE_OR_BYPASS :配置该宏可选择 ADC 的电压采样范围,可选择的值如下。

    • ADC_DIVIDE_MODE :在 Divide Mode 下,ADC 的采样电压值范围为 0~3.3V。

    • ADC_BYPASS_MODE :在 Bypass Mode 下,ADC 的采样电压值范围为 0~0.9V。

编译和下载

该示例的工程路径如下:

Project file: board\evb\io_sample\ADC\OneShotMode_Polling\mdk

Project file: board\evb\io_sample\ADC\OneShotMode_Polling\gcc

请按照以下步骤操作构建并运行该示例:

  1. 打开工程文件。

  2. 按照 快速入门编译 APP Image 给出的步骤构建目标文件。

  3. 编译成功后,在路径 mdk\bingcc\bin 下会生成 app bin app_MP_xxx.bin 文件。

  4. 按照 快速入门MP Tool 给出的步骤将 app bin 烧录至 EVB 内。

  5. 按下 reset 按键,开始运行。

测试验证

  1. ADC 初始化配置:

    1. 若配置为 ADC_DIVIDE_MODE ,则会打印如下 log。

      [ADC] ADC sample mode is divide mode !
      
    2. 若配置为 ADC_BYPASS_MODE ,则会打印如下 log。

      [ADC] ADC sample mode is bypass mode !
      
  2. ADC 采样结束后,会在 Debug Analyzer 工具内打印采集得到的 raw data 和转换后的电压值。

    [io_adc] io_adc_voltage_calculate: ADC one shot mode sample data_0 = xxx, voltage_0 = xxxmV
    [io_adc] io_adc_voltage_calculate: ADC one shot mode sample data_1 = xxx, voltage_1 = xxxmV
    ...
    

代码介绍

该章节分为以下几个部分:

  1. 源码路径

  2. 初始化函数将在 初始化 章节介绍。

  3. 初始化后的功能实现将在 功能实现 章节介绍。

源码路径

  • 工程路径: sdk\board\evb\io_sample\ADC\OneShotMode_Polling

  • 源码路径: sdk\src\sample\io_sample\ADC\OneShotMode_Polling

该工程的工程文件代码结构如下:

└── Project: adc_oneshot_polling
    └── secure_only_app
        └── include
            ├── app_define.h
            └── rom_uuid.h
        ├── cmsis                    includes CMSIS header files and startup files
            ├── overlay_mgr.c
            ├── system_rtl876x.c
            └── startup_rtl876x.s
        ├── lib                      includes all binary symbol files that user application is built on
            ├── rtl8752h_sdk.lib
            ├── gap_utils.lib
            ├── ROM.lib
            └── adc.lib
        ├── peripheral               includes all peripheral drivers and module code used by the application
            ├── rtl876x_rcc.c
            ├── rtl876x_pinmux.c
            ├── rtl876x_nvic.c
            └── rtl876x_adc.c
        ├── profile
        └── app                      includes the ble_peripheral user application implementation
            └── main.c

初始化

当 EVB 复位启动时,执行 main 函数,执行以下流程:

int main(void)
{
    extern uint32_t random_seed_value;
    srand(random_seed_value);
    adc_demo();

    while (1)
    {
        DBG_DIRECT("[ADC]Polling reads adc sample data !");
        adc_sample_demo();
        for (uint32_t i = 500000; i > 0; i--);
        ADC_Cmd(ADC, ADC_ONE_SHOT_MODE, ENABLE);
    }
}

adc_demo 中,包含了 ADC 校准、PAD/PINMUX 设置,ADC 外设的初始化等流程。

void adc_demo(void)
{
    /* Initialize adc k value! */
    bool adc_k_status;
    adc_k_status = ADC_CalibrationInit();
    if (false == adc_k_status)
    {
        APP_PRINT_ERROR0("[ADC]ADC_CalibrationInit fail!");
    }
    /* Configure pad and pinmux firstly! */
    board_adc_init();

    /* Initialize adc peripheral */
    driver_adc_init();

    /* Enable adc */
    ADC_Cmd(ADC, ADC_ONE_SHOT_MODE, ENABLE);
}

board_adc_init 为 PAD/PINMUX 设置,包含如下流程:

  1. 配置 PAD:设置引脚、SW 模式、PowerOn、无内部上拉、输出失能。

driver_adc_init 为 ADC 外设的初始化,包含如下流程:

  1. 使能 RCC 时钟。

  2. 配置 ADC 的采样通道,配置所有通道为 P2_7 单端模式,设置 Bitmap 为 0xFFFF。

  3. 若开启 Bypass Mode,执行函数 ADC_BypassCmd() 开启对应引脚的 Bypass 模式。

  4. 配置 ADC ADC_INT_ONE_SHOT_DONE 中断。

void driver_adc_init(void)
{
    RCC_PeriphClockCmd(APBPeriph_ADC, APBPeriph_ADC_CLOCK, ENABLE);

    ADC_InitTypeDef ADC_InitStruct;
    ADC_StructInit(&ADC_InitStruct);
    ADC_InitStruct.ADC_SampleTime       = 255;
    for (uint8_t i = 0; i < 16; i++)
    {
#ifdef INTERNAL_VBAT_TEST
        ADC_InitStruct.ADC_SchIndex[i] = INTERNAL_VBAT_MODE;
#else
        ADC_InitStruct.ADC_SchIndex[i]  = EXT_SINGLE_ENDED(ADC_SAMPLE_CHANNEL_7);
#endif
    }
    ADC_InitStruct.ADC_Bitmap           = 0xFFFF;
    ADC_InitStruct.ADC_PowerAlwaysOnEn  = ADC_POWER_ALWAYS_ON_ENABLE;
    ADC_Init(ADC, &ADC_InitStruct);

#if (ADC_MODE_DIVIDE_OR_BYPASS == ADC_BYPASS_MODE)
    /* High bypass resistance mode config, please notice that the input voltage of
    adc channel using high bypass mode should not be over 0.9V */
    ADC_BypassCmd(ADC_SAMPLE_CHANNEL_6, ENABLE);
    DBG_DIRECT("[ADC]ADC sample mode is bypass mode !");
#else
    DBG_DIRECT("[ADC]ADC sample mode is divide mode !");
#endif
    ADC_INTConfig(ADC, ADC_INT_ONE_SHOT_DONE, ENABLE);
}

功能实现

  1. 执行 ADC_Cmd() ,开启 ADC 采样。在主函数中,循环执行 adc_sample_demo ,对 ADC 采样数据进行处理。

  2. adc_sample_demo 中,循环判断 ADC 单次转换完成中断状态。ADC 单次转换完成后,清除中断标志位。

  3. 执行 ADC_ReadRawData() ,读取 ADC 采样数据。

  4. 执行 ADC_GetVoltage() ,将采样数据转换为电压值。

    void adc_sample_demo(void)
    {
        uint16_t sample_data[16] = {0};
        float sample_voltage[16] = {0};
        ADC_ErrorStatus error_status = NO_ERROR;
    
        while (ADC_GetINTStatus(ADC, ADC_INT_ONE_SHOT_DONE) == RESET);
        ADC_ClearINTPendingBit(ADC, ADC_INT_ONE_SHOT_DONE);
        for (uint8_t i = 0; i < 16; i++)
        {
            sample_data[i] = ADC_ReadRawData(ADC, ADC_Schedule_Index_0 + i);
        }
    
        for (uint8_t i = 0; i < 16; i++)
        {
    #if (ADC_MODE_DIVIDE_OR_BYPASS == ADC_BYPASS_MODE)
            sample_voltage[i] = ADC_GetVoltage(BYPASS_SINGLE_MODE, (int32_t)sample_data[i], &error_status);
    #else
            sample_voltage[i] = ADC_GetVoltage(DIVIDE_SINGLE_MODE, (int32_t)sample_data[i], &error_status);
    #endif
            if (error_status < 0)
            {
                DBG_DIRECT("[ADC]adc_sample_demo: ADC parameter or efuse data error! i = %d, error_status = %d", i,
                        error_status);
            }
            else
            {
                DBG_DIRECT("[ADC] adc_sample_demo: ADC one shot mode sample data_%d = %d, voltage_%d = %dmV ", i,
                        sample_data[i], i, (uint32_t)sample_voltage[i]);
            }
        }
    }
    

常见问题

  1. 若拿到的 IC 未经过 FT 校验,ADC 则无法转换为正确的电压值。在 log 工具内会打印如下信息。

    [ADC]ADC_CalibrationInit fail!
    
  2. 若 ADC 采样值不正确,则会打印错误状态信息。

    ADC parameter or efuse data error! i = xxx, error_status = xxx