文章目录
目的
从去年(2022)开始新塘官方的NUC980 5.10.y内核的项目开始展开,这篇文章将测试在NUC980上使用5.10.y内核。
这篇文章中内容均在下面的开发板上进行测试:
《新唐NUC980使用记录:自制开发板(基于NUC980DK61YC)》
对于NUC980芯片本身的一些内容可以参考:
《新唐NUC980使用记录:基础说明与资料索引》
基础准备
烧录环境
烧录这里在Windows上进行,准备工作的话就是安装下设备驱动,准备烧录软件,相关内容仓库地址如下:
https://github.com/OpenNuvoton/NUC980_NuWriter
电脑上安装了 Git 的话可以 git clone
来下载,没有的话也可以直接在网页上下载。
如果是Linux平台,相关内容仓库地址为:
https://github.com/OpenNuvoton/NUC980_NuWriter_CMD
开发编译环境
下载安装Ubuntu Desktop(这里使用版本为22.04.2):
https://ubuntu.com/download/desktop
我这里使用VirtualBox(本文中版本为7.0.8)虚拟机安装Ubuntu,相关使用说明见下文:
《免费虚拟机软件VirtualBox快速入门》
安装完成后进行基础环境安装与设置:
sudo apt update
sudo apt install -y build-essential
# 下面两行内容是我个人习惯设置
# 在虚拟机中:安装增强功能、设置分辨率、初次软件更新&关闭更新检查、关闭熄屏
# 在VirtualBox对虚拟机进行设置:共享粘贴板、共享文件夹设置网卡2为桥接网卡
以下根据需求安装:
# 安装SSH服务
sudo apt install -y openssh-server
# 安装编辑器 VS Code
# 从官网中下载 .deb 格式安装包: https://code.visualstudio.com/
# 通过内置浏览器下载的话默认会下载到 ~/Downloads/ 目录下
sudo apt install ~/Downloads/code_1.78.0-1683145611_amd64.deb
# 安装完成后可以使用 code 命令打开编辑器
# VS Code中可以安装Embedded Linux Kernel Dev扩展,方便开发
因为需要从GitHub下载项目所以还要安装git:
sudo apt install -y git-all
# git使用时可能需要设置用户名和邮箱
# git config --global user.name "naisu"
# git config --global user.email naisu@example.com
下面是 u-boot & linux & rootfs 配置编译过程中可能需要用到的各种库(不一定全部需要或是完全够,先装一些是一些):
sudo apt install -y libusb-1.0-0-dev zlib1g-dev
sudo apt install -y pkg-config
sudo apt install -y python2-dev python3-dev
sudo apt install -y swig
sudo apt install -y libncurses-dev libncurses5-dev
sudo apt install -y libssl-dev
sudo apt install -y libc6:i386 lib32stdc++6 lib32z1
sudo apt install -y u-boot-tools
sudo apt install -y flex
建立工作目录:
# 本文将工作目录设置在用户目录($HOME)下的nuc980-sdk文件夹中
cd ~
mkdir nuc980-sdk
SD卡分区
嵌入式Liunx系统通常分为Bootloader、Linux Kernel、RootFS三个部分,三个部分分别存储在三个位置中。具体对于SD卡而言存储分布如下:
- Bootloader放在开头1M以内位置上(这部分空间通常分区工具分区时会自动跳过);
通常还需跳过开头至少512Bytes,这部分用于保存SD卡分区信息; - Linux Kernel放在第一个分区上,通常使用FAT32(vfat)格式分区,通常不需要太大;
- RootFS放在第二个分区上,分区文件系统可以根据需求选择,这个可以大点,甚至分配剩下所有的空间;
SD卡可以通过读卡器在电脑上进行分区。Ubuntu上可以使用 GParted 工具进行分区:
安装方式: sudo apt install gparted
上面分区中唯一需要注意的是必须有一个fat32格式的分区(通常是第一个分区),用来存放内核和设备树等,不需要很大。
当然Ubuntu上也可以选择使用命令行方式进行分区:
# 先将SD卡插入Ubuntu中
# 使用 lsblk 查看SD卡设备号sdX
# 我这里显示为sdb,下面均以此进行说明
# 如果已经分过区了那么Ubuntu可能会自动挂载
# 逐条使用 sudo umount /dev/sdbn 进行卸载
# 对SD(TF)卡进行分区
sudo fdisk /dev/sdb
# 如果有分区的话可以输入 d 回车依次删除
# 输入 n 新建分区,分区大小根据需要设置即可
# 下面是我新建的两个分区的输入情况
# n回车 回车(p) 回车(1) 回车(2048) +32M回车 (如果有额外提示则Y回车)
# n回车 回车(p) 回车(2) 回车(67584) +200M回车 (如果有额外提示则Y回车)
# 输入 w 回车保存退出,输入使用 lsblk 查看分区情况
# 格式化分区建立文件系统
sudo mkfs.vfat /dev/sdb1
sudo mkfs.ext4 /dev/sdb2
制作和设置编译工具链
制作toolchain和rootfs
这里使用buildroot来制作rootfs,先制作rootfs是打算后面用的交叉编译工具链也通过这里生成。
下载、配置与编译 buildroot:
buildroot下载地址从官网获取 https://buildroot.org/ ,这里使用版本为 2023.02 。
cd ~/nuc980-sdk/
wget https://buildroot.org/downloads/buildroot-2023.02.tar.xz
tar -xJf buildroot-2023.02.tar.xz
# 进入buildroot目录
cd buildroot-2023.02/
# 进行配置
# 这里做测试使用,只要配置下目标平台和工具链即可,详见后面截图
make menuconfig
# 编译
make
编译完成后 output 目录下的 host 目录中就是交叉编译工具链(toolchain); output 目录下的 images 目录中的 rootfs.tar 就是生成的根文件系统。
拷贝rootfs内容到SD卡
因为最终测试时是需要用到rootfs的,所以这里直接先进行拷贝。
将SD卡接入到Ubuntu中,使用 lsblk
查看挂载情况:
使用下面命令拷贝rootfs内容到SD卡:
# cd ~/nuc980-sdk/buildroot-2023.02/
# sudo rm -rf /media/nx/rootfs/*
sudo tar -xf output/images/rootfs.tar -C /media/nx/rootfs/
设置编译工具链
注意PATH使用自己的路径,每次打开终端都需要重新设置:
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabi-
export PATH=$PATH:/home/nx/nuc980-sdk/buildroot-2023.02/output/host/bin
u-boot编译与测试
下载、配置与编译
下载 u-boot:
cd ~/nuc980-sdk/
git clone --depth=1 https://github.com/OpenNuvoton/NUC970_U-Boot_v2016.11.git
# 得到的NUC970_U-Boot_v2016.11文件夹就是uboot项目了,这个是NUC970和NUC980共用的
# 当前版本由cwweng-nuvoton在2022-12-06最后提交,hash为d4ba46e
# 可以打包备份下:tar -cJf NUC970_U-Boot_v2016.11.tar.xz NUC970_U-Boot_v2016.11/
# 进入u-boot目录
cd NUC970_U-Boot_v2016.11/
修改源码以支持SD卡:
# cp include/configs/nuc980_evb.h include/configs/nuc980_evb.h.original
gedit include/configs/nuc980_evb.h
配置文件中找到对应位置进行修改:
/*#define CONFIG_SYS_USE_SPIFLASH */
/*#define CONFIG_SYS_USE_NANDFLASH */ // 屏蔽
/*#define CONFIG_ENV_IS_IN_NAND */ // 屏蔽
/*#define CONFIG_ENV_IS_IN_SPI_FLASH */
#define CONFIG_ENV_IS_IN_MMC // 51行 启用MMC
// include/configs/nuc980_evb.h 这个文件中还定义了很多位置和大小的参数
配置 u-boot:
# cd ~/nuc980-sdk/NUC970_U-Boot_v2016.11
# make distclean
# 加载默认配置
make nuc980_defconfig
# 进行针对性配置
# 这里主要配置启用SD1
make menuconfig
需要注意的是下面的内核默认是启用了设备树支持的,而这个u-boot早先版本是没有启用设备树的,如果使用的是2022.08.19以前的版本的话需要启用 Library routines -> Enable the FDT library 。
编译 u-boot:
# export ARCH=arm; export CROSS_COMPILE=arm-buildroot-linux-gnueabi-
# export PATH=$PATH:/home/nx/nuc980-sdk/buildroot-2023.02/output/host/bin
make
# 可以根据电脑配置使用make -jx等加快编译速度
烧录u-boot与环境变量
烧录 u-boot:
编译完成后u-boot.bin位于当前目录下。将其拷贝至Windows中进行烧录。比如我的 /media/sf_common/ 是和Windows共享的目录,拷贝到这里即可:
# cd ~/nuc980-sdk/NUC970_U-Boot_v2016.11
# 拷贝至Windows电脑上
# sudo cp u-boot.bin /media/sf_common/
烧录U-Boot需要将SD卡插在开发板上。拨动拨动开关将 PG[1:0]
设置为 00
,按下复位键。在Windows中使用NuWriter进行烧录(烧录通过USB0,调试交互默认通过UART0):
烧录u-boot环境变量:
在Windows中新建env.txt文件,写入下面内容:
bootdelay=3
baudrate=115200
stderr=serial
stdin=serial
stdout=serial
loadkernel=fatload mmc 0:1 0x7fc0 uImage
loaddtb=fatload mmc 0:1 0xc00000 nuc980-dev-v1.0.dtb
bootcmd=run loadkernel;run loaddtb;bootm 0x7fc0 - 0xc00000
烧录环境变量:
完成后拨动拨动开关将 PG[1:0]
设置为 01
,按下复位键。可以在串口终端界面中看到启动信息:
linux kernel编译与测试
下载、配置与编译
下载 linux kernel:
cd ~/nuc980-sdk/
# 默认情况下下面项目编译时会将生成的Image和dtb文件拷贝到项目目录同级的image目录中,所以需要创建该目录
# mkdir image
# 但是实际使用时需要用到uImage文件,但是该文件却没有拷贝出来,所以下面操作中干脆把拷贝这个操作注释掉了,这样也不用收到创建image目录了
git clone --depth=1 https://github.com/OpenNuvoton/NUC980-linux-5.10.y
# 得到的NUC980-linux-5.10.y文件夹就是linux kernel项目了
# 当前版本由yclu-ntc在2023-04-27最后提交,hash为74db56f
# 可以打包备份下:tar -cJf NUC980-linux-5.10.y.tar.xz NUC980-linux-5.10.y/
# 进入linux kernel目录
cd NUC980-linux-5.10.y/
配置 linux kernel:
# make distclean
make nuc980_defconfig
# 进行针对性配置
make menuconfig
默认使用ramfs,而本文使用sd卡分区上的fs,所以需要取消默认设置:
启用ext4文件系统支持:
修改设备树文件:
# cp arch/arm/boot/dts/nuc980-dev-v1.0.dts arch/arm/boot/dts/nuc980-dev-v1.0.dts.original
gedit arch/arm/boot/dts/nuc980-dev-v1.0.dts
设备树文件中主要就是要注意sd接口要启用,并且不和其它功能冲突,本文中设备树文件内容见文章结尾。
修改Makefile文件以取消编译时拷贝image和dtb文件操作:
# cp Makefile Makefile.original
# cp arch/arm/boot/Makefile arch/arm/boot/Makefile.original
gedit Makefile
gedit arch/arm/boot/Makefile
# 装了VS Code也可以用VS Code来修改
# code ...
编译 linux kernel 和 设备树:
# 设置编译工具链
# export ARCH=arm; export CROSS_COMPILE=arm-buildroot-linux-gnueabi-
# export PATH=$PATH:/home/nx/nuc980-sdk/buildroot-2023.02/output/host/bin
# 编译生成内核镜像
make uImage
# 可以根据电脑配置使用make -jx等加快编译速度
# 编译生成设备树文件
make dtbs
编译生成的系统镜像 uImage
在 arch/arm/boot/
目录下,设备树文件 nuc980-dev-v1.0.dtb
在 arch/arm/boot/dts/
目录下。
系统运行测试
拷贝文件到SD卡boot分区:
# 拷贝至Windows电脑上
# sudo cp arch/arm/boot/uImage /media/sf_common/
# sudo cp arch/arm/boot/dts/nuc980-dev-v1.0.dtb /media/sf_common/
# 在电脑上将两个文件拷贝到SD卡boot分区
拷贝完成后将SD开插回开发板,上电测试:
默认情况下登录用户名为 root
,没有密码。如果登录有问题的话检查buildroot相关配置:
如果启动有问题的话根据控制台输出来检查。比如内核和设备树加载有问题的话可以检查环境变量,检查内核镜像和设备树文件等;文件系统加载问题的话检查文件系统分区、文件系统内容等;如果init进程启动失败的话尝试重新编译拷贝根文件系统内容。具体情况具体分析处理。
总结
根据上面的内容基本可以基于SD1位置使用SD卡在NUC980上运行起系统来了。 5.10.y 内核和之前 4.4 内核相比最大的区别是默认就启用了设备树,这也是目前 arm linux 比较流行的方式。
设备树文件内容
/*
* Device Tree Source for NUC980 DEV board
*
* Copyright (C) 2018 Nuvoton Technology Corp.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/dts-v1/;
#include "nuc980.dtsi"
/ {
model = "Nuvoton NUC980 DEV V1.0";
compatible = "nuvoton,nuc980-dev-v1.0", "nuvoton,nuc980";
chosen {
bootargs = "console=ttyS0,115200n8 noinitrd rootfstype=ext4 root=/dev/mmcblk0p2 rw rootwait mem=64M";
};
apb {
uart1: serial@b0071000 {
status = "disabled";
};
uart2: serial@b0072000 {
status = "disabled";
};
uart3: serial@b0073000 {
status = "disabled";
};
uart4: serial@b0074000 {
status = "disabled";
};
uart5: serial@b0075000 {
status = "disabled";
};
uart6: serial@b0076000 {
status = "disabled";
};
uart7: serial@b0077000 {
status = "disabled";
};
uart8: serial@b0078000 {
status = "disabled";
};
uart9: serial@b0079000 {
status = "disabled";
};
can0: can@b00a0000 {
status = "disabled";
};
can1: can@b00a1000 {
status = "disabled";
};
rtc: rtc@b0041000 {
status = "disabled";
};
nadc: nadc@b0043000 {
status = "disabled";
};
pwm0: pwm@b0058000 {
status = "disabled";
};
pwm1: pwm@b0059000 {
status = "disabled";
};
etimer0: etimer0@b0050000 {
status = "disabled";
};
etimer1: etimer1@b0050100 {
status = "disabled";
};
etimer2: etimer2@b0051000 {
status = "disabled";
};
etimer3: etimer3@b0051100 {
status = "disabled";
};
i2c0: i2c0@b0080000 {
status = "disabled";
};
i2c1: i2c1@b0081000 {
status = "disabled";
pinctrl-0 = <&pinctrl_i2c1_PB>;
};
i2c2: i2c2@b0082000 {
status = "disabled";
pinctrl-0 = <&pinctrl_i2c2_PB>;
};
};
ahb {
usbh_ehci@b0015000 {
status = "okay";
};
usbh_ohci@b0017000{
status = "okay";
};
usbdev@b0016000 {
status = "okay";
};
fmi@b0019000 {
status = "disabled";
};
sdh@b0018000 {
status = "okay";
};
emac0@b0012000 {
status = "disabled";
};
emac1@b0022000 {
status = "disabled";
};
ccap0@b0024000 {
status = "disabled";
};
i2c_gpio0: i2c-gpio-0 {
status = "disabled";
};
ccap1@b0014000 {
status = "disabled";
};
i2c_gpio1: i2c-gpio-1 {
status = "disabled";
};
dma@b0008000 {
status = "okay";
};
i2s: i2s@b0020000 {
status = "disabled";
};
i2s_pcm: i2s_pcm {
status = "disabled";
};
sound {
compatible = "nuvoton,nuc980-audio";
i2s-controller = <&i2s>;
i2s-platform = <&i2s_pcm>;
status = "disabled";
};
ebi: ebi@b0010000 {
status = "disabled";
};
};
};