【嵌入式】总结——Linux系统移植(二)

        同上一篇,本篇是对这一阶段学习历程的总结,仅作参考

引言

        这算是学习嵌入式Linux的二阶段,这一阶段虽是裸机开发与linux开发的过渡篇,但这一阶段也非常容易劝退。就我个人经验而言,学完裸机驱动后不应该直接看这一阶段的视频教程,因为从裸机驱动开发直接过渡到烧录镜像,这其中缺乏太多前置知识,导致学的过程中不解其意,只晓得盲目跟做却难以独自动手实操。不能理解,意味着遗忘。其次是,由于教程发布得较早,教程里的linux源码与现有的开发环境已经有了不少的差距,即便每一步照着视频做,却仍有可能重复不出相同结果。

        就我个人而言,我的首选目标自然是真正能用linux开发出实际的东西,哪怕点个灯。可一直在Makefile里打转,很容易消磨学习热情。至于uboot、linux、根文件系统的修改属于那种听着就像很后期的东西,个人认为本阶段能区分它们并知道怎么移植就行了,且并不适合放在过渡篇,起码应该学了设备树、熟练开发linux驱动后再来学习。

        过渡篇应该简单一点为好,我个人倾向于分为“移植”和“编译”这两步,移植只要能让开发板运行Linux就行了,至于Linux哪来的暂时不用关心。编译呢,能通过就行,不该花费太多精力在这过渡段。

        不过此外还需要学习一下uboot如何ping虚拟机,这里需要补充一些网络工程知识。这是为下一篇Linux驱动开发做准备,这有很多博客可以参考,可自行查找IMX6UL的uboot无法ping主机或Ubuntu

一、移植

1,前置知识

uboot:

        我们要做的事情只有一件——让linux运行在开发板上,那么首先就要知道linux运行在开发板上需要哪些基础条件。

        同时我们知道linux作为一个软件,不可能适配所有设备(不然就违背了精简的原则,变得异常臃肿),那么自然不可能一放到某某设备的内存中就可以运行了;同时linux作为一个操作系统,有着广泛的应用,可以在计算机、嵌入式设备等设备上运行,那意味着有什么东西可以抵消硬件设备的差异性,提供基础条件供linux运行在不同设备上。

        这就引出了一类软件“引导”,引导设备运行操作系统。对于Windows来说,这个“引导”可以是NT Loader或Windows Boot Manager,对于嵌入式Linux来说,这个“引导”可以是uboot,当然这个引导并非是唯一的,有很多选择。

        在这里uboot的主要作用是进行硬件检查、初始化DDR(靠的是imx文件里开头的那3KB)、内核配置等,进行这一系列工作的目的是确保 Linux 能够识别并正确使用开发板上的硬件资源。除此之外,最重要的就是uboot可以辅助调试,同时uboot也是裸机程序,与前面写的点灯实验在本质上并无二致。

        那么这就涉及到了IMX6ULL如何运行程序,这篇博客讲得很详细IMX6ULL启动流程详解

 Linux内核及镜像:

        在此我们先不关心Linux内核怎么来的,我们先考虑怎么用它,而我们所要移植的Linux内核其实一个镜像,那么何为镜像?根据字面意思来解释,就是向照镜子一样把一个存储介质上的数据原模原样地复制到另一个存储介质上,但这样的解释容易让人误解成“镜像对称”什么的。

        其实镜像就是一种存储介质上的物理布局,可以原模原样的把数据复制到不同的存储介质上。那为什么不直接复制呢?直接复制也可以得到原模原样的数据,比如把包含一堆图片的文件夹拷到U盘里。这就牵涉到了文件系统,向SD卡、磁盘这些大容量存储设备上都是有文件系统的,文件系统让这些图片看似排列在一块,其实在物理上的分布并非是连续的,而镜像则是连续的一块布局。

根文件系统:

        说白了就是资源库以供linux调用,此时要注意,我们所说的linux其实是指运行在内存中的那段程序。为了精简以及模块化,linux内核自然不可能包含各种资源文件,这就好比打仗,前线负责打仗需要轻装上阵,后勤需要考虑带上很多东西。

        那为什么是一定是根文件系统呢?其实理论上只要是个文件系统就行了,哪怕你随便往这里塞一些乱七八糟的的文件、文件夹构成了一个“自定义的文件系统”,因为所谓根文件系统其实就是EXT4或别的什么文件格式下的一堆文件。当然由于Linux早已与根文件系统深深绑定,所以哪怕是自定义的文件系统也需要遵循一定的文件系统布局。

        但根文件系统相当于标准库,这里有大量常用的一些资源,好比开发C时你可以选择自己造轮子写一个printf,但直接调用标准库的pirntf显然更好。

 2,SD卡烧录

         补充了一些前置知识后,我们知道想要在开发板上运行Linux需要三个必备的东西uboot、linux内核和根文件系统。那么这三个东西又该如何装载在存储介质上的呢?是压缩在一块还是按照顺序烧录到存储介质上的呢?

镜像布局:

        首先,我们要清楚之所以说存储介质而不是SD卡、EMMC或NAND FLASH等,是因为对于芯片加载程序来说,本质上没有任何区别。

        其次这牵扯到了镜像布局,还不能直接讲如何烧录。那么何为镜像布局呢?

镜像布局你可以简单理解为存储介质按照一定物理布局组织数据形成的排布,下面是援引imx6ull - 制作烧录SD卡_里的图片,可以形象地理解镜像布局,同时博客里面也有细致的烧录SD卡的过程。

        至于这种图哪来的呢?其实它是根据NXP官方给的数据手册里画的,具体可以查看上面那篇博客,总之它有官方背书哈。

        这张图的前面就像之前学的裸机驱动,裸机实验里得到的imx文件存放的位置其实这就这张图里U-boot所在的位置(所以说在本质上,裸机点灯程序与u-boot没有什么区别),并且前面也空了1KB。只不过空了1KB这件事好像没讲,但这个可以到正点原子提供imxdownload的源码里面可以看到,里面会有这样一条如下形式命令

dd if=xxx of=xxx bs=512 seek=2 ...

        bs这个参数表示512为一个扇区,seek=2表示从第二扇区开始烧录,前面正好空了0、1这两个扇区,共1KB

烧录流程:

      OK,现在我们可以回答烧录这个问题了,只要把文件按照NXP要求的布局去烧录到SD卡上,那么开发板就能通过SD卡运行Linux。从图中能看出,我们需要烧录的三样东西有着不同格式,U-boot没有任何格式,也就是说相当于直接把文件顺序烧录到那片区域里,0x400对应的是u-boot.imx的第一个字节,以此类推。

        而内核镜像和Rootfs都是有文件系统的,且格式不同,前面说过有文件系统和没有文件系统是有很大区别的,首先就是文件在物理上的排布情况。然后呢就是识别问题,文件系统是可以直接被识别的,而fats和ext3、ext4也是都能被uboot这个裸机程序识别

        于是呢,制作SD卡烧录这件事就变成了

SD卡分两个区       →→→    把两个区分别设置成指定文件格式  →→→ 

把imx烧录到SD上    →→→    把内核镜像、设备树、根文件系统拷到对应分区

①SD卡分区

     在此之前一定要确保你的SD卡是FAT模式,因为这种模式Linux和Windows都能识别并操作。如果你不确定,那么直接执行格式化

        接下来,先把SD连接到虚拟机,可以通过下面虚拟机右下方这个选项让SD卡快速连接或断开虚拟机。

         然后,给SD卡分区我们需要使用到fdisk这个工具,使用方法很简单,先进入fdisk的窗口,这里我的SD设备是/dev/sdb。进入之后就是下面的界面,这个红字只是提醒你对存储设备的操作要小心,不是报错提示。

sudo fdisk /dev/sdb

        接下来的操作与命令行没有什么区别,也是输入命令。只不过这里我们只需要认识到三个命令就行了分别是n、p、d

                n:即new,创建分区的意思

                p:即print,打印分区的意思

                d:即delete,删除分区的意思


命令p:

       接下来我们熟悉一下命令的使用,先使用p打印分区,可以看到的是这里我有两个分区


命令d:

        接下来,我们准备把所有分区删除。先输入命令d,然后会让你选择分区,由于此时一共只有两个分区,所以你只能在1和2之间选,并且默认删除最后一个(分区2)。可以按回车,默认删除最后一个分区

        此时,输入命令p显示分区,还剩下最后一个

        由于此时只有一个分区,直接输入命令d后,会直接删除

        至此全部删除干净,不过可能会遇到有个分区无法删除的情况,选用SD卡烧录的原因这里有解决办法

        此时可以按w退出保存


命令n:

        到这,我们就可以创建分区了,前面说过,我们一共需要两个分区,一个用于存放内核镜像、设备树的,另一个用于存放根目录的。

        我们输入命令n,接下来就会有两个选项让你选,一个是初始分区类型,只有4个分区;另一个是扩展类型,分区比较多。这里我们选择默认即可,所以按一下回车

        紧接着下面会让你选分区的名称,一共有四种,如果我们选择2,那么输入命令

ls /dev/sd*】时就会出现【/dev/sdb2】这个分区了。此时我们选择1,所以按一下回车

        此时我们回顾一下,由于创建第一个分区时前面要预留给uboot一定的空间,所以我们可以把第一个分区的起始扇区地址设为20480(一个扇区512B),所以是10MB(uboot一般就几百KB)

        当我们输入起始扇区20480后,接下来是让你输入这个分区大小的,我们可以使用【+ 数字 单位】的形式。一般zImage就10MB左右,但没办法,现在SD卡容量都大,分配200MB、500MB、1GB都随意。这里选择500MB,后面的m大小写都行

        后面弹出这个红字是因为我前面删除分区时,并没有保存,换句话说,我们在这里进行的所有操作并没有被真正执行,就跟Linux拖拽文件一样。这里我选择y,移除重新开始

        接下来如法炮制,创建第二个分区。稍有不同的是,选择分配存储大小时,由于没有分区需要创建了,可以把剩下所有的空间给第二个分区,所以直接按回车


命令w:

        是不是多了一个命令?哈哈哈,这个命令就是保存退出的,之所以没有跟前面放在一块,是因为这种命令不容易忘。就比如vim里的命令,别的命令你或许会忘,但:wq命令一定熟得不能再熟了

        不过我这稍微有那么一点点意外发生哈

②设定分区格式

        设定分区就简单多了,前面提到,第一个分区是fat格式,第二个分区是ext4(或ext3)格式,这里只需要用到mkfs

        这是把第一个分区制作成fat格式,注意分区不要写错

sudo mkfs.vfat /dev/sdb1

        这是把第二个分区制作为ext4格式,需要等待一会,不要着急

sudo mkfs.ext4 /dev/sdb2

③烧录u-boot

        烧录uboot直接使用烧录工具就可以了,可以使用正点原子提供的,或者基于正点原子的IMX6UL烧录工具,亦或者直接使用命令来烧录

        这里使用的是dd命令,if后面跟要烧录的文件(这里是imx文件),of后面跟要烧录的设备,此时我们选择的自然是SD本身而不是什么分区。bs是烧录的扇区大小(单位嘛),seek则表示是从第几个扇区开始烧录(第一个扇区是0号扇区),由于前面要空1KB,所以你可以选择【bs=1k seek=1】的组合,也可以选择【bs=512 seek=2】。后面的【conv=fsync】表示烧录完之后进行同步,这是由于Linux传输数据的特性,得选择同步,不然你把SD卡拔出来后,Linux都未必开始把数据烧录到卡上。

sudo dd if=u-boot.imx of=/dev/sdb bs=1k seek=1 conv=fsync

        不过这其中就有一个坑,我们要选择第三个。至于下面第十个,给我的印象不太好,好像有什么bug啥的

        如果你选择第三个,这里面我遇到了一个坑,那就是make之后生成的u-boot.imx有问题,不能正常使用。还是得需要imxdownload这个烧录工具,把bin转为imx


        差点忘了,现在还没有到编译阶段,uboot、镜像什么的到下面路径里找,可能不一定管用(肯定比不上开发板里左盟主已经配好的),但用来学习是足够的

【正点原子】阿尔法Linux开发板(A盘)-基础资料\08、系统镜像\02、教程系统镜像\02、V2.4版本及以后的底板

④拷镜像和根文件系统

        拷镜像和根文件系统时,不能直接把文件拖拽到SD卡分区里!!会出大问题的,文件会损耗或者压根没有。前面也提到,Linux传输数据时不按套路,你直接拖拽,实际上有没有传输谁也不知道,而且由于是通过图形界面的操作,没有校验步骤,sync同步命令也无处使用(得在同一个命令行里才行)

        所以要通过挂载的方式,一般情况下/mnt这个目录为空,就是让你用来挂载的,挂载挂载,就是让这个文件夹成了SD卡分区的替身,你往这个文件夹里放文件,其实就是在往SD卡里放文件。


镜像:

        首先,我们先通过mount命令,把SD卡的第一个分区挂到/mnt

sudo mount /dev/sdb1 /mnt

        然后,把对应内核镜像和设备树文件移动到/mnt

sudo cp zImage /mnt
sudo cp imx6ull-alientek-emmc.dtb /mnt

        接着,不要忘记同步!!

sync

        最后,也不要忘记取消挂载

sudo umount /dev/sdb1

根文件系统:

        这里的步骤跟上面一样,不过多了一步解压和移动。这里选择哪个根文件系统都行

sudo mount /dev/sdb2 /mnt
sudo cp ubuntu-base-16.04.5-base-armhf.tar.gz /mnt

# 进入/mnt目录后
sudo tar -zcvf ubuntu-base-16.04.5-base-armhf.tar.gz 

# 由于解压后的文件可能会在ubuntu-base-16.04.5-base-armhf文件夹里
# 我们需要把它全部取出来
# 不要忘记同步(解压其实也需要同步,这里一次性同步掉)
sudo mv ubuntu-base-16.04.5-base-armhf/* /mnt
sync

# 然后删除空目录,直接用rmdir会显示非空
# 这里强制删除即可
sudo rm -rf ubuntu-base-16.04.5-base-armhf

# 最后不要忘记取消挂载,不过由于此时处于挂载目录/mnt下,会显示繁忙
# 我们随便进入一个目录后再取消挂载
cd ~
sudo umount /dev/sdb2

        不过这一步只是体验一下,因为流程是很清晰的,等会测试时,我们完全可以使用开发板emmc里自带的根文件系统

3,测试SD卡

        当我们把烧录好的SD卡插到开发板上,同时拨码开关选择SD卡启动。此时打开开发板上的开关,同时要把串口工具打开,此时会打印一堆信息。至此就行了,因为这说明uboot没有问题,至于linux内核能不能启动现在还不重要(因为不能确保那些文件是否还能正常使用),因为后面会使用编译工程得到文件开始真正的测试,上面是为了熟悉制作SD卡烧录的流程。

        如果这一步中,可以正常使用uboot,但是无法启动linux内核,那么可以先放着,继续往下看,回头再来

选用SD卡烧录的原因

        虽然视频里建议用EMMC来学习,不建议用SD卡来学习Linux移植。但我个人认为应该先用SD卡来学习而不是EMMC,原因有三:

其一,由于例程源码已经有段时间了,一开始我根本无法复刻视频里的结果,担心把仅有的EMMC里的Linux内核给搞没。这个说起来我人都麻了,该装的库我装了,该添的工具我也添了,该改的代码我也改了,该有的操作我也照做了,但始终无法编译出zImage,总有两个混蛋一直报错。后来才知道是gcc版本不对,并且还需要对正点原子的Linux内核进行一点点更改


 其二,先用SD学习处理能衔接上前面的裸机驱动,也能加深对文件系统、存储布局的理解,直接使用mfgtools就没有这个效果了。而且在使用SD卡后,你难免需要频繁用到ubuntu里的fdisk和uboot,这些实操会大大加深你对linux移植和文件系统的理解


其三,先学SD卡一不怕弄坏,那意味着可以尽情发挥、尝试,没有任何顾忌;二来呢,即使上手EMMC也不会有什么阻碍

        SD卡的烧录工具在这篇博客里有代码——IMX6UL烧录工具及其使用,也可用正点原子教程里的,这里的烧录工具只是烧录uboot的。因为uboot是裸机程序,就如前面的裸机实验,需要烧录到SD卡上,而linux内核是镜像文件只需要加载到内存就行了,根文件系统是个文件系统,存储在SD卡上,自然也不用烧录。

        更确切的说,就是烧录的uboot是二进制文件(当然,前面还有3KB的表),烧录到SD卡上形成一定的物理布局,不需要文件系统,而linux内核镜像文件自带物理布局放在文件系统里就行了,根文件系统都本身就是文件系统。这里就牵扯到了镜像布局

Tips:

        制作SD卡分区时,出现过一个诡异的情况,那就是有一个分区(我的是/dev/sdb2)怎么也删除不掉,大小和起始扇区都显示为0,并且ID为74。

        后来使用尝试了各种方法,有一次误打误撞输入命令,终于把这个分区给抹除掉了

sudo mkfs.vfat -F 32 -n boot /dev/sdb1

       

二、编译

1,前置内容

前言:

        坦白来说,这一步是还挺难的。难在哪呢?难在对于全流程的把握上。由于视频教程的版本比较落后了,上网查教程呢,大多都是2022或者2021年的了,即便是2024的教程,里面内容大多是老一套。基本内容要么直接拿正点原子的例程源码,要么放个所谓的NXP官方源码链接,多少有种授人以鱼的感觉。

        下面将先介绍如何找官方源码,以便后期学有所成之时可以自行更改官方源码


NXP官方源码:

        现在很多官方喜欢把源码放在github上,我们可以直接自己去github上查找(不过有时github可能打不开,可以刷新一下或者换个点再来),github毕竟也能搜索,直接搜索nxp会有两个网站,第一个就是很多博客里会放的官方链接(可以看描述),第二个看图标也知道是NXP官方的。

        接下来我们用第二个,因为更清晰,网址为nxp-imx (github.com)。插一嘴,github注册时,这个性别选项嘛就很西方,很民主,武装直升飞机、沃尔玛购物袋什么什么的

        如下所示,从这个nxp-imx名称可以快速地知道,这是NXP关于imx系列芯片的源码

        在这个界面里,我门可以看到有不少公共资源,其中下面三个是我们可能需要的

       


uboot:        

        现在我们可以先点击进去看看uboot-imx有哪些资源,进去后直接映入眼帘就是uboot的源码。但此时我们需要关注两个东西,一个是左上角的分支,另一个是右下角的标签

        打开分支后,你可以看到一堆命令奇怪的分支,怪在哪呢?怪在时间排序上,一般我们查找源码工程时,希望能看到按时间排序的版本,从而方便挑选适合的版本。而使用分支来查看并不是个合适的方法

        此时我们应该关注的是标签tags,它可以很清晰地列出发行的各种版本,按照一定顺序。直接点击上上个图中的右下角,进入tags里,此时我们可以观察到各种版本,有lf-6.6x.x的、也有android-14.x.x(毕竟安卓也是嵌入式,imx可以运行也很正常)。         但此时我们要找到不是这些,我们需要找的是rel_imx_x.x.x(往后翻页就能找到),为什么是它呢?因为前面的rel就是release,即它是imx的发行版,我们可以正常使用的适用于imx系列的源码。同时你也会发现rel_imx到2023年后就没有版本了,这可能是因为“新欢胜旧欢”吧         点击后我们就可以进入下载界面,由于这个源码工程是在Ubuntu里使用的,我们可以直接下tar.gz版本,然后传输到Ubuntu里,或者直接在Ubuntu里下载这个资源
        接下来我们同样的方法进入到Linux源码里,我们一样进入到tags里,找到rel_imx_x.x版本,此时可以注意到的是linux下也有一个一模一样的版本rel_imx_5.24_2.14版,一一对应嘛。只不过在NXP官方里,linux的版本要远多于uboot的

2,正式开始编译

准备:

        这次我们选择【例程源码】里的【正点原子Uboot和Linux出厂源码】,这个应该就是开发板里emmc装载的,版本差不多

uboot编译:

        先在Makefile里把架构和编译器都定下来,大概在两百多行的样子,可以通过搜索ARCH找到

ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-

        然后就可以按照这篇编译正点原子Linux内核报错博客里的,把这个文件里的变量前加上extern

        之后就可以正式编译了,编译后会在项目当前目录下生成uboot.bin和uboot.imx,只不过这个imx不可以使用,还是需要imxdownload工具。

        这个配置文件就在项目根目录下的configs里

make distclean
make mx6ull_14x14_evk_emmc_defconfig
make -j16

 Linux编译:

        同上,只不过编译时需要输入下面命令,产生的zImage在arch/arm/boot下,设备树文件在arch/arm/boot/dts下的imx6ull-14x14-emmc-7-1024x600-c.dtb(我的是7寸1024*600的屏幕,这个根据自行情况去选择)

make distclean
make imx_v7_deconfig
make -j16

三、正式运行Linux

1,在uboot里设置环境变量

前置知识:

        在uboot里,mmc你可以简单地理解为存储设备,这个正点原子开发板里我们能碰见两个mmc设备,一个是SD卡,另一个是EMMC(或者NAND,接下来只讲EMMC了)。并且mmc是有编号的,mmc 0表示SD卡,mmc 1表示EMMC

        mmc 0:1则表示SD卡里的第一个分区,mmc 1:2则表示EMMC的第二个分区,很好理解。

bootargs:

        把编译出的文件烧录到SD卡上,然后插入到开发板中,并以SD卡启动。同时打开串口助手并连接上,在开发板打开开关后,在串口助手中按下回车键进入uboot里

        此时我们可以使用命令【printenv bootargs】把这个启动参数打印出来,这个启动参数是要传递给linux内核的。这时候我们需要设置启动参数

  • console=ttymxc0,115200  表示的是使用串口0输出到控制台,同时以115200的比特率进行通信
  • rootwait 表示等待mmc设备初始化完后在挂载根文件系统
  • root=/dev/mmcblk1p2  表示把mmc设备1中的第二个分区挂载为根文件系统,即使用EMMC里的根文件系统,当然我们也可以使用SD卡里的根文件系统,此时只要更改为root=/dev/mmcblk0p2 就行了,前提是你的根文件系统放在了SD卡的第二个分区
  • rw 表示以读写的方式挂载根文件系统
setenv bootargs console=ttymxc0,115200 rootwait root=/dev/mmcblk1p2 rw
saveenv 

# 保存后,需要重启才能生效

手动加载linux镜像和设备树:

        首先我们要先查看SD卡对应分区,前面提到SD卡上有两个分区,一个是fat格式,另一个是ext4格式。此时我们可以使用下面命令(文件格式+linux里的ls命令),来查看对应分区里的文件。如果你的两个分区没有问题的话,可以在输入命令后看到对应的文件

fatls mmc 0:1
ext4ls mmc 0:2

        接下来就可以直接把文件加载到内存里了(linux是运行在内存里的),前面列出来文件名字,也是方便把文件名直接复制过来,而不必一个一个手敲(通过右键串口窗面来复制粘贴,Ctrl+C在这里是停止的意思)。此时我们会把内核镜像放在前面,设备树紧跟其后,这与bootz这个命令有关。

        这个时候我们可以选用0x83000000这个地址作为起始地址(裸机驱动开发时很常见嘛),也可以使用别的地址,只要在0x80000000-0xFFFFFFFF里,当然不能太离谱。正点原子里用的是0x80800000。设备树由于是放在内核后面的,所以设备树的起始地址-内核镜像起始地址至少要大于内核镜像大小,不然就覆盖了一部分导致内核镜像有损。

load mmc 0:1 0x83000000 zimage
load mmc 0:1 0x83800000 imx6ull-14x14-emmc-7-1024x600-c.dtb

        最后我们可以直接使用bootz来启动内核,两个地址都不能少。此时如果一切正常的话,会显示starting kernel,之后就是一堆linux启动的信息。如果你卡在starting kernel的话,可能是镜像文件损坏了,比如直接把文件拖拽到USB里,即使文件坏了也没有魔数提示(是魔数,不是错别字)

bootz 0x83000000 - 0x83800000

        接下来如果一切顺利的话,你会看到linux正常启动,就跟使用EMMC启动模式一样,界面上没有任何区别

2,使用脚本启动

        我们可以通过【printenv bootcmd】来查看原来的bootcmd,那么bootcmd这个环境变量是干什么的呢?其实它就是uboot倒计时结束后执行的内容

        根据前面的启动流程,我们可以设置自己的bootcmd,不过建议把原先的bootcmd先保存一下

setenv bootcmd 'load mmc 0:1 0x83000000 zimage; load mmc 0:1 0x83800000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 0x83000000 - 0x83800000 '
saveenv

3,uboot的其他操作

        uboot也可以进行文件传输,把文件在EMMC与SD卡间相互传输,其实就是先把文件放到内存里,然后再从内存里把文件数据写到存储设备上。总而言之,想要实现什么功能,问一下,简单的问题AI基本都能回答正确

# 加载文件到内存
fatload mmc 1:1 0x80000000 file1.txt
# 将文件写入SD卡的第一个分区
fatwrite mmc 0:1 0x80000000 file1.txt ${filesize}

# 加载文件到内存
fatload mmc 1:1 0x80000000 file2.txt
# 将文件写入SD卡的第一个分区
fatwrite mmc 0:1 0x80000000 file2.txt ${filesize}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值