[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文件,将下面的网络节点添加到文件的最后面:

&ethernet0 { status = "okay"; pinctrl-0 = <&ethernet0_rgmii_pins_a>; pinctrl-1 = <&ethernet0_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 = <&ltdc_pins_b>; pinctrl-1 = <&ltdc_pins_sleep_b>; backlight = <&panel_backlight>; status = "okay"; port { panel_in_rgb: endpoint { remote-endpoint = <&ltdc_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节点,我们可以在文件的最后添加下面的代码:

&ltdc { 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中的基础命令,在使用基础命令的同时,也可以测试我们的移植是否成功。好了,最后,感谢大家的观看!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/10900.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单细胞-第四节 多样本数据分析,下游画图

文件在单细胞\5_GC_py\1_single_cell\2_plots.Rmd 1.细胞数量条形图 rm(list ls()) library(Seurat) load("seu.obj.Rdata")dat as.data.frame(table(Idents(seu.obj))) dat$label paste(dat$Var1,dat$Freq,sep ":") head(dat) library(ggplot2) lib…

高速稳定,功能强大的免费下载工具!!

今天&#xff0c;我向你们介绍一款超强的下载器——破姐版本&#xff0c;它完全免费&#xff0c;支持高速下载&#xff0c;将彻底解决你的下载难题。 01 软件介绍 P2P下载器免费下载工具&#xff0c;它以高速稳定、功能强大、无广告的特点&#xff0c;为你提供卓越的下载体验…

C++:虚函数与多态性习题2

题目内容&#xff1a; 编写程序&#xff0c;声明抽象基类Shape&#xff0c;由它派生出3个派生类&#xff1a;Circle、Rectangle、Triangle&#xff0c;用虚函数分别计算图形面积&#xff0c;并求它们的和。要求用基类指针数组&#xff0c;使它每一个元素指向一个派生类对象。 …

C#,入门教程(10)——常量、变量与命名规则的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(09)——运算符的基础知识https://blog.csdn.net/beijinghorn/article/details/123908269 C#用于保存计算数据的元素&#xff0c;称为“变量”。 其中一般不改变初值的变量&#xff0c;称为常变量&#xff0c;简称“常量”。 无论…

list的使用,及部分功能的模拟实现(C++)

目录&#xff08;文章中"节点"和"结点"是同一个意思&#xff09; 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 list的构造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers 1.2.6 list…

MySQL 索引

MySQL 索引 文章目录 MySQL 索引1. 索引概念2. 索引结构3. 索引分类4. 索引使用4.1 单列索引和联合索引4.2 覆盖索引4.3 前缀索引 5. SQL提示6. 索引失效情况 1. 索引概念 索引可以理解为MySQL中用来高效检索数据的数据结构&#xff0c;它是有序的&#xff0c;因为它底层使用的…

JVM方法区

一、栈、堆、方法区的交互关系 二、方法区的理解: 尽管所有的方法区在逻辑上属于堆的一部分&#xff0c;但是一些简单的实现可能不会去进行垃圾收集或者进行压缩&#xff0c;方法区可以看作是一块独立于Java堆的内存空间。 方法区(Method Area)与Java堆一样&#xff0c;是各个…

STM32 TIM定时器配置

TIM简介 TIM&#xff08;Timer&#xff09;定时器 定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断 16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能&#xff…

自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import precision_score, recall_score, f1_score# 数据准备 class1_points np.array([[1.9, 1.2],[1.5, 2.1],[1.9, 0.5],[1.5, 0.9],[0.9, 1.2],[1.1, 1.7],[1.4,…

< OS 有关 > 阿里云 几个小时前 使用密钥替换 SSH 密码认证后, 发现主机正在被“攻击” 分析与应对

信息来源&#xff1a; 文件&#xff1a;/var/log/auth.log 因为在 sshd_config 配置文件中&#xff0c;已经定义 LogLevel INFO 部分内容&#xff1a; 2025-01-27T18:18:55.68272708:00 jpn sshd[15891]: Received disconnect from 45.194.37.171 port 58954:11: Bye Bye […

[创业之路-270]:《向流程设计要效率》-2-企业流程架构模式 POS架构(规划、业务运营、支撑)、OES架构(业务运营、使能、支撑)

目录 一、POS架构 二、OES架构 三、POS架构与OES架构的差异 四、各自的典型示例 POS架构典型示例 OES架构典型示例 示例分析 五、各自的典型企业 POS架构典型企业 OES架构典型企业 分析 六、各自典型的流程 POS架构的典型流程 OES架构的典型流程 企业流程架构模式…

【贪心算法篇】:“贪心”之旅--算法练习题中的智慧与策略(一)

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;贪心算法篇–CSDN博客 文章目录 一.贪心算法1.什么是贪心算法2.贪心算法的特点 二.例题1.柠…

Python 梯度下降法(二):RMSProp Optimize

文章目录 Python 梯度下降法&#xff08;二&#xff09;&#xff1a;RMSProp Optimize一、数学原理1.1 介绍1.2 公式 二、代码实现2.1 函数代码2.2 总代码 三、代码优化3.1 存在问题3.2 收敛判断3.3 函数代码3.4 总代码 四、优缺点4.1 优点4.2 缺点 五、相关链接 Python 梯度下…

【2025年更新】1000个大数据/人工智能毕设选题推荐

文章目录 前言大数据/人工智能毕设选题&#xff1a;后记 前言 正值毕业季我看到很多同学都在为自己的毕业设计发愁 Maynor在网上搜集了1000个大数据的毕设选题&#xff0c;希望对大家有帮助&#xff5e; 适合大数据毕业设计的项目&#xff0c;完全可以作为本科生当前较新的毕…

three.js+WebGL踩坑经验合集(6.2):负缩放,负定矩阵和行列式的关系(3D版本)

本篇将紧接上篇的2D版本对3D版的负缩放矩阵进行解读。 (6.1):负缩放&#xff0c;负定矩阵和行列式的关系&#xff08;2D版本&#xff09; 既然three.js对3D版的负缩放也使用行列式进行判断&#xff0c;那么&#xff0c;2D版的结论用到3D上其实是没毛病的&#xff0c;THREE.Li…

反向代理模块jmh

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当…

软件工程经济学-日常作业+大作业

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

【回溯】目标和 字母大小全排列

文章目录 494. 目标和解题思路&#xff1a;回溯784. 字母大小写全排列解题思路&#xff1a;回溯 494. 目标和 494. 目标和 给你一个非负整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式…

告别复杂,拥抱简洁:用plusDays(7)代替plus(7, ChronoUnit.DAYS)

前言 你知道吗?有时候代码里的一些小细节看起来很简单,却可能成为你调试时的大麻烦。在 Java 中,我们用 LocalDateTime 进行日期和时间的操作时,发现一个小小的替代方法可以让代码更简洁,功能更强大。这不,今天我们就来探讨如何用 LocalDateTime.now().plusDays(7) 替代…

《苍穹外卖》项目学习记录-Day10订单状态定时处理

利用Cron表达式生成器生成Cron表达式 1.处理超时订单 查询订单表把超时的订单查询出来&#xff0c;也就是订单的状态为待付款&#xff0c;下单的时间已经超过了15分钟。 //select * from orders where status ? and order_time < (当前时间 - 15分钟) 遍历集合把数据库…