NXP - 用MDK建立基于arm-none-eabi工具链的工程框架
文章目录
- NXP - 用MDK建立基于arm-none-eabi工具链的工程框架
- 概述
- 笔记
- 实验环境
- MDK4的版本
- 从小白开始模拟如何"用MDK建立基于arm-none-eabi工具链的工程框架"
- OS
- 安装arm-none-eabi工具链
- 插上实验板
- 新建工程
- 将工具链切到自己指定的arm-gcc
- 配置分散加载文件
- 试试单步调试
- 验证是否由于分散加载文件定义引起的问题
- 备注 - RDDI-DAP Error
- END
NXP - 用MDK建立基于arm-none-eabi工具链的工程框架
概述
想单步调试Smoothieware固件工程,如果用Smoothieware工程提供的方法,就得用MRI + GDB去调试。效率太低了,不想这么搞。
经过权衡和实验(gcc4-mbed 去掉MRI, mbed Studio, LPCXPress, MCU Xpresso, eclipseCPP, MDK)后,准备使用MDK(MDK4和MDK5都可)来建立一个基于arm-none-eabi工具链的工程框架,然后将Smoothieware移植过来。这样就能舒服高效的单步调试。
现在关于工程本身如何建立已经知道了,还有些其他的问题,后续再研究。已经知道问题在哪里了。
先记录一下,如何用MDK建立基于arm-none-eabi工具链的工程框架。
因为实验前期遇到一些编译错误问题,这里就模拟我还是小白,从头到尾来建立工程。如果遇到错误,再去改对应的编译选项。
最后让程序编译通过,0错误,0警告。然后再将遇到的不能单步调试的问题原因抛出,后续再解决。
笔记
“用MDK建立基于arm-none-eabi工具链的工程框架”这个问题是没有完整文档的,但是MDK提供了从默认ARMCLANG工具链切到arm-gcc工具链的UI选项,说明这一定是一个烂大街的问题,不难。
基于搜索引擎是找不到这个问题的解决方法的。
后来去github观摩大神们的作品, 看谁用了MDK工程,并且使用了arm-none-eabi工具链. 然后将工程迁出到本地,看看MDK参数配置,再自己建立工程,出现错误后,再比对大神们的正常工程,这就可以得出正确的结论了。如果一个大神的工程没有涉及到这个知识点,那就再找一个大神的工程看,我大概是找了10多个工程后,终于看到大神如何在MDK中用arm-gcc工具链干活的了 😛
其实,搜索资料也是需要经验的。"有事问百度"只适合小白程度的入门级同学,能用百度搜到的东西都是烂大街的入门级的知识点。
再细节一些的知识点,只要知道如何搜索资料,再加上自己实验,都是不难的。就怕找不到资料(连一个有效线索都没有)。
实验环境
MDK4和MDK5都是可以的。
因为本次要单步调试LPC1768/1769的Smoothieware的工程,MDK4本身就包含LPC17xx的MCU的库。那就先用MDK4来实验。
知道了正确流程后,用MDK5也是一样的,选项差别不大,只是UI选项显示的稍有不同。
现在就模拟一个小白来做实验(将遇到的问题和解决方法记录下来).
MDK4的版本
MDK4最后的版本是MDK474, ARM官方文档推荐用MDK460.
掌握方法后,用哪个版本都行。因为只要将参数配置对了,用哪个MDK版本都可以。
我就用MDK460来实验。
从小白开始模拟如何"用MDK建立基于arm-none-eabi工具链的工程框架"
OS
win10
安装arm-none-eabi工具链
用当前官方最新版的14.3.rel1
官方提供有安装版的,也有解压版的。
我这里选用的是官方编译好的解压版本。
安装/释放到自己的本地目录 D:\my-arm-gnu-toolchain\arm-gnu-toolchain
插上实验板
实验板只要是LPC1768/1769的MCU就行。
这里我采用OM11043(mbed-NXP-LPC1768)的官方板子,将板子用USB线连上开发机,开发机可以识别板子的CMSIS-DAP设备。
新建工程
手工建立工程目录 D:\my_tmp\uv4\case2
MCU选为LPC1768
MDK根据版本不同,可能会主动提供MCU编程相关的系统实现, 也可以不选择MDK提供的文件, 因为移植开源工程,东西都是全的,不需要MDK来提供。
这里为了演示报错场景,选择是.
将工具链切到自己指定的arm-gcc
MDK默认的工具链是ARMCLANG.
一旦切换了工具链,编译的参数都变了,需要重新核对参数。
尝试先模拟小白,先编译一下工程
这些报错,是说MDK默认提供的这个启动.s的语法是不对的。
因为默认提供的启动.s, 只适合于ARMCLANG的工具链。
此时,要将工程中的不合适的.s删除,添加arm-gcc版本的.s.
现在从Smoothieware工程,将.ld和.s拷贝过来。
对于ARMCLANG工具链,用的分散加载文件是.sct; 对于arm-gcc工具链,用的分散加载文件是.ld或者.lds. 语法是不一样的。
配置分散加载文件
尝试编译工程
现在出了一个很奇怪的报错,是说gcc编译时的参数’-W1’不对。
-Wl
参数是个链接时的参数,现在还没到链接阶段呢,报错好奇怪。
且这个参数无法通过UI选项去掉,一直存在。
后来通过比对github大神的工程,知道了,原来要勾选"产生map文件"才行。
默认的Listing是没有map文件的,需要勾选"产生map文件"
Listing产生的这些辅助文件,对于查看编译的过程, 对于优化程序是有帮助的,就全勾上。
再尝试编译,没有’-W1’报错了。
现在看到,有个SystemInit()没实现。去看.s
从.s看,这是用户要实现的一个函数,用来初始化硬件。正常的SystemInit函数要实现初始化时钟,gpio这些外设。
为了简单,就添加一个空函数。这个空函数要添加在自己的实现中。自己的实现可以是.c, 也可以是.cpp.
Smoothieware工程是一个C和C++混编的工程,这里我们就用.cpp.
在工程目录下,手工新建my_main.cpp, 添加空函数SystemInit(), 如下:
现在提示_start函数没定义,是在Reset_Handler中用到的。看看.s
_start函数,如果是在x86/x64的win程序中,还要做C运行时库的初始化,然后由_start函数调用main函数,才进入应用层的实现。
但是对于固件工程,Reset_Handler就相当于_start函数,SystemInit就相当于做了C运行时库的初始化,_start函数就相当于main函数。
看了大神的固件工程实现,验证了这个判断。
这时,可以将_start改为main, 然后实现自己的main就行。
但是考虑到不能改系统实现,所以在自己的my_main.cpp中,实现_start函数是个合适的选择。
现在程序就编译过了。
试试单步调试
单步调试见笔记(NXP - MDK460的调试设置)
现在出现调试报错,说0x417c的内存地址不能访问。
这有可能是.ld文件配置错误。
因为同一个硬件板子,用ARMCLANG工具链编译的工程是可以单步调试的。
2个固件工程(一个是MDK默认的ARMCLANG工具链的正常工程,一个是arm-gcc工具链的不正常工程,在配置没问题的基础上,大概率的区别就是分散加载文件的区别)
验证是否由于分散加载文件定义引起的问题
先看一下好的.sct生成的map, 再看一下.ld生成的map.
在比较.sct内容和.ld的内容,排除语法上的区别,看看定义的内存访问地址和访问权限是否一致。
大概率是.ld文件引起的问题。
因为Smoothieware的原始工程,并不是一个从头跑到尾的正常工程。而是由bootloader程序升级的程序。
程序入口地址, Reset例程的地址,中断函数表的地址和正常的固件工程是不一样的。
这个实验还在进行中,后续笔记中会记录。
备注 - RDDI-DAP Error
如果调试器硬件或者配置有问题(包括但是不限于, 没连接调试器,调试器没上电,SWD引脚接触不好, SWD时钟选的太高了),会在单步调试链接时,看到"RDDI-DAP Error"的提示。
如果本来是SWD方式联机的调试器(e.g. 板载的LPC-LINK), 却选成了JTAG连接方式,在参数选项对话框中就能看到"RDDI-DAP Error"的提示。