Funpack5-1 FRDM-MCXA346基于RT-Thread的ADC数据采集
该项目使用了FRDM-MCXA346,实现了ADC数据采集的设计,它的主要功能为:基于RT-Thread操作系统实现ADC数据采集。
标签
嵌入式系统
Funpack活动
ADC
rt-thread
FRDM-MCXA346
枫雪天
更新2026-03-16
12

任务介绍

本项目实现了Funpack活动中NXP FRDM-MCXA346开发板的任务,基于RT-Thread操作系统完成了ADC外设驱动的适配与启用,实现了ADC电压采样功能,并通过串口定时打印采样值与换算后的电压值,同时配合LED闪烁与按键中断功能,展示了RT-Thread设备驱动框架的完整应用。

硬件平台

本次使用NXP推出的FRDM-MCXA346开发板,是一款面向嵌入式开发的高性价比评估平台。该开发板搭载了基于ARM Cortex-M33内核的MCXA346系列MCU,具备丰富的外设资源,包括多路ADC通道、UART串口、GPIO接口等,非常适合用于实时嵌入式系统的开发与验证。开发板集成了板载调试器、USB接口、用户可编程LED与按键,便于快速搭建原型系统。

在软件方面,本项目采用RT-Thread实时操作系统作为底层运行环境。RT-Thread以其轻量级、高可扩展性和良好的跨平台支持而著称,适用于资源受限的嵌入式设备。通过在FRDM-MCXA346平台上适配RT-Thread的ADC设备驱动,实现了标准化的ADC采样接口调用、串口输出以及GPIO控制等功能。

image.png

主控设备:NXP FRDM-MCXA346开发板

  • 搭载MCXA346 MCU(ARM Cortex-M33内核)
  • 集成USB接口与板载调试器
  • 板载用户可编程LED指示灯与按键
  • 支持多线程实时操作系统(RT-Thread)

外设资源

  • 多路12位ADC模拟输入通道
  • UART2串口用于调试输出
  • GPIO控制LED与按键输入

任务分析与实现

本系统实现了基于RT-Thread实时操作系统的嵌入式ADC电压采样平台,主要功能包括:

  • ADC电压采样
    • 采样通道:ADC0通道1
    • 16位分辨率采样,量程0~3.3V
    • 每500ms执行一次采样
  • 串口数据输出
    • 实时打印ADC原始值与换算电压
    • 使用UART2作为控制台输出
  • GPIO控制
    • LED按500ms周期交替闪烁
    • 按键下降沿中断触发回调

系统框图如下:

RT-Thread ADC驱动适配过程

本项目基于NXP FRDM-MCXA346开发板,在RT-Thread操作系统上完成了ADC外设驱动的适配与启用,实现了标准化的ADC电压采样功能。以下详细描述了ADC驱动适配的关键流程和核心要点。

一、适配前的准备

1. 硬件环境

  • 主控芯片:NXP MCXA346(ARM Cortex-M33内核)
  • 开发板:FRDM-MCXA346
  • 外设资源
    • ADC0模拟输入通道用于电压采样
    • GPIO控制LED输出与按键输入
    • UART2串口调试输出

2. 软件环境

  • RT-Thread 版本:RT-Thread 5.3.0
  • 编译工具链:ARM Compiler V6(armclang)
  • 构建工具:RT-Thread Env Tool + Keil MDK5
  • 底层支持库:NXP MCX Series SDK驱动包

二、环境搭建与工程构建

1. 使用Env工具初始化工程

首先通过RT-Thread Env Tool进入BSP目录,执行 scons 命令进行工程构建。首次构建时提示缺少依赖包,需要先执行 pkgs --upgrade 更新软件包索引,再执行 pkgs --update 下载所需的NXP MCX CMSIS驱动和MCX Series驱动包。

在Env工具中依次执行命令,切换到BSP目录后运行 scons,系统提示依赖包缺失。随后执行 pkgs --upgrade 升级包,从GitHub成功拉取了 nxp-mcx-cmsis-latest  nxp-mcx-series-latest 两个驱动包,为后续的ADC驱动编译提供了必要的底层支持。整个过程的交互与日志如下。

RT-Thread Env Tool (ConEmu) Version 2.0.0
\ | /
- RT - Thread Operating System
/ | \
2006 - 2024 Copyright by RT-Thread team

Activate Python VENV in D:\ProgramData\env-windows-v2.0.0\env-windows\tools\bin\..\..\.venv

(.venv) Administrator@DESKTOP-ION73G2 D:\ProgramData\env-windows-v2.0.0\env-windows
# cd /d "C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346"

(.venv) Administrator@DESKTOP-ION73G2 C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346
# scons
scons: Reading SConscript files ...
Newlib version: 4.1.0

===============================================================================
Dependency packages missing, please running 'pkgs --update'...
If no packages are fetched, run 'pkgs --upgrade' first, then 'pkgs --update'...
===============================================================================

(.venv) Administrator@DESKTOP-ION73G2 C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346
# pkgs --upgrade
Error message:[Errno 2] No such file or directory: 'D:\\ProgramData\\env-windows-v2.0.0\\env-windows\\tools\\bin\\..\\..\\tools\\scripts\\cmds\\.config'
open .config failed
[Use Github server - auto decision based on IP location]
Begin to upgrade env packages.
remote: Enumerating objects: 768, done.
remote: Counting objects: 100% (374/374), done.
remote: Compressing objects: 100% (16/16), done.
Receiving objects: 96% (738/768)used 366 (delta 358), pack-reused 394 (from 1)Receiving objects: 95% (730/768)
Receiving objects: 100% (768/768), 142.21 KiB | 1018.00 KiB/s, done.
Resolving deltas: 100% (462/462), completed with 70 local objects.
From https://github.com/RT-Thread/packages
* branch HEAD -> FETCH_HEAD
==============================> Env packages upgrade done
(.venv) Administrator@DESKTOP-ION73G2 C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346

# pkgs --update

[Use Github server - auto decision based on IP location]
Cloning into 'C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346\packages\nxp-mcx-cmsis-latest'...
remote: Enumerating objects: 26, done.
remote: Counting objects: 100% (26/26), done.
remote: Compressing objects: 100% (21/21), done.
Receiving objects: 80% (21/26), 60.00 KiB | 95.00 KiB/sremote: Total 26 (delta 9), reused 15 (delta 3), pack-reused 0 (from 0)
Receiving objects: 100% (26/26), 77.55 KiB | 142.00 KiB/s, done.
Resolving deltas: 100% (9/9), done.
==============================> NXP_MCX_CMSIS_DRIVER latest is downloaded successfully.
Cloning into 'C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346\packages\nxp-mcx-series-latest'...
remote: Enumerating objects: 938, done.
remote: Counting objects: 100% (938/938), done.
remote: Compressing objects: 100% (637/637), done.
remote: Total 938 (delta 501), reused 714 (delta 287), pack-reused 0 (from 0)
Receiving objects: 100% (938/938), 3.62 MiB | 628.00 KiB/s, done.
Resolving deltas: 100% (501/501), done.
==============================> NXP_MCX_SERIES_DRIVER latest is downloaded successfully.
C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346\packages\nxp-mcx-cmsis-latest
==============================> nxp-mcx-cmsis update done
C:\Files\Codes\Embed\RTT_FRDM\rt-thread\bsp\nxp\mcx\mcxa\frdm-mcxa346\packages\nxp-mcx-series-latest
==============================> nxp-mcx-series update done
Operation completed successfully.

2. 生成Keil MDK5工程

驱动包下载完成后,执行以下命令生成Keil工程文件:

scons --target=mdk5

3. 初始验证——设备列表检查

生成工程后首先进行基础验证,编译下载后通过串口终端查看系统启动信息。此时使用 list device 命令查看已注册的设备列表,发现系统中仅有 pin  uart2 两个设备,尚未出现ADC设备:

这说明ADC驱动尚未被启用,需要进一步修改配置文件以开启ADC支持。


三、启用ADC驱动的核心步骤

1. 修改 rtconfig.h 配置文件

要启用ADC驱动,需要在 rtconfig.h 中添加ADC相关的宏定义。在 On-chip Peripheral Drivers 配置段中增加以下三行定义:

#define BSP_USING_ADC
#define BSP_USING_ADC0
#define BSP_USING_ADC0_CH22

如代码所示,BSP_USING_ADC 开启ADC框架支持,BSP_USING_ADC0 启用ADC0外设实例,BSP_USING_ADC0_CH22 指定使用通道22。这些宏定义会在ADC驱动源码 drv_adc.c 中通过条件编译被引用,从而将ADC0设备注册到RT-Thread设备框架中。

2. 解决ADC驱动编译错误

启用ADC宏定义后进行编译,发现 drv_adc.c 中存在未定义标识符的编译错误。ADC驱动中的时钟配置结构体使用了 kFRO12M_to_ADC0  kCLOCK_DivADC0 两个标识符,但在MCXA346的时钟头文件 fsl_clock.h 中这些标识符的命名有所不同。

通过在 fsl_clock.h 中搜索相关定义,发现MCXA346平台使用的正确标识符为:

  • 时钟附着标识:kFRO_LF_DIV_to_ADC(替代 kFRO12M_to_ADC0
  • 时钟分频标识:kCLOCK_DivADC(替代 kCLOCK_DivADC0

3. 时钟与引脚配置

在NXP的图形化配置工具中,使能ADC引脚,将生成的初始化代码加入到 pin_mux.c 的引脚初始化函数中。

4. 修改 drv_adc.c 驱动源码

根据查找结果,修改 drv_adc.c 中ADC0的初始化配置结构体,将时钟相关字段更新为正确的标识符:

如上图所示,修改完成后重新编译,0 Error(s),0 Warning(s),编译通过。下载至开发板后,再次使用 list device 命令检查设备列表,可以看到 adc0 设备已成功注册为 ADC Device 类型,说明ADC驱动适配成功。


四、外设驱动注册与自动初始化

ADC驱动使用RT-Thread提供的组件自动初始化机制,在系统启动时自动完成设备注册:

#ifdef RT_USING_COMPONENTS_INIT
INIT_BOARD_EXPORT(rt_hw_adc_init); // 自动调用ADC注册函数
#endif

代码详解


整体软件流程图:

一、硬件初始化与外设配置

系统上电后,main 函数首先输出编译器版本和开发板标识信息,随后完成外设初始化序列,关键流程如下:

  • 配置LED引脚为输出模式,初始设为低电平
  • 配置按键引脚为上拉输入模式,并注册下降沿中断回调
  • 查找并启用ADC0设备,准备进行电压采样
/* Configure LED pin as output */
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
rt_pin_write(LED_PIN, PIN_LOW);

/* Configure button pin as input with pull-up */
rt_pin_mode(BUTTON_PIN, PIN_MODE_INPUT_PULLUP);

/* Attach interrupt to button pin */
rt_pin_attach_irq(BUTTON_PIN, PIN_IRQ_MODE_FALLING, button_irq_callback, RT_NULL);
rt_pin_irq_enable(BUTTON_PIN, PIN_IRQ_ENABLE);

/* Find and enable ADC device */
adc_dev = (rt_adc_device_t) rt_device_find("adc0");
if(adc_dev == RT_NULL)
rt_kprintf("adc device find error\r\n");
rt_adc_enable(adc_dev, 1);

通过RT-Thread标准设备框架的 rt_device_find 接口按名称查找ADC设备,再调用 rt_adc_enable 使能指定通道,实现了设备驱动与应用层的解耦。


二、主循环——ADC采样与数据输出

主循环每500ms执行一次迭代,核心功能包括ADC采样、电压换算、串口打印和LED翻转:

rt_kprintf("Hello, DigiKey Funpack 5-1\r\n");
while (1)
{
value = rt_adc_read(adc_dev, 1);
// Convert 16-bit ADC value to voltage (0.0~3.3V) with 0.1 resolution
voltage = (float)value * 3.3f / 65535.0f;

/* Print voltage using sprintf */
char buffer[64];
sprintf(buffer, "adc value = %d, voltage = %.1f V\r\n", value, voltage);
rt_kprintf("%s", buffer);

/* Toggle LED state */
led_state = !led_state;
rt_pin_write(LED_PIN, led_state ? PIN_HIGH : PIN_LOW);

rt_thread_mdelay(500);
}

其中 rt_adc_read 从ADC0通道1读取16位原始采样值,随后通过公式 voltage = value * 3.3 / 65535 将原始值转换为0.0~3.3V范围内的实际电压。使用 sprintf 格式化输出字符串,保留一位小数精度,最后通过 rt_kprintf 输出至串口终端。同时每次循环翻转LED状态,通过闪烁指示系统正常运行。调用 rt_thread_mdelay(500) 让出CPU时间片,实现500ms的采样周期。

效果展示

硬件连接:使用ADALM2000提供直流电压信号。

编译下载后,通过串口终端可以观察到打印的欢迎信息,以及ADC持续采样输出的结果。

我们使用Scopy控制M2K提供的电压输出信号。

系统每500ms打印一次ADC原始值和换算后的电压值,且LED同步闪烁:

从输出结果可以看到,ADC采样值稳定在57200~57450范围内,换算电压约为2.9V,数据波动较小,说明ADC采样工作正常、精度良好。

此时输入 list device 命令,可以看到设备已经出现adc0:

遇到的难题与解决办法

问题一:首次使用Env工具执行 scons 构建时,提示依赖包缺失,无法完成编译。

解法:按照提示依次执行 pkgs --upgrade 更新软件包索引和 pkgs --update 下载所需的NXP MCX CMSIS驱动包和MCX Series驱动包,确保底层SDK文件就位后重新构建即可。

问题二:在 rtconfig.h 中添加ADC宏定义后,编译 drv_adc.c 出现未定义标识符错误,kFRO12M_to_ADC0  kCLOCK_DivADC0 在MCXA346的头文件中不存在。

解法:通过在 fsl_clock.h 中全局搜索ADC相关的时钟定义,找到MCXA346平台使用的正确标识符 kFRO_LF_DIV_to_ADC  kCLOCK_DivADC,修改 drv_adc.c 中的配置结构体后编译通过。整个排查过程需要对NXP SDK的时钟树配置有一定了解,不同MCX系列芯片的时钟命名规则存在差异,需逐一核对。

整个适配过程中,需重点关注:

  • ADC外设时钟源的正确挂载与分频配置
  • 不同MCX系列芯片间SDK接口命名的差异
  • RT-Thread设备驱动框架中宏定义开关的层级关系

活动感想

通过本项目实践,深入掌握了RT-Thread操作系统ADC设备驱动框架的工作原理与适配方法,熟悉了RT-Thread在ARM Cortex-M33架构上的设备管理机制与驱动编写规范。NXP FRDM-MCXA346开发板丰富的外设资源与MCUXpresso SDK的完善支持极大提升了开发效率。整个适配过程中,体会到嵌入式系统开发需要对底层硬件寄存器、时钟树配置以及驱动框架有清晰的理解,每一个标识符的正确匹配都直接影响功能的实现。

感谢硬禾学堂和得捷电子联合举办的Funpack活动,祝硬禾的活动越办越好!

附件下载
frdm-mcxa346.zip
源代码
团队介绍
个人
团队成员
枫雪天
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号