[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/bash

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

消息队列篇--原理篇--常见消息队列总结(RabbitMQ,Kafka,ActiveMQ,RocketMQ,Pulsar)

1、RabbitMQ 特点&#xff1a; AMQP协议&#xff1a;RabbitMQ是基于AMQP&#xff08;高级消息队列协议&#xff09;构建的&#xff0c;支持多种消息传递模式&#xff0c;如发布/订阅、路由、RPC等。多语言支持&#xff1a;支持多种编程语言的客户端库&#xff0c;包括Java、P…

家居EDI:Hom Furniture EDI需求分析

HOM Furniture 是一家成立于1977年的美国家具零售商&#xff0c;总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品&#xff0c;满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…

【go语言】数组和切片

一、数组 1.1 什么是数组 数组是一组数&#xff1a;数组需要是相同类型的数据的集合&#xff1b;数组是需要定义大小的&#xff1b;数组一旦定义了大小是不可以改变的。 1.2 数组的声明 数组和其他变量定义没有什么区别&#xff0c;唯一的就是这个是一组数&#xff0c;需要给…

51单片机 01 LED

一、点亮一个LED 在STC-ISP中单片机型号选择 STC89C52RC/LE52RC&#xff1b;如果没有找到hex文件&#xff08;在objects文件夹下&#xff09;&#xff0c;在keil中options for target-output- 勾选 create hex file。 如果要修改编程 &#xff1a;重新编译-下载/编程-单片机重…

HTML一般标签和自闭合标签介绍

在HTML中&#xff0c;标签用于定义网页内容的结构和样式。标签通常分为两类&#xff1a;一般标签&#xff08;也称为成对标签或开放闭合标签&#xff09;和自闭合标签&#xff08;也称为空标签或自结束标签&#xff09;。 以下是这两类标签的详细说明&#xff1a; 一、一般标…

【EasyX 图形化编程保姆级喂嘴里教程】(C/C++) graphics.h 头文件库安装

文章目录 EasyXEasyX 是什么&#xff1f;超低的学习成本超多的应用场景超轻的发布过程 EasyX安装下载好后打开安装文件, 点击下一步。它自动检测已有的IDE&#xff0c;自行选择安装点击安装会提示安装成功接下来就可以在代码中使用 graphics.h 头文件库 EasyX EasyX 是什么&am…

吊打同类软件免费又可批量使用

聊一聊 对于经常用到席卡的人来说&#xff0c;每次打印都觉得麻烦&#xff0c;要是有个软件&#xff0c;直接输入名称就能打印就好了。 这不&#xff0c;只要你想&#xff0c;就肯定能实现&#xff1b;如果没实现&#xff0c;就说明你不够想。 这个软件我测试了下&#xff0…

2.攻防世界PHP2及知识点

进入题目页面如下 意思是你能访问这个网站吗&#xff1f; ctrlu、F12查看源码&#xff0c;什么都没有发现 用kali中的dirsearch扫描根目录 命令如下&#xff0c;根据题目提示以及需要查看源码&#xff0c;扫描以php、phps、html为后缀的文件 dirsearch -u http://61.147.17…

网络工程师 (11)软件生命周期与开发模型

一、软件生命周期 前言 软件生命周期&#xff0c;也称为软件开发周期或软件开发生命周期&#xff0c;是指从软件项目的启动到软件不再被使用为止的整个期间。这个过程可以细分为多个阶段&#xff0c;每个阶段都有其特定的目标、任务和产出物。 1. 问题定义与需求分析 问题定义…

深度学习练手小例子——cifar10数据集分类问题

CIFAR-10 是一个经典的计算机视觉数据集&#xff0c;广泛用于图像分类任务。它包含 10 个类别的 60,000 张彩色图像&#xff0c;每张图像的大小是 32x32 像素。数据集被分为 50,000 张训练图像和 10,000 张测试图像。每个类别包含 6,000 张图像&#xff0c;具体类别包括&#x…

力扣257. 二叉树的所有路径(遍历思想解决)

Problem: 257. 二叉树的所有路径 文章目录 题目描述思路复杂度Code 题目描述 思路 遍历思想(利用二叉树的先序遍历) 利用先序遍历的思想&#xff0c;我门用一个List变量path记录当前先序遍历的节点&#xff0c;当遍历到根节点时&#xff0c;将其添加到另一个List变量res中&…

力扣第149场双周赛

文章目录 题目总览题目详解找到字符串中合法的相邻数字重新安排会议得到最多空余时间I 第149场双周赛 题目总览 找到字符串中合法的相邻数字 重新安排会议得到最多空余时间I 重新安排会议得到最多空余时间II 变成好标题的最少代价 题目详解 找到字符串中合法的相邻数字 思…

算法题(54):插入区间

审题&#xff1a; 需要我们把newinterval的区间与interval的区间合并起来&#xff0c;并返回合并后的二维数组地址 思路&#xff1a; 方法一&#xff1a;排序合并区间 我们可以先把newinterval插入到interval中&#xff0c;进行排序然后复用合并区间的代码 方法二&#xff1a;模…

网工_HDLC协议

2025.01.25&#xff1a;网工老姜学习笔记 第9节 HDLC协议 9.1 HDLC高级数据链路控制9.2 HDLC帧格式&#xff08;*控制字段&#xff09;9.2.1 信息帧&#xff08;承载用户数据&#xff0c;0开头&#xff09;9.2.2 监督帧&#xff08;帮助信息可靠传输&#xff0c;10开头&#xf…

[免费]微信小程序智能商城系统(uniapp+Springboot后端+vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序智能商城系统(uniappSpringboot后端vue管理端)&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序智能商城系统(uniappSpringboot后端vue管理端) Java毕业设计_哔哩哔哩_bilibili 项目介绍…

nth_element函数——C++快速选择函数

目录 1. 函数原型 2. 功能描述 3. 算法原理 4. 时间复杂度 5. 空间复杂度 6. 使用示例 8. 注意事项 9. 自定义比较函数 11. 总结 nth_element 是 C 标准库中提供的一个算法&#xff0c;位于 <algorithm> 头文件中&#xff0c;用于部分排序序列。它的主要功能是将…

CF 581A.Vasya the Hipster(Java实现)

题目分析 红色袜子数量a&#xff0c;蓝色袜子数量b&#xff0c;题目是个潮哥儿&#xff0c;首先选择两种袜子混搭&#xff0c;搭不出来就纯色 思路分析 混搭数量取决于最小数量&#xff0c;剩余的纯色数量取决于哪个还有剩余且数量要/2 代码 import java.util.*;public class…

C基础寒假练习(6)

一、终端输入行数&#xff0c;打印倒金字塔 #include <stdio.h> int main() {int rows;printf("请输入倒金字塔的行数: ");scanf("%d", &rows);for (int i rows; i > 0; i--) {// 打印空格for (int j 0; j < rows - i; j) {printf(&qu…

Python在线编辑器

from flask import Flask, render_template, request, jsonify import sys from io import StringIO import contextlib import subprocess import importlib import threading import time import ast import reapp Flask(__name__)RESTRICTED_PACKAGES {tkinter: 抱歉&…