M
使用的是内部1.2V的基准源,外部进行300K+100K分压,io口最高承受3.6V,-u版本的IOLDO参考源末端线性不准所以不建议使用外部3.3V的基准源
/*
******************************************************************************
* @file saradc_demo.c
* @author FreqChip Firmware Team
* @version V1.0.0
* @date 2025
* @brief SARADC demo based on driver_adc_pro.
*
* 与旧 ADC(driver_adc / adc_demo)的区别:
* 1. 旧 ADC 引脚通道硬件固定,PD1 = AuxADC6 / ADC_CHANNEL_6
* (见 driver_gpio.h PortD MUX 的 GPIO_FUNCTION_8)。
* 2. SARADC 的 SARADC_CHANNEL_0~9 是逻辑通道,不绑死引脚。
* 采哪根脚由 ch_map_p 决定,PD1 对应 ADC_CH_MAP_PORTD_1。
* 3. loop_max_channel = N 时,硬件只轮询 CHANNEL_0 ~ CHANNEL_(N-1)。
* 单通道必须用 SARADC_CHANNEL_0,不能配 CHANNEL_1/6。
* 4. saradc_get_channel_data() 返回 10bit 原始码 (0~1023),需自行换算。
*
* 电压换算(10bit):
* Vpin(mV) = raw * Vref(mV) / 1024
* Vin(mV) = Vpin * 外部分压比
* 本板 PD1 有外部 4 分 1 电阻,1.2V 参考:
* Vin(mV) = raw * 1200 * 4 / 1024
* 外部已分压时,内部 ATT 必须 BYPASS,否则会分压两次。
******************************************************************************
*/
#include "saradc_demo.h"
#include "driver_gpio.h"
#include "driver_pmu.h"
#include "driver_adc_pro.h"
#include "driver_system.h"
#include "co_printf.h"
#include "co_log.h"
/* 10bit:Vin(mV) = raw * 参考电压(mV) * 分压比 / 1024 */
#define SARADC_RAW_TO_MV(raw, vref_mv, div) (((uint32_t)(raw) * (vref_mv) * (div)) / 1024)
/**
* @brief 把 GPIO 配成模拟输入:输入、无上下拉。
* SARADC 通过 ch_map_p 选脚,不再需要旧 ADC 的 GPIO_FUNCTION_8。
*/
static void saradc_gpio_analog_init(enum_GPIOx_t port, uint32_t pin)
{
GPIO_InitTypeDef GPIO_Handle;
GPIO_Handle.Pin = pin;
GPIO_Handle.Mode = GPIO_MODE_INPUT; /* 模拟输入 */
GPIO_Handle.Pull = GPIO_NOPULL; /* 禁止上下拉,避免拉偏采样 */
gpio_init(port, &GPIO_Handle);
}
/**
* @brief SARADC 公共初始化。
* 内部 1.2V 参考;clock_div 必须为偶数;sampling_cycle 建议 15。
*/
static void saradc_common_init(saradc_InitConfig_t *Init)
{
Init->saradc_reference = SARADC_REF_INTERNAL_1P2V; /* 内部 1.2V 基准 */
Init->saradc_clock_div = 2; /* 采样时钟分频,最小 2 */
Init->saradc_sampling_cycle = 15; /* 采样周期,1~16 */
saradc_init(Init);
}
/************************************************************************************
* @fn saradc_demo
*
* @brief SARADC demo based on driver_adc_pro.
*
* @param fe_Demo: demo select.
*/
void saradc_demo(enum_SARADC_Demo_t fe_Demo)
{
saradc_InitConfig_t saradc_InitConfig;
saradc_LoopConfig_t LoopConfig;
saradc_ChannelConfig_t ChannelConfig;
uint16_t raw;
__SYSTEM_ADC_CLK_ENABLE(); /* 打开 ADC/SARADC 时钟 */
__SYSTEM_GPIO_CLK_ENABLE(); /* 打开 GPIO 时钟,才能配引脚 */
switch (fe_Demo)
{
/*
* 单通道:采 PD1。
* 逻辑通道用 CHANNEL_0(loop_max=1 只转 CH0)。
* 引脚用 ADC_CH_MAP_PORTD_1,不是旧的 ADC_CHANNEL_6。
* 外部已有 4 分 1,内部 ATT 旁路。
*/
case SARADC_DEMO_SINGLE_CHANNEL:
{
saradc_gpio_analog_init(GPIO_D, GPIO_PIN_1);
saradc_common_init(&saradc_InitConfig);
LoopConfig.loop_max_channel = 1; /* 只转 CH0 */
LoopConfig.loop_interval_mode = SARADC_INTVL_DISABLE; /* 通道间不插间隔 */
LoopConfig.loop_interval_len = 0;
LoopConfig.loop_FIFO_enable = SARADC_FUNC_DISABLE; /* 不用 FIFO,读通道寄存器 */
LoopConfig.loop_FIFO_channel_sel = 0;
LoopConfig.loop_FIFO_almost_threshold = 0;
saradc_loop_config(&LoopConfig);
ChannelConfig.ch_mode = SARADC_CH_MODE_SINGLE; /* 单端 */
ChannelConfig.ch_map_p = ADC_CH_MAP_PORTD_1; /* 正极接到 PD1 */
ChannelConfig.ch_map_n = ADC_CH_MAP_VSSA; /* 负极接模拟地 */
ChannelConfig.ch_voltage_divider = SARADC_VOLTAGE_DIVIDER_BYPASS;/* 内部不再分压 */
ChannelConfig.ch_source_follower_en = SARADC_FUNC_DISABLE;
saradc_channel_config(SARADC_CHANNEL_0, &ChannelConfig);
saradc_loop_convert_start(); /* 启动循环转换 */
co_delay_100us(1500); /* 等待模拟建立 */
co_printf("SDK V1.5 SARADC start\r\n");
while (1)
{
/* 该逻辑通道转换完成才会置位 */
if (saradc_get_channel_valid_status(SARADC_CHANNEL_0))
{
raw = saradc_get_channel_data(SARADC_CHANNEL_0); /* 10bit raw */
/* 1.2V 参考 + 外部 4 分 1:Vin = raw * 1200 * 4 / 1024 */
co_printf("SDK V1.5 SARADC raw=%d, mv=%d\r\n",
raw, SARADC_RAW_TO_MV(raw, 1200, 4));
}
co_delay_100us(2000);
}
}
/*
* 多通道:PD0~PD3 映射到逻辑 CH0~CH3。
* loop_max_channel 必须等于实际通道数 4,否则后面的通道不会转换。
*/
case SARADC_DEMO_MULTI_CHANNEL:
{
saradc_gpio_analog_init(GPIO_D, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
saradc_common_init(&saradc_InitConfig);
LoopConfig.loop_max_channel = 4; /* 转 CH0~CH3 */
LoopConfig.loop_interval_mode = SARADC_INTVL_DISABLE;
LoopConfig.loop_interval_len = 0;
LoopConfig.loop_FIFO_enable = SARADC_FUNC_DISABLE;
LoopConfig.loop_FIFO_channel_sel = 0;
LoopConfig.loop_FIFO_almost_threshold = 0;
saradc_loop_config(&LoopConfig);
ChannelConfig.ch_mode = SARADC_CH_MODE_SINGLE;
ChannelConfig.ch_map_n = ADC_CH_MAP_VSSA;
ChannelConfig.ch_voltage_divider = SARADC_VOLTAGE_DIVIDER_0P25; /* 内部 1/4,无外部分压时可用 */
ChannelConfig.ch_source_follower_en = SARADC_FUNC_DISABLE;
ChannelConfig.ch_map_p = ADC_CH_MAP_PORTD_0;
saradc_channel_config(SARADC_CHANNEL_0, &ChannelConfig);
ChannelConfig.ch_map_p = ADC_CH_MAP_PORTD_1;
saradc_channel_config(SARADC_CHANNEL_1, &ChannelConfig);
ChannelConfig.ch_map_p = ADC_CH_MAP_PORTD_2;
saradc_channel_config(SARADC_CHANNEL_2, &ChannelConfig);
ChannelConfig.ch_map_p = ADC_CH_MAP_PORTD_3;
saradc_channel_config(SARADC_CHANNEL_3, &ChannelConfig);
saradc_loop_convert_start();
while (1)
{
for (int i = 0; i < 4; i++)
{
if (saradc_get_channel_valid_status((enum_saradc_channel_t)i))
{
raw = saradc_get_channel_data((enum_saradc_channel_t)i);
co_printf("CH[%d] raw=%d, mv=%d\r\n",
i, raw, SARADC_RAW_TO_MV(raw, 1200, 4));
}
}
co_delay_100us(2000);
}
}
/*
* 内部 1/4 VBAT。
* 模拟前端已做电池分压,通道 ATT 旁路;换算时再 *4 得到 VBAT。
*/
case SARADC_DEMO_VBAT:
{
saradc_common_init(&saradc_InitConfig);
saradc_vbat_measure_enable(); /* 打开内部 VBAT 分压电路 */
LoopConfig.loop_max_channel = 1;
LoopConfig.loop_interval_mode = SARADC_INTVL_DISABLE;
LoopConfig.loop_interval_len = 0;
LoopConfig.loop_FIFO_enable = SARADC_FUNC_DISABLE;
LoopConfig.loop_FIFO_channel_sel = 0;
LoopConfig.loop_FIFO_almost_threshold = 0;
saradc_loop_config(&LoopConfig);
ChannelConfig.ch_mode = SARADC_CH_MODE_SINGLE;
ChannelConfig.ch_map_p = ADC_CH_MAP_VBAT; /* 内部 VBAT */
ChannelConfig.ch_map_n = ADC_CH_MAP_VSSA;
ChannelConfig.ch_voltage_divider = SARADC_VOLTAGE_DIVIDER_BYPASS;
ChannelConfig.ch_source_follower_en = SARADC_FUNC_DISABLE;
saradc_channel_config(SARADC_CHANNEL_0, &ChannelConfig);
saradc_loop_convert_start();
while (1)
{
if (saradc_get_channel_valid_status(SARADC_CHANNEL_0))
{
raw = saradc_get_channel_data(SARADC_CHANNEL_0);
co_printf("1/4 VBAT raw=%d, vbat=%d mV\r\n",
raw, SARADC_RAW_TO_MV(raw, 1200, 4));
}
co_delay_100us(2000);
}
}
/*
* 核温 VBE,无外部分压,换算比取 1。
*/
case SARADC_DEMO_VBE:
{
saradc_common_init(&saradc_InitConfig);
saradc_vbe_measure_enable(); /* 打开内部温度传感 */
LoopConfig.loop_max_channel = 1;
LoopConfig.loop_interval_mode = SARADC_INTVL_DISABLE;
LoopConfig.loop_interval_len = 0;
LoopConfig.loop_FIFO_enable = SARADC_FUNC_DISABLE;
LoopConfig.loop_FIFO_channel_sel = 0;
LoopConfig.loop_FIFO_almost_threshold = 0;
saradc_loop_config(&LoopConfig);
ChannelConfig.ch_mode = SARADC_CH_MODE_SINGLE;
ChannelConfig.ch_map_p = ADC_CH_MAP_VBEP; /* VBE 正极 */
ChannelConfig.ch_map_n = ADC_CH_MAP_VSSA;
ChannelConfig.ch_voltage_divider = SARADC_VOLTAGE_DIVIDER_BYPASS;
ChannelConfig.ch_source_follower_en = SARADC_FUNC_DISABLE;
saradc_channel_config(SARADC_CHANNEL_0, &ChannelConfig);
saradc_loop_convert_start();
while (1)
{
if (saradc_get_channel_valid_status(SARADC_CHANNEL_0))
{
raw = saradc_get_channel_data(SARADC_CHANNEL_0);
co_printf("VBE raw=%d, mv=%d\r\n",
raw, SARADC_RAW_TO_MV(raw, 1200, 1));
}
co_delay_100us(2000);
}
}
default:
break;
}
}