这篇文章中将测试在 NUC980 中运行Linux系统(基于SPI NAND)。
本文相关的开发环境准备请查看下面这篇文章:
《新唐NUC980使用记录:开发环境准备与编译配置基础说明》
这篇文章中内容均在下面的开发板上进行测试(理论上也可以在新唐官方NUMAKER NUC980 IIOT开发板中进行测试):
《新唐NUC980使用记录:自制开发板(基于NUC980DK61YC)》
开始前请将将开发板的USB0和UART0都接到Windows电脑上,电脑上使用终端工具连接UART0。
NUC980 U-Boot针对不同启动源的修改调整具体参考BSP包中的文档《NUC980 U-Boot v2016_11 User Manual》。
我这里使用自制的开发板所以从nuc980_evb.h和nuc980_defconfig这对最基础的配置上进行修改:
cd ~/nuc980-sdk/
cd NUC970_U-Boot_v2016.11/
修改配置文件:
# cp include/configs/nuc980_evb.h include/configs/nuc980_evb.h.original
gedit include/configs/nuc980_evb.h
配置文件中找到对应位置进行修改:
#define CONFIG_SYS_USE_SPIFLASH // 47行 启用SPI FLASH
#define CONFIG_SYS_USE_NANDFLASH
#define CONFIG_ENV_IS_IN_NAND
/*#define CONFIG_ENV_IS_IN_SPI_FLASH */
/*#define CONFIG_ENV_IS_IN_MMC */
/****************************************/
#ifdef CONFIG_ENV_IS_IN_NAND
#define CONFIG_ENV_OFFSET 0x80000
#define CONFIG_ENV_SIZE 0x20000 // 129行 调整uboot环境变量存储区域大小
// include/configs/nuc980_evb.h 这个文件中还定义了很多位置和大小的参数
// 比如bootm命令启动的内核最大尺寸、NAND的分区设置等,可以按照需求调整
修改配置选项:
# make distclean
make nuc980_defconfig
make menuconfig
配置选项中找到对应位置进行设置:
进行编译:
export PATH=$PATH:/home/nx/nuc980-sdk/arm_linux_4.8/bin
make
编译完成后u-boot.bin位于当前目录下,对于NAND而言还需要spl目录下的u-boot-spl.bin。将其拷贝至Windows中进行烧录。比如我的 /media/sf_common/ 是和Windows共享的目录,拷贝到这里即可:
# 拷贝至Windows电脑上
# sudo cp u-boot.bin /media/sf_common/
# sudo cp spl/u-boot-spl.bin /media/sf_common/
拨动拨动开关将PG[1:0]设置为00,按下复位键。在Windows中使用NuWriter进行烧录:
烧录完成后拨动拨动开关将PG[1:0]设置为11,按下复位键。可以在终端界面中看到启动信息:
U-Boot最重要的是用来启动 Linux Kernel 的,比较常用的做法是使用U-Boot环境变量中设置的参数来读取内核镜像,然后启动内核。
环境变量可以写死在U-Boot程序中,可以使用U-Boot命令来设置,也可以通过烧录工具烧录到保存环境变量的存储区域。下面是最后一种方式的演示:
拨动拨动开关将PG[1:0]设置为00,按下复位键。在Windows中使用NuWriter进行烧录(如果选择时看不到文件,弹窗右下角选择All Files):
烧录完成后拨动拨动开关将PG[1:0]设置为11,按下复位键。可以在终端界面中看到启动信息:
上面烧录的环境变量如下:
bootdelay=3
baudrate=115200
stderr=serial
stdin=serial
stdout=serial
loadkernel=nand read 0x7fc0 0x200000 0x1000000
bootcmd=run loadkernel;bootm 0x7fc0
上面环境变量中使用 nand 命令从nand的0x200000位置读取0x1000000大小(16M)的数据到内存0x7fc0位置;然后启动位于内存0x7fc0开始的程序。当然因为现在还没有烧录内核所以启动会失败。
NUC980 U-Boot针对不同启动源的修改调整具体参考BSP包中的文档《NUC980 Linux 4.4 BSP User Manual》。
我这里使用自制的开发板所以以nuc980_defconfig这个最基础的配置进行使用:
cd ~/nuc980-sdk/
cd NUC980-linux-4.4.y/
套用配置:
# make distclean
make nuc980_defconfig
进行编译:
export PATH=$PATH:/home/nx/nuc980-sdk/arm_linux_4.8/bin
make uImage
注意默认配置下编译时会将 NUC980-linux-4.4.y 同级的 rootfs 目录打包进内核(作为ramfs启动),同时会将编译出的镜像 980uimage 放到 NUC980-linux-4.4.y 同级的 image 目录中。
将其拷贝至Windows中进行烧录。比如我的 /media/sf_common/ 是和Windows共享的目录,拷贝到这里即可:
# 拷贝至Windows电脑上
# sudo cp ../image/980uimage /media/sf_common/
拨动拨动开关将PG[1:0]设置为00,按下复位键。在Windows中使用NuWriter进行烧录(如果选择时看不到文件,弹窗右下角选择All Files):
烧录完成后拨动拨动开关将PG[1:0]设置为11,按下复位键。可以在终端界面中看到启动信息:
前面U-Boot配置文件中对NAND的分区设置中除去U-Boot、环境变量、内核等需要的空间,剩余空间都被分配为user分区。但是上面默认编译出来的内核并没有把这个分区用起来,如果想用的话需要进行调整。
首先内核要支持对应的 SPI NAND 芯片型号:
# 我这里使用的W25N01GV已经默认包含了,所以不需要调整
# gedit drivers/mtd/nand/nand_ids.c
接着要确保相关芯片驱动:
gedit arch/arm/mach-nuc980/dev.c
找到对应位置进行修改:
// SPI NAND使用驱动为mt29f
static struct flash_platform_data nuc980_qspi0_flash_data = {
// 下面838行加上默认配置中对应开发板CONFIG_BOARD_NUC980
#if defined(CONFIG_BOARD_IOT) || defined(CONFIG_BOARD_ETH2UART) || defined(CONFIG_BOARD_LORAG) || defined(CONFIG_BOARD_NUC980)
.name = "mt29f",
#else
.name = "m25p80",
#endif
.parts = nuc980_qspi0_flash_partitions,
.nr_parts = ARRAY_SIZE(nuc980_qspi0_flash_partitions),
.type = "mx66l51235l",
};
/****************************************/
// 下面854行加上默认配置中对应开发板CONFIG_BOARD_NUC980
#if defined(CONFIG_BOARD_IOT) || defined(CONFIG_BOARD_ETH2UART) || defined(CONFIG_BOARD_LORAG) || defined(CONFIG_BOARD_NUC980)
.modalias = "mt29f",
#else
.modalias = "m25p80",
#endif
修改配置选项:
# make distclean
make nuc980_defconfig
make menuconfig
配置选项中找到对应位置进行设置:
上面mode也可以设置为 Quad mode ,使用时读写速度会更快些。
重新编译烧录内核就可以看到效果了:
# export PATH=$PATH:/home/nx/nuc980-sdk/arm_linux_4.8/bin
# make uImage
# sudo cp ../image/980uimage /media/sf_common/
前面的使用中根据默认配置,用的是ramfs,这个对嵌入式设备来说是挺不错的,可以有效防止断电引起的文件系统出错的问题,缺点就是无法在烧录后运行时对rootfs修改保存。通常直接使用flash上多余的分区存放rootfs是更加常见的做法。
在上节的基础上取消ramfs,然后设置从flash分区启动rootfs:
上面启动命令如下:
noinitrd root=/dev/mtdblock2 rootfstype=yaffs2 rootflags=inband-tags console=ttyS0,115200n8 rdinit=/sbin/init mem=64M
修改后重新编译内核并烧录:
# export PATH=$PATH:/home/nx/nuc980-sdk/arm_linux_4.8/bin
# make uImage
# sudo cp ../image/980uimage /media/sf_common/
要使用SPI NAND YAFFS2作为rootfs,还需要制作可供烧录到flash中的rootfs数据。新唐的NUC980_Linux_Applications项目中的yaffs2utils套件工具可以将rootfs目录转化为可供烧录的数据。
cd ~/nuc980-sdk/
cd NUC980_Linux_Applications/yaffs2utils/
make
# 编译生成的 mkyaffs2 就是我们需要的工具了
# 把工具临时添加到环境变量
export PATH=$PATH:/home/nx/nuc980-sdk/NUC980_Linux_Applications/yaffs2utils
cd ~/nuc980-sdk/
# 将当前目录下的rootfs目录打包成数据文件
mkyaffs2 --inband-tags -p 2048 rootfs rootfs_yaffs2.img
# --inband-tags:yaffs2的tag儲存在DATA區塊 / -p:設定NAND Flash頁的大小(Page Size)
# 当前目录下的 rootfs_yaffs2.img 就是需要的数据了
# sudo cp rootfs_yaffs2.img /media/sf_common/
修改后的内核和文件系统烧录完成后就可以测试了:
上面烧录过程都是分块一个个进行的,烧录不同的内容还需要设置不同的参数,开发中这样没问题,但是批量烧录时这样并不方便。使用NuWriter工具可以将所有需要的内容打包成一个镜像,烧录时也只要烧录这一个镜像即可。
下面是打包生成镜像演示:
镜像使用非常方便,并不需要关系地址参数等:
如果觉得镜像文件存放占空间的话可以镜像压缩(使用前需要解压):
更多内容可以参考BSP包中的文档《NUC980 NuWriter User Manual》。
根据上面的内容基本可以基于SPI NAND在NUC980上运行起系统来了。接下来使用中更多的是根据需求对kernel、rootfs、application的调整编写等。