[Linux]从零开始的STM32MP157 U-Boot移植
一、前言
在上一次教程中,我们了解了STM32MP157的启动流程与安全启动机制。我们还将FSBL的相关代码移植成功了。大家还记得FSBL的下一个步骤是什么吗?没错,就是SSBL,而且常见的我们将SSBL作为存放U-Boot的地方。所以本次教程,我们需要移植一份适用于我们开发板的U-Boot。当然,本次教程依然使用的是正点原子的STM32MP157开发板,这里还是强烈建议大家的开发板和我一样的,如果你准备好了,就让我们开始吧!
二、谁适合本次教程
因为STM32MP157的程序下载需要U-Boot的辅助,也就是说,我们想要移植并下载一个U-Boot前提是先有一个U-Boot,这就非常抽象了,又像是回到了TF-A那样的“死锁”状态。当然,这里我们下载Uboot时,可以直接使用正点原子已经移植好的Uboot来将我们自己移植的Uboot下载进去。所以,在移植之前请确保你对STM32MP157的程序下载有一定的了解。关于STM32MP157的程序下载在之前TF-A移植教程中已经讲过了,而且正点原子的手册中也有非常详细的讲解,本次教程就不过多讲解了:
STM32MP157 TF-A移植:[Linux]从零开始的STM32MP157启动流程讲解与TF-A的移植-CSDN博客
三、资料的准备
这里我们使用到的资料同样是正点原子的官方资料,在最开始的环境搭建教程中已经讲解了如何下载正点原子的官方资料,如果你还不知道如何下载请前往STM32MP157的开发环境搭建教程:
STM32MP157开发环境搭建:[Linux]从零开始的STM32MP157交叉编译环境配置_stm32mp157 linux 开发 单片机开发-CSDN博客
准备好的资料如下图:
如果你已经准备好了相关资料就让我们开始吧!
四、Uboot的作用以及不同厂家的Uboot
首先我们需要明确一点,Uboot并不是有一个系统,它是一个非常庞大的裸机程序,主要用于基本外设的初始化和拉起操作系统。我们的操作系统在被编译以后,并不是单纯的二进制文件,而是一个以img为后缀的系统文件。显然这个文件不像二进制文件那样可以直接被烧录运行,这时我们就需要一段代码来拉起这个img格式的系统文件。这个拉起系统的程序就是我们常说的Bootloader引导程序。Bootloader有非常多的种类,比如U-Boot、vivi、RedBoot。在嵌入式领域或者一些智能通讯设备领域最常用的还是Uboot。所以,为了能在我们的开发板上运行Linux内核,我们就必须用一个Bootloader程序来引导它,这里正点原子的开发板选择的是Uboot。总结一下,简单来说,Uboot主要就是一个用于引导系统的Bootloader程序。
当我们准备移植Uboot时,我们可能会面临三种Uboot分别是:Uboot官方开源出来的Uboot,这个Uboot往往是最纯正的;还有就是芯片厂家开放的Uboot,芯片厂家会从Uboot的官方下载一份Uboot并且对其进行修改使其适配自己的芯片;最后就是开发板厂家的Uboot,就拿正点原子来举例,正点原子使用ST公司的STM32MP157芯片生产了开发板,正点原子会从ST那里下载芯片对用的Uboot,并且对其进行修改从而适配自己的开发板。这里我们要进行的移植其实就是让原本芯片厂商的Uboot对我们的开发板进行适配。不同厂家的Uboot的关系可以看下面这张图:
当然,大家可能会有疑问,明明正点原子已经帮我们移植好了Uboot,为什么我们还要再移植一次呢?其实答案也很简单,正点原子移植Uboot的当然只适配正点原子的开发板。如果我们自己设计了一块开发板,这个板子的外设或者供电和正点原子的开发板不一样,就会导致这个Uboot在我们的开发板上不适用。我们移植Uboot的目的就是学习这个移植的过程,在以后我们自己设计了开发板以后也能将Uboot移植上去。
五、正点原子官方Uboot的编译与烧录
这里我们先来编译一下正点原子官方的Uboot,让大家体验一下Uboot编译与烧录的过程,这样也有助于大家对Uboot移植的整个步骤有一定的了解。这次的教程同样同步于正点原子的“【正点原子】STM32MP1嵌入式Linux驱动开发指南V2.1.pdf”文档,它被放在了正点原子资料目录下的“09、文档教程(非常重要)”目录下:
下面我们来编译正点原子的Uboot吧,正点原子的Uboot被放在了正点原子资料目录下的“01、程序源码\01、正点原子Linux出厂系统源码”目录下:
1.正点原子官方uboot的编译
这里我们新建一个文件夹来存放uboot:
创建的路径无所谓,大家自己决定即可。我们再在这个已经创建好文件夹中再创建一个文件夹用于存放正点原子的Uboot源码,我这里文件夹就叫“atk-uboot”:
然后,大家可以使用FTP服务将正点原子的Uboot源码上传到目录中,这里FTP传输文件在环境搭建的教程中已经讲得很详细了,大家自行操作即可,这里就不进行多的演示了。
我们将文件上传到指定目录后如图:
这里我们先使用下面的命令将正点原子的uboot进行解压:
tar -vxf u-boot-stm32mp-2020.01-gdb2b13ef-v1.6.tar.bz2
这里压缩文件的文件名可能会变化,大家根据自己当时的文件名解压就好。
解压过程可能比较久,毕竟uboot是一个非常庞大的程序并且也兼容了非常多的芯片。解压完成以后就得到了下面的文件:
现在我们先不着急编译正点原子的uboot源码,我们先安装编译所需的环境,不然编译会产生错误,我们使用下面的命令来安装对应的环境:
sudo apt-get install libncurses5-dev bison flex
安装好环境以后,我们在正点原子的uboot源码目录执行下面的命令来清除一下已经编译的内容:
make distclean
这里建议大家在编译之前都清除一下避免错误。
我们再使用下面的命令对编译进行一些初始化:
make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- stm32mp157d_atk_defconfig
下面我来逐一解释一下这些选项的含义,首先是ARCH=arm,它指定我们交叉编译的架构为arm。然后是CROSS_COMPILE=arm-none-linux-gnueabihf-,它指定了我们要使用的交叉编译器,这里表示要使用名为“arm-none-linux-gnueabihf-”的交叉编译器,也就是我们在STM32MP157开发环境搭建中安装的交叉编译器。最后stm32mp157d_atk_defconfig表示使用预定义的配置文件。 编译之前会使用stm32mp157d_atk_defconfig生成 .config文件。后面的make命令会根据对应的.config文件进行编译。这里生成的.config文件是对我们开发板的基础配置。
当我们执行完上面的命令以后,就得到了以下输出,在输出中已经提示我们.config已经被成功写入了:
当我们成功生成.config文件以后,就可以开始准备编译了,我们使用下面的命令对正点原子的uboot进行编译:
make V=1 ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabihf- DEVICE_TREE=stm32mp157d-atk all
这里多了一个V=1的选项,这个选项表示在uboot编译时输出详细的编译过程。这里还多了一个
DEVICE_TREE=stm32mp157d-atk选项,表示要使用的设备树文件,这里我们指定要使用的设备树文件为我们自己的开发板的设备树。
最后面的all表示编译所有,所以这个all不能少。我们同样可以加上-j的参数来修改编译时使用的线程数量,编译完成以后,就得到了下面的输出:
这里正点原子官方的uboot编译一般是不会有错误的,如果你出现的错误,可以看看是不是遗漏了上面的某些步骤。编译之后生成的文件就被放在了uboot的源码目录下:
我们这里重点关注u-boot.bin文件和u-boot.stm32文件。这里的u-boot.bin就是uboot源码被编译以后生成的二进制文件,而u-boot.stm32则是在u-boot.bin的基础上加上头部信息的文件。是的uboot也和TF-A一样需要在编译后的二进制文件前面加上一段头部信息。
2.正点原子官方uboot的烧录
下面,我们就可以来烧录这个我们已经编译好的正点原子的uboot。这里我直接在自己电脑的桌面上新建了一个“stm32mp157_uboot”文件夹用于存放uboot相关的文件和下载时会用到的文件以及STM32CubeProgrammer的配置文件:
还记得我们在上一次教程中创建的“stm32mp157_tf-a”文件夹吗?是的,这个文件夹我们主要是用来下载TF-A的,我们可以直接借鉴这个文件夹中的内容,我们可以将stm32mp157_tf-a文件夹中的文件全部复制到stm32mp157_uboot中:
复制完成以后,我们需要进行一些小小的修改,首先就是将原本的u-boot.stm32删掉,换成我们自己编译出来的u-boot.stm32文件,大家注意文件的时间,确保自己替换成功了:
然后我们需要将原本的STM32CubeProgrammer配置文件的名字改以下,以前的配置文件名为“tf-a.tsv”我们将其改为“uboot.tsv”,修改完以后如下图所示:
然后我们需要对“uboot-tsv”的内容就行一些修改,我们在tsv文件的最下面插入下面这样一行:
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
注意,这里的开头就是P,不是PD或者别的,如果从正点原子原本的文件中复制,这里可能是PD,这会导致烧录不成功。配置文件修改完以后如图所示:
这里我们启动STM32CubeProgrammer对我们编写好的uboot进行下载,连接和下载的具体步骤在TF-A的教程中已经讲得很清楚了,这里就不多说了。下载完以后会收到如下提示,如果前面一直按照我的步骤下载的话应该是不会有错误的:
下载完成以后如图:
然后我们可以将拨码拨到串口启动,然后使用串口终端工具看看输出:
我们可以看到下面这里我们的uboot已经成功启动,并且输出了uboot的编译时间。我们也可以通过这里的编译时间判断我们的烧录是否成功。
至此,我们正点原子的uboot编译与烧录就已经完成了。
六、ST官方uboot的移植与烧录
在上面,我们已经成功的编译了正点原子的uboot源码,并且已经成功的在正点原子的开发板上运行了起来。当然,使用正点原子的开发板的目的就是为了让我们学习并且理解uboot的移植过程。那么现在就来教大家如何在ST官方uboot的基础上为我们的开发板移植一份uboot。这里大家可能会有疑问,为什么我们一定要从ST官方的uboot的基础上进行移植,而不是直接移植uboot官方开放出来的uboot。这是因为虽然uboot官方开放的uboot对ST的芯片有适配,但是适配程度肯定没有ST那么好。而且让我们在原本的uboot上进行移植这几乎是不可完成的。所以让uboot官方代码适配自己的芯片这个事一般是芯片厂商来做,我们只需要在芯片厂商已经移植的uboot的基础上为我们的开发板移植一份uboot。
1.编译ST官方的uboot:
这里我们首先需要编译ST官方的uboot代码,只有将uboot官方代码编译过了以后我们才能开始移植。ST官方的代码被放在了正点原子资料目录下的“01、程序源码\05、ST官方原版Linux源码”目录下:
我们同样使用FTP服务将其传输到Linux中,这里我创建了一个名为st_uboot的文件夹:
我们再使用下面的命令将这个源码包解压:
tar -xvf en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz
解压以后得到如下文件夹:
这里我们进入“stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24”文件夹中的“sources/arm-ostl-linux-gnueabi”文件夹下可以看到以下文件夹。这些文件夹里面就是里面就是uboot、optee、tf-a、kernel 源码:
下面有一张这些文件夹对应源码的对照表:
这里很明显,我们要用到的文件夹是“u-boot-stm32mp-2020.01-r0”。
我们可以在一开始创建的“UBOOT”文件夹中新建一个my_uboot的文件夹,将u-boot-stm32mp-2020.01-r0下的所有文件都拷贝进去,使用下面的命令:
cp u-boot-stm32mp-2020.01-r0/* /home/chulingxiao/linux/UBOOT/my_uboot/
我们将文件复制到my_uboot后如图所示:
这里和我们TF-A的源码一样,以.patch结尾的文件都是补丁文件,我们需要使用这些补丁文件为uboot打补丁。我们使用下面的命令将uboot的源码解压:
tar -xvf u-boot-stm32mp-2020.01-r0.tar.gz
解压以后,我们进入uboot的源码目录就能看到以下文件和文件夹了:
我们在源码目录下,使用下面的命令对源码进行打补丁:
for p in `ls -1 ../*.patch`;do patch -p1 < $p;done
同样的,看到一堆输出过去以后,补丁就打成功了:
下面我们需要修改以下makefile文件,还记得一开始我们编译正点原子提供的uboot的时候吗?当时我们编译输入了命令非常长,为了编译方便一些,我们直接修改makefile,将我们编译时的一些选项直接写入makefile中,这样我们也就省去了很长的命令。
uboot的makefile就放在了uboot的源码目录下,我们直接使用下面的命令打开修改即可:
nano Makefile
我们这里在使用nano编辑时,可以直接按下“ctrl+w”搜索“CROSS_COMPILE”找到如下位置:
我们直接在它的下方加入如下两行:
ARCH=arm
CROSS_COMPILE=arm-none-linux-gnueabihf-
插入以后如图所示:
修改完makefile以后,我们使用下面的命令来生成编译所需的.config文件:
make stm32mp15_trusted_defconfig
然后我们再使用下面的命令进行编译,用编译命令时还是需要指定设备树,并且也要加上all,表示编译所有,最后可以加上-j的参数来选择编译时使用的线程:
make DEVICE_TREE=stm32mp157d-ev1 all -j12
这里大家可能会有疑问,为什么我们要使用stm32mp157d-ev1开发板的设备树文件,我们不是要编译正点原子开发板的uboot吗。因为正点原子的STM32MP157开发板参照了stm32mp157d-ev1开发板,所以,我们这里编译一份与正点原子开发板非常类似的开发板uboot。我们可以将这个编译出来的uboot烧录到正点原子的开发板中,当然,烧录进去肯定是不能运行的,我们要根据具体的问题对代码进行修改,这就是移植的过程,通过不断的烧录,测试,从而移植一个能运行的uboot。
编译完成以后,就会看到下面的日志输出了:
我们可以看到uboot的源码目录下也生成了编译后的二进制文件:
至此,ST官方uboot的编译就已经完成了。
2.烧录ST官方的uboot
当我们编译完ST官方的uboot以后,就可以准备烧录了。但是在烧录期间我们会遇到一个问题,因为STM32MP157的程序下载方式,是先将uboot加载到DDR中,然后通过uboot将程序下载到EMMC中,但是我们现在uboot都没有移植成功,那就更不可能可以成功的将uboot下载到EMMC中了。怎么办呢?我们可以使用正点原子已经移植好的uboot将我们现在编译的uboot烧录进去。我们先将我们编译好的uboot改名为my_u-boot.stm32,然后将其复制到我们下载uboot的文件夹中:
然后我们需要修改一下tsv文件,这里我们将tsv文件的最后一行替换为如下:
P 0x06 ssbl Binary mmc1 0x00080000 my_u-boot.stm32
修改完以后如图所示:
这里表示,我们烧录代码时使用的uboot名为“u-boot.stm32”,实际烧入的uboot名为“my_u-boot.stm32”。然后我们使用STM32CubeProgrammer加载文件:
我们将其烧入,如果你上面是跟着我操作的,一般是不会有错误的:
烧录以后,我们将拨码拨到从EMMC启动以后,我们使用串口终端工具查看输出,发现,我们的开发板正在反复重启,并且蜂鸣器也在响。当然实际的代码中没有让蜂鸣器鸣响的代码,只是因为uboot不能运行开发板反复重启拉到的蜂鸣器的电平。总的来说我们将EV1开发板的uboot直接放在正点原子的开发板中是无法运行的:
下面,我们就来进行代码移植,使得适配正点原子的开发板。
3.移植ST官方的uboot到正点原子开发板
因为我们要将uboot移植到正点原子的开发板上,那么我们需要为正点原子的开发板添加一些必要的文件。首先就是配置文件,还记得一开始我们编译uboot使用的生成配置文件的make stm32mp15_trusted_defconfig命令吗?这个命令调用相关的文件为我们生成了编译所需的.config文件。我们现在也要为正点原子的开发板创建一个这样的文件,用来生成正点原子开发板独有的.config配置文件。因为正点原子的开发板参考了EV1的开发板,所以这个配置文件我们可以直接复制,我们首先进入uboot源码目录下的configs目录:
cd configs/
然后使用下面的命令复制开发板的配置文件并将其改名为“stm32mp15_atk_trusted_defconfig ”,这个文件就是我们开发板独有的配置文件了:
cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig
然后我们再在uboot源码目录下使用下面的命令去到设备树相关的目录:
cd arch/arm/dts/
然后我们使用下面的命令复制相关的设备树文件,一共有三个文件:
cp stm32mp157d-ed1.dts stm32mp157d-atk.dts
cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi
cp stm32mp157a-ed1-u-boot.dtsi stm32mp157d-atk-u-boot.dtsi
复制以后得到的这些设备树文件,就是正点原子开发板的专属设备树文件了,我们修改也是在我们复制出来的文件的基础上进行修改。
在修改文件之前,我这里为大家推荐一种更为简单的文件修改方式——samba,我们可以将linux虚拟机中的文件直接映射为windows中的一个磁盘,这样我们就可以直接在windows上修改Linux中的文件了,查看起来也会更简单。当然,如果你觉得这个方法不好,也可以不采纳,直接在Ubuntu中使用vscode修改的效果也是一样的。下面是samba的安装教程:
samba服务安装:[Linux]在Ubuntu中安装samba并且正确配置(详细)_ubuntu samba-CSDN博客
如图所示,我已经将我的samba配置好了:
这里再次强调一下,如果你是小白,直接使用ubuntu里面的vscode配置即可,如果你有一定的基础并且觉得我的这个方法还不错,那么,你可以采用我的方法。
下面,我们就可以直接打开uboot的源码文件夹,不管你是使用samba映射或者是直接在ubuntu中直接使用vscode,都需要使用vscode打开uboot的文件夹,打开以后如图:
下面我们打开uboot源码目录下的“arch/arm/dts/”目录下的stm32mp157d-atk.dts文件:
我们需要将第14行,也就是【#include "stm32mp15xx-edx.dtsi"】一行改为如下内容:
#include "stm32mp157d-atk.dtsi"
修改完以后如图所示:
随后我们需要修改一下电源管理设置,我们打开同位于这个目录下的“stm32mp157d-atk-u-boot.dtsi”文件:
我们将位于51-53行的如下代码直接删除:
&pmic { u-boot,dm-pre-reloc; };
随后我们再将23-31行的如下代码直接删除:
red { label = "error"; gpios = <&gpioa 13 GPIO_ACTIVE_LOW>; default-state = "off"; status = "okay";
};
随后再将21-22行的如下代码直接删除:
st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
这里文件比较长,我就不放删除以后的截图了,大家按照我的步骤进行操作即可。
下面我们要修改stm32mp157d-atk.dtsi文件,同样位于这个目录下。我们找到“&i2c4”节点,我们将“&i2c4”节点整个删掉,也就是文件中的143行到298行:
注意,这里一定是将i2c4节点整个删掉。
删掉以后上下文就是这样的:
然后我们再找到“&dac”节点,也就是114-125行,将其全部删除:
删除以后上下文如下:
然后我们再找到“&adc”节点,也就是90-104行,将其全部删除:
删除以后,上下文如下:
然后,我们继续修改stm32mp157d-atk.dtsi这个文件,找到“led”和“sd_switch”节点:
将这两个节点全部删掉:
删掉以后,上下文如图:
我们需要在stm32mp157d-atk.dtsi文件的\下添加自己的电源管理信息,我们直接来到58行处,添加如下代码:
vddcore: regulator-vddcore { compatible = "regulator-fixed"; regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-boot-on; };v3v3: regulator-3p3v { compatible = "regulator-fixed"; regulator-name = "v3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-boot-on; }; v1v8_audio: regulator-v1v8-audio { compatible = "regulator-fixed"; regulator-name = "v1v8_audio"; regulator-min-microvolt = <1800000>;regulator-max-microvolt = <1800000>; regulator-always-on; regulator-boot-on; };vdd: regulator-vdd { compatible = "regulator-fixed"; regulator-name = "vdd"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-boot-on; };vdd_usb: regulator-vdd-usb { compatible = "regulator-fixed"; regulator-name = "vdd_usb"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-boot-on; };
添加完成以后如图所示,注意这里的括号不要弄错位了:
上述代码定义了5个电源节点,分别为:vddcore、v3v3、v1v8_audio、vdd和vdd_usb, 至此,电源管理相关配置已经设置好了。
下面我们来修改TF卡和EMMC相关的配置,我们继续修改stm32mp157d-atk.dtsi文件,找到sdmmc1和sdmmc2两个节点,将其修改为如下:
&sdmmc1 {pinctrl-names = "default", "opendrain", "sleep"; pinctrl-0 = <&sdmmc1_b4_pins_a>; pinctrl-1 = <&sdmmc1_b4_od_pins_a>; pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; st,neg-edge; broken-cd; bus-width = <4>; vmmc-supply = <&v3v3>; status = "okay";
};
&sdmmc2 {pinctrl-names = "default", "opendrain", "sleep";pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>; pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>; non-removable; st,neg-edge; bus-width = <8>; vmmc-supply = <&v3v3>; keep-power-in-suspend; status = "okay";
};
修改完成以后,如图所示:
就在这个文件中,我们找到“usbotg_hs”节点,直接将其注释掉:
这个节点配置了OTG的电源,因为ST官方的开发板电源是使用电源管理芯片配置的,而正点原子的开发板中并没有使用电源管理芯片给OTG供电,所以,为了避免报错,我们直接注释掉即可。
下面我们来编译一下uboot,在编译uboot之前要先让编译器知道我们要编译哪个设备树 文件,打开 arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_STM32MP15x)”配置项,然后在此配置项中 加入“stm32mp157d-atk.dtb”,添加完以后如图所示:
大家还记得我们一开始的编译经历了哪些步骤吗?我们首先清除了以前编译的内容,然后生成了.config的配置文件,最后才是编译,这样的步骤我们每次编译都需要输入三条命令,太麻烦了,我们可以直接在uboot的源码目录下创建一个shell脚本来编译,我们可以在uboot的源码目录下使用下面的命令来创建一个shell脚本:
touch build
注意,这个脚本一定要创建在uboot的源码目录下。然后我们再使用下面的命令给这个脚本可执行权限:
chmod +x build
然后我们打开这个脚本输入下面的内容,这些内容就是我们要使用的命令了:
#!/bin/bashmake distclean
make stm32mp15_atk_trusted_defconfig
make DEVICE_TREE=stm32mp157d-atk all -j12
然后我们直接在uboot的源码目录下输入下面的命令就可以调用这个编译脚本来编译了:
./build
注意,这里的“./”不能省略。大家别忘了在编译时,将修改过的文件都保存一下。一定要保存,这一步很重要。
如果你上面是严格的跟着我操作的,那么编译是不会有错误的,编译完成后,如图:
我们使用查看命令可以发现,这里已经编译出了我们所需的uboot.stm32文件:
这里我们同样将其改名为my_u-boot.stm32然后复制到uboot对应的下载目录中:
这里的tsv文件我们不用修改,下面打开STM32CubeProgrammer并且加载tsv文件:
我们将这些文件下载到开发板中,下载应该是不会出错的:
然后我们将拨码切换到EMMC启动,随后使用串口终端工具查看输出:
这里我们可以看到,我们的uboot已经成功的在我们的开发板上运行起来了,那,这就表示我们的uboot已经移植成功了吗?当然还没有,我们uboot的网络和OTG都不能正常工作,我们还需要修改网络和OTG相关的部分。
下面,我们首先来修改网络节点,打开stm32mp157d-atk.dtsi文件,将下面的网络节点添加到文件的最后面:
ðernet0 { status = "okay"; pinctrl-0 = <ðernet0_rgmii_pins_a>; pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; pinctrl-names = "default", "sleep"; phy-mode = "rgmii-id"; max-speed = <1000>; phy-handle = <&phy0>; mdio0 { #address-cells = <1>; #size-cells = <0>; compatible = "snps,dwmac-mdio"; phy0: ethernet-phy@0 { reg = <0>; }; }; };
添加好以后,如图所示:
下面我们还需要为网络芯片添加驱动,正点原子的开发板使用了YT8511作为网络驱动芯片,它的驱动文件被放在了正点原子资料目录下的“1、程序源码\08、模块驱动源码\01、YT8511驱动源码\uboot下修改方法”文件夹下:
这个.c的文件就是网络芯片的驱动代码。
我们使用这个phy.c替换掉uboot源码目录下的“/drivers/net/phy/phy.c”,我这里为了方便就直接使用samba文件映射进行替换了:
这里我们使用vscode打开这个phy.c的文件找到phy_connect这个函数,大概在1095行的位置,我们需要将这个函数中的addr直接写0:
这样我们网络部分就差不多弄好了,下面来修改USBOTG。
首先我们来为USBOTG添加一个节点,我们可以直接将下面的代码添加到stm32mp157d-atk.dtsi文件的“\”节点下,注意这里一定要是“\”节点:
usb_phy_tuning: usb-phy-tuning { st,hs-dc-level = <2>; st,fs-rftime-tuning; st,hs-rftime-reduction; st,hs-current-trim = <15>; st,hs-impedance-trim = <1>; st,squelch-level = <3>; st,hs-rx-offset = <2>; st,no-lsfs-sc; };
添加完成以后如图所示:
正点原子STM32MP157开发板上的USB OTG接口类型为Type-C,使用STUSB1600芯片 来实现此接口功能,STUSB1600有一个I2C接口,此I2C接口用来配置芯片,因此我们还需要 在设备树中添加STUSB1600相关的I2C节点内容。将如下内容添加到stm32mp157d-atk.dtsi的 最后面:
&i2c1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c1_pins_a>; pinctrl-1 = <&i2c1_pins_sleep_a>; i2c-scl-rising-time-ns = <100>; i2c-scl-falling-time-ns = <7>; status = "okay"; /delete-property/dmas; /delete-property/dma-names; stusb1600@28 { compatible = "st,stusb1600"; reg = <0x28>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; interrupt-parent = <&gpiog>; pinctrl-names = "default"; pinctrl-0 = <&stusb1600_pins_a>; status = "okay"; vdd-supply = <&vin>; connector { compatible = "usb-c-connector"; label = "USB-C"; power-role = "dual"; power-opmode = "default"; port { con_usbotg_hs_ep: endpoint { remote-endpoint = <&usbotg_hs_ep>; }; }; }; }; };
添加完成以后,如图所示:
同样是在这个文件下面,继续添加USB接口相关节点,我们直接将下方的代码复制到文件末尾即可:
&usbh_ehci { phys = <&usbphyc_port0>; status = "okay"; }; &usbotg_hs { phys = <&usbphyc_port1 0>; phy-names = "usb2-phy"; usb-role-switch; status = "okay"; port { usbotg_hs_ep: endpoint { remote-endpoint = <&con_usbotg_hs_ep>; }; }; }; &usbphyc { status = "okay"; };
添加完以后,如图所示:
最后,我们需要在“stm32mp157d-atk-u-boot.dtsi”文件中添加osbotg_hs节点,将下面的代码直接添加到stm32mp157d-atk-u-boot.dtsi的最下方:
&usbotg_hs { u-boot,force-b-session-valid; hnp-srp-disable; /* TEMP: force peripheral for USB OTG */ dr_mode = "peripheral";
};
添加以后,如图所示:
至此,我们usbotg的相关节点就已经完成了。
下面,我们还需要使能boot和bootd命令,在ST原本的uboot代码中,这两条命令并没有被使能。使能这两条命令也非常简单,只需要添加一条宏定义就行,我们打开uboot源码目录下的“include/configs/”目录下的stm32mp1.h文件:
将下面这一行代码添加到258行处:
#define CONFIG_CMD_BOOTD
添加完成以后如图所示:
这样一来我们的uboot和ubootd命令就使能了。
下面我们还需要一下LCD的驱动,使uboot能够支持LCD显示。我们再次回到“stm32mp157d-atk.dts”这个文件:
我们需要在这个文件下的“\”节点下添加panel_backlight和panel_rgb两个节点:
panel_rgb: panel-rgb { compatible = "simple-panel"; pinctrl-names = "default", "sleep"; pinctrl-0 = <<dc_pins_b>; pinctrl-1 = <<dc_pins_sleep_b>; backlight = <&panel_backlight>; status = "okay"; port { panel_in_rgb: endpoint { remote-endpoint = <<dc_ep0_out>; }; }; display-timings { native-mode = <&timing0>; /* 时序信息 */ timing0: timing0 { /* 7寸1024*600分辨率 */ clock-frequency = <51200000>; /* LCD 像素时钟,单位 Hz */ hactive = <1024>; /* LCD X 轴像素个数 */ vactive = <600>; /* LCD Y 轴像素个数 */ hfront-porch = <160>; /* LCD hfp 参数 */ hback-porch = <140>; /* LCD hbp 参数 */ hsync-len = <20>; /* LCD hspw 参数 */ vback-porch = <20>; /* LCD vbp 参数 */ vfront-porch = <12>; /* LCD vfp 参数 */ vsync-len = <3>; /* LCD vspw 参数 */ }; }; };
添加完成以后如图:
正点原子不同的屏幕对应的panel-rgb下的display-timings 也不同,我代码中对应的是正点原子的1024x600的7寸屏幕,其他屏幕的display-timings 大家根据正点原子的文档自行修改即可。
就在当前文件,我们需要添加一个ltdc节点,我们可以在文件的最后添加下面的代码:
<dc { status = "okay"; pinctrl-names = "default"; port { #address-cells = <1>; #size-cells = <0>; ltdc_ep0_out: endpoint@0 { reg = <0>; remote-endpoint = <&panel_in_rgb>; }; };
};
添加完成以后,如图所示:
当我们完成上面的步骤以后,我们的uboot就算是已经移植完成了。
我们再次使用我们的编译脚本进行编译:
4.uboot自下载测试
至此,我们的uboot已经和正点原子的uboot并没有什么区别了,我们再也不需要my_u-boot.stm32了。我们可以直接将uboot下载目录下的my_u-boot.stm32和u-boot.stm32都删掉,将我们已经编译好的u-boot.stm32拷贝到uboot的下载目录下:
我们再修改一下tsv文件,将最后一行替换为下面的内容:
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
替换完成以后,如下图:
然后再次打开STM32CubeProgrammer加载脚本:
我们可以看到,这里使用我们自己的uboot是可以正常下载程序的:
至此,我们就完成了uboot的移植与自下载测试。
七、结语
这篇教程未免有些太长了,我写起来也有些累,在下一次的教程中,我会教大家如何使用uboot中的基础命令,在使用基础命令的同时,也可以测试我们的移植是否成功。好了,最后,感谢大家的观看!
相关文章:

[Linux]从零开始的STM32MP157 U-Boot移植
一、前言 在上一次教程中,我们了解了STM32MP157的启动流程与安全启动机制。我们还将FSBL的相关代码移植成功了。大家还记得FSBL的下一个步骤是什么吗?没错,就是SSBL,而且常见的我们将SSBL作为存放U-Boot的地方。所以本次教程&…...

【Unity3D】实现横版2D游戏——攀爬绳索(简易版)
目录 GeneRope.cs 场景绳索生成类 HeroColliderController.cs 控制角色与单向平台是否忽略碰撞 HeroClampController.cs 控制角色攀爬 OnTriggerEnter2D方法 OnTriggerStay2D方法 OnTriggerExit2D方法 Update方法 开始攀爬 结束攀爬 Sensor_HeroKnight.cs 角色触发器…...

【llm对话系统】大模型 Llama 源码分析之 LoRA 微调
1. 引言 微调 (Fine-tuning) 是将预训练大模型 (LLM) 应用于下游任务的常用方法。然而,直接微调大模型的所有参数通常需要大量的计算资源和内存。LoRA (Low-Rank Adaptation) 是一种高效的微调方法,它通过引入少量可训练参数,固定预训练模型…...

算法随笔_35: 每日温度
上一篇:算法随笔_34: 最后一个单词的长度-CSDN博客 题目描述如下: 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升…...

嵌入式硬件篇---CPUGPUTPU
文章目录 第一部分:处理器CPU(中央处理器)1.通用性2.核心数3.缓存4.指令集5.功耗和发热 GPU(图形处理器)1.并行处理2.核心数量3.内存带宽4.专门的应用 TPU(张量处理单元)1.为深度学习定制2.低精…...

STM32 PWM驱动舵机
接线图: 这里将信号线连接到了开发板的PA1上 代码配置: 这里的PWM配置与呼吸灯一样,呼吸灯连接的是PA0引脚,输出比较单元用的是OC1通道,这里只需改为OC2通道即可。 完整代码: #include "servo.h&quo…...

设计心得——平衡和冗余
一、平衡 在前面分析了一些软件设计的基础和原则后,今天分析一下整体设计上的一些实践问题。首先分析一下设计上的平衡问题。平衡非常好理解,看到过天平或者标称的同学们应该都知道什么平衡。无论在哪个环境里,平衡都是稳定的基础。 既然说到…...

webrtc协议详细解释
### 一、概述与背景 WebRTC(Web Real-Time Communication)最早由 Google 在 2011 年开源,旨在为浏览器与移动端应用提供客户端直连(点对点)方式进行实时音视频及数据传输的能力。传统的网络应用在进行高实时性音视频通…...
动手学强化学习(四)——蒙特卡洛方法
一、蒙特卡洛方法 蒙特卡洛方法是一种无模型(Model-Free)的强化学习算法,它通过直接与环境交互采样轨迹(episodes)来估计状态或动作的价值函数(Value Function),而不需要依赖环境动态…...

网络原理(3)—— 传输层详解
目录 一. 再谈端口号 二. UDP协议(用户数据报协议) 2.1 UDP协议端格式 2.2 UDP报文长度 2.3 UDP校验和 三. TCP协议(传输控制协议) 3.1 TCP协议段格式 3.2 核心机制 3.2.1 确认应答 —— “感知对方是否收到” 3.2.2 超时重传 3.3.3 连接管理 —— 三次握手与四…...

2025美赛美国大学生数学建模竞赛A题完整思路分析论文(43页)(含模型、可运行代码和运行结果)
2025美国大学生数学建模竞赛A题完整思路分析论文 目录 摘要 一、问题重述 二、 问题分析 三、模型假设 四、 模型建立与求解 4.1问题1 4.1.1问题1思路分析 4.1.2问题1模型建立 4.1.3问题1样例代码(仅供参考) 4.1.4问题1样例代码运行结果&…...

Elasticsearch的开发工具(Dev Tools)
目录 说明1. **Console**2. **Search Profiler**3. **Grok Debugger**4. **Painless Lab**总结 说明 Elasticsearch的开发工具(Dev Tools)在Kibana中提供了多种功能强大的工具,用于调试、优化和测试Elasticsearch查询和脚本。以下是关于Cons…...

Python-基于PyQt5,pdf2docx,pathlib的PDF转Word工具
前言:日常生活中,我们常常会跟WPS Office打交道。作表格,写报告,写PPT......可以说,我们的生活已经离不开WPS Office了。与此同时,我们在这个过程中也会遇到各种各样的技术阻碍,例如部分软件的PDF转Word需要收取额外费用等。那么,可不可以自己开发一个小工具来实现PDF转…...

小程序-视图与逻辑
前言 1. 声明式导航 open-type"switchTab"如果没有写这个,因为是tabBar所以写这个,就无法跳转。路径开始也必须为斜线 open-type"navigate"这个可以不写 现在开始实现后退的效果 现在我们就在list页面里面实现后退 2.编程式导航…...

UE5制作视差图
双目深度估计开源数据集很多都是用UE制作的,那么我们自己能否通过UE制作自己想要的场景的数据集呢。最近花了点时间研究了一下,分享给需要的小伙伴。 主要使用的是UnrealCV插件,UnrealCV是一个开源项目,旨在帮助计算机视觉研究人…...

海浪波高预测(背景调研)
#新星杯14天创作挑战营第7期# ps:图片由通义千问生成 历史工作: 针对更高细粒度、更高精度的波浪高度预测任务: Mumtaz Ali 等人提出了一种多元线性回归模型(MLR-CWLS),该模型利用协方差加权最小二乘法&a…...

代码随想录算法训练营第四十二天-动态规划-股票-188.买卖股票的最佳时机IV
题目要求进行k次买卖其实就是上一题的扩展,把2次扩展为k次定义动规数组依然是二维,第一个维度表示第几天,第二个维度表示第几次买入和卖出所以第二个维度的长度应该是2k1在for循环内,要使用一个内循环来表示第几次买入或卖出&…...

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)
文章目录 Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理(Plugin Management)基础配置模板案例:Android项目标准配…...

软件工程经济学-日常作业+大作业
目录 一、作业1 作业内容 解答 二、作业2 作业内容 解答 三、作业3 作业内容 解答 四、大作业 作业内容 解答 1.建立层次结构模型 (1)目标层 (2)准则层 (3)方案层 2.构造判断矩阵 (1)准则层判断矩阵 (2)方案层判断矩阵 3.层次单排序及其一致性检验 代码 …...

论文阅读(三):微阵列数据的图形模型和多变量分析
1.论文链接:Graphical Models and Multivariate Analysis of Microarray Data 摘要: 基因表达数据的通常分析忽略了基因表达值之间的相关性。从生物学上讲,这种假设是不合理的。本章介绍的方法允许通过稀疏高斯图形模型来描述基因之间的相关…...

【大模型LLM面试合集】大语言模型架构_MHA_MQA_GQA
MHA_MQA_GQA 1.总结 在 MHA(Multi Head Attention) 中,每个头有自己单独的 key-value 对;标准的多头注意力机制,h个Query、Key 和 Value 矩阵。在 MQA(Multi Query Attention) 中只会有一组 k…...

向上调整算法(详解)c++
算法流程: 与⽗结点的权值作⽐较,如果⽐它⼤,就与⽗亲交换; 交换完之后,重复 1 操作,直到⽐⽗亲⼩,或者换到根节点的位置 这里为什么插入85完后合法? 我们插入一个85,…...

【Transformer】手撕Attention
import torch from torch import nn import torch.functional as F import mathX torch.randn(16,64,512) # B,T,Dd_model 512 # 模型的维度 n_head 8 # 注意力头的数量多头注意力机制 class multi_head_attention(nn.Module): def __init__(self, d_model, n_hea…...

844.比较含退格的字符串
目录 题目思路解法收获 题目 给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。 注意:如果对空文本输入退格字符,文本继续为空。 思路 如何解退格之后left…...

图书管理系统 Axios 源码__编辑图书
目录 功能概述: 代码实现(index.js): 代码解析: 图书管理系统中,删除图书功能是核心操作之一。下是基于 HTML、Bootstrap、JavaScript 和 Axios 实现的删除图书功能的详细介绍。 功能概述: …...

LabVIEW纤维集合体微电流测试仪
LabVIEW开发纤维集合体微电流测试仪。该设备精确测量纤维材料在特定电压下的电流变化,以分析纤维的结构、老化及回潮率等属性,对于纤维材料的科学研究及质量控制具有重要意义。 项目背景 在纤维材料的研究与应用中,电学性能是评估其性能…...

Commander 一款命令行自定义命令依赖
一、安装 commander 插件 npm install commander 二、基本用法 1. 创建一个简单的命令行程序 创建一个 JavaScript 文件,例如 mycli.js,并添加以下代码: // 引入 commander 模块并获取 program 对象。const { program } require("…...

Day24 洛谷普及2004(内涵前缀和与差分算法)
零基础洛谷刷题记录 Day01 2024.11.18 Day02 2024.11.25 Day03 2024.11.26 Day04 2024.11.28 Day05 2024.11.29 Day06 2024 12.02 Day07 2024.12.03 Day08 2024 12 05 Day09 2024.12.07 Day10 2024.12.09 Day11 2024.12.10 Day12 2024.12.12 Day13 2024.12.16 Day14 2024.12.1…...

遗传算法与深度学习实战(33)——WGAN详解与实现
遗传算法与深度学习实战(33)——WGAN详解与实现 0. 前言1. 训练生成对抗网络的挑战2. GAN 优化问题2.1 梯度消失2.2 模式崩溃 2.3 无法收敛3 Wasserstein GAN3.1 Wasserstein 损失3.2 使用 Wasserstein 损失改进 DCGAN 小结系列链接 0. 前言 原始的生成…...

gitlab云服务器配置
目录 1、关闭防火墙 2、安装gitlab 3、修改配置 4、查看版本 GitLab终端常用命令 5、访问 1、关闭防火墙 firewall-cmd --state 检查防火墙状态 systemctl stop firewalld.service 停止防火墙 2、安装gitlab xftp中导入安装包 [rootgitlab ~]#mkdir -p /service/tool…...