全面认识海思SDK及嵌入式层开发(3)

一、编译osdrv

1、编译策略和方法研究

(1)整体编译,遇到问题解决问题。

我们展示下上篇文章最后编译的结果:
在这里插入图片描述
找不到mkimage,无法制作U-Boot images,我们进入uboot源码目录:发现已经有了uboot.bin,但是由于找不到mkimage所以未生成U-Boot images

1、为什么要用U-boot的mkimage工具处理内核映像zImage?
   因为在用bootm命令引导内核的时候,bootm需要读取一个64字节的文件头,来获取这个内
核映象所针对的CPU体系结构、OS、加载到内存中的位置、在内存中入口点的位置以及映象名等
等信息。这样bootm才能为OS设置好启动环境,并跳入内核映象的入口点。而mkimage就是添加
这个文件头的专用工具

在这里插入图片描述

cd tools
ls
sudo cp mkimage /usr/local/bin/#放到该目录下,使得这个mkimage可以被找到

在这里插入图片描述

#回到osdrv目录,接着去make整体编译osdrv
make OSDRV_CROSS=arm-hisiv300-linux CHIP=hi3518ev200 all

在这里插入图片描述
这次uboot就编译成功了,紧接着又开始编译内核了。但你会发现再次编译是在 清除掉原来编译痕迹 的基础上,重新开始编译,这样就比较耗费时间了,我们可以选择部分编译,只编译我们需要的,以此节约时间。
在这里插入图片描述
最终编译并没有完全成功,编译mkfs.jffs2出错了,不过这不影响我们当前的操作,这个问题我们之后会解决。编译完的image,rootfs等存放在osdrv/pub目录下。
在这里插入图片描述
uboot、内核已经编译好了,并且通过busybox得到了根文件系统的雏形,linuxrc也有了。
(2)部分编译,需要哪部分单独编译哪部分。

(1)单独编译kernel:
	待进入内核源代码目录后,执行以下操作
	cp arch/arm/configs/hi3516cv200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev201_full_defconfig  .config
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- menuconfig
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- uImage
	或者
	cp arch/arm/configs/hi3516cv200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev201_full_defconfig  .config
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux- menuconfig
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux- uImage

(2)单独编译模块:
	待进入内核源代码目录后,执行以下操作
	cp arch/arm/configs/hi3516cv200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev201_full_defconfig  .config
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- menuconfig
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- modules
	或者
	cp arch/arm/configs/hi3516cv200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev200_full_defconfig  .config
	cp arch/arm/configs/hi3518ev201_full_defconfig  .config
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux- menuconfig
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux- modulesa

(3)单独编译uboot:
	待进入boot源代码目录后,执行以下操作
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- hi3516cv200_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- hi3518ev200_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- hi3518ev201_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux-
	将生成的u-boot.bin 复制到osdrv/tools/pc/uboot_tools/目录下
	运行./mkboot.sh reg_info.bin u-boot-ok.bin
	生成的u-boot-ok.bin即为可用的u-boot镜像
	或者
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux-  hi3516cv200_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux-  hi3518ev200_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux-  hi3518ev201_config 
	make ARCH=arm CROSS_COMPILE=arm-hisiv400-linux-
	将生成的u-boot.bin 复制到osdrv/tools/pc/uboot_tools/目录下
	运行./mkboot.sh reg_info.bin u-boot-ok.bin
	生成的u-boot-ok.bin即为可用的u-boot镜像
(3)制作文件系统镜像:
在osdrv/pub/中有已经编译好的文件系统,因此无需再重复编译文件系统,只需要根据单板上flash的规格型号制作文件系统镜像即可。

	spi flash使用jffs2格式的镜像,制作jffs2镜像时,需要用到spi flash的块大小。这些信息会在uboot启动时会打印出来。建议使用时先直接运行mkfs.jffs2工具,根据打印信息填写相关参数。下面以块大小为256KB为例:
	osdrv/pub/bin/pc/mkfs.jffs2 -d osdrv/pub/rootfs_uclibc -l -e 0x40000 -o osdrv/pub/rootfs_uclibc_256k.jffs2
	或者
	osdrv/pub/bin/pc/mkfs.jffs2 -d osdrv/pub/rootfs_glibc -l -e 0x40000 -o osdrv/pub/rootfs_glibc_256k.jffs2

	nand flash使用yaffs2格式的镜像,制作yaffs2镜像时,需要用到nand flash的pagesize和ecc。这些信息会在uboot启动时会打印出来。建议使用时先直接运行mkyaffs2image工具,根据打印信息填写相关参数。下面以2KB pagesize、4bit ecc为例:
	osdrv/pub/bin/pc/mkyaffs2image100 osdrv/pub/rootfs_uclibc osdrv/pub/rootfs_uclibc_2k_4bit.yaffs2 1 2
	或者
	osdrv/pub/bin/pc/mkyaffs2image100 osdrv/pub/rootfs_glibc osdrv/pub/rootfs_glibc_2k_4bit.yaffs2 1 2
	eMMC 使用ext4格式的镜像,制作ext4镜像时,需要用到eMMC的启动参数bootargs中文件系统rootfs所在分区大小。这个信息是用户想要通过eMMC启动时要配置的参数。下面以32M的分区大小为例:
	osdrv/pub/bin/pc/make_ext4fs -l 32M -s osdrv/pub/rootfs_glibc osdrv/pub/rootfs_glibc_32M.ext4

来源于:	Hi3518E_SDK_V1.0.3.0/osdrv/readme_cn.txt

二、编译rootfs

我们来解决一下上边编译根文件系统出现的错误。
在这里插入图片描述

1、缺zlib错误

错误:compr_zlib.c:39:18: fatal error: zlib.h: No such file or directory

  因为找不到zlib.h所以编译错误,原本我们需要去移植zlib库解决这个问题,但华为海思提供的这个sdk中已经给我准备了这个文件。
在这里插入图片描述
  zlib.h在tools/pc/zlib/tmp/include目录中有,只需要复制到tools/pc/jffs2_tool/tmp/include目录中即可。

  注意同时要将zconf.h也复制过去的。还有,要将tools/pc/zlib/tmp/lib/目录下的libz.a libz.so libz.so.1 libz.so.1.2.7等4个文件复制到tools/pc/jffs2_tool/tmp/lib目录下,不然一会儿还得报错。

cp tools/pc/zlib/tmp/include/* tools/pc/jffs2_tool/tmp/include/
cp tools/pc/zlib/tmp/lib/* tools/pc/jffs2_tool/tmp/lib/ -rf
再次编译:
make OSDRV_CROSS=arm-hisiv300-linux CHIP=hi3518ev200 all

2、报错

在这里插入图片描述

错误信息:serve_image.c:32:18: error: storage size of ‘hints’ isn’t known

解决方案,参考:http://blog.csdn.net/mtbiao/article/details/77052659
在这里插入图片描述
在这里插入图片描述
这个的#endif在 681 行

修改操作系统头文件/usr/include/netdb.h,将此宏__USE_XOPEN2K注释(注意#ifdef#endif是一一对应的),注意该文件不止一个地方使用了该宏,有两处条件编译都使用了。

修改后再次编译:
make OSDRV_CROSS=arm-hisiv300-linux CHIP=hi3518ev200 all

3、在32位ubuntu中编译时的一个错误

Ubuntu16.04是64位的,应该不会出现这个,我的没有出现。

编译错误:/usr/bin/ld: i386:x86-64 architecture of input file `mkyaffs2image.o' is incompatible with i386 output

这个是因为sdk中本来就有在64位系统下编译的.o文件,而我们用的是32位的ubuntu,解决办法是进入tools/pc/mkyaffs2image/mkyaffs2image目录下,rm *.o(或者make clean)删除所有之前编译的痕迹即可。实际上我们板子上用的是spi flash,合适用jffs2文件系统,所以不会做yaffs2文件系统,这个东西要不要都无所谓的。

4、手工单独制作rootfs

请添加图片描述
  还报错就不管了,经过上面的操作,此时已经有了mkfs.jffs2了,我们就是只要这个而已,手工将其复制到osdrv/pub/bin/pc目录下即可。
在这里插入图片描述
在这里插入图片描述
第一步产生mkyaffs2image100已经成功了,第二步复制没有成功,复制之前的那条命令的编译过程出问题了我们手动进行复制。

modules:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

这句是Makefile的规则:这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录
转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的
话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块
源码,将其编译,生成KO文件。

在这里插入图片描述
在这里插入图片描述

ls tools/pc/jffs2_tool/tmp/mtd-utils-1.5.0/
cp tools/pc/jffs2_tool/tmp/mtd-utils-1.5.0/mkfs.jffs2 pub/bin/pc/
ls pub/bin/pc/

制作参数为:
osdrv/pub/bin/pc/mkfs.jffs2 -d osdrv/pub/rootfs_uclibc -l -e 0x10000 -o osdrv/pub/rootfs_uclibc_64k.jffs2

0x10000:一个块的大小64KB,我们开发板用的SPI型flash一个块大小为64KB

在这里插入图片描述
经过上述操作后,我们可以尝试修改Makefile,使编译继续下去:
在这里插入图片描述

5、编译最终完成的标准

在这里插入图片描述
在osdrv/pub/image_uclibc目录下得到的uboot和uImage即是我们要的uboot镜像和kernel的uImage镜像,而根文件系统镜像在osdrv/pub目录下。

注意:如果你的osdrv是完整编译结束的,那么得到的rootfs镜像中应该是不缺东西的。但是因为我做的时候是不完整编译的,rootfs是手工制作的,所以rootfs镜像中有一些缺陷。
在这里插入图片描述
标注出的这三个是我们需要的!

三、uboot的烧写和flash分区

1、裸机烧录uboot

(1)什么叫裸机烧录?
设备是空白的,未经烧录的,就叫裸机。

(2)裸机烧录一个设备有2种方案:

1、是用外部烧录器来烧录板载flash(外部烧录器烧录SPIFLASH时和HI3518E没有关系,有时
候经常SPIFLASH先单独通过烧录器和支架来烧录好镜像,然后再把烧录过镜像的SPIFLASH焊接
到板子上。现在很多烧录器也可以在板子上直接烧了);

2、是通过主芯片提供的isp下载的机制来间接烧录板载flash,如下图所示:hi3518e内部提供
支持isp机制的代码(即BL0

在这里插入图片描述
(3)运行Hi_tool来烧录uboot
  Hi_tool是由eclipse软件使用JAVA语言进行开发的,无法直接在Windows中点击运行,需要先安装jre-6u45-windows-i586(一定要安装这个版本才可以,因为这个SDK中的Hi_tool是在这个版本下开发的)方可运行,软件链接如下:

链接:https://pan.baidu.com/s/1kE3_9lhW_yFjsEKK4sWzpg
提取码:5aoy
–来自百度网盘超级会员V5的分享
在这里插入图片描述
在这里插入图片描述
我们使用串口的方式进行烧录。

2、flash分区

在这里插入图片描述
(1)因为嵌入式系统为了简化,没有使用分区表来自动管理flash,所以都是事先定死的。所以在部署一个嵌入式系统前都要人为的定下一个分区

(2)原则1:每个分区要足够放镜像;原则2:尽量留一点扩展余地。原则3:在满足1和2情况下你随便搞。

(3)我定的分区:

分区名		分区大小  	起始地址		    截至地址
bootloader:1M			0x00000000		0x00100000
kernel:	3M			0x00100000		0x00400000
rootfs:		12M			0x00400000		0x01000000

在这里插入图片描述
在这里插入图片描述

3、uboot的环境变量参数

在这里插入图片描述

4、各种常见flash的简单讲解

(1)买到的flash芯片,其实是内部的flash存储颗粒+外部封装的控制器来构成的。

(2)像EMMC、SD、MMC、SPIFLASH、NANDFLASH等差异都在于控制器。

(3)SPIFLASh的优势就是接口简单,主芯片只需要支持SPI接口就可以外接。很多MCU或者CPU在需要外扩一个8M/16M/32M/64M这么大级别的外部存储器时,选择SPIFLASH是很好的。

(4)NANDFLASH其实控制器是最老的,像EMMC(现在手机内部装的就是,更换不同容量不需要修改驱动程序)、SD等都比NANDFlash要更新一些,更好一些。

四、kernel和rootfs烧录与启动系统

1、将镜像从pc上位机中下载到开发板HI3518E内部的SDRAM64M)中
2、擦除清空SPI Flash中相应的分区
3、将下载到SDRAM中的镜像烧录到SPI Flash中

1、烧录kernel、烧录rootfs

(1)HI3518E内部的SDRAM地址范围:80000000-83FFFFFF(查数据手册得到)
(2)tftp得能通能下载,才能烧录。ip设置是:本地192.168.1.10,serverp是192.168.1.141

2、uboot的各环境变量介绍和设置

(1)网络地址:ipaddr 192.168.1.10, serverip 192.168.1.141
(2)bootcmd、bootargs设置正确,烧录后方能正常启动。

1:烧录命令
---------------------------------------------------
set serverip 192.168.1.141 

tftp更新并重新烧写uboot的命令序列:
mw.b 0x82000000 ff 0x100000 #以字节为单位将0x82000000开始的1M大小的内存写成ff
tftp 0x82000000 u-boot-hi3518ev200.bin #tftp方式下载uboot镜像
sf probe 0  #选中SPI Flash
sf erase 0x0 0x100000  #擦除
sf write 0x82000000 0x0 0x100000 #从SDRAM0x82000000开始的1M内容写到Flash的0x0 开始的地方
--------------------------------------------------
tftp更新并重新烧写kernel的命令序列:
mw.b 0x82000000 ff 0x300000
tftp 0x82000000 uImage_hi3518ev200
sf probe 0
sf erase 0x100000 0x300000
sf write 0x82000000 0x100000 0x300000
---------------------------------------------------
tftp更新并重新烧写rootfs的命令序列:
mw.b 0x82000000 ff 0xc00000
tftp 0x82000000 rootfs_hi3518ev200_64k.jffs2
sf probe 0
sf erase 0x400000 0xc00000
sf write 0x82000000 0x400000 0xc00000

0xc00000设置不对,会使得文件系统的校验不通过,进行报错

附2:正确的bootcmd和bootargs对应的设置命令:
set bootcmd 'sf probe 0;sf read 0x82000000 0x100000 0x300000;bootm 0x82000000'
set bootargs mem=32M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=jffs2 mtdparts=hi_sfc:1024K(boot),3072K(kernel),12288K(rootfs)

mem=32M:HI3518E内部的SDRM是有64M的,但我们这里只用了32M。是因为内部的SDRAM有两个用途:1、给Linux系统用 2、给mpp用,即海思的H.264视频编解码压缩体系,有很多库文件和ko文件。

mtdparts:分区表,内核中源码静态地写死了一张分区表,但也可通过uboot动态传参得到一个分区表,动态传参的这个优先级更高。
12288K可以也可设置为10240k

五、rootfs启动后做了什么

在这里插入图片描述
在这里插入图片描述
1、/etc目录我们重点关注
fstab文件:挂载了各种虚拟文件系统

proc		/proc		proc	defaults	0	0
sysfs		/sys		sysfs	defaults	0	0
tmpfs		/dev		tmpfs	defaults	0	0

fs-version文件版本号相关的文件
group文件管理用户与登录有关的文件
inittab文件实在busybox中被调用的
mtab文件挂载虚拟文件系统相关的
passwd、passwd-与登陆用户名、密码相关的
protocols协议相关的文件
services文件与各种网络服务相关的

profile文件设置环境变量,全局调用

# /etc/profile: system-wide .profile file for the Bourne shells
#
#

set_path_before()
{
	[ -d $1 ] && PATH="$1:$PATH"
}

PATH="/usr/bin:/usr/sbin:/bin:/sbin"
set_path_before /usr/local/sbin
set_path_before /usr/local/bin

LD_LIBRARY_PATH="/usr/local/lib:/usr/lib"

export PATH
export LD_LIBRARY_PATH

# ANSI COLORS
CRE="
[K"
NORMAL="[0;39m"
RED="[1;31m"
GREEN="[1;32m"
YELLOW="[1;33m"
BLUE="[1;34m"
MAGENTA="[1;35m"
CYAN="[1;36m"
WHITE="[1;37m"

umask 022

echo "${GREEN}Welcome to HiLinux.${NORMAL}"

udev文件夹与即插即用设备相关的,如usb设备
init.d文件夹中都是比较重要的,S00devs设备节点相关的文件
在这里插入图片描述/etc/init.d//rcS这个文件是最关键的,其他文件用大写S开头是为了便于在rcS中调用这几个文件:for initscript in /etc/init.d/S[0-9][0-9]*

#! /bin/sh

/bin/mount -a

echo "
            _ _ _ _ _ _ _ _ _ _ _ _
            \  _  _   _  _ _ ___
            / /__/ \ |_/
           / __   /  -  _ ___
          / /  / /  / /
  _ _ _ _/ /  /  \_/  \_ ______
___________\___\__________________
"
for initscript in /etc/init.d/S[0-9][0-9]*
do
	if [ -x $initscript ] ;
	then
		echo "[RCS]: $initscript"
		$initscript
	fi
done

修改一下S80network 文件,添加两条命令:
在这里插入图片描述

注:本资料大部分由朱老师物联网大讲堂课程笔记整理而来并且引用了部分他人博客的内容,如有侵权,联系删除!水平有限,如有错误,欢迎各位在评论区交流。

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小嵌同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值