使用F1C200S从零制作掌机之u-boot移植

1 参考网址

小白自制Linux开发板
一. 瞎抄原理图与乱画PCB
二. u-boot移植
三. Linux内核与文件系统移植
四. 通过SPI使用ESP8266做无线网卡
五. Debian文件系统制作,以及WIFI配置、交换分区配置
六. SPI TFT屏幕修改与移植
七. USB驱动配置
八. Linux音频驱动配置
九. 修改开机Logo
十. NES游戏玩起来

SIPEDD WIKI: https://en.wiki.sipeed.com/soft/Lichee/zh/Nano-Doc-Backup/get_started/first_eat.html
外国大神自制名片: https://www.thirtythreeforty.net/posts/2020/01/mastering-embedded-linux-part-3-buildroot/

https://www.cnblogs.com/yanye0xcc/p/16341719.html

https://linux-sunxi.org/Bootable_SD_card

https://linux-sunxi.org/Main_Page

https://linux-sunxi.org/F1C100s

2 概念

BootLoader启动过程可分为单阶段和多阶段(stage1、stage2),其中stage1完成初始化硬件,如CPU寄存器、内存控制器,为stage2准备内存空间。一般stage1是可以直接在nor flash中运行的,并将stage2复制到内存RAM中,设置堆栈,然后跳转到stage2(从这也可以看出stage2是在RAM中运行的,与stage1不同)

Boot Parameters顾名思义,就是配置了要启动内核的参数,包含要加载系统内核相关文件的位置,要加载到内存中的位置,定位到文件系统的位置,相关输入输出的呈现等一系列参数。

kernel在存放在bootloader之后,对于SoC来说,代码都需要在RAM中运行,这里与MCU不一样的地方就是引入了MMU(内存管理单元)。对于MCU而言,由于其执行速度低,因此运行代码都在ROM中直接运行,而对于Flash而言,其读取速度远不及RAM的速度,因此对于运行速度非常快的SoC而言,所有的代码都需要在RAM中运行。但是这里有一个问题,RAM掉电数据将会丢失,故代码保存不可能放在RAM中,当前所有的嵌入式设备而言,代码保存都是放在ROM中,因此在SoC中运行代码需要将代码搬运到RAM中然后再执行。

Root Filesystem由于其执行过程需要对ROM进行读写操作,因此可以不用搬运到RAM中,但是实际过程中内核启动后会产生一个虚拟的文件系统,该文件系统是挂在根文件系统的关键所在,这里不详细讲解。整体来说,大致的过程为,嵌入式设备上电后将执行bootloader,对硬件进行硬件和堆栈初始化,然后搬运内核到RAM中并启动内核,紧接着挂载根文件系统。

bootcmd主要用于描述控制Linux内核文件以及其他描述文件加载到内存中位置以及启动Linux内核系统等

bootargs用于配制文件系统、串口信息等。

3 f1c100s 特性

  • F1c100s/F1c200s,100s内置32MB DDR1内存,200s内置64MB DDR1内存,200s贵一点,他们都是QFN88封装。
  • ARM926ejs内核,主频默认408MHz,据了解做产品出货的一般在600M左右。
  • 带有100M的SPI接口2个,SDIO接口1个,USB OTG接口,还有CSI摄像头接口,LCD RGB显示屏接口,音频接口,I2C I2S UART PWM等等。
  • 还有就是他们不支持硬件浮点,所以浮点运算使用软浮点方式。

4 问题

linux卡片机:u-boot编译烧录。https://zhuanlan.zhihu.com/p/652556669

4.1 启动流程?

4.2 uboot地址

img

这里的启动流程图是全志V3S的,F1C200S/F1C100S用户手册中并没有相关说明,启动顺利都是一样的

\1. 上电后, f1c100s内部BROM(芯片内置,无法擦除)启动
\2. 首先检查 SD0有没有插卡, 如果有插卡就读卡8k偏移数据,是否是合法的启动数据, 如果是BROM引导结束, 否则进入下一步
\3. 检测SPI0 NOR FLASH(W25QXXX, MX25LXXX) 是否存在, 是否有合法的启动数据, 如果是BROM引导结束, 否则进入下一步
\4. 检测SPI0 NAND FLASH是否存在, 是否有合法的启动数据, 如果是BROM引导结束, 否则进入下一步
因为找不到任何可以引导的介质,系统进入usb fel模式, 可以用USB烧录了。

根据上面这些内容,我们知道F1C200s启动的时候会优先去SD08k偏移处读取数据,所以需要我们把uboot写入到sd8k偏移处即可被正常读取。

序号启动介质注意事项
1stMicroSD Card/eMMC只支持PF0 ~ PF5这六个脚复用为SDC0启动, 控制器支持到SD2.0和eMMC4.41,设备端可以使用主流的eMMC5.1(eMMC存储器可以向前兼容)
2ndSPI Nor/Nand Flash只支持PC0 ~ PC3这四个脚复用为SPI0启动, 支持标准SPI和DOUT模式, BROM启动时SPI Nand固定为1024字节/页,SPI Nor无特殊限制
3rdBROM FEL Mode以上介质都无启动代码时,自动运行芯片内部USB程序(FEL Mode)(USB Full-Speed@12Mbps),USB脚是固定的无其它复用功能
SDC0启动

硬件连线使用以下引脚,BootROM读取eMMC或SDCard中的SPL程序时,只使用了1bit-sdio,且最大速度限制在25MHz,因此正常启动最少需要接CMD、CLK、D0这三根线;
但eMMC或SDCard在启动完成后还可作为应用程序的存储器,为了提升传输速度建议CMD、CLK D0~D3这6根线都接上,F1C100S的SDIO控制器最大支持SDR-4bit@50MHz。

img

通过逻辑分析仪抓取BootROM读取eMMC中的SPL程序的过程,可以看到只使用了1bit模式。

img

SPL程序需要从eMMC UDA物理分区的第16个扇区(512字节/扇区)开始烧录,下图是eMMC UDA物理分区内的布局图:
前8KB(扇区0 ~ 扇区15)存放MBR分区表或者非标准的GPT分区表,扇区16开始存放SPL程序,BROM将从这里读取程序到SRAM并执行,扇区80开始可以存放用户的程序,如果是启动linux,这里可以存放uboot,如果是嵌入式系统或者裸机,这里直接存放应用程序。

img

SPI0启动

标准的4线SPI接口,最大速度是AHB总线时钟的2分频,AHB通常设置为200MHz,因此SPI的时钟最大为100MHz。
BootROM加载SPL程序时默认使用标准SPI,具体时钟速度忘记了,大概10MHz以内,这段启动时间是无法优化的。
SPL启动后,加载用户程序时,推荐使用DOUT模式,用带宽换时钟,降低SPI布线要求,100MHz的SPI读写Flash实测不是很稳定。

img

nor-flash和nand-flash需要从物理0地址(0号扇区0地址)开始烧录SPL程序。

img

spi nor-flash直接使用sunxi-fel工具烧录

img

spi nand-flash有一个改版的sunxi-fel工具可用,目前大部分的spi nand-flash都是4K/扇区的,烧录的时候每扇区只使用前1K,剩下的空着(spi nand启动还未测试过)。

USB启动

当SDC0,SPI0都没有读取到SPL程序时,自动运行芯片固化的USB程序(FEL),此时可以通过该程序提供的API,通过USB对芯片下载程序或执行ARM汇编代码。

img

在usb-fel模式下,usb接口默认是全速的(12Mbps),F1C100S的usb也支持高速模式(480Mbps),因此在USB端口的ESD二极管等效电容尽可能小,推荐使用5pF左右的。
windows下需要使用zadig安装winusb(libusb)驱动,然后才能使用sunxi-fel工具进行nor-flash烧录,发送程序到DRAM执行等。

img

4.3 Linux地址

boot分区

4.4 dts

boot分区

5 交叉编译器工具

交叉编译器F1C200S必须高于6.0版本,这里我们使用7.2版本

#下载完成后解压文件
tar -vxJf gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz
#然后在/usr/local目录下新建arm-linux-gcc目录
sudo mkdir /usr/local/arm-linux-gcc
#进入解压目录下:
cd gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi/
#将该目录下的所有文件复制到新建的目录下
sudo cp -rd * /usr/local/arm-linux-gcc/
#最后需要添加该工具链的环境变量使其可以在任何目录下执行,打开/etc/profile文件
sudo nano /etc/profile
#在文件末尾添加以下内容
PATH=$PATH:/usr/local/arm-linux-gcc/bin
#添加完毕,使路径生效
source /etc/profile
#接下来在终端输入:
arm-linux-gnueabi-gcc -v
#安装动态链接库
sudo apt-get install lib32ncurses5 lib32z1

img

6 u-boot

最新版本的uboot几乎包含当前主流的SoC芯片,前面提到本开发板使用的芯片和licheePI nano相同,大部分硬件也是兼容的,为了快速移植该部分,这里采用licheePI nano的u-boot来进行移植。

#在终端输入如下命令克隆u-boot:
git clone https://gitee.com/LicheePiNano/u-boot.git
#克隆完毕文件会保存在当前目录下,进入该目录,
cd u-boot
#在该文件夹下有很多分支,我们可以查看所有分支,使用如下命令:
git branch -a
#现在我们使用的是nano开发板,所以将当前分支切换到nano分支,命令如下:
git checkout nano-v2018.01

默认的没有指定交叉工具链和架构,因此在编译之前需要指定交叉工具链和芯片架构,u-boot的交叉编译器在u-boot 的根目录下中的Makefile文件中定义了。打开文件找到CROSS_COMPILE变量,修改为如下:

ARCH=arm
CROSS_COMPILE=arm-linux-gnueabi-

在u-boot项目的config目录下存在对多种板子的配置描述文件,由于每个板子的外设不同,因此编译之前必须要对u-boot进行配置。然而配置是一件比较繁琐的事情,特别是像u-boot这种比较复杂的项目而言,初学者几乎无法完成。幸运的是对于大部分开发板而言,config目录下有其配置好的默认配置文件。进入config目录中,然后执行ls查看当前所有的配置文件

cd configs
ls

img

找到licheepi_nano_defconfig 和 licheepi_nano_spiflash_defconfig,前者表示为TF卡启动,后者表示从SPI 设备启动,因为我们做的小板只有从TF卡启动,所以我们需要使用 licheepi_nano_defconfig。

现在回到上级目录,把licheepi_nano_defconfig 作为默认配置项。

make licheepi_nano_defconfig
sudo apt-get install build-essential
sudo apt-get install make
sudo apt-get install libncurses5-dev

图形界面进行配置

make menuconfig

img

6.1 bootcmd

在最开始提到过,内核一般不在flash中运行,这样就需要将内核搬运到内存中,这个过程需要u-boot来完成。对于mmc (TF卡)而言,在u-boot有专门的命令load mmc,该命令可以将mmc中的代码从flash搬运到指定的地址处。

当u-boot中环境变量bootdelay计数到0时,此时uboot就会开始执行bootcmd中的命令。

bootdelay这个环境变量是一个计数器,当u-boot主体运行完毕后,此时bootdelay该变量的值将会开始递减,递减时间为1s,当递减到0时,此时u-boot将会跳转到bootcmd处开始执行bootcmd命令,(你可以简单理解为PC启动后有一两秒时间等待,你可以可以通过F8或Enter键打断进入Bios设置的过程,这个等待时间就由u-boot中的bootdelay来控制)。

下面我们需要记住这句指令,这就是我们当前制作的开发板需要用到的bootcmd全部内容

load mmc 0:1 0x80008000 zImage;load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;bootz 0x80008000 - 0x80c08000;

对于上面命令,我们根据分号拆分为3部分:

1> load mmc 0:1 0x80008000 zImage;
2> load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;
3> bootz 0x80008000 - 0x80c08000;

其中两个 load mmc 命令、一个bootz 命令。

先看第一条:

load mmc 0:1 0x80008000 zImage

load mmc有三个参数:第一个参数是mmc(TF卡)分区,第二个参数是内存中目标地址,第三个参数是源文件。

即上面的命令意思是将mmc的0:1 分区中的zImage复制到内存中的0x80008000地址处。这里的zimage就是Linux内核,后续会提到该文件编译,0:1这个可以这样理解0表示TF卡(TF卡属于mmc存储器的一种),1这表示TF卡的第一个分区(boot分区)后面会提到。

而对于内存位置 0x80008000 地址位置,将其理解为默认值就行了。这样完成了zImage的加载。

下面分析第二条命令:

load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb

有了上面的加载zImage的说明,可以很轻松的理解上面的命令意思是将mmc的0:1分区中的suniv-f1c100s-licheepi-nano.dtb文件加载到内存中的0x80c08000地址处。对于suniv-f1c100s-licheepi-nano.dtb 这个文件,叫做设备树文件,简单来说就是当前开发板上面所有外设备描述文件,这部分将会在后续内核编译部分进行详细说明。

对于第三条命令:

bootz 0x80008000 - 0x80c08000

的意思是告诉内核镜像的起始地址为0x80008000,加载的设备树地址为0x80c08000。这里是告诉cpu从这里开始启动Linux, bootz命令的格式是:bootz空格0x80008000空格-空格0x80c08000, 注意-左右有空格。

除了bootz命令外,有些系统里面还可能存在一个叫做bootm命令,这是是对没有使用设备树内核的镜像启动命令,早期版本的内核没有引入设备树,因此对于早期的内核一般使用的是bootm,其命令格式为bootm内核地址,比如bootm x0x30008000,意思是从0x30008000开始启动内核,启动内核的过程其实是将pc指针指向该地址,这样处理器就会从该地址处运行代码。

这里我们就完成了bootcmd的说明,接下来我们看另外一个参数。

6.2 bootargs

bootargs也是u-boot环境变量中一个非常重要的变量,上面已经讲解了内核的启动可以通过bootcmd来完成,那接下来内核启动完毕后必须挂在根文件系统(rootfs)。但是内核并不知道根文件系统的具体位置,我们必须要告诉根文件的位置后内核才能将其挂载,这时就需要有bootargs变量。该变量的作用是告诉内核根文件系统的位置和属性以及必要的配置,

console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 earlyprintk rw

同上面分析的方法一样,我们依然将这部分命令拆成几部分来说明。这里需要说明的是,这部分配置信息是由u-boot 直接按照参数字符串方式提供给Linux内核,然后由Linux内核进行执行的,这也说明里为什么格式与bootcmd配置方式不一致。

console=ttyS0,115200 表示终端为ttyS0即串口0,波特率为115200;

panic=5 字面意思是恐慌,即linux内核恐慌,其实就是linux不知道怎么执行了,此时内核就需要做一些相关的处理,这里的5表示超时时间,当Linux卡住5秒后仍未成功就会执行Linux恐慌异常的一些操作。

rootwait 该参数是告诉内核挂在文件系统之前需要先加载相关驱动,这样做的目的是防止因mmc驱动还未加载就开始挂载驱动而导致文件系统挂载失败,所以一般bootargs中都要加上这个参数。

root=/dev/mmcblk0p2 表示根文件系统的位置在mmc的0:2分区处,/dev是设备文件夹,内核在加载mmc中的时候就会在根文件系统中生成mmcblk0p2设备文件,这个设备文件其实就是mmc的0:2分区(这里对应TF卡的第二个分区:rootfs),这样内核对文件系统的读写操作方式本质上就是读写/dev/mmcblk0p2该设备文件。

earlyprintk 参数是指在内核加载的过程中打印输出信息,这样内核在加载的时候终端就会输出相应的启动信息。

rw表示文件系统的操作属性,此处rw表示可读可写。

6.3 u-boot参数配置

load mmc 0:1 0x80008000 zImage;load mmc 0:1 0x80c08000 suniv-f1c100s-licheepi-nano.dtb;bootz 0x80008000 - 0x80c08000;
console=ttyS0,115200 panic=5 rootwait root=/dev/mmcblk0p2 earlyprintk rw

img

6.4 u-boot编译

make -j8
libfdt_env错误,编译的时候需要卸载
sudo apt-get remove libfdt-dev
sudo apt-get install libfdt-dev
sudo ln -sf /usr/bin/python3 /usr/bin/python
sudo apt-get install python3-distutils
sudo apt install python-dev
sudo apt install swig

image-20240312092352277

编译完成后会在当前目录生成u-boot-sunxi-with-spl.bin烧录文件。该文件就是我们最终要烧录的二进制文件。

img

在当前目录下会有一个隐藏的文件.config,该文件是u-boot编译后根据各个选项产生的配置文件,这个配置文件记录了所有配置选项的宏开关,编译的时候是根据最终的.config文件来进行编译的,当然编译前是需要有脚本解析.config文件然后进行相应的编译。

6.5 u-boot烧录

只要将u-boot-sunxi-with-spl.bin烧录到tf卡的8k偏移处地址就可以了,烧录步骤如下:使用dd命令进行块搬移:

sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8

该命令中:

  • if 文件名:输入文件名,缺省为标准输入。即指定源文件。< if=input file >
  • of 文件名:输出文件名,缺省为标准输出。即指定目的文件。< of=output file >
  • bs bytes:同时设置读入/输出的块大小为bytes个字节。
  • seek blocks:从输出文件开头跳过blocks个块后再开始复制。

这里的输出文件(of)为主机电脑的/dev/sdb文件,也就是TF卡,这里也体现了Linux一切皆文件的思想

/dev/sdb 这个可以用gparted 软件查看,该软件可以直接用命令安装即可:

sudo apt-get install gparted

img

打开软件img

在右上角可以看到两个硬盘,/dev/sda 为本地硬盘,/dev/sdb 是我们将要写数据的TF(当然这是自己的配置使然,具体情况请根据实际情况而定),因此这里的of=/dev/sdb 烧录到8k偏移地址处是指绝对地址,这个绝对地址指的是TF卡的物理地址。这8K的值是由F1C200S 中固化的启动代码决定的,所以照抄即可。

sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdb bs=1024 seek=8

img

命令执行完后注意这里是烧写速度,如果是几百MB/s,大概率你烧写出问题了。可能是选择TF卡

6.6 u-boot验证

6.6.1 需要的硬件:
  • 正常退出TF卡
  • Lichee_nano开发板
  • USB线
  • TTL-USB转换模块
6.6.2 调试端口:

使用开发板的串口UART0

6.6.3 连接:

Lichee_nano开发板通过TTL转换模块连接到电脑。

image-20230902073658795

打开MobaXterm,新建串口连接:115200 8 N 1

6.6.3.1 无卡插入,板载flash

打开串口连接的时候可能未必会看到信息,重启,就可以看到如下的输出信息了,这是板载flash内的系统。

image-20230902074054640

这就是u-boot,执行到u-bbot计数完成后会产生错误,那是因为还没有进行系统内核的移植,所以默认就会进入u-boot命令模式

6.6.3.2 插入TF卡
6.6.3.2.1 程序启动流程

image-20230902074724390

6.6.3.2.2 插入TF卡

插入上一步做好的TF卡,打开串口连接的时候可能未必会看到信息,重启,就可以看到如下的输出信息了,这就是u-boot,执行到u-boot计数完成后会产生错误,那是因为还没有进行系统内核的移植,所以默认就会进入u-boot命令模式

输入pri命令打印环境变量的所有值,可以找到已经配置的bootcmd 和bootargs

image-20240326213535334

至此完成了u-boot移植的全部内容,对于u-boot的移植方法,在后续移植Linux内核和文件系统时都会用到,都是大同小异的,所以有了本篇的说明,之后操作将会非常简单。

  • 25
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
F1C200s是一款基于MIPS架构的嵌入式处理器,广泛应用于低功耗、嵌入式设备中。Linux6可以指代Linux内核的第6个主要版本。结合起来,F1C200s Linux6是指在F1C200s处理器上运行的基于Linux内核的操作系统。 F1C200s处理器是一种低功耗的嵌入式处理器,具有良好的性能和功耗比。它可以用于各种类型的嵌入式设备,例如智能家居设备、智能监控摄像头、机器人等。Linux6作为一个成熟、稳定的操作系统内核,可以为F1C200s提供强大的功能和广泛的软件支持。 在F1C200s上运行Linux6可以实现许多功能。首先,它可以为设备提供多任务处理能力,使其能够同时执行多个应用程序。其次,Linux6可以支持多种外设和接口,如USB、SPI、I2C等,使设备能够与其他设备进行通信和交互。此外,Linux6还可以提供网络连接功能,使设备能够与其他设备或互联网进行通信。 从开发者角度来看,使用F1C200s Linux6可以借助丰富的开发工具和应用程序库,轻松开发各种应用程序和驱动程序。同时,由于Linux6是开源的,开发者可以根据自己的需求自由定制和修改内核。 总之,F1C200s Linux6提供了一种强大的嵌入式系统解决方案。它既具有低功耗、高性能的处理器,又支持稳定、成熟的Linux6操作系统。这使得F1C200s Linux6在各种嵌入式设备中得到广泛应用,并为开发者提供了一个灵活且强大的开发平台。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值