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分析为例。

分析要点:

  1. 看uboot的uboot.lds,可以知道代码如何分布。
  2. 看目录下生成的.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,再次启动,问题解决,功能正常!

历史命令也是可以切换了!这样验证了前面所说的“拷贝达到极限”的猜测。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值