NXP RT1170 搭载双 LPADC 模块,支持 A/B 双路通道划分(ADC1 含 6A+6B 通道、ADC2 含 7A+7B 通道),默认 SDK 示例仅支持 A 通道单端采样,实际开发中若需使用 B 通道并实现多通道连续采样,需完成通道引脚配置、A/B 通道切换寄存器配置、链式采样命令设置三步核心操作。本文基于 RT1170-EVKB 开发板与 MCUXpresso IDE,以 ADC1 的 CH1B/CH2B/CH3B 三通道为例,详解 B 通道启用、多通道链式采样的代码修改与硬件测试流程,解决 B 通道采样失败、多通道轮询效率低等问题。
资料获取:[RT1170] ADC多通道采样实验
1. RT1170 ADC 核心特性与问题根源
1.1 双 ADC 模块与 A/B 通道架构
RT1170 的 LPADC 模块采用A/B 双通道分离设计,核心特性如下:
- ADC1:共 12 通道,分为 6 个 A 通道(CH0A~CH5A)、6 个 B 通道(CH0B~CH5B),对应 GPIO_AD_06~GPIO_AD_15 引脚;
- ADC2:共 14 通道,分为 7 个 A 通道(CH0A~CH6A)、7 个 B 通道(CH0B~CH6B),对应 GPIO_AD_16~GPIO_AD_25 引脚;
- 单端 / 差分模式:支持单端采样(单独 A/B 通道)、差分采样(A+B 通道对),由专用寄存器控制;
- 通道复用:双 ADC 模块共用 6 个通道资源,整机实际可用 20 个独立 ADC 通道。
1.2 B 通道采样失败的核心原因
SDK 默认示例(如lpadc_polling_cm7)仅能实现 A 通道采样,B 通道采样失败的根本原因是寄存器默认配置为 A 通道单端采样,关键控制位为 LPADC 转换命令中的 **sampleChannelMode与硬件寄存器的DIFF/ABSEL**:
| 寄存器位 | 配置值 | 采样模式 | 通道选择 |
|---|---|---|---|
| DIFF(差分使能) | 0 | 单端模式 | 由 ABSEL/sampleChannelMode决定 |
| ABSEL(A/B 选择) | 0 | 单端模式 | 选择 A 通道 |
| ABSEL(A/B 选择) | 1 | 单端模式 | 选择 B 通道 |
sampleChannelMode(SDK 枚举) |
kLPADC_SampleChannelSingleEndSideA |
单端模式 | 底层配置 ABSEL=0,A 通道 |
sampleChannelMode(SDK 枚举) |
kLPADC_SampleChannelSingleEndSideB |
单端模式 | 底层配置 ABSEL=1,B 通道 |
sampleChannelMode设为 A 通道,未修改该配置时,即使配置了 B 通道引脚,也无法实现有效采样。1.3 多通道采样的两种实现方式
- 轮询采样:单命令单通道,循环触发不同通道的采样命令,实现简单但效率较低;
- 链式采样:多命令级联,配置通道采样命令的下一跳指令,由 ADC 模块自动完成多通道连续采样,无需 CPU 频繁干预,效率更高(本文重点实现)。
2. 实验环境准备
2.1 软硬件环境
- 硬件:RT1170-EVKB 开发板、杜邦线、电位器(用于模拟模拟量输入)、3.3V 电源(可选);
- 软件:MCUXpresso IDE V11.9.0、RT1170 SDK 2.15.000;
- 基础工程:SDK 自带的
lpadc_polling_cm7(ADC 轮询采样示例,基于 ADC1,默认 CH0A 采样); - 核心引脚:ADC1 的 CH1B/CH2B/CH3B 对应 RT1170-EVKB 引脚(均为 Freedom Header J26):
- CH1B:GPIO_AD_09 → J26[10]
- CH2B:GPIO_AD_11 → J26[4]
- CH3B:GPIO_AD_13 → J26[8]
2.2 工程导入
- 打开 MCUXpresso IDE,点击「Import SDK Examples」;
- 选择硬件为
MIMXRT1170-EVK,筛选lpadc分类,导入lpadc_polling_cm7工程; - 编译工程并烧录,默认可实现 CH0A(GPIO_AD_06)的单端采样,串口可输出采样值,验证基础工程有效性。
3. 核心配置步骤:B 通道启用 + 三通道链式采样
步骤 1:B 通道引脚配置(ConfigTool)
- 打开工程中的「Pins」配置工具(左侧栏 ConfigTools → Pins);
- 筛选引脚
GPIO_AD_09、GPIO_AD_11、GPIO_AD_13,将其功能均配置为ADC1输入; - 配置引脚电气属性:慢摆率、高驱动能力、禁止上拉 / 下拉、禁止开漏(与默认 ADC 引脚配置一致,配置值 0x02U);
- 点击「Update Code」,工具自动更新
BOARD_InitPins.c文件,完成引脚底层初始化。
步骤 2:ADC 基础配置修改(启用 FIFO,支持多结果存储)
- 找到工程中 ADC 初始化代码,修改
LPADC_GetDefaultConfig后的配置项:LPADC_Config_t mLpadcConfigStruct; LPADC_GetDefaultConfig(&mLpadcConfigStruct); // 关键修改:设置FIFO水位线为2,FIFO可存储3个采样结果(水位线=存储数-1) mLpadcConfigStruct.FIFOWatermark = 2; // 启用模拟预采样,提升采样精度 mLpadcConfigStruct.enableAnalogPreliminary = true; // 初始化ADC1 LPADC_Init(DEMO_LPADC_BASE, &mLpadcConfigStruct); - 宏定义保持 ADC1 为基础模块,无需修改:
#define DEMO_LPADC_BASE LPADC1。
步骤 3:链式采样命令配置(核心:A/B 通道切换 + 命令级联)
chainedNextCommandNumber实现命令级联,同时将sampleChannelMode设为 B 通道,实现 CH1B→CH2B→CH3B 的自动采样:核心配置逻辑
- 命令 1(CMD1):采样 CH1B,下一跳命令为 2(CMD2);
- 命令 2(CMD2):采样 CH2B,下一跳命令为 3(CMD3);
- 命令 3(CMD3):采样 CH3B,下一跳命令为 0(无后续命令,链式结束);
- 所有命令的
sampleChannelMode均设为kLPADC_SampleChannelSingleEndSideB,启用 B 通道。
完整代码实现
LPADC_ConvCommandConfig_t mLpadcCommandConfigStruct;
// 配置CMD1:CH1B,下一跳CMD2
LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
mLpadcCommandConfigStruct.chainedNextCommandNumber = 2; // 下一跳命令2
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB; // B通道
mLpadcCommandConfigStruct.channelNumber = 1; // CH1B
LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, 1, &mLpadcCommandConfigStruct);
// 配置CMD2:CH2B,下一跳CMD3
LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
mLpadcCommandConfigStruct.chainedNextCommandNumber = 3; // 下一跳命令3
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB; // B通道
mLpadcCommandConfigStruct.channelNumber = 2; // CH2B
LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, 2, &mLpadcCommandConfigStruct);
// 配置CMD3:CH3B,下一跳0(链式结束)
LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
mLpadcCommandConfigStruct.chainedNextCommandNumber = 0; // 无后续命令
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB; // B通道
mLpadcCommandConfigStruct.channelNumber = 3; // CH3B
LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, 3, &mLpadcCommandConfigStruct);
步骤 4:采样结果读取(循环读取 FIFO,区分通道)
LPADC_GetConvResult循环读取 FIFO 数据,并根据commandIdSource区分采样通道(对应 CMD1/CMD2/CMD3):LPADC_ConvResultConfig_t mLpadcResultConfigStruct;
while (1)
{
// 按任意键触发链式采样(SDK默认串口触发,可改为自动触发)
GETCHAR();
// 触发CMD1,启动链式采样(1U为trigger0掩码)
LPADC_DoSoftwareTrigger(DEMO_LPADC_BASE, 1U);
// 读取CMD1(CH1B)结果
while (!LPADC_GetConvResult(DEMO_LPADC_BASE, &mLpadcResultConfigStruct)){}
PRINTF("ADC CMD1(CH1B) value: %drn", (mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift);
// 读取CMD2(CH2B)结果
while (!LPADC_GetConvResult(DEMO_LPADC_BASE, &mLpadcResultConfigStruct)){}
PRINTF("ADC CMD2(CH2B) value: %drn", (mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift);
// 读取CMD3(CH3B)结果
while (!LPADC_GetConvResult(DEMO_LPADC_BASE, &mLpadcResultConfigStruct)){}
PRINTF("ADC CMD3(CH3B) value: %drn", (mLpadcResultConfigStruct.convValue) >> g_LpadcResultShift);
PRINTF("-------------------------rn");
}
- 注:
g_LpadcResultShift为采样结果移位值,SDK 默认定义,用于将原始采样值转换为实际有效数值(RT1170 ADC 为 12 位,取值 0~4095)。
4. 硬件测试与结果验证
4.1 硬件接线
- 将电位器的两个固定端分别连接开发板的GND和3.3V;
- 电位器的滑动端通过杜邦线连接到 CH1B(J26 [10]),CH2B/CH3B 可接固定电平(GND/3.3V)作为对比;
- 连接开发板的 UART 串口(GPIO_AD_24/TXD、GPIO_AD_25/RXD)到 PC,配置串口工具(波特率 115200、8N1)。
4.2 烧录与测试
- 编译修改后的工程,烧录到 RT1170-EVKB 开发板;
- 打开串口工具,复位开发板,串口输出提示信息:
LPADC Polling Example ADC Full Range:4096; - 按串口工具的任意键,触发链式采样,串口输出采样结果:
Please press any key to get user channel's ADC value. ADC CMD1(CH1B) value: 1256 ADC CMD2(CH2B) value: 0 ADC CMD3(CH3B) value: 4095 ------------------------- ADC CMD1(CH1B) value: 2048 ADC CMD2(CH2B) value: 0 ADC CMD3(CH3B) value: 4095 ------------------------- - 旋转电位器,CH1B 的采样值会随电位器阻值变化在 0~4095 之间连续变化,说明 B 通道采样有效;CH2B 接 GND 值为 0,CH3B 接 3.3V 值为 4095,验证采样精度正常。
5. 扩展配置:支持更多 B 通道 / 混合 A/B 通道采样
5.1 增加 B 通道数量
// 配置CMD4:CH4B,下一跳CMD5
mLpadcCommandConfigStruct.chainedNextCommandNumber = 5;
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB;
mLpadcCommandConfigStruct.channelNumber = 4;
LPADC_SetConvCommandConfig(DEMO_LPADC_BASE, 4, &mLpadcCommandConfigStruct);
// 同时调整FIFO水位线为通道数-1,确保能存储所有结果
5.2 混合 A/B 通道采样
sampleChannelMode分别设为 A/B 通道即可:// CMD1:CH1A(A通道)
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideA;
mLpadcCommandConfigStruct.channelNumber = 1;
// CMD2:CH2B(B通道)
mLpadcCommandConfigStruct.sampleChannelMode = kLPADC_SampleChannelSingleEndSideB;
mLpadcCommandConfigStruct.channelNumber = 2;
5.3 改为硬件触发 / 自动采样
// 自动循环采样,间隔100ms
while (1)
{
LPADC_DoSoftwareTrigger(DEMO_LPADC_BASE, 1U);
// 读取采样结果...
HAL_Delay(100); // 延时100ms
}
6. 常见问题排查与避坑指南
6.1 B 通道采样值固定为 0/4095,无变化
- 原因 1:引脚未正确配置为 ADC1 功能,仍为默认 GPIO 功能;
- 原因 2:
sampleChannelMode未改为kLPADC_SampleChannelSingleEndSideB,仍为 A 通道; - 原因 3:引脚电气属性配置错误(如开启上拉 / 下拉,导致电平被固定);
- 解决:重新通过 ConfigTool 配置引脚功能,核对
sampleChannelMode配置,确保引脚电气属性为 0x02U。
6.2 链式采样仅能读取第一个通道结果
- 原因 1:FIFO 水位线设置过小,未存储后续通道结果;
- 原因 2:
chainedNextCommandNumber配置错误(如下一跳命令号为 0,导致链式提前结束); - 原因 3:未循环调用
LPADC_GetConvResult,仅读取了一次 FIFO 数据; - 解决:将 FIFO 水位线设为通道数 - 1,核对命令级联配置,确保按通道数循环读取 FIFO。
6.3 采样结果乱序,通道与数值不匹配
- 原因:链式命令的
channelNumber与commandIdSource对应关系错误,或 FIFO 读取顺序与采样顺序不一致; - 解决:确保命令号与通道号一一对应(CMD1→CH1B、CMD2→CH2B),按命令级联顺序依次读取 FIFO,不打乱读取顺序。
6.4 编译报错:kLPADC_SampleChannelSingleEndSideB未定义
- 原因:SDK 版本过低,未支持 B 通道枚举定义;
- 解决:升级 RT1170 SDK 至 2.15.000 及以上版本,或直接通过寄存器配置 ABSEL=1(不推荐,不如 SDK 枚举直观)。
sampleChannelMode设为kLPADC_SampleChannelSingleEndSideB,启用 B 通道;二是配置采样命令的chainedNextCommandNumber,实现多通道自动级联。同时需配合引脚配置、FIFO 水位线设置,确保采样结果的正确存储与读取。该方案基于 SDK 原有工程改造,无需编写底层寄存器操作代码,实现简单、兼容性强,既支持纯 B 通道采样,也支持 A/B 通道混合采样,可灵活扩展通道数量。相比传统轮询采样,链式采样由 ADC 模块自动完成多通道连续采样,大幅降低 CPU 干预频率,提升采样效率,适用于工业检测、数据采集等需要多通道连续 ADC 采样的场景。
153