找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 803|回复: 0

【嵌入式】折腾荔枝派Nano的SPI-FLASH Linux(u-boot篇)

[复制链接]

1111

主题

1651

回帖

7万

积分

用户组: 管理员

一只技术宅

UID
1
精华
244
威望
743 点
宅币
24241 个
贡献
46222 次
宅之契约
0 份
在线时间
2297 小时
注册时间
2014-1-26
发表于 2022-12-9 10:07:07 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×

折腾荔枝派Nano的SPI-FLASH Linux(u-boot篇)

为了实现我的个人项目——“单片机”解H.264并用320x240 SPI屏幕显示,在各路大佬的讨论之下,大家都建议我使用 全志F1C100s 来实现这一目标。

当然也有大佬告诉我说 h264的话f1c100s基本没用。复杂的解不出来简单的卡。 但我觉得无所谓。我已经有好几个亲戚朋友预订了我的单片机小电视,他们并不在乎卡顿,而我只需要给他们封装一个FFmpeg的GUI,作为给他们使用的PC端软件,自动帮我生成“简单的”H.264视频,然后让他们复制到TF卡里,能出一个大致会动的图像就行。

顺带一提,虽然但是,我知道 F1C100s 不是单片机,而是 SoC(System on Chip)。

网上搜了一堆教程,发现一个共同点

那就是:你需要以下这几件套:

这几个东西从目录树上来看,都长得像 Linux,每一个都包含 Linux 里面提取出来的代码,或者干脆就是 Linux 的代码;每一个都需要使用一个make menuconfig的命令,冒出一个灰蓝灰蓝的文本菜单用于配置各项参数。它给我一种感觉:我使用一个 Linux 来 boot 另一个 Linux,然后这个 Linux 被用来 boot 我的第三个 Linux,而我的第三个 Linux 它有文件系统和 shell,我可以弄自己的脚本,从而让“单片机”能运行我自己的东西了。我需要在仅有的 16 MB SPI-FLASH 里面部署三个 Linux,感觉十分奇怪。

网友 大能猫 告诉我第一个主要用于 boot,它编译出来的体积能降低到 1 MB 以内,甚至 250 KB。第二个是 Linux 内核提供驱动,它提供你的“单片机”的外设 API,第三个是应用层的东西,有文件系统,你写脚本。

我总觉得这三个干嘛不合三为一呢,这真是奇怪。但我只是想想而已,谁提出想法谁去实践。所以只能是我提出想法后我自己去实践。呃!懒得弄了。

某“保姆级教程”看起来不错,我决定照着他说的做

保姆级教程链接:https://whycan.com/t_7558.html

分区规划

分区序号        分区大小                分区作用        地址空间及分区名
mtd0        1MB (0x100000)      spl+uboot   0x0000000-0x0100000 : “uboot”
mtd1        64KB (0x10000)      dtb文件       0x0100000-0x0110000 : “dtb”
mtd2        4MB (0x400000)      linux内核 0x0110000-0x0510000 : “kernel”
mtd3        剩余 (0xAF0000)       根文件系统   0x0510000-0x1000000 : “rootfs”

这个看起来比另一个教程的更合适一些,少了一个overlay的分区,这个overlay分区看起来是为了存储WiFi相关的内容,而我不需要WiFi。

顺带一提,官方教程和这个保姆级教程的环境是 Ubuntu。但我更想在 WSL2 Debian 的环境下进行编译,因为我可以使用 Windows 的文本编辑器来修改各种需要修改的部分,操控性更好一些。虽然 sunxi-fel 的 Linux 版不能在 WSL2 里面进行 USB 的读写,但有 sunxi-fel.exe 这个 Windows 版的工具(使用mingw32-w64编译)。我选择使用 sunxi-fel.exe 来进行 SPI-FLASH 的烧写。

在 Windows 下你需要在使用 sunxi-fel.exe 之前,先使用 http://zadig.akeo.ie/ 提供的工具找到你的 Allwinner Soc in FEL mode 设备,给它安装一个 WinUSB 的驱动,你才能进行烧写,否则你会看到ERROR: Allwinner USB FEL device not found!。请看此教程:https://linux-sunxi.org/FEL/USBBoot

另外,你需要你的设备在进入 FEL 模式后,你才能用 sunxi-fel 对其 SPI-FLASH 进行烧写,这里有个捷径:使用一个特殊的TF卡系统,插入即进入 FEL,不用短接 CS 也能进入 USB FEL 模式:

wget https://github.com/linux-sunxi/sunxi-tools/raw/master/bin/fel-sdboot.sunxi
dd if=fel-sdboot.sunxi of=/dev/sdX bs=1024 seek=8 #sdX换成你的TF卡实际设备!

虽然以防万一我还是装了个 Debian 的虚拟机,但根据多次尝试,我发现这个虚拟机主要的优势就是能运行 sunxi-fel 进行直接的烧写(除此以外就是文件系统区分大小写),但需要我设置虚拟机把荔枝派Nano的USB接入虚拟机。虚拟机如果抽风,你就会听到电脑死循环播放“发现新USB设备”和“USB设备断开”的音效,隔壁的无关的 Windows 虚拟机也突然疯狂提示“正在查找新设备”、“正在安装设备驱动”,与此同时虚拟机界面上显示的USB图标也一闪一闪的,看着令人感到血压飙升

那个保姆级教程只告诉你如何配置,却没有告诉你怎么编译

可能保姆大佬觉得这没必要教,make的时候设置CROSS_COMPILE编译工具前缀就行了。

但这样就不够保姆了。所以我决定一边抄它那个教程,一边补充一些内容。

u-boot 配置

先安装必要的工具:(这个里面没有多余的库,缺一不可)

sudo apt-get install git build-essential swig libncurses-dev python2 python-dev device-tree-compiler

下载 u-boot 的荔枝派Nano分支。注意:这里使用nano-lcd800480的分支,和保姆式教程不同。

git clone https://gitee.com/LicheePiNano/u-boot.git -b nano-lcd800480

打开配置菜单。

cd u-boot
make licheepi_nano_spiflash_defconfig
make menuconfig

原“保姆级教程”里提到的设置引导命令参数的

  • Enable a default value for bootcmd
  • Enable boot arguments已经不再需要去设置了。因为在nano-lcd800480这个分支,这些引导参数的内容已经被RobotFly加入到include/configs/suniv.h文件里:

    #define CONFIG_BOOTCOMMAND   "sf probe 0 50000000; " \
                         "sf read 0x80C00000 0x100000 0x4000; " \
                         "sf read 0x80008000 0x110000 0x400000; " \
                         "bootz 0x80008000 - 0x80C00000"

    所以已经不需要自己再把这个东西再设置一遍了。

    nano-lcd800480分支里xt25f128b已经被加入到设备树里,无需修改设备树

    原“保姆级教程”里提到你需要把xt25f128b加入到设备树里使 SPI-FLASH 得到支持,但nano-lcd800480分支已经把它加入了进去。

    编译 u-boot

    make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j

    你的编译不会顺利通过。因为你会遇到YYLTYPE yylloc;重定义的问题。所以其实你不必现在就急着编译,而是先看下面的章节,处理这些问题后再用上面的命令进行编译。

    删除YYLTYPE yylloc;这句bug代码

    scripts/dtc/dtc-lexer.lex.l 源码文件里有一句YYLTYPE yylloc;这一句是一个 bug 代码,要把它删掉。同样,scripts/dtc/dtc-lexer.lex.c_shipped里面的YYLTYPE yylloc;也要删掉。

    我曾怀疑是gcc版本太高的缘故,因为官方“初体验”教程推荐的是 gcc-7 而且直接提供了编译好了的 gcc-7 的 bin,下载后配置PATH即可使用。官方教程原文是用 wget 下载一个 gcc 的 bin,然后解压到 /opt 里面,再在.bashrc里设置 PATH,这对于我而言,是一种往看不到的地方拉屎的行为,令我感到十分不舒服,因为以后如果忘记了今天的这一操作,那就一辈子只能用这个被遗忘的 gcc-7 了。时间一长,可能连硬盘是怎么被用掉的都忘了。于是我把这个 gcc-7 解压到工作目录下,写了个 bash 负责临时设置 PATH。把屎拉在看得到的地方令我感到舒适。试了一下 gcc -v 它的输出没有问题。但好像其实不需要装 gcc-7。官方说“此处为获取7.2.1版本,您可获取其他版本或者通过链接直接下载。”

    实际上,gcc-10默认开启-fno-common编译选项,而旧gcc则默认开启-fcommon选项。其中,-fcommon使gcc自动合并不同的编译单元导出的同名的全局变量,而-fno-common则是一种语法严谨的设计,会告诉你“符号冲突”从而让链接器在lto过程中拒绝生成代码。合理的做法是把scripts/dtc/dtc-lexer.lex.lscripts/dtc/dtc-lexer.lex.c_shipped的bug代码删掉,然后使用 gcc-10 编译,而非改用旧gcc或者使用-fcommon选项。

    删除scripts/Makefile.lib第321行的多余的转义符号

    当上面那个bug问题解决后,我还在make的时候遇到了另一个bug问题:

      LD      u-boot
      OBJCOPY u-boot-nodtb.bin
      OBJCOPY u-boot.srec
      SYM     u-boot.sym
      DTC     arch/arm/dts/suniv-f1c100s-licheepi-nano.dtb
    Error: arch/arm/dts/.suniv-f1c100s-licheepi-nano.dtb.pre.tmp:59.1-10 syntax error
    FATAL ERROR: Unable to parse input tree

    检查得知生成的 .suniv-f1c100s-licheepi-nano.dtb.pre.tmp 最后一行竟然出现了一个反斜杠:

    ...
    &usbphy {
        usb0_id_det-gpio = <&pio 4 2 GPIO_ACTIVE_HIGH>; /* PE2 */
        status = "okay";
    };
    \#include "sunxi-u-boot.dtsi"

    在经过各种“文件内查找”后,我终于找到了.suniv-f1c100s-licheepi-nano.dtb.pre.tmp的来源,在scripts/Makefile.lib里面第321行

    (cat $<; $(if $(u_boot_dtsi),echo '\#include "$(u_boot_dtsi)"')) > $(pre-tmp); \

    可以看到里面多了个转义符号。将其删除,得到以下的正确代码:

    (cat $<; $(if $(u_boot_dtsi),echo '#include "$(u_boot_dtsi)"')) > $(pre-tmp); \

    然后删除.suniv-f1c100s-licheepi-nano.dtb.pre.tmp并重新编译。

    u-boot的编译需要你的python命令是python2

    很坑爹吧!你需要使用update-alternatives来切换你的默认python命令的版本:

    sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 3
    sudo update-alternatives --install /usr/bin/python python /usr/bin/python2 2
    sudo update-alternatives --config python

    运行后,它提示如下:

    There are 2 choices for the alternative python (providing /usr/bin/python).
    
      Selection    Path              Priority   Status
    ------------------------------------------------------------
    * 0            /usr/bin/python3   3         auto mode
      1            /usr/bin/python2   2         manual mode
      2            /usr/bin/python3   3         manual mode
    
    Press <enter> to keep the current choice
  • , or type selection number:
  • 要选择python2,需要输入1,然后按下回车。作为 python 用户,我实在接受不了自己的默认 python 变成了2,这种难受的感觉堪比你的 vcxproj 文件被 VC6 关联、CMD、BAT 批处理被 git bash 关联了一样难受。

    试了一下发现这样不行,因为我有安装过pyenv,所以update-alternatives不起作用(它让/usr/bin/python变为一个符号链接来指定你的python版本,但pyenvpython命令变为/home/username/.pyenv/shims/python)。于是只好用最简单粗暴的办法:

    alias python=python2

    重新编译时这个问题解决。

    就快要编译成功了,结果提示:No rule to make target 'checkarmreloc', needed by 'all'.  Stop.

    我在顶层Makefile里发现了checkarmreloc: u-boot这句。它依赖u-boot文件,而这个文件也确实存在,为什么就 No rule to make target 了呢?

    网上搜到似乎和荔枝派 Nano 毫无关系的内容:“如何移植u-boot”。发现搜到的内容套用到荔枝派 Nano 似乎有效。

    打开u-boot/arch/arm/Kconfig,找到config ARCH_SUNXI,在下面插入一行select SUPPORT_SPL

    然后重新编译。

    如何重新编译

    每次编译时,若遇到bug问题停止了编译,在修改了bug文件后,应当运行make clean来删除编译过程中产生的中间文件,然后重新运行make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j来编译,以确保你对bug文件的修改能产生效果。make clean会提示“无法删除SPL,它是个目录”。此时你可以手动把u-boot的spl目录删除,再重新运行make clean,就可以清理干净,然后重新编译了。

    经过多次编译、一顿操作后,python2无法引用_libfdk的问题依然不好解决

    我选择去世。

    换另一个人的 u-boot 重新试一下编译

    他也是这样配置的三件套:

    这人他对 u-boot 做了这样的处理:和我之前一样删除了多余的YYLTYPE yylloc;声明,将 SPI FLASH xt25f128b加入到驱动里。但他还做了更多、更细致的修改,比如把各种 sunxi 外设驱动和寄存器加入了进去,把 MMC 加入到了设备树里、设置启用了 MMC,以及修复了原有 u-boot 的若干问题。他其实是直接从 u-boot/u-boot fork 过来后进行修改,而我则是拿 LicheePiNano/u-boot 来用,还发现不那么好用。

    未完待续。

  • 回复

    使用道具 举报

    QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

    GMT+8, 2024-4-24 21:22 , Processed in 0.047052 second(s), 32 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表