XR872 移植 u-boot-v2021.07
背景说明
去年下半年时间较多,每天下班了总得找点事干,之后偶尔看到XR872这款芯片,感觉可玩性还比较高,蓝牙WIFI、PSRAM、CSI编解码应有尽有,本着玩一玩的心态,计划是要将最新的uboot和linux移植上去的(据说uClinux已经融入linux主线,支持NOMMU了,所以也想验证一下)。但是后来由于干其他的事去了,uboot的移植已经搁浅差不多半年了,所以现在把我移植的代码分享出来,给后边喜欢折腾的朋友提供一个参考。
目前移植的u-boot已经可以入命令行,启动后开发板指示灯亮起,可正常使用loadx和go命令跑裸板程序了。
这是之前发的几篇文章,为本篇做铺垫:
XR872 打包自定义镜像与烧录https://blog.csdn.net/qq_28824733/article/details/124436295XR872 官方bootloader程序分析https://blog.csdn.net/qq_28824733/article/details/124436820XR872 自打包的镜像烧录出现Verify boot error解决办法https://blog.csdn.net/qq_28824733/article/details/124438272
环境说明
编译系统:Ubuntu
uboot蓝本:u-boot-v2021.07.tar.gz
交叉工具链:gcc-arm-none-eabi-10.3-2021.07-x86_64-linux.tar.bz2
我的代码仓库:https://gitee.com/huxiangjs/u-boot-v2021.07
测试开发板:
编译步骤
(1)克隆工程源码
git clone https://gitee.com/huxiangjs/u-boot-v2021.07.git
(2)编译命令
cd u-boot-v2021.07
make xr872_defconfig O=../build_xr872
make CROSS_COMPILE=../../arm-gcc/gcc-arm-none-eabi-10.3-2021.07/bin/arm-none-eabi- ARCH=arm O=../build_xr872
(3)制作烧录镜像
./mkimage
关于这个工具的说明请看我之前发表的铺垫文章,目前我的image.cfg文件内容为:
{"magic" : "AWIH","version" : "0.4","OTA" : {"addr": "1024K", "size": "4K"},"image" : {"max_size": "1020K"},"count" : 1,"section" :[{"id": "0xa5ff5a00", "bin": "../build_xr872/u-boot.bin", "cert": "null", "flash_offs": "0K", "sram_offs": "0x00200000", "ep": "0x002003fc", "attr": "0x1"},{}]
}
如上步骤是正确的,最终会得到xr_system.img文件,烧录到开发板即可。
UBOOT实际测试
(1)启动之后
(2)help命令
(3)loadx命令(传入了一个uart裸板测试程序)
(4)go命令
程序已经正常跑起来了。
后面附上调试的一些记录,如有错误请指出,3Q
UBOOT分析及调试记录
首先分析UBOOT, 以stm32f429分析为例。
分析要点:
- 看uboot的uboot.lds,可以知道代码如何分布。
- 看目录下生成的.o文件,可以知道哪些源码被编译过。
先用stm32的默认配置编译一下(生成.o文件):
make stm32f429-discovery_defconfig
make menuconfig
make CROSS_COMPILE=../gcc-arm-none-eabi-10.3-2021.07/bin/arm-none-eabi- ARCH=arm
或者指定目录:
make stm32f429-discovery_defconfig O=../build
make menuconfig O=../build
make CROSS_COMPILE=../../arm-gcc/gcc-arm-none-eabi-10.3-2021.07/bin/arm-none-eabi- ARCH=arm O=../build -j8
uboot.lds中得到代码组织顺序:
搜索这个字段在哪儿:
u-boot-v2021.07/arch/arm$ grep -rn vectors
找到结果(带m的,因为是Cortex-M系列,而且目录下有vectors_m.o表示编译过):
内容如下:
分析下一块,也就是start.o的源码start.S,文件再u-boot-v2021.07/arch/arm/cpu/armv7m/start.S,其中reset这个就是在上边中断向量表中指定的。
查找这个_main在哪里:
u-boot-v2021.07/arch/arm$ grep -rn _main
找到:
分析crt0.S文件,crt为C runtime environment的缩写,也就是c运行环境。看看_main处的入口代码:
寻找board_init_f函数:
u-boot-v2021.07/common$ grep -rn board_init_f
发现:
分析这个函数内容:
也就是把这个函数指针数组里的代码都调用一遍:
顺着代码,开始移植。首先建立配置文件:
接接下来就要编写这个文件了,要知道如何写,就要分析Makefile函数,首先看uboot根目录下的Makefile文件,看看我们传进去的ARCH=arm参数干嘛用了:
所以重点就在arch/arm/Makefile下,分析一下这个文件。
所以在目录下新建xr872:
xr872_defconfig中增加:
重新defconfig,提示代码段地址无效:
那就设置一个,这个地址不一定对,后边根据需要调整:
至此,defconfig已经没有问题了,但是编译会有问题。
编译提示的错误:
代码如下:
检查.config,发现CONFIG_ARM64被默认打开了:
好吧,看来是有地方还需要增加。首先对Kconfig增加芯片选项吧,加入:
这里可以通过select CPU_V7M来选择指令集,所以可以把xr872_defconfig中的那一行去掉了。此时不出意外,menuconfig中就可以找到这个选项了:
此时再检查生成的.config文件中,CONFIG_ARM64已经没有了。
再次编译,报错:
查看这个文件(注意这个是在指定的编译目录下):
发现在这个目录有很多config文件:
依葫芦画瓢,建一个我们的config文件:touch xr872.h,编译一下,还是有问题,那说明不是这个问题,那就借鉴一下stm32的看看:
原来,板级文件夹还没有创建呢。但是这个路径CONFIG_BOARDDIR是如何确定的呢,看看构建的文件:
参考stm32,原来在这而定义的:
它被这个文件包含:
而这个文件又被这个文件包含:
所以最终还是被mach-*下的Kconfig文件控制着。那就继续画瓢,创建这些内容。
而mach-*下的Kconfig文件是在arm文件夹下的Kconfig中包含。
arm文件夹则就是我们make时候ARCH=arm所指定的,所以层层控制。
依葫芦画瓢完,再次编译,之前的问题已经没有了,这时候应该制作Makefile文件了:
提示板级Makefile错误:
直接上面的Makefile拷贝一个即可。
新问题:
依葫芦画瓢添加(这个地址后续调整,目前只要求编译通过):
如下问题,也这么解决,可以参考其它芯片的配置。
再次编译,还有错,是因为我们还没有创建源文件呢:
添加(文件内容置空就OK):
再次编译,编译阶段已经没有问题了,链接出错,因为有些函数还没有实现:
研究代码,发现如果要调用print_cpuinfo是需要打开CONFIG_DISPLAY_CPUINFO宏的,默认是打开,所以我们关闭它:
解决dram_init未实现,首先看出错的地方:
发现没有宏来控制,那就实现一下这个函数把:
文件头很漂亮,因为是VScode自动生成的。
board_init问题,看源码:
要使这些宏都为0才可以保证不调用这个函数,但是这个CONFIG_ARM肯定是需要被配置的,所以就实现这个函数吧:
cread_line问题,看源码:
默认是打开的:
那就关掉它(后续需要时打开):
接下来就到了串口问题:
那就实现一下这个函数(内容以后再实现):
接下来就是滴答时钟的问题:
实现一下这个函数:
编译成功:
之后加入led函数:
加进init_sequence_f中:
led此时已经可以点亮了,说明程序可以运行到这里面了。
把led_on移动到init_sequence_f尾部,发现不能点亮,那说明这中间有函数出问题了。
测试发现是在serial_init中卡死的,这个是因为之前那个default_serial_console函数中,直接返回了个NULL指针,估计这个函数是被serial_init调用了,所以出错,看代码,果然:
好吧,那就先把串口实现了!
实现完后,串口已经有输出了,但是肯定卡在哪个地方了:
通过led的指示,发现在这个函数卡死了:
看来是重定位代码出问题了,先把debug打开:
再次启动,有很多调试信息输出了:
分析上面的log,明显可以看出来有些地址是不对的:
新栈指针都设置错了,那肯定有问题:
好,那就分析一下看看代码是如何重定位relocation代码的:
预留的空间直接是从栈空间里减掉。
上面代码中,r9原先保存了gd所在的地址,之后做了一个操作,把r9切换到了new_gd所在位置。下边来分析一下relocate_code是如何实现的:
那么现在可以得出如下结论:
(1)保证gd->new_gd ->reloc_off等于0,这样返回地址就是目前here的地方。
(2)保证gd->new_gd ->relocaddr等于__image_copy_start。
确保这俩个条件无误,应该就可以跳过代码重定向了。
看看gd->new_gd是如何被设置的:
通过如上分析,可以知道,只要把ram_base设置为适当的位置,就可以跳过代码重定向,但是,为啥要gd->relocaddr = gd->ram_top呢?往后看就知道:
那么新分配的new_gd又是如何初始化的呢:
综合上述,可以知道只需要做gd->ram_base和gd->ram_size的初始化,uboot就可以正常跑起来,那就再dram_init中做吧:
果然跑起来的,进入可控制台,把DEBUG关掉后效果如下:
目前串口的输入还没实现,看一下这几个函数的功能:
顺着代码跳转,看看uboot的读取机制:
实现后效果:
发现控制台不好看,=>符合前少了些什么,同分析发现可通过如下来定义:
效果如下:
另外发现按上下键没有出现命令历史记录,这是由于前面在defconfig中把CONFIG_CMDLINE_EDITING关闭掉了,而这个宏控制了这个功能:
那就删除掉这一句:
# CONFIG_CMDLINE_EDITING is not set
再次编译, 发现卡死了,那这个问题暂时不解决吧,毕竟RAM有限:
目前loadx命令还不能用,卡在第一个C位置:
分析代码,发现每次接受超时会有个延时操作:
而可以看到这个延时和滴答时钟有关系:
之后发现了我们之前实现的一个函数,这个函数直接返回了0,这是一个滴答时钟与微秒的比例系数:
而滴答时钟的初始化在这里:
用命令看一看,发现滴答时钟没有运行:
经过研究发现,uboot在进入loadx后会每隔一段时间发送一个C字符,电脑在收到这个C字符后开始传输数据,目前就是卡在第一个C字符,后面就不会有C字符输出,原因在这里:
看一看get_timer的代码:
看看这个timer_read_counter函数:
所以实现一下试试:
这个时候C可以一个一个出现,传输数据也没有问题了:
当然这只是个实验,还是要想办法把滴答时钟打开!
接下来要启用滴答时钟:
经过研究发现,armv7m/systick-timer.c受一个宏控制:
所以在xr872_defconfig中可以把这个宏设置为y,再次编译,发现还以没有编译systick-timer.c这个文件,之后通过menuconfig发现它还依赖ARM64或者ARMV7A,之后我在把ARMV7A也值为y,发现也没有编译这个问题。(连.config中都没出现CONFIG_SYS_ARCH_TIMER这个宏)。
所以直接粗暴简单:
还发现一个问题是,之前在xr872_defconfig中配置的CONFIG_TIMER=y,也没有在.config文件中找到,所以属于无效配置,在menuconfig中看看,发现确实有依赖:
依赖DM,所以暂时不处理,直接CONFIG_TIMER=y也注释掉。
再次编译,发现提示get_tbclk多重定义,这时候回到soc.c中,去掉我们之前加的那个get_tbclk函数,再次编译,成功。
启动uboot是没有问题的,但是使用loadx就直接挂了:
经过调试,发现问题,原因是因为0除以0出现问题。这个get_ticks()获取到的值为0,而gd->arch.timer_rate_hz也为0
这里应该要根据手册,把滴答时钟的时钟源打开,手册上已经找到了。滴答时钟源有俩种,低速和高速,当使用高速时钟,也就是cpu的时钟,这时候就不需要配置其它寄存器了,因为这个时钟直接从cpu引过来了,所以这里不再配置其它寄存器,直接使用cpu时钟了。
指定CPU频率:
之后loadx就已经可以使用了。
优化一下直接简单粗暴, 修改Kconfig:
恢复原状:
再次编译,OK
==============
实现历史命令选择:
设置CONFIG_CMDLINE_EDITING=y
发现启动后卡死,现在log.h中把DEBUG打开
发现只要调用mem_malloc_init就卡死,通过直接读取mem_malloc_init所在地址的数据发现,这个函数的代码竟然没被拷贝过去,难道是拷贝达到极限了?待后续确定
需要缩减u-boot.bin的尺寸,首先,分析每一个built-in.o文件大小,
发现网络占了比较大的空间,所以首先关掉网络:
重新编译后,xr_system.img大小从107KB减少到了85.3 KB
这时候再开启CONFIG_CMDLINE_EDITING=y
编译后的xr_system.img大小为:86.8 KB,再次启动,问题解决,功能正常!
历史命令也是可以切换了!这样验证了前面所说的“拷贝达到极限”的猜测。
XR872 移植 u-boot-v2021.07相关推荐
- 电脑公司win11旗舰版32位镜像v2021.07
电脑公司win11旗舰版32位镜像v2021.07是一款非常好用的电脑操作系统,系统中的功能较为全面,且充满了独具的特色,让你可以快速的将系统完成安装,而且不用激活,安装完成就能立即使用,大大节省用户 ...
- 系统之家win11旗舰版32位镜像v2021.07
系统之家win11旗舰版32位镜像v2021.07是一款非常好用的电脑操作系统,系统中的功能较为全面,且充满了独具的特色,让你可以快速的将系统完成安装,而且不用激活,安装完成就能立即使用,大大节省用户 ...
- 深度技术win11 32位全新专业版系统v2021.07
深度技术win11 32位全新专业版系统v2021.07是一款有着多种安装方式可供用户们选择的装机系统,系统优化清理,空间纯使用,无任何垃圾,优化系统运行环境,不影响稳定性,自动安装最新官方驱动,充分 ...
- 番茄花园win11 32位专业版镜像系统v2021.07
番茄花园win11 32位专业版镜像系统v2021.07是一款有着多种安装方式可供用户们选择的装机系统,系统优化清理,空间纯使用,无任何垃圾,优化系统运行环境,不影响稳定性,自动安装最新官方驱动,充分 ...
- 中关村windows11 32位专业版镜像v2021.07
中关村windows11 32位专业版镜像v2021.07是一款精心设计过的优秀装机系统,支持多种安装方式,系统中的服务项.注册表等,都是经过全面优化,能够很好的兼容各种功能,系统能够专业化的匹配专业 ...
- 新萝卜家园win11全新专业版64位系统v2021.07
新萝卜家园win11全新专业版64位系统v2021.07是一款专为游戏玩家准备的电脑操作系统,所需的运行文件也完全集成,实现软件安装运行更加稳定可靠.全新独创系统安装方式.同时应用商店也有了改进优化, ...
- 番茄花园win11专业版32位系统v2021.07
番茄花园win11专业版32位系统v2021.07是一款非常好用的操作系统,这款系统在稳定性上进一步优化和提升,可以更好的获得整个纯版系统的稳定性,,能够很好的兼容各种功能,系统能够专业化的匹配专业的 ...
- 电脑公司win11 64位旗舰版镜像文件v2021.07
电脑公司win11 64位旗舰版镜像文件v2021.07是目前非常受欢迎的电脑操作系统,系统中的功能十分的强大,能够智能判断出电脑的型号,然后为广大用户们安装相对应的驱动程序等,可以满足广大用户的所有 ...
- 技术员联盟win11旗舰版64位镜像v2021.07
技术员联盟win11旗舰版64位镜像v2021.07是微软最新推出的电脑操作系统,这款系统带来全新的功能,如任务栏居中,右键刷新等等,采用最实用.最纯粹的系统,轻松满足用户多样化的系统服务需求,用户可 ...
- 深度技术win11旗舰稳定版v2021.07
深度技术win11旗舰稳定版v2021.07是微软最新推出的电脑操作系统,这款系统带来全新的功能,如任务栏居中,右键刷新等等,采用最实用.最纯粹的系统,轻松满足用户多样化的系统服务需求,用户可以在本站 ...
最新文章
- 独家 | 如何跳出编程这个坑
- js 获取图片url的Blob值并预览
- python对象编程例子-python面向对象编程:python类和实例讲解
- MySQL 清理slowlog方法
- Leetcode 207. 课程表 解题思路及C++实现
- mybatis清除一级缓存的几种方法
- notepad++的好用快捷键整理
- 【AI-1000问】为什么LeNet5倒数第二个全连接层维度为84?
- 不吹不黑,赞一下应用运维管理的cassacdra
- SPI的4种工作模式(备忘)
- thinkphp-查询某一列的值column
- spring加载xml配置文件
- CPU漏洞可导致RSA被攻击
- js日期函数表达天,时,分,秒
- Mac python3连接mysql
- c语言void swap1,C语言的一些遗留问题(1):关于交换两个数的swap()函数的一些问题...
- 你应该知道的,十二大CNN算法
- BGP——基本概念3(路由聚合)
- 计算机一直显示配置更新失败怎么办,电脑更新新系统的时候出现配置更新失败问题怎么办...
- Python爬虫实例(2)-用BeautifulSoup爬取一个网页上的多张照片(以百度贴吧为例)