ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

XMC四路串口并行通信实战:USIC通道配置与调度技巧

XMC四路串口并行通信实战:USIC通道配置与调度技巧 简介面向英飞凌 XMC 系列开发者的多路串口并行通信例程包聚焦 UART0/UART1 四个通道的独立收发配置通过宏定义清晰指定通道引脚与中断解决多路串口同时工作的驱动组织与资源分配问题。包体共69个文件以 C 源文件、头文件为主覆盖 USIC 串口初始化、环形缓冲接收、Shell 交互调试等模块同时包含 Keil MDK 工程配置、编译中间文件及说明文档压缩包仅 1.42MB结构紧凑便于对照学习。例程中重点展示四路 UART 的并行处理思路使用发送/接收缓冲与中断服务配合避免串口数据丢失适用于需要多串口通信的嵌入式项目或入门 XMC 外设开发的学习者。已有530人学习下载代码注释和工程目录清晰可帮助读者快速搭建多路串口收发框架理解通道复用、中断映射等关键细节并在实际板上直接验证。1. 四路串口并行通信的本质是XMC的USIC通道抢占同一份外设时钟拿到一个命名像 UART_Demmo 的压缩包例程第一件事不是解压找 main.c而是先确认这颗英飞凌 XMC 芯片里 UART 挂在哪个外设上。XMC4000 系列没有传统单片机那种一个串口对应一组独立寄存器的 UART 外设它把串行功能整合进 USIC 模块一个 USIC 再拆成两个通道通道配置成 UART 模式之后才看到串口。所以四路串口并行通信核心是 USIC 通道的分配、引脚映射和中断调度而不是简单地把初始化 UART 的代码复制四遍。下面按这个顺序展开先讲 USIC 通道和引脚怎么选再给 DAVE 和 XMCLib 两种初始化写法然后把多路并行收发的队列调度和错误排查说透最后给一套能直接搬走的验证技巧。适合正在做多路采集、测试治具和协议转换器或者想把 XMC 底层串口机制一次搞明白的人。2. XMC的UART从哪里来USIC通道、引脚复用与波特率误差2.1 USIC通道数量和四路UART的硬件底座USIC 全称 Universal Serial Interface Channel本质是一个可配置的串行通信引擎。和普通 MCU 里 UART 外设最大的区别在于USIC 本身不是某种固定协议而是通过模式选择变成 UART、SPI、I2C 等接口。相同的外设时钟被多个通道共享每个通道又有独立的收发状态机、FIFO 和事件逻辑。因此四路 UART 并行通信硬件上是真实的并行四个状态机各自按自己的波特率工作不依赖 CPU 轮询。软件上要解决的只是数据怎么搬、中断进了谁、缓冲满不满。XMC4000 系列常见型号的 USIC 模块数量并不完全一样可以参考下表理解通道上限系列USIC 模块数量四路并行 UART 可行性XMC45004 个 USIC每模块 2 通道轻松支持引脚资源宽裕XMC4700 / XMC480046 个 USIC支持同时还能保留足够 CAN、以太网引脚XMC1000 系列12 个 USIC通道少不建议做四路资源太紧我一般在选型时不会把“可用通道数”推到上限因为通道引脚会和其他外设抢位置。四路 UART 是 XMC4000 系列比较舒服的负载通道有余量中断占用的 NVIC 资源也还划算。如果项目到了需要让六路 UART 同时在 921600bps 持续收发那要注意共享外设时钟的相位噪声和 FIFO 深度后面会专门说。2.2 引脚分配查ALT功能表是最费时但最值得做的步骤XMC 的引脚几乎都是多功能复用同一路 UART 的 TX/RX 可以映射到好几组引脚。开始写代码前第一步不是初始化 UART而是打开对应型号的数据手册查 USIC 通道的 ALT 功能表。下面这个分配表仅用于说明查表方法不代表所有封装的合法映射动手前一定要核对对应型号数据手册。串口通道TX 候选引脚RX 候选引脚UART0USIC0_CH0P0.2 / P1.4 / P2.14P0.3 / P1.5 / P2.15UART1USIC0_CH1P0.0 / P1.0 / P2.0P0.1 / P1.1 / P2.1UART2USIC1_CH0P0.6 / P1.6 / P5.0P0.7 / P1.7 / P5.1UART3USIC1_CH1P0.8 / P2.7 / P5.4P0.9 / P2.8 / P5.5四路并行时最怕的是四路配置到同一个通道上或者某个引脚被 SWD 调试口、CAN、以太网悄悄占用。我一般会做一张引脚占用表把四路需要的 8 个引脚先列出来再和板上的功能模块逐个比对。很多例程跑不起来不是因为 UART 配置错而是 TX 和 RX 接反或者引脚被调试口占用。拿到板子后先看原理图确认实际接线不要迷信例程里的默认引脚。2.3 波特率误差四路并行时不能只看单路误差XMC 的 USIC 波特率由外设时钟经过整数分频和分数分频得到常规 UART 通信协议本身不要求误差必须小于多少但四路并行时误差叠加在四根线上某一路单独发数据正常不代表四路同时跑高波特率时不出错。我通常把误差控制在 ±0.2% 以内超过 ±2% 就放弃该组合改时钟源或采样点。这里给一个能直接运行的 Python 脚本批量扫分数分频值看哪个组合能让目标波特率误差最小def check_baud(target, fperiph, oversampling16): best None for fdiv in range(1025): baud fperiph / (oversampling * (1 fdiv / 1024.0)) err abs(baud - target) / target if best is None or err best[2]: best (fdiv, baud, err) print(ftarget{target}, fdiv{best[0]}, fbaud{best[1]:.2f}, err{best[2]*100:.3f}%) check_baud(115200, 144000000) check_baud(460800, 144000000) check_baud(921600, 144000000)逻辑说明fdiv遍历的是分数分频器可写的有效步进baud是理论输出波特率err是相对误差。实际 XMC 是整数分频和分数分频两级脚本里只演示了分数部分但足以帮你判断某颗芯片上的外设时钟能不能干净地生成目标波特率。参数说明fperiph是 USIC 模块输入时钟不同工程里可能是 PLL 分频得到也可能是外部晶振直通必须从时钟树里确认oversampling常规设 16噪声大时可以设 8 配合更大的采样窗口但寄存器限制不同。2.4 USIC外设时钟是四路共享的不能单独调一路四个 UART 通道共用同一个 USIC 外设时钟域所以不能通过“单独给某一路换时钟源”来修正波特率误差唯一灵活的是分频组合和采样点。在 DAVE 里Clock 配置页会显示 USIC 模块的时钟来源。如果四路波特率分别是 9600、115200、460800、921600要保证外设时钟能在同一个分频体系下同时满足四个目标必要时牺牲第一路改用非标采样点。这也是四路并行和单路 UART 最不一样的地方单路只要把自己调准四路必须在一个公共时钟下找平衡。3. 基本例程的落地DAVE图形化配置与XMCLib手动初始化3.1 DAVE 添加四个 UART APP而不是复制一个DAVE CE 里做四路 UART 的常规做法是添加四个 UART APP分别绑定不同的 USIC 通道。操作顺序大致是新建工程后在 APP Library 里搜索 UART添加 4 个实例生成 UART_0 到 UART_3。双击每个 APP在 Configuration 里绑定 USIC 通道和引脚。分别设置波特率、数据位、停止位、奇偶校验。打开 RX 接收完成中断四路都允许产生中断事件。保存并 Generate Code检查生成的UART_Init()入口。DAVE 不会阻止两个 APP 绑定同一个 USIC 通道。如果误操作生成代码不报错但运行后两个 APP 会轮流改写同一个通道的寄存器配置。基本例程里最典型的故障是UART_0 和 UART_1 共享 USIC0_CH0最终只有一路能工作。检查方式是打开UART_Init()生成代码搜索XMC_UART0_CH0是否被赋值两次。DAVE 只是生成器底层调的还是英飞凌 XMCLib。正式项目里如果代码已经脱离 DAVE 工程或者要维护老例程初始化就是填充配置结构体并调用底层接口下面这份骨架可以当起点。#include xmc_uart.h #include xmc_gpio.h void uart0_pin_init(void) { /* ALT 模式从数据手册的引脚复用表里查不要照抄其他型号 */ XMC_GPIO_SetMode(XMC_GPIO_PORT1, 4U, XMC_GPIO_MODE_MODE_ALT1); XMC_GPIO_SetMode(XMC_GPIO_PORT1, 5U, XMC_GPIO_MODE_MODE_ALT1); } void uart0_init(void) { XMC_UART_CH_CONFIG_t cfg; cfg.baudrate 115200U; cfg.data_bits 8U; cfg.stop_bits 1U; cfg.parity_mode XMC_USIC_CH_PARITY_MODE_NONE; cfg.oversampling 16U; uart0_pin_init(); XMC_UART_CH_Init(XMC_UART0_CH0, cfg); XMC_UART_CH_Start(XMC_UART0_CH0); }逻辑说明XMC_UART_CH_Init负责把 USIC0_CH0 配置成 UART 模式并写入分频参数Start才真正打开收发。参数说明baudrate就是目标波特率data_bits和stop_bits对应串口协议格式parity_mode常用NONEoversampling保持 16 即可改采样范围要同时确认寄存器允许的边界。XMC_GPIO_SetMode里的 ALT1 只是示例编号实际以芯片引脚表为准。四路并行不要写四个几乎一样的初始化函数用通道数组和循环更稳妥static const XMC_UART_CH_t *const uart_ch[4] { XMC_UART0_CH0, XMC_UART0_CH1, XMC_UART1_CH0, XMC_UART1_CH1 }; void uart4_all_init(void) { XMC_UART_CH_CONFIG_t cfg { .baudrate 115200U, .data_bits 8U, .stop_bits 1U, .parity_mode XMC_USIC_CH_PARITY_MODE_NONE, .oversampling 16U }; for (int i 0; i 4; i) { uart_pin_init_by_index(i); /* 每路分配各自的引脚和 ALT 模式 */ XMC_UART_CH_Init(uart_ch[i], cfg); XMC_UART_CH_Start(uart_ch[i]); } }逻辑说明uart_ch数组按索引对应 UART0UART3循环里每路独立初始化。初始化顺序对并行没有影响但建议把 NVIC 中断使能放在所有通道Start之后避免上电瞬间通道还在复位时中断就进来。3.2 发送用队列不要用轮询死等基本例程里通常只示范单字节发送例如调用XMC_UART_CH_Transmit()。这对四路串口并行通信不安全如果 TX FIFO 已满调用可能忙等或直接丢数据。四路同时发数据时总有一条先满死等会让 CPU 停在那条路上其他路的 RX FIFO 就可能溢出。所以每路要有独立的发送缓冲区主循环只把数据放进队列发送由中断或 DMA 慢慢取。#define UART_TX_FIFO_LEN 512 typedef struct { volatile uint8_t data[UART_TX_FIFO_LEN]; volatile uint16_t head; volatile uint16_t tail; } soft_uart_tx_t; static soft_uart_tx_t tx_pool[4]; static uint16_t next_idx(uint16_t idx) { return (idx 1U) % UART_TX_FIFO_LEN; } void uart_tx_put(uint8_t uart_id, uint8_t byte) { uint16_t n next_idx(tx_pool[uart_id].head); if (n tx_pool[uart_id].tail) { return; /* 缓冲区满视项目决定丢弃还是置错误标志 */ } tx_pool[uart_id].data[tx_pool[uart_id].head] byte; tx_pool[uart_id].head n; } uint8_t uart_tx_get(uint8_t uart_id) { uint8_t byte tx_pool[uart_id].data[tx_pool[uart_id].tail]; tx_pool[uart_id].tail next_idx(tx_pool[uart_id].tail); return byte; }逻辑说明head指向待写入位置tail指向待发送位置n tail表示缓冲区满。volatile在单核 MCU 里不能保证“原子性”但能在大多数场景下防止编译器把变量优化进寄存器真正的并发保护还是要靠临界区。参数说明512 字节缓冲在 115200 波特率下约能撑 44ms足够主循环调度如果某一路数据量大密集建议改成 1024 或直接用 DMA。3.3 接收中断的标准化写法四路并行通信的接收中断里只做两件事读数据、入队。协议解析放到主循环否则高波特率下一帧长数据就能把其他路的接收打断。void USIC0_0_IRQHandler(void) { uint32_t flag XMC_UART_CH_GetStatusFlag(XMC_UART0_CH0); if (flag XMC_UART_CH_STATUS_FLAG_RECEIVE_INDICATION) { uint8_t byte XMC_UART_CH_GetReceivedData(XMC_UART0_CH0); uart_rx_queue_push(0U, byte); } /* 错误标志单独处理不要在中断里做协议解析 */ XMC_UART_CH_ClearStatusFlag(XMC_UART0_CH0, flag); }逻辑说明先读状态再读数据最后清标志顺序反了会丢接收事件。RECEIVE_INDICATION这类宏名在不同版本 XMCLib 里可能有差异以实际头文件为准。多路共用一个 IRQ 的型号要在处理函数开头根据通道参数判断是哪一路触发的。四个中断都及时清标志才不会互相拖累。4. 多路并行UART的调度与错误排查4.1 中断优先级不能全部设成同一个值NVIC 里四个 UART 中断如果同优先级同时触发时系统会按硬件编号排队每个中断服务里的关中断区间会互相阻挡。高波特率通道尤其明显。我一般把四路分成两组NVIC_SetPriority(USIC0_0_IRQn, 2); NVIC_SetPriority(USIC0_1_IRQn, 3); NVIC_SetPriority(USIC1_0_IRQn, 2); NVIC_SetPriority(USIC1_1_IRQn, 3);逻辑说明同一时刻不会四条优先级完全一样如果其中一路是 921600单独给它最低的数值也就是最高优先级。四路都是 115200 时分成两档足够不用每路一档。这个做法的目的是让高波特率通道能打断低波特率通道的处理缩短 FIFO 等待时间。4.2 临界区要短不要在协议解析期间关中断主循环往 TX 队列里写数据中断从 TX 队列取数据两个动作不是原子的。简单做法是主循环写head时短暂关中断uint32_t primask __get_PRIMASK(); __disable_irq(); uart_tx_put(0U, byte); __set_PRIMASK(primask);逻辑说明__get_PRIMASK和__disable_irq是 CMSIS 自带接口临界区越短越好。不要在整个协议解析期间关中断否则四路里只要有一路数据量大RX FIFO 就会溢出。分段收、分段放行是四路并行通信的基本修养。4.3 接收错误标志一览错误类型常见宏名出现场景建议处理FIFO 溢出OVERRUN中断响应太慢上一字节还没读走加大 FIFO 阈值或缩短临界区帧错误FRAMING对端波特率偏差、线路干扰核对对端波特率看采样点奇偶校验错误PARITY对端数据位/校验设置不一致确认协议帧格式起始位错误START BIT线路毛刺、电平不匹配加串阻/上拉查电平转换一旦出现溢出基本例程里最简单有效的办法不是把波特率降下来而是用 XMC 的 FIFO 中断模式让中断在收到 4 个字节后再触发。多路并行时尤其适用中断频率降为原来的四分之一发数据的时间窗更长。提示基本例程里通常只演示单路串口回环四路并行时需要自己补上调度层错误标志检查绝不能省。4.4 外接调试台FT232R/FT231x 和 Linux 下的串口节点四路并行通信调试最常见的是用四路 USB 转串口接到同一台电脑。Windows 下 FT232R、FT231x 装好 USB UART 驱动后设备管理器里会多出 COM3COM6Linux 下一般是 /dev/ttyUSB0ttyUSB3。打开四个终端同时看输出能直接看到四路各自的数据流。注意电平方向XMC 的 UART 电平是 3.3V如果外接设备是 1.8V 电平需要加电平转换电路不要直接飞线。TTL 转 USB 模块上标注的 TX 连接 MCU 的 RXRX 连接 MCU 的 TX这两根线接反是最常见的低级故障。5. 四路同时通信的验证技巧回环、帧序号和波形取样5.1 先做软件回环排除外部接线XMC 的 USIC 通道支持 loopback 模式让 TX 数据在芯片内部回到 RX 路径。好处是排除杜邦线、电平转换、USB 转串口这些外部因素。初始化后使能 loopback发一串已知数据看是否能原样收回。如果回环通过但外接不通问题一定在接线或外部电平不需要怀疑 UART 配置。5.2 四路互相对发用帧序号定位丢数把第 1 路 TX 接第 2 路 RX第 3 路 TX 接第 4 路 RX每路发带帧序号的数据例如 0x55、0xAA、序号。用串口终端看序号是否连续。如果某一帧丢在中间说明该通道 FIFO 溢出或中断被别的路堵了此时优先查对应中断的优先级和 RX FIFO 阈值设置。5.3 逻辑分析仪抓四路波形量实际波特率四路并行验证一个简单但有说服力的测量是让四路同时发同步头 0x55用逻辑分析仪四个通道抓波形把四路起始沿对齐量每一帧的位宽。偏差超过 2%重点查时钟分频误差和负载电容带来的边沿变形。四路波形放在同一个触发条件下对比比单独看每个通道更容易发现分频参数是否被意外覆盖。5.4 混合波特率压力测试我通常会的收尾动作是把四路波特率分别拉到 9600、115200、460800、921600同时跑 10000 帧压力测试统计丢帧率。能同时通过再算四路串口并行通信达标。本文还有配套的精品资源点击获取
返回列表