备赛电赛,用的高云GW1N-9 FPGA,搭了蜂鸟E203软核,串口调试助手收到的全是乱码。我检查过PLL输出频率和波特率寄存器,跟115200算出来应该没问题。但有人说软核启动时如果GPIO复用没配好,UART引脚电平不稳定也会导致首帧乱码。想问问有经验的大佬,这种问题一般是先查波特率误差还是先查软核启动时序?有没有快速定位手段?
2026年了,FPGA大赛用国产高云FPGA做RISC-V软核,串口打印乱码,波特率配置和软核启动时序哪个嫌疑大?
7 个回答

先把逻辑分析仪或者示波器探头怼到 UART_TX 引脚上,看波形数一下起始位到第一个数据位的时间宽度,和 8.68us(1/115200)比一比。如果差得离谱,那波特率时钟源或者分频系数就有问题;如果时间宽度对,只是首字节乱后面全对,那基本就是软核复位释放瞬间 GPIO 还没切到 UART 功能,引脚上先跑了几拍默认电平,被接收端当成起始位了。个人感觉你先抓波形比纠结寄存器靠谱得多,波形能直接告诉你到底是时序问题还是电平问题。另外别忘了高云 IDE 里下载 bit 流之后,软核复位默认是拉低的,你得确认复位释放时机是不是在 PLL lock 之后。要是抓波形不方便,也可以先发 0x55 这种交替位模式,看是不是每字节都错同一位,能帮你判断是波特率偏差还是帧格式问题。你用的蜂鸟 E203 是官方移植版还是自己改过的?

先别急着二选一,这俩嫌疑其实可以靠一个动作分开:把波特率临时降到 9600,重新上电发一串 0x00 或 0xFF。如果降速后乱码变成「每个字节错半个位宽」或者干脆能认出帧头,那波特率误差的锅更大;如果降速后还是整段乱码、甚至首字节吞掉,那就往软核启动时序方向查。高云 GW1N-9 的 GPIO 复用寄存器默认值在数据手册里写得很清楚,上电后到软核执行第一条指令之间,引脚方向和三态控制是由 FPGA 配置决定的,但 RISC-V 核里如果你在启动代码里重新配置了 GPIO(比如蜂鸟 E203 的 uart_init),这个配置发生在 main 之前还是之后会影响首帧。常见坑是软核从 Flash 启动时,JTAG 或 SPI 复用脚还没切干净,UART TX 在头几十微秒被别的模块驱动,等你 printf 第一字节时,接收端已经因为前导噪声错乱了帧同步。快速定位手段:在 FPGA 顶层例化一个计数器,从软核复位释放开始延时 100us 再拉高复位,或者干脆把软核复位信号接到一个可调延时模块上,对比延时前后首帧是否稳定。另一个更狠的办法是写个纯 Verilog 状态机直接驱动 UART TX 发固定字节,绕开软核,如果这样还乱码就是硬件或者 PLL 问题,如果正常就 100% 是软核启动代码时序。我之前调过类似问题,最后发现是 E203 的 system clock 和 UART clock 不是同源,PLL 输出给 CPU 的 50MHz 和给 UART 的 50MHz 相位差太大,寄存器里算的波特率分频值看着对,实际边沿采样点正好落在数据位边界上,降速或者把 UART 时钟改成和 CPU 同源就好了。你现在 PLL 是给软核和 UART 共用一路输出,还是分了两个输出?

说个容易被忽略的旁路问题:高云 GW1N-9 的下载器如果走 JTAG,调试时软核是暂停在复位向量里的,你串口助手收到乱码可能是因为调试器占住了 CPU,UART TX 引脚被 tris 态拉高拉低产生毛刺,而不是真的波特率错。建议你先用独立电源给板子上电,拔掉下载线,让软核从 SPI Flash 自启动,再观察串口输出。如果自启动正常而 JTAG 调试时乱码,那问题在调试接口的引脚复用冲突,跟波特率一点关系没有。另外,蜂鸟 E203 的 uart 初始化里经常有人把 GPIO 方向寄存器配置放在时钟使能之前,导致前几拍输出阻抗不确定,示波器上看 TX 引脚会有 1-2us 的抖动,这时接收端可能把第一个字节的起始位提前采样了。我遇到过类似情况,解法是把 GPIO 复用配置挪到 uart_init 最前面,并且给软核复位加一个由 PLL lock 信号与门控制的延时释放,别用固定计数器因为不同温度下 lock 时间会漂。你如果手头有第二块板子,可以先把软核换成高云官方那个硬核 ARM Cortex-M3 的例程(如果 GW1N-9 支持的话,其实 GW1NSR 才有),对比一下是不是软核移植的初始化遗漏。最后补一句:别信 115200 的标称误差,FPGA 里分频是整数除法,115200 除以 50MHz 等于 434.027,取整 434 后实际波特率是 115207,误差只有 0.006%,完全没问题,所以波特率寄存器这块基本可以排除。你用的是哪个版本的 E203 源码?官方 GitHub 那个还是学校老师改过的?

我建议你换个思路,别纠结波特率还是时序,先确认你的串口助手是不是配置错了。很多国产调试助手默认带校验位或者停止位不对,你寄存器算的是 8N1,但助手那边可能是 8E1 或者 7E1,出来的乱码特征是完全随机但每个字节都差不多长度。先拿逻辑分析仪抓一发波形,手动数一下起始位后是不是正好 8 个数据位加 1 个停止位,这个比调软核快多了。如果波形帧格式对,那再怀疑软核启动时序。高云的 FPGA 上电配置时间一般在几十毫秒量级,如果你的软核复位信号是直接接在 FPGA 的全局复位上,而全局复位又由外部按键控制,那按键弹跳会在启动瞬间产生多个复位脉冲,导致 GPIO 初始化执行一半被打断,UART 引脚配置没写完就进 main 开始打印。解决办法是把复位按键信号先经过一个去抖模块,或者干脆在软核启动代码里加个软件延时,等 200ms 再初始化 UART。另外你检查过 PLL 的 locked 信号有没有接到软核复位释放逻辑里吗?如果没接,CPU 可能在时钟还没稳定就开始跑指令,第一条 printf 的波特率分频值是从 Flash 里加载的,但时钟抖动会让分频器计数不稳,输出波形宽度忽大忽小,串口助手就显示乱码。这种情况你算波特率误差是算不出来的,因为瞬时频率在跳。快速定位方法:把 printf 改成循环发送同一个字节 0x41,用示波器看 TX 引脚上每个字节的位宽是否一致,如果不一致就是时钟抖动的锅。你 PLL 的输入时钟是板载晶振还是外部信号发生器?如果外部输入的话,检查一下信号幅度是否达到 LVCMOS 阈值,高云对输入时钟边沿速率有要求,太慢的话 PLL 锁定后 jitter 会偏大。

题主你这个问题我当年备赛也踩过,说下我的排查顺序供参考。第一步一定是看波形,逻辑分析仪比示波器好用,因为能长时间抓连续乱码。你把串口助手设为 HEX 显示,发 0x55,正常应该收到 0x55,如果收到 0x2A(01010101 反了)或者 0xAA(相位偏半位),那就是波特率采样点偏了;如果收到的是 0x95 这种带进位错的,那可能是帧格式里停止位被当成了数据位。第二步查软核启动代码里 GPIO 复用寄存器,蜂鸟 E203 的 system verilog 里 GPIO 和 UART 共用一组引脚,必须在 uart_init 里把对应 bit 设为外设功能,但很多移植版把这个配置放在了 timer 初始化之后,导致前几个字节发出去时引脚还是 GPIO 模式,电平由内部上拉决定,波形上会有毛刺。第三步也是最容易忽略的,高云 IDE 的 IP 核生成器里 UART 的时钟源选择,如果你选了 PLL 的 50MHz 输出,但 PLL 的相位偏移设了 90 度,那 UART 时钟边沿和 CPU 时钟错开,寄存器读写没问题,但 TX 移位寄存器的采样时刻会偏移,导致位宽不一致。我上次就是被这个坑的,改 PLL 相位偏移为 0 就好了。你现在的 PLL 配置是直接用了官方模板还是自己调的?如果自己调的,把相位偏移和 duty cycle 截图发出来看看。另外建议你把软核的复位信号接到一个拨码开关上,手动控制复位释放时机,如果手动复位后打印正常而自动上电乱码,那就是启动时序里 PLL lock 等待不够,加个状态机在 lock 后延时 10ms 再释放复位就行。

说实话,你这个排查思路有点把自己绕进去了。先别管波特率还是启动时序,最靠谱的做法是拿逻辑分析仪直接怼在UART_TX引脚上抓一发波形,看起始位到第一个数据位的宽度是不是8.68us(对应115200)。如果宽度对,那波特率配置就是对的,问题八成在软核启动时序上;如果宽度不对,那就去查PLL分频和寄存器写入顺序。我个人经验是,蜂鸟E203这种软核跑在高云上,乱码大概率不是波特率算错,而是GPIO复用配置的时机问题——很多移植版把uart_init里的引脚切换放在复位释放之后执行,但FPGA上电后到软核跑起来之间,引脚默认是GPIO模式,电平可能被上拉电阻拉高拉低,接收端就会把这段毛刺当成起始位。你可以试试在FPGA侧加一个延时模块,让软核复位信号在配置完成后再释放,或者干脆在启动代码最前面先写GPIO复用寄存器,再初始化时钟。另外有个快速定位的小技巧:把波特率临时降到9600,如果乱码变成每个字节都错半位,那是波特率误差;如果还是整段乱码甚至首字节丢失,那就往启动时序方向查。你现在用的蜂鸟E203是高云官方移植版还是自己改过的?这决定了我能帮你细化到哪一步。

其实你这个问题有个更隐蔽的可能:串口助手的配置。很多国产调试助手默认不是8N1,可能是8E1或者7E1,你寄存器算的是115200 8N1,但助手那边校验位不对,出来的乱码特征就是每个字节长度差不多但内容完全随机。你先别折腾软核,把串口助手改成8N1无校验,再发0x55试一下。如果还乱,那就用逻辑分析仪抓波形,手动数一下起始位后面是不是正好8个数据位加1个停止位——这一步比调任何寄存器都快,能直接告诉你帧格式对不对。帧格式没问题的话,再考虑软核启动时序。高云GW1N-9上电配置时间一般在几十毫秒,如果你把软核复位直接接在外部按键上,按键弹跳会产生多个复位脉冲,GPIO初始化可能执行一半就被打断,UART引脚配置没写完就进main开始打印。解决办法是加个去抖模块,或者干脆在启动代码里写个软件延时,等引脚稳定后再初始化UART。说实话,这种问题九成是启动时序,波特率算错反而少见,因为PLL输出频率你既然检查过,那分频系数大概率没错。你手头有逻辑分析仪吗?没有的话用示波器看波形也行,但要注意把时基调到微秒级,不然看不到起始位的细节。
发表回答
登录后可在本页底部提交回答