首页 / 资讯中心 / 文章详情

NIOS II老工程移植Eclipse全攻略:从导入到排错

NIOS II老工程移植Eclipse全攻略:从导入到排错 ★ FEATURED ARTICLE
接手一个跑了六七年的NIOS II老工程最崩溃的时刻往往不是看不懂代码而是把整个工程拷到新电脑、打开Eclipse之后发现工程导不进来或者导进来了全是红叉编译时连system.h都找不到。这篇文章把这类问题掰开揉碎讲清楚——从Eclipse如何正确加载已有NIOS II工程到老工程移植后最常见的几个坑以及完整的排错思路。适合刚接手旧项目的FPGA工程师也适合被新工具链折腾得没脾气的维护型开发者。1. 加载工程前先搞清NIOS II工程的文件构成很多人习惯把工程文件夹直接拖进Eclipse的workspace目录然后发现项目浏览器里什么都没有或者提示“Invalid project description”。这不怪Eclipse而是NIOS II工程和纯手写的裸机工程不一样它有一套自己的工程描述文件体系少一个都认不出来。1.1 Eclipse识别工程的真实依据Eclipse判断一个目录是不是工程看的不是源码文件而是工程根目录下有没有.project和.cproject这两个文件。.project记录工程名称、构建器、依赖关系.cproject记录C/C的编译器设置、include路径、宏定义、Makefile生成方式。NIOS II的软件工程在Eclipse里本质是一个C/C工程只不过构建命令被定制成了nios2-elf-gcc那一套。所以当你只把源码文件夹拷过来没有这两个隐藏文件Eclipse会直接无视它。即使你把.project也拷过来了但.cproject里的路径还指向原来电脑上的某个绝对路径导入后同样编译不过。先认清这一点排查时就不会像个无头苍蝇一样到处乱点。1.2 .sopcinfo、BSP和app之间的绑定关系NIOS II工程里最重要的三个东西.sopcinfo、BSP工程、app工程。它们的关系可以类比成盖房子.sopcinfo是户型图。它是由Platform Designer老版本叫QSys自动导出的系统描述文件里面包含CPU型号、外设类型、每个外设的基地址、中断号、数据总线宽度等所有硬件信息。BSP工程是精装修。它根据.sopcinfo自动生成HAL驱动、系统头文件system.h、alt_types.h、链接脚本linker.ld以及各类外设驱动库。你代码里#include system.h用的就是它。app工程是家具布置。它包含你的业务代码、逻辑算法、应用层驱动编译时依赖BSP提供的头文件和库。这三个是强绑定关系。也就是说只有源代码文件而丢了.sopcinfo你没法徒手生成BSP就像没有户型图没法搞精装修。很多老工程移植失败根源就在这里——代码还在但系统和BSP的“血缘关系”断了。1.3 快速判断你的工程属于哪个时代NIOS II的软件工具链经历过两个阶段早期的Nios II IDE基于Eclipse 3.4/3.5常见于Quartus 9.x到12.x以及后来的Nios II SBT for EclipseSoftware Build Tools常见于Quartus 13.x之后主导航路径是Tools - Nios II Software Build Tools for Eclipse。判断方法很简单如果工程目录里有software目录里面还分出app和syslib两个子工程这是老IDE产物。如果工程目录里有.sopcinfo文件而且软件工程是分开的app_bsp和app两层这是SBT产物。如果连Eclipse工程文件都没有只有一个.qsys和一个Makefile那可能是别人手工写的构建脚本没有走标准工程流程。搞清楚自己拿到的是哪种工程决定了后续加载策略完全不同。老IDE工程不能直接原封不动导入新SBT必须做一个转换动作这个转换就是下一章的重头戏。2. 把已有工程正确加载进Eclipse的操作路径加载NIOS II工程正确姿势不是“打开”而是“导入”。先记住这个区别能帮你绕开一半的坑。2.1 用Import而不是直接拷贝工程目录无论工程在U盘里、同事发你的压缩包里还是git仓库里都不要把它直接解压到workspace目录。正确步骤是打开Nios II SBT for Eclipse从Quartus的Tools菜单进或者直接打开Eclipse后选择正确的workspace。点击菜单 File - Import - General - Existing Projects into Workspace。在Select root directory里选中工程所在目录或者在Select archive file里选中zip包。下方会列出识别到的工程勾选需要导入的项目点击Finish。这里有个关键选择是否勾选Copy projects into workspace。我的建议是如果工程原本就在git版本库里千万别勾保持原位引用如果是从压缩包导入可以勾上让Eclipse把工程拷贝到当前workspace统一管理。导入完成后项目浏览器里应该能看到工程图标。如果什么项目都没有先回第一章检查有没有.project文件。没有就说明这根本不是标准的Eclipse工程需要先做个转换封装。2.2 app工程与bsp工程结对恢复SBT时代的工程以“一个BSP 一个或多个app”为一组。导入之后最常见的状态是app和bsp各自都在但app右键Properties里的Nios II设置中BSP路径还是旧的指向某台已不存在的电脑上的绝对路径。遇到这种情况不要手动改代码直接在Eclipse里重新关联右键app工程 - Properties - Nios II Application。在BSP Settings或BSP Project一栏指定现有的bsp工程路径。如果app工程里找不到这个菜单说明这个app不是用SBT插件创建的普通工程需要新建一个SBT工程把源码放进去。如果只有app代码没有BSP需要自己创建一个。创建时SBT会要求你指定一个.sopcinfo然后选择BSP类型HAL、MicroC/OS-II等点Generate就算完成了。这一步等于把房子的户型图和精装修重新绑定起来。2.3 从老IDE工程手工迁移到SBT的完整流程拿到一个Quartus 11时代的老工程目录里是software/app和software/syslib里面还有.project但文件名格式和SBT的新版差别很大直接导入SBT十有八九会失败。正确做法是放弃老工程文件结构重建一个新的SBT工程用新版Quartus的Platform Designer打开老qsys文件重新Generate一次得到新的.sopcinfo。如果连qsys文件都没有那你只能在FPGA工程里找找有没有遗留的.sopcinfo副本或者从老Quartus里找到对应版本导出一份。用Nios II SBT的File - New - Nios II Application and BSP from Template创建一对新工程。选中新生成的.sopcinfo选择HAL作为BSP类型。把老syslib里手动改过的代码谨慎地合并到新BSP设置里但千万不要直接覆盖新生成的system.h。把老app里的业务源码那些.c、.h复制到新app工程里。重新编译逐项清理报错。这个流程为什么能解决大多数问题说到底老IDE生成的系统库工程和新SBT的BSP工程本质是同一个东西的不同形态但文件组织、Makefile模板、编译器版本完全不同。与其在旧结构上缝缝补补不如用新工具生成一份骨架再把真正的业务代码搬进去。3. 老工程换环境后最容易翻车的几类问题从工程能成功导入Eclipse到最终在目标板上跑起来中间还有很长一段路。下面几类问题是我在实际项目里反复踩过的每一个都足以让人卡上一整天。3.1 工具链版本跨度太大引发的连锁反应新版本Quartus带的Nios II编译器版本肯定比六年前的新。编译器升级带来的第一个麻烦是警告变多、报错变多这是正常的。比如老代码里常见的隐式函数声明老编译器睁一只眼闭一只眼新编译器直接报error。更隐蔽的是BSP内部生成的HAL库代码变化。HAL驱动在某些外设上改了函数实现加了参数甚至改了函数名。你会发现老工程里调用的一些alt_系列函数在新BSP里直接找不到定义。处理顺序很重要先保证BSP能用编译器版本编译通过再解决app代码。如果BSP本身是SBT新生成的它天然就是新的HAL版本这时候app代码里那些老写法就必须跟着改。改的时候不要凭记忆乱改建议直接打开新版system.h看外设名和地址宏打开HAL库源码看函数原型。3.2 老硬件描述文件与实际FPGA工程不匹配这类问题的典型表现是工程导入成功、BSP也生成了、编译也过了但下载到FPGA后外设读写全乱串口输出乱码或者程序直接跑飞。原因大概率是.sopcinfo和实际下载到FPGA里的.sof不匹配。.sopcinfo是从硬件设计导出的如果硬件工程后来改过外设地址、中断号但软核工程一直用的老的.sopcinfo生成的BSP那代码访问外设就是在内存映射错乱的空间里瞎跑。解决办法是在工程属性里确认当前使用的.sopcinfo是否和Quartus工程里的.qsys或.qpf/qsf里的约束一致。最好做成同一个版本控制库里同步更新的关系硬件改动后必须重新生成BSP。3.3 编码、路径与文件行尾混战老工程在Windows下开发源码注释可能是GBK编码。新装Eclipse默认UTF-8打开文件一堆乱码更严重的是编译时把注释里的字节流当成代码解析报各种莫名其妙的多字符错误。处理方式有三步在Eclipse的Window - Preferences - General - Workspace里把Text file encoding从UTF-8改成Other并选择GBK或者反过来根据源码实际编码来定。也可以对单个文件右键 - Properties - Resource - Text file encoding单独设置。如果工程里源码编码不统一建议用编辑器统一转成UTF-8避免后续在Linux构建环境或CI服务器上炸锅。路径问题同样坑人。工程目录不要放在带中文或空格的路径下Eclipse本身能忍但Nios II工具链里的GNU Make和一堆脚本经常忍不了。建议整个开发链都安在一个纯英文路径比如C:\work\project_nios。3.4 JTAG调试和下载阶段的老工程疑难编译过了、下载时却找不到处理器这是移植后极常见的一幕。这里要分清几个环节目标板FPGA里有没有配置.sof如果直接点Debug而没有先下载硬件配置Nios II处理器根本不存在调试器当然找不到。如果是USB-Blaster驱动问题Quartus的Programmer里会直接报Unable to find USB-Blaster。这时候去设备管理器里查驱动是否正常手动更新驱动到Quartus安装目录下的驱动路径。如果是.sof版本太老与BSP的.sopcinfo不匹配Debug时能连上JTAG但下载软件后PC指针会乱跳。这种问题重新下载最新的.sof就能解决。调试配置本身也可能有坑。右键app工程 - Debug As - Nios II Hardware弹窗里要确认ELF文件路径正确并且目标中已经用Programmer下好了.sof。有些人只改了工程名忘了改Debug Configuration里的ELF路径导致永远在调试一个旧二进制。4. 一次完整移植排错从编译失败到目标板跑通前面讲了一堆规则不如实际操作一次让你看明白。上个季度我就处理过一个典型的老NIOS II工程你遇到的情况大概率跟它类似。4.1 接到老工程后的第一眼观察工程是Quartus 13.0时代创建的目标器件是Cyclone III软件部分是一个带串口、定时器和自定义逻辑的HAL工程。换了新电脑装了Quartus Prime 18.1导入工程后项目浏览器是能看到工程但整个工程从app到底层bsp一片红叉。第一件事不是去改代码而是先看Problems视图里的报错列表。那次报错集中在三类找不到system.halt_main未定义一大堆关于外设寄存器宏的undefined reference4.2 逐层递进排查的真实日志第一层问题是找不到system.h。system.h是BSP生成的不在app源码目录里。打开app工程的Properties - C/C General - Paths and Symbols看include路径里指向的BSP路径是否还存在。结果发现那个路径指向原来同事电脑的C:\Users\oldman\workspace\app_bsp当然不存在。把BSP工程重新导入Eclipse后我选择不手动改路径而是直接右键bsp工程 - Nios II - Generate BSP Settings有的版本叫BSP Editor让它重新生成一次。这一步会强制BSP根据它关联的.sopcinfo刷新system.h和库文件。生成完成后include路径的报错消失了。第二层问题是alt_main未定义。这个报错的本质是程序入口设置与BSP的启动设置冲突。SBT的HAL启动文件默认先执行alt_main如果你代码里写的是标准main需要在BSP Settings里把--hal.enable_alt_mainfalse这样的选项确认一下不同版本写法略有差异但都在syslib的BSP Editor里能改。或者更保险的办法是直接检查BSP设置中关于stdout、stderr、stdin的device配置把入口点设为main。但那次真正的原因不是这个。老工程里所有的#include system.h都是自定义路径他们老代码里写的是#include inc/system.h而新BSP生成的头文件在BSP根目录。于是只要报错提示找不到alt_main其实是因为HAL的头文件根本没正确包含进来。把include路径改准确后alt_main的报错随之消失。第三层是外设寄存器宏的undefined reference。这个更麻烦因为老工程里有一批自定义IP核新Platform Designer重新生成硬件后IP核的CSR地址偏移定义变了。打开新system.h看那些MY_CUSTOM_IP_BASE宏发现地址确实和旧代码里硬编码的地址不一致。代码里不能直接用宏定义的地方全用的是#define MY_IP_BASE 0x00002000这种硬编码而新版硬件把它挪到了0x00003000。这几处硬编码我已经用system.h里的宏替换了重新编译报错清零。但光编译过不算移植成功还得继续验证。4.3 移植完成后的验证清单编译通过只是第一步后面的验证我按这个清单逐项打勾每项都要有实际观测证据验证项操作方式通过标准FPGA配置下载Quartus Programmer下载最新.sof下载成功目标板JTAG链正常软件下载Nios II Hardware Debug下载.elf能全速运行不跑飞串口通讯上位机观察串口输出日志格式正确无乱码定时器中断示波器或计数器观测中断频率中断周期与预期一致自定义外设读写通过调试窗口读写寄存器读回值与写入值一致掉电重启保持配置固化到EPCS/Flash后重新上电系统自动恢复不依赖JTAG那次验证过程中串口输出一度全是乱码。排查后不是代码问题而是波特率配置表在HAL新版本里默认值变了BSP设置里我需要找到UART的baud_rate选项重新改成115200。这里多说一句如果你也遇到乱码先分清楚是物理链路问题还是代码配置问题。把示波器接在TX引脚上看波形如果波形本身正常那就去查BSP里的uart配置如果波形都是乱的那就是FPGA逻辑或电平转换的问题不用在Eclipse里折腾。5. 移植结束后必须做的事工程卫生与版本管理工程跑通只是开始如果不想让下一个接手的人重蹈覆辙我强烈建议趁热打铁做好三件事。第一把工作区依赖的.sopcinfo、.qsys、Makefile、BSP设置文件全部纳入git仓库但把.metadata、Debug、release这些生成目录加进.gitignore。很多团队只提交源码结果换台机器连BSP都生成不出来。第二永远不要手动修改system.h。它每次重新生成都会被覆盖改了个寂寞还会误导下一个人。所有需要针对具体硬件调整的参数能走BSP设置就走BSP设置不能的写在app层自己的配置头文件里。第三在博客或项目文档里留下一份工具链版本对照表。不止记录Quartus版本和Eclipse版本还要记录Platform Designer的版本、nios2-elf-gcc的版本、以及BSP使用的HAL版本。老项目最怕的是“之前明明能跑”五个字版本对了问题就少了一大半。我一般在项目里建一个docs/toolchain.md内容非常简单列上主机的操作系统版本、Quartus安装版本、SDK补丁号、以及打开工程时用的workspace路径。花费十分钟能省下未来几十倍的时间。
阅读完成 · 觉得有帮助?
咨询建站