项目中使用Hi3556AV100_MobileCam_SDK_V2.0.1.1进行开发,按照其中《HiMobileCam SDK安装使用说明》的指导一步步进行配置、编译,之后将编译出来的u-boot-hi3519av100.bin通过HiTool中的Hiburn工具进行烧录,如下图所示:
正常来说,烧录结束会出现uboot烧录成功的提示,而且通过串口能够看到uboot正常运行了,如下所示:
##########################################################################################
串口已经连接,请给单板上电,若已经上电,请断电后重新上电。
############################### ---- 10%
############################## ---- 20%
############################## ---- 30%
############################## ---- 41%
############################## ---- 51%
############################## ---- 61%
############################## ---- 71%
############################## ---- 81%
############################## ---- 92%
####################### ---- 100%
Boot download completed!
System startup
Uncompress Ok!
U-Boot 2016.11 (Jul 07 2020 - 09:26:34 +0800)hi3519av100
Relocation Offset is: 3f72b000
Relocating to 5ff2b000, new gd at 5fe8aef0, sp at 5fe8aed0
MMC: ** First descriptor is NOT a primary desc on 0:1 **
MMC/SD Card:
MID: 0x15
Read Block: 512 Bytes
Write Block: 512 Bytes
Chip Size: 7456M Bytes (High Capacity)
Name: "8GTF4"
Chip Type: MMC
Version: 5.1
Speed: 200000000Hz
Bus Width: 8bit
Mode: HS400ES
hisi-sdhci: 0 (eMMC)
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
boot_media emmc!
Net: gmac0
Error: gmac0 address not set.
start download process.
Boot started successfully!
Send command: mmc write 0x0 0x21000000 0x0 0x20a
MMC write: dev # 0, block # 0, count 522 ... 522 blocks written: OK
[EOT](OK)
Fastboot burnt successfully!
Send command: reset
reset success!
##########################################################################################
笔者之前也编译过很多海思系列芯片的SDK,Hi3518EV200、Hi3519V101、Hi3559AV100和Hi3519AV100,都成功了,没有在这一步遇到过问题。但是这一次不同,第一次在这个阶段遇到问题。前边都还正常,但是到
System startup
Uncompress Ok!
U-Boot 2016.11 (Jul 07 2020 - 09:26:34 +0800)hi3519av100
之后就不再有打印了,过看了一段时间控制台出现以下提示:
##############################################################
等待boot启动超时,单板上无fastboot或当前fastboot无法启动。
Failed to download fastboot!
##############################################################
同时,软件弹出如下图所示对话框:
为什么会出现以上错误?为什么之前那么多次编译烧录都没有问题,偏偏这次有问题?为什么只是简单烧录uboot都会有问题?网上搜索解决方案,看看其他人有没有遇到过,结果都是说需要自行跟踪调试uboot代码,看问题出在哪里。看来没有捷径,只能踏踏实实地研究uboot源码。
在uboot源码路径(osdrv/opensource/uboot/u-boot-2016.11/)下搜索关键字"Uncompress ",得到十几个结果,十里挑一,我们需要的代码在u-boot-2016.11/arch/arm/cpu/armv7/hi3519av100/hw_compressed/startup.c中,void start_armboot(void)函数中,第81行uart_early_puts("\r\nUncompress ");打印出的"Uncompress ",第103行uart_early_puts("Ok!");打印出的“OK”。既然到这里还能正常运行,那么在接下来的几个地方加打印,看看到哪不能出现要打印的内容,则其上边一段就是程序出错的地方。
跟踪发现,问题出现在了startup.c的114行,start_armboot函数的uboot();在其之下的打印没有出现。uboot函数的定义在哪里?又是实现什么功能?其实uboot的定义就在上边2行,void (*uboot)(void);和uboot = (void (*))CONFIG_SYS_TEXT_BASE;。可以看到,uboot是一个函数指针,指向了CONFIG_SYS_TEXT_BASE,也就是说执行uboot();时实际是在执行地址为CONFIG_SYS_TEXT_BASE的代码。CONFIG_SYS_TEXT_BASE又在哪里赋值?在osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3519av100.h中,37行:#define CONFIG_SYS_TEXT_BASE 0x20800000。看到这里,似乎也没发现有什么不正常的,似乎走进了死胡同。
没办法,只能求助于供应商,请他们对于这个问题给予一定支持。他们也是第一次遇到这种问题,而且只能提供远程支持,所以也说不好问题出在了哪里。好在他们手边有一套之前可以正常编译并且烧录的SDK,给我们发了过来,让我们基于这个SDK进行对比,找找不同的地方。拿到他们的SDK后,用SDK中已经编译好的u-boot-hi3519av100.bin进行烧录,发现这次可以正常烧录,没有问题。于是基于这个SDK进行编译,运行make osdrv命令,之后不用等待全部编译完,只要能编译出uboot就可以了。用新编译出来的u-boot-hi3519av100.bin进行烧录,结果仍然出现了上边的错误。为什么?究竟是哪里出现了问题?
这里用一个小技巧。将供应商发过来的SDK解压,将其中uboot源码文件夹作为文件夹比较的左侧,把经过make osdrv编译后的供应商的SDK中的uboot源码文件夹作为文件夹比较的右侧,通过Beyond Compare工具进行比较。结果发现,绝大多数的文件都相同,包括之前怀疑的.config文件等,但是唯独有一个文件,有2处不同,这个文件正是我们刚才跟踪到的osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3519av100.h。
hi3519av100.h中的这两处不同分别是:
43行的
#define PHYS_SDRAM_1_SIZE 0x40000000 正确
#define PHYS_SDRAM_1_SIZE 0 错误
和
185行的
#define CFG_BOOT_PARAMS (0x25800000 - 0x100) 正确
#define CFG_BOOT_PARAMS (0 - 0x100) 错误
为什么PHYS_SDRAM_1_SIZE会改变?哪里使其改变了?
有两种情况可以使hi3519av100.h的内容在编译时发生改变:1.在某个位置有另一个hi3519av100.h,编译过程中用它覆盖了这个hi3519av100.h;2.某个脚本直接通过关键字修改了hi3519av100.h中的这2个值。对于第一种情况,在整个SDK路径下进行了搜索,只找到了这一处,也就是说第一种情况被排除了。那么只可能是第二种情况,某个脚本修改的。哪个脚本文件?怎么修改的?
在uboot路径下搜索,不,应该是在SDK根目录下搜索PHYS_SDRAM_1_SIZE,在osdrv/osdrv_mem_cfg.sh中第56行:UBOOT_CFG_DDR_SIZE_NEW="#define PHYS_SDRAM_1_SIZE $UBOOT_CFG_DDR_SIZE",
而这个UBOOT_CFG_DDR_SIZE_NEW又在下边用到,第87行:
sed -i "s/$UBOOT_CFG_DDR_SIZE_MATCH/$UBOOT_CFG_DDR_SIZE_NEW/g" ./opensource/uboot/u-boot-2016.11/include/configs/${CHIP}.h
这句话的意思是将./opensource/uboot/u-boot-2016.11/include/configs/${CHIP}.h中的$UBOOT_CFG_DDR_SIZE_MATCH替换为$UBOOT_CFG_DDR_SIZE_NEW。其中:UBOOT_CFG_DDR_SIZE_MATCH在本文件中60行定义:UBOOT_CFG_DDR_SIZE_MATCH="#define.*PHYS_SDRAM_1_SIZE.*$";
UBOOT_CFG_DDR_SIZE_NEW见上边;
而CHIP则是经由.config中的CONFIG_HI3519AV100=y,build/kconfig.mak中的CFG_SUBCHIP_TYPE := hi3519av100,base_hi3536av100.mak中的OSDRV_COMPILE_OPT := CHIP=$(CFG_SUBCHIP_TYPE) BOOT_MEDIA=$(BOOT_MEDIA) OSDRV_CROSS=$(LINUX_CROSS)以及Makefile中的@make OSDRV_CROSS=$(OSDRV_CROSS) $(OSDRV_COMPILE_OPT) all -C $(OSDRV_ROOT)||exit $?传入到osdrv/Makefile的,再由Makefile中的./osdrv_mem_cfg.sh uboot $(CHIP)传入到osdrv_mem_cfg.sh 中来。osdrv_mem_cfg.sh的第14行:CHIP=$2,对应前一句,而$2就是$(CHIP),即CFG_SUBCHIP_TYPE,也即hi3519av100。
因此sed -i "s/$UBOOT_CFG_DDR_SIZE_MATCH/$UBOOT_CFG_DDR_SIZE_NEW/g" ./opensource/uboot/u-boot-2016.11/include/configs/${CHIP}.h这句话的意思是将./opensource/uboot/u-boot-2016.11/include/configs/hi3519av100.h中的包含
"#define.*PHYS_SDRAM_1_SIZE.*$"的行替换为 #define PHYS_SDRAM_1_SIZE $UBOOT_CFG_DDR_SIZE。
搞清楚了这一段,接下来看UBOOT_CFG_DDR_SIZE。这个UBOOT_CFG_DDR_SIZE又是从何而来?值是多少?
UBOOT_CFG_DDR_SIZE在本文件中定义,22行:UBOOT_CFG_DDR_SIZE=0。这就奇怪了,为什么会是0?对比原SDK中的这个文件,值为UBOOT_CFG_DDR_SIZE=0x40000000。为什么会这样?
在SDK根目录下搜索UBOOT_CFG_DDR_SIZE,在build/config_memory_hi3556av100.sh中第52行有这样一句:sed -i "s/^UBOOT_CFG_DDR_SIZE=.*0x.*$/UBOOT_CFG_DDR_SIZE=${CONFIG_MEM_DDR_SIZE}/g" ${1}。结合上边的说明,
这句话的意思是在osdrv/osdrv_mem_cfg.sh中找到“UBOOT_CFG_DDR_SIZE=.*0x.*”的行,之后将其替换为UBOOT_CFG_DDR_SIZE=${CONFIG_MEM_DDR_SIZE}。那么CONFIG_MEM_DDR_SIZE又是在哪里赋值?
其实CONFIG_MEM_DDR_SIZE就在上边赋的值,47行:CONFIG_MEM_DDR_SIZE=$(awk 'BEGIN{printf("%#x",'$CONFIG_MEM_TOTAL_SIZE'*0x100000)}')。CONFIG_MEM_TOTAL_SIZE在.config中赋值,为1024。按照道理来说,这句话执行结果应该是CONFIG_MEM_DDR_SIZE=1024*0x100000,即1024M,这才对,但实际上这条语句的执行结果为0。这就奇怪了,为什么会这样?难道是海思SDK中本身存在错误?为什么供应商的SDK可以成功编译?
经过一番原因探究,最终找到了问题的根源:ubuntu下自带的awk无法解析包含“0x”字样的内容,因此执行结果为0。如果想要解析,必须通过sudo apt-get install gawk,通过gawk才可以解析。实际上不怪海思,人家在《HiMobileCam SDK安装使用说明》“2开发环境搭建” “2.2.3 软件包安装” 步骤2中已经明确说了需要安装gawk,我们之前没有照做,这时候就得到教训了。不过这样也好,本事只有在遇到问题的时候才长得快。
解决了这个问题,CONFIG_MEM_DDR_SIZE正确了,但是make osdrv编译的时候发现UBOOT_CFG_DDR_SIZE还是为0。而且不光是UBOOT_CFG_DDR_SIZE,UBOOT_TEXT_BASE,LITEOS_DDR_MEM_SIZE也都为0,而供应商原SDK中的这几个值不是0,分别为0x25800000,0x40000000,0x40000000。这又是哪里出的问题?
其实引起这个问题的地方上边已经看到了,sed -i "s/^UBOOT_CFG_DDR_SIZE=.*0x.*$/UBOOT_CFG_DDR_SIZE=${CONFIG_MEM_DDR_SIZE}/g" ${1}。
参见上边说明,这句话的意思是查找osdrv/osdrv_mem_cfg.sh中包含“UBOOT_CFG_DDR_SIZE=.*0x.*”的行,但是由于之前没有下载gawk,因此实际osdrv_mem_cfg.sh中相应的行是UBOOT_CFG_DDR_SIZE=0,即没有0x,因此上边sed语句的执行结果就为0。当然,不止这一处,上边提到的3处都是一个道理。这属于海思代码不够健壮了,确实如果是正常编译,最终解析出来的内容没有问题,但一旦出现异常,比如出现了0而非0x,应该也能正确解析才是。不过可能有点吹毛求疵了吧,呵呵。
至此,错误都已经找到原因并解决了。再次编译,这次生成的u-boot-hi3519av100.bin再通过Hiburn烧录就正常而不会出现之前的错误了。