最近画了一个Linux板子,主控是全志的F1C100S,自带了32M RAM,不是很大,但是可以学习下;
板子图片:
板子正面 板子反面 UBoot启动

FLASH下载工具使用
1、通过命令 sudo sunxi-fel ver 来确认有无成功进入fel模式;
sudo sunxi-fel ver
2、短接FLASH1和4脚,可以进入fel模式,其实就是CS引脚拉低;
3、单次运行(下载到RAM中):
sunxi-fel uboot /your/path/to/u-boot-sunxi-with-spl.bin
4、烧进 spi-flash (开机自启)
sunxi-fel -p spiflash-write 0 /your/path/to/u-boot-sunxi-with-spl.bin
其中0是烧录偏移地址;
Uboot编译
sudo apt-get install git
git clone https://gitee.com/LicheePiNano/u-boot.git
cd u-boot
# 查看分支
git branch -a
# 切换到 Nano 分支
git checkout nano-lcd800480
git clone -b nano-lcd800480 --depth=1 https://github.com/Lichee-Pi/u-boot.git
此处告知make采用arm-linux-gnueabi下的所有交叉编译工具,目标架构为Arm,设定各项默认配置为 nano 的spiflash支持版
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- f1c100s_nano_uboot_defconfig
# 若不带spi-flash的板子,请换成 licheepi_nano_defconfig
# 进行可视化配置
make ARCH=arm menuconfig
# 修改默认bootcmd
gedit include/configs/suniv.h
# 需要修改为
#define CONFIG_BOOTCOMMAND "run distro_bootcmd"
# 开始编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8
只需要u-boot-sunxi-with-spl.bin即可;
boot.scr
根据上面对
bootcmd的修改,u-boot启动时会从第一分区读取boot.scr文件,并执行其中的脚本。我们可以通过这个来设置要传递给linux内核的参数、来加载内核和设备树、来启动内核。
在uboot目录下新建boot.cmd文件,向其中写入u-boot要执行的脚本:
cd ~/f1c100s-sdk/u-boot/
touch boot.cmd
gedit boot.cmd
写入以下内容:
#设置传递给内核的bootargs参数
#读取内核镜像和设备树到内存中指定位置
#启动内核程序
setenv bootargs console=tty0 console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 rw
load mmc 0:1 0x80008000 zImage
load mmc 0:1 0x80C00000 suniv-f1c100s-licheepi-nano.dtb
bootz 0x80008000 - 0x80C00000
使用u-boot编译后tools目录下的 mkimage 工具可以将boot.cmd文件生成为 boot.scr 文件,通过下面命令:
#arm架构;不压缩;script文件;输入boot.cmd文件;输出boot.scr文件
tools/mkimage -A arm -C none -T script -d boot.cmd boot.scr
生成的 boot.scr 文件就在当前目录下;
Linux编译
1、Linux下载
git clone https://gitee.com/LicheePiNano/Linux.git
cd ./Linux
2、Linux编译
make ARCH=arm f1c100s_nano_linux_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16 INSTALL_MOD_PATH=out modules_install
编译成功后,生成文件所在位置:
内核img文件:
./arch/arm/boot/zImage设备树dtb文件:
./arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtbmodules文件夹:
./out/lib/modules
buildrooft构建根文件系统
buildroot可用于构建小型的linux根文件系统。 大小最小可低至2M,与内核一起可以放入最小8M的spi flash中。 buildroot中可以方便地加入第三方软件包(其实已经内置了很多),省去了手工交叉编译的烦恼。
下载安装
首先安装一些依赖,比如linux头文件:
apt-get install linux-headers-$(uname -r)
然后下载安装:
wget https://buildroot.org/downloads/buildroot-2021.02.4.tar.gz
tar xvf buildroot-2021.02.4.tar.gz
cd buildroot-2021.02.4/
make menuconfig
配置
make menuconfig
以下选项为基础配置:
- Target options
- Target Architecture (ARM (little endian))
- Target Variant arm926t
- Toolchain
- C library (musl) # 使用musl减小最终体积
- System configuration
- Use syslinks to /usr .... # 启用/bin, /sbin, /lib的链接
- Enable root login # 启用root登录
- Run a getty after boot # 启用登录密码输入窗口
- (licheepi) Root password # 默认账户为root 密码为licheepi
另可自行添加或删除指定的软件包
一些配置的简单说明
Target options --->
Target Architecture Variant (arm926t) ---> // arm926ejs架构
[ ] Enable VFP extension support // Nano 没有 VFP单元,勾选会导致某些应用无法运行
Target ABI (EABI) --->
Floating point strategy (Soft float) ---> // 软浮点
System configuration --->
(Lichee Pi) System hostname // hostname
(licheepi) Root password // 默认账户为root 密码为licheepi
[*] remount root filesystem read-write during boot // 启动时重新挂在文件系统使其可读写
编译
make
编译的过程如果带上下载软件包的时间比较漫长,很适合喝杯茶睡个午觉;(buildroot不能进行多线程编译)
编译完成的镜像包,是buildroot-2021.02.4/output/images/rootfs.tar;
测试程序
嵌入式linux开发最终是需要在系统上运行应用程序来实现特定的功能需求,这里编写个基础的应用程序用于测试:
建立程序文件夹并进入
mkdir helloworld
cd helloworld/
建立程序文件并编写程序
touch helloworld.c
gedit helloworld.c
写入以下内容:
#include
int main(void)
{
printf("Hello, world!\n");
}
编译生成可执行文件:
arm-linux-gnueabi-gcc -static helloworld.c -o helloworld
生成的 helloworld 就是我们需要的可执行文件了。
需要静态编译;
系统烧录(SD卡)
在SD卡中放了以下文件:
├── boot.cmd
├── boot.scr*(这个可以在Uboot中输入对应命令达到相同的结果)
├── helloworld*
├── rootfs.tar*
├── suniv-f1c100s-licheepi-nano.dtb*
├── u-boot-sunxi-with-spl.bin*
└── zImage*
带星号的是加载进SD卡中的; 分别是U-boot、rootfs、Linux、boot.scr、测试程序; 关于boot.scr: 修改默认bootcmd:
gedit include/configs/suniv.h需要修改为:
#define CONFIG_BOOTCOMMAND "run distro_bootcmd"然后就可以编译了: 根据上面对bootcmd的修改,u-boot启动时会从第一分区读取 boot.scr 文件,并执行其中的脚本。我们可以通过这个来设置要传递给linux内核的参数、来加载内核和设备树、来启动内核。
也可以使用Uboot中的boot命令:
boot 命令也是用来启动 Linux 系统的,只是
boot会读取环境变量bootcmd来启动 Linux 系 统,bootcmd是一个很重要的环境变量!其名字分为“boot”和“cmd”,也就是“引导”和“命 令”,说明这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可 以修改的。比如我们要想使用 tftp 命令从网络启动 Linux 那么就可以设置bootcmd为“tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 -83000000”,然后使用saveenv将bootcmd保存起来。然后直接输入 boot 命令即可从网络启动Linux 系统,命令如下:$:setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb;bootz 80800000 - 83000000' $:saveenv $:boot
boot命令使用如下所示:
$:setenv bootcmd 'setenv bootargs console=tty0 console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 rw; load mmc 0:1 0x80008000 zImage; load mmc 0:1 0x80C00000 suniv-f1c100s-licheepi-nano.dtb; bootz 0x80008000 - 0x80C00000'
$:saveenv
$:boot
最后输入boot,启动linux系统,并且重启后仍会自动跳转进入linux系统;
得到了需要的所有文件,接下来是烧录到SD卡中;
文件烧录:
前面编译生成的内容可以分块分别烧录进SD卡进行测试,也可以将 u-boot & linux & rootfs 整块打包烧录进SD卡进行测试,其实本质上是一样的,这里先进行分块测试的介绍,打包烧录介绍将在后面的章节说明。
先将SD卡插入Ubuntu中;
使用 lsblk 查看SD卡设备号sdX;
我这里显示为sdb,下面均以此进行说明;
分区设置:
准备SD卡并按要求分区,空间划分参考下表:
start sector size usage
0KB 0 8KB Unused, available for an MBR or (limited) GPT partition table
8KB 16 32KB Initial SPL loader
40KB 80 Max 984KB U-Boot
1MB 2048
bootfs and rootfs
下面是在Ubuntu终端中进行分区划分示例:
如果已经分过区了那么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
分块烧录:
u-boot:
u-boot-sunxi-with-spl.bin 文件需要放置在SD卡8k开始的位置上:
cd ~/f1c100s-sdk/u-boot/
sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8
linux & dtb & boot.scr
这三个放在刚才新建的第一个分区里(sdb1):
#如果分区已挂载到别的地方先进行卸载
sudo umount /dev/sdb1
#将分区挂载到 /mnt
sudo mount /dev/sdb1 /mnt
#拷贝linux和dtb
cd ~/f1c100s-sdk/linux/
sudo cp arch/arm/boot/zImage /mnt/
sudo cp arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dtb /mnt/
#拷贝boot.scr
cd ~/f1c100s-sdk/u-boot/
sudo cp boot.scr /mnt/
#保存退出
sync
sudo umount /dev/sdb1
rootfs:
这个放在刚才新建的第二个分区里(sdb2):
#如果分区已挂载到别的地方先进行卸载
sudo umount /dev/sdb2
#将分区挂载到 /mnt
sudo mount /dev/sdb2 /mnt
#解压并拷贝rootfs
cd ~/f1c100s-sdk/buildroot-2022.02/
sudo tar -xf output/images/rootfs.tar -C /mnt/
#保存退出
sync
sudo umount /dev/sdb2
测试程序:
#如果分区已挂载到别的地方先进行卸载
sudo umount /dev/sdb2
#将分区挂载到 /mnt
sudo mount /dev/sdb2 /mnt
#拷贝helloworld
cd ~/f1c100s-sdk/helloworld/
sudo cp helloworld /mnt/root/
#保存退出
sync
sudo umount /dev/sdb2
系统烧录(SPI FLASH 16M)
Flash分区:
分区序号 分区大小 分区作用 地址空间及分区名
mtd0 1MB spl+uboot 0x0000000-0x0100000 : “uboot”
mtd2 64KB dtb文件 0x0100000-0x0110000: “dtb”
mtd2 4MB linux内核 0x0110000-0x0510000 : “kernel”
mtd3 剩余 根文件系统 0x0510000-0x0c00000 : “rootfs”
mtd4 剩余 用户区 0x0c00000-0x1000000 : “user”
烧录前要进入fel模式,然后进行程序下载;
烧录文件准备:
只有根文件系统烧录文件与TF卡的不同,其他文件均相同;
准备根文件系统,生成rootfs.img镜像文件:
1、新建一个目录make_rootfs(这个目录随便找一个路径放就可以了),拷贝rootfs.tar到make_rootfs目录下。
2、使用命令解压:
tar -xf rootfs.tar
然后删除压缩包:
rm -rf rootfs.tar
3、回到上级目录make_rootfs:
cd ../
4、然后使用命令生成rootfs.img:
mkfs.jffs2 -s 0x100 -e 0x10000 -p 0x6F0000 -d rootfs/ -o rootfs.img
说明:(0x10000:块擦除大小),(0x6F0000:分区的大小);
5、mtd-utils安装:
此步骤是上一步制作根文件系统的命令没有的前提下进行的;
安装mkfs.jffs2工具:
sudo apt-get install mtd-utils
烧录命令:
清空flash,进入FEL模式:
sf probe 0
sf erase 0 0x100000 #清空flash
reset #即可重新进入fel模式
烧录u-boot
sudo sunxi-fel -p spiflash-write 0 ./u-boot-sunxi-with-spl.bin
烧录kernel
sudo sunxi-fel -p spiflash-write 0x0110000 ./zImage
烧录dtb
sudo sunxi-fel -p spiflash-write 0x0100000 ./suniv-f1c100s-licheepi-nano.dtb
烧录rootfs
sudo sunxi-fel -p spiflash-write 0x0510000 ./rootfs.img
烧录userfs
说明:这个是个人创建的文件系统,该分区如果不需要可以不烧了;
sudo sunxi-fel -p spiflash-write 0x0c00000 userfs.img
U-boot中启动系统:
sf probe 0 50000000
sf read 0x80C00000 0x100000 0x10000 #加载dtb设备树
sf read 0x80008000 0x110000 0x400000 #加载内核
bootz 0x80008000 - 0x80C00000
setenv bootcmd 'sf probe 0 50000000; sf read 0x80C00000 0x100000 0x10000; sf read 0x80008000 0x110000 0x400000; bootz 0x80008000 - 0x80C00000'
saveenv
U-boot中sf命令用法:
sf read用来读取flash数据到内存;
sf write写内存数据到flash;
sf erase 擦除指定位置,指定长度的flash内容, 在进行写flash的时候一定要先进行擦除,否则会失败,因为flash只能从1变为0;
具体用法:
sf - SPI flash sub-system
Usage:0
sf probe [[bus:]cs] [hz] [mode] - init flash device on given SPI bus
and chip select
sf read addr offset len - read `len' bytes starting at
`offset' to memory at `addr'
sf write addr offset len - write `len' bytes from memory
at `addr' to flash at `offset'
sf erase offset [+]len - erase `len' bytes from `offset'
`+len' round up `len' to block size
sf update addr offset len - erase and write `len' bytes from memory
at `addr' to flash at `offset'
示例:
连接flash:
sf probe 0
在使用sf的其他命令之前必须先进行此操作进行连接flash;
写flash:
sf write 0x82000000 0x8000 0x20000
把内存0x8200 0000处的数据, 写入flash的偏移0x80000, 写入数据长度为0x20000(128KB), 操作偏移和长度最小单位是Byte;
读flash:
sf read 0x82000000 0x10000 0x20000
把flash偏移0x10000(64KB)处, 长度为0x20000(128KB)的数据, 写入到内存0x82000000, 操作偏移和长度最小单位是Byte;
擦除flash:
sf erase 0x0 0x10000
擦除偏移0x0处, 到0x10000之间的擦除块, 擦除操作是以erase block为单位的, 要求offset和len参数必须是erase block对齐的;
sunxi-fel工具的使用:
安装:
git clone -b f1c100s-spiflash https://github.com/Icenowy/sunxi-tools.git
cd sunxi-tools
make && sudo make install
sudo apt install pkg-config
sudo apt install pkgconf
sudo apt-get install zlib1g-dev
sudo apt-get install libusb-1.0-0-dev
用法:
Usage: ./sunxi-fel [options] command arguments... [command...]
-h, --help Print this usage summary and exit
-v, --verbose Verbose logging
-p, --progress "write" transfers show a progress bar
-l, --list Enumerate all (USB) FEL devices and exit
-d, --dev bus:devnum Use specific USB bus and device number
--sid SID Select device by SID key (exact match)
spl file Load and execute U-Boot SPL
If file additionally contains a main U-Boot binary
(u-boot-sunxi-with-spl.bin), this command also transfers that
to memory (default address from image), but won't execute it.
uboot file-with-spl like "spl", but actually starts U-Boot
U-Boot execution will take place when the fel utility exits.
This allows combining "uboot" with further "write" commands
(to transfer other files needed for the boot).
hex[dump] address length Dumps memory region in hex
dump address length Binary memory dump
exe[cute] address Call function address
reset64 address RMR request for AArch64 warm boot
memmove dest source size Copy bytes within device memory
readl address Read 32-bit value from device memory
writel address value Write 32-bit value to device memory
read address length file Write memory contents into file
write address file Store file contents into memory
write-with-progress addr file "write" with progress bar
write-with-gauge addr file Output progress for "dialog --gauge"
write-with-xgauge addr file Extended gauge output (updates prompt)
multi[write] # addr file ... "write-with-progress" multiple files,
sharing a common progress status
multi[write]-with-gauge ... like their "write-with-*" counterpart,
multi[write]-with-xgauge ... but following the 'multi' syntax:
addr file [addr file [...]]
echo-gauge "some text" Update prompt/caption for gauge output
ver[sion] Show BROM version
sid Retrieve and output 128-bit SID key
clear address length Clear memory
fill address length value Fill memory
spiflash-info Retrieves basic information
spiflash-read addr length file Write SPI flash contents into file
spiflash-write addr file Store file contents into SPI flash
示例:
烧录文件到FLASH:
sudo sunxi-fel -p spiflash-write 0 Your-Flash-BIN
烧录到RAM中:
sudo sunxi-fel uboot u-boot-sunxi-with-spl.bin
检测usb设备:
$: sudo sunxi-fel -l
USB device 002:005 Allwinner F1C100s
列出设备信息:
$:
AWUSBFEX soc=00001663(F1C100s) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000
F1C100S GPIO操作:
#使用sysfs操作GPIO的例子:
echo 192 > /sys/class/gpio/export #导出 PG0, GREEN
ls /sys/class/gpio/
export gpio192 gpiochip0 unexport
ls /sys/class/gpio/gpio192/
active_low direction subsystem/ value device/ power/ uevent
echo "out" > /sys/class/gpio/gpio192/direction #设置为输出
echo 0 > /sys/class/gpio/gpio192/value #亮灯
echo 1 > /sys/class/gpio/gpio192/value #灭灯
echo "in" > /sys/class/gpio/gpio192/direction #设置为输入
cat /sys/class/gpio/gpio192/value #读取电平
0
引脚计算规则:
在Linux中,GPIO 使用0~MAX_INT之间的整数标识。 对于32位CPU,每组GPIO 32个,引脚号就是按顺序排列。 从PA0开始gpio是0,那么PE3对应是32*4+3=131,经试验已验证;
这个板子是PE12引脚为LED引脚,故:
PIN_{num}=32\times4+12=140 故点灯的脚本如下:
echo "out" > /sys/class/gpio/gpio140/direction #设置为输出
#死循环
while true
do
echo 0 > /sys/class/gpio/gpio140/value
echo "点亮"
sleep 0.1
echo 1 > /sys/class/gpio/gpio140/value
sleep 0.1
echo "熄灭"
done
Linux取消开机登录输入账户密码:
找到 /etc/inittab 文件的:
console::respawn:/sbin/getty -L console 0 vt100 # GENERIC_SERIAL
修改为:
console::respawn:-/bin/sh
重启后就没有恼人的 login 提示了;