一、项目介绍
MAX32690 评估套件提供了一个平台,用于评估 MAX32690 微控制器的功能,该微控制器是一款先进的片内系统 (SoC)。它采用了 Arm Cortex-M4F CPU,可高效计算复杂的功能和算法,并采用了最新一代的 Bluetooth 5 低功耗(蓝牙 LE)射频,专为可穿戴和便携式健身设备、便携式和可穿戴式医疗设备、工业传感器/网络、物联网 (IoT) 和资产追踪而设计。
Zephyr RTOS:由Linux 基金会托管的开源实时操作系统,专为资源受限物联网设备设计(最小 8kB 内存),支持 ARM/RISC-V 等架构,内置蓝牙/Wi-Fi 协议栈,广泛应用于工业、医疗及消费电子 。
本项目使用 ADI 的MAX32690EVKIT 评估套件,完成基于 Zephyr RTOS 的 UART 回显示例,通过 UART2 中断驱动接收串口数据,将字符大小写互换后回传给上位机,并在每接收 10 个字符或遇到换行符时统计上报已接收字符总数;项目使用消息队列实现中断与主循环的线程安全通信。
二、硬件介绍

本项目使用到的硬件是 ADI的MAX32690EVKIT评估套件
MAX32690微控制器(MCU)是一款先进的片上系统(SoC),配备Arm® Cortex®-M4F CPU、大容量闪存和SRAM内存,支持蓝牙® 5.2低功耗(LE)射频,兼具强大处理能力与物联网应用所需的连接功能。
MAX32690的工作温度范围为-40°C至+105°C,非常适合工业环境,提供68引脚TQFN-EP(0.40mm间距)、140凸点WLP(0.35mm间距)和144-CTBGA(0.8mm间距)封装形式。
MAX32690集成的蓝牙5.2低功耗(LE)射频支持远程(编码)和高吞吐量模式。可选的RISC-V核心能够处理时间敏感型控制任务,使开发人员无需担心蓝牙LE中断延迟问题。
内部代码和SRAM空间可通过两个Quad-SPI就地执行(SPIXF和SPIXR)接口扩展,每个接口最大支持512MB。
加密工具箱(CTB)提供模运算加速器(MAA)、高级加密标准(AES)引擎、真随机数生成器(TRNG)和SHA-2引擎。器件还具备丰富的安全特性,包括128位唯一序列号(USN)、物理不可克隆函数(PUF)、安全非易失性密钥存储、用于SPIXF和SPIXR的内存解密完整性单元(MDIU)及Arm内存保护单元(MPU)。可选的安全通信协议引导加载程序(SCPBL)提供不可变的信任根,支持使用ECDSA进行安全启动和闪存完整性验证,具备安全固件更新功能。
器件支持多种高速接口,包括多个QSPI、UART、CAN 2.0B和I2C串行接口,而且包含一个用于连接音频编解码器的I2S端口。大多数接口支持在内存(闪存或SRAM)与外设之间进行DMA驱动的数据传输。12输入(8个外部)、12位SAR ADC,以高达1Msps的速度采样模拟数据。
MAX32690EVKIT评估套件的原理图如下:

三、程序设计思路
软件的设计框图入下:

1、main 函数:检查 UART 设备就绪 → 注册中断回调 → 启用接收中断 → 进入消息队列阻塞循环
2、UART 中断:每收到一个字符触发中断,读取字符,进行简单处理。
3、消息队列:中断作为生产者,main 循环作为消费者,实现线程安全的数据传递
4、回显输出:从队列取出数据后通过 uart_poll_out 逐字符发送回 PC 串口终端
四、软件介绍
1.Zephyr 配置
查看设备树文件,确保相关的外设配置正确,本项目中使用 UART2,引脚为 P1.9 和 P1.10,UART 波特率设置为 115200,无奇偶校验,一个停止位,8 个数据位。
&uart2a_rx_p1_9 {
power-source = <MAX32_VSEL_VDDIO>;
bias-pull-up;
};
&uart2a_tx_p1_10 {
power-source = <MAX32_VSEL_VDDIO>;
};
&uart2 {
pinctrl-0 = <&uart2a_rx_p1_9 &uart2a_tx_p1_10>;
pinctrl-names = "default";
clock-source = <ADI_MAX32_PRPH_CLK_SRC_IBRO>;
current-speed = <115200>;
parity = "none";
stop-bits = "1";
data-bits = <8>;
status = "okay";
};
编辑 Kconfig 文件,启用相关功能
CONFIG_SERIAL=y
CONFIG_UART_INTERRUPT_DRIVEN=y
# 默认构建调试版本(无优化)
CONFIG_DEBUG=y
CONFIG_NO_OPTIMIZATIONS=y
# 启用调试时的线程信息
CONFIG_THREAD_NAME=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_THREAD_ANALYZER=y
# 启用 Zephyr 核心转储支持
CONFIG_DEBUG_COREDUMP=y
CONFIG_DEBUG_COREDUMP_BACKEND_FLASH_PARTITION=y
CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_THREADS=y
CONFIG_SMP=n
CONFIG_PRINTK=y
CONFIG_LOG=y
CONFIG_HEAP_MEM_POOL_SIZE=8192
CONFIG_MAIN_STACK_SIZE=16384
# 启用 Flash 支持
CONFIG_FLASH=y
2、程序入口 main 函数
按顺序执行以下步骤:
if (!device_is_ready(uart_dev)) {return 0;}
int ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
if (ret < 0) {return 0;}
uart_irq_rx_enable(uart_dev);
while (k_msgq_get(&uart_msgq, &tx_buf, K_FOREVER) == 0) {
print_uart(tx_buf);
}
设备就绪检查:通过 device_is_ready 验证 UART外设是否已完成初始化并处于可用状态。若设备未就绪则直接返回,避免后续操作引发异常。
注册中断回调:调用 uart_irq_callback_user_data_set将 serial_cb 函数注册为 UART 接收中断的处理回调,使硬件中断触发时能自动调用该函数。
启用接收中断:通过 uart_irq_rx_enable开启 UART 的接收中断使能,此后每当 UART中有数据到达时,硬件会自动触发中断。
进入阻塞循环:使用 k_msgq_get从消息队列中阻塞等待数据。队列中有数据时立即取出,无数据时挂起当前任务,由 Zephyr 内核调度其他任务运行,实现高效的资源利用。
3、UART 中断处理流程
void serial_cb(const struct device *dev, void *user_data)
{
uint8_t c;
if (!uart_irq_update(uart_dev)) {return;}
if (!uart_irq_rx_ready(uart_dev)) {return;}
while (uart_fifo_read(uart_dev, &c, 1) == 1) {
if ((c == '\n' || c == '\r') && rx_buf_pos > 0) {
rx_buf[rx_buf_pos] = '\0';
sprintf(c_info,"\ntotal:%d\n",rx_buf_pos);
k_msgq_put(&uart_msgq, &rx_buf, K_NO_WAIT);
k_msgq_put(&uart_msgq, &c_info, K_NO_WAIT);
rx_buf_pos = 0;
} else if (rx_buf_pos < (sizeof(rx_buf) - 1)) {
if('a'<=c && c<='z'){c-=32;}
else if('A'<=c && c<='Z'){c+=32;}
rx_buf[rx_buf_pos++] = c;
if(rx_buf_pos%10==0){
sprintf(c_info,"\ntotal:%d\n",rx_buf_pos);
k_msgq_put(&uart_msgq, &c_info, K_NO_WAIT);
}
}
}
}
serial_cb 是 UART 接收中断的核心回调函数,负责逐字符处理接收数据:
中断状态清理:首先调用 uart_irq_update() 清除 UART 中断状态寄存器,防止中断重复触发。若状态清除失败则直接返回。
接收数据检测:通过 uart_irq_rx_ready() 检查 FIFO 中是否有待读取的字符。若无数据则退出中断服务程序。
循环读取:使用 uart_fifo_read() 循环读取 FIFO 中所有可用字符,直到 FIFO 为空为止,确保不遗漏任何数据。
字符处理逻辑:
换行符处理:当遇到 \n 或 \r 时,将当前缓冲区内容以 \0 结尾,格式化统计信息,并将原始消息和统计信息同时入队,最后重置缓冲区位置。
普通字符处理:对字母字符进行大小写转换(小写减 32、大写加 32),存入接收缓冲区。每累积 10 个字符时自动生成统计信息并入队,便于实时反馈接收进度。
缓冲区溢出保护:当缓冲区已满时自动丢弃多余字符,防止内存越界。
五、功能展示

数据以↩︎为结束符,可以看到,发送字符可以被回显出来,并输出计数统计。当发送字母时,大小写会被转换。发送每超过 10 个字符时,会先输出一次计数,收到↩︎再完整输出所有字符。
六、遇到的问题及心得体会
这次遇到的问题主要是之前对于 Zephyr 不熟悉,学习过程遇到很多困难,设备树和 kconfig 是我之前不太了解的内容。不过好在现在 AI 很厉害,可以帮我解答文件,解释代码,帮助我完成这个项目。通过本项目,我深入理解了 Zephyr 的 UART 中断驱动开发模式。Devicetree 配置让硬件引脚映射一目了然,K_MSGQ 消息队列实现了中断与主循环的线程安全通信。中断中只做轻量数据处理,耗时操作放在主循环,这种设计显著提升了系统实时性。Zephyr 简洁的 API 和模块化架构,让嵌入式开发更加高效规范。