当前位置: 首页 > news >正文

正点原子嵌入式linux驱动开发——TF-A移植

经过了之前的学习,除了TF-A的详细启动流程仍待更新,TF-A的使用和其对应的大致启动流程已经进行过了学习。但是当我们实际做产品时,硬件平台肯定会和ST官方的有区别,比如DDR容量会改变,自己的硬件没有使用到官方EVK开发板所使用的PMIC芯片等等。因此就涉及到将半导体原厂提供的TF-A移植到我们的硬件上,本章就来讲解一下如何将ST官方提供的TF-A源码移植到正点原子的STM23MP157开发板上

编译ST官方TF-A源码

编译官方TF-A源码的原因

所谓的移植就是让半导体官方提供的软件在自己的硬件平台上运行起来,准确的说应该是将自己的硬件添加到官方软件包TF-A是ARM官方出品的一个软件包,半导体厂商会从ARM官方下载这个最正宗的TF-A软件包,然后将自己公司的SOC芯片添加进去,最终打包好提供给SOC用户,这个就是所谓的SDK包。我们在之前完成的对TF-A源码打的补丁就是ST编写的针对自家芯片的补丁文件,打完补丁以后的TF-A就支持了ST公司的芯片,所有使用ST芯片的厂商都会使用这个TF-A源码。打完补丁以后的TF-A能不能正常工作是需要验证的,也就是需要在一个硬件平台上运行测试,所有半导体厂商都会针对自家的芯片出一个或多个官方开发板。ST官方就有STM32MP157 EVK开发板,ST提供给用户的软件包都是在这个开发板上验证通过的,包括TF-A、uboot、linux kernel等。所有使用STM32MP157芯片的厂商都会在ST官方的开发板硬件基础上进行修改,制作自己的硬件,比如正点原子的 STM32MP157开发板就参考了 ST官方的STM32MP157 EVK开发板。

既然硬件参考了ST官方的开发板,那么软件肯定也是在官方提供的软件包基础上修改的,所以本章TF-A的移植就是在ST官方提供的TF-A源码上进行。首先肯定要先编译一下ST官方提供的 TF-A源码,目的如下:

  1. 掌握半导体官方软件编译方法
  2. 验证开发环境搭建是否正确,比如交叉编译器设置是否正确,所依赖的第三方库有没有安装等;
  3. 观察编译结果,比如编译完成以后的可执行文件保存在哪个目录下,都有哪些可执行文件及其区别等;
  4. 在自己的开发板上运行编译出来的可执行文件,所谓的移植就是改bug的过程,将编译出来的STM32MP157官方开发板可执行文件在自己的板子上运行,然后观察运行过程有没有错误,没错误最好,有错误就改,直到能在自己的开发板上正常运行,这就是移植过程。

编译TF-A

在之前的学习中已经准备好了ST官方的TF-A源码(按照之前的步骤完成打补丁之后再编译),可以另外新建一个名为“my-tfa”的目录来存放并编译ST官方的TF-A源码,如下图所示:
TF-A源码文件
上图中我们重点关注Makefile.sdk和tf-a-stm32mp-2.2.r1。Makefile.sdk是编译要用到的Makefile,其实Makefile.sdk主要是配置编译选项,最终是通过调用 tf-a-stm32mp-2.2.r1下的Makefile来完成具体编译过程的。tf-a-stm32mp-2.2.r1就是打完补丁后的ST官方TF-A源码文件,也就是我们要编译的。

修改Makefile.sdk

首先要修改上图中的Makefile.sdk,因为此文件定义编译选项,包括交叉编译器,要使用自己的交叉编译器,也就是已经安装的arm-none-linux-gnueabihf-gcc编译器。用VIM编辑器打开Makefile.sdk找到“CROSS_COMPILE”,将其改为“arm-none-linux-gnueabihf-”;修改完成后保存退出,进入到tf-a-stm32mp-2.2.r1目录下,然后进行编译,命令如下:

cd tf-a-stm32mp-2.2.r1/ //进入到 tf-a源码目录下
make -f ../Makefile.sdk all //编译

如果需要加快编译速度,可是使用多线程编译,线程数 最好和自己给虚拟机分配的物理核心一致,使用-j来指定线程数,命令如下:

make -f ../Makefile.sdk -j8 all //使用 8线程编译

编译完成以后会在tf-a-stm32mp-2.2.r1文件夹的上层目录 (也就是Makefile.sdk同级目录下)下生成一个名为“build”的文件夹,build文件夹下就是编译生成的所有可执行文件,进入到build目录下,有三个子目录,如下图所示:
编译结果
上图中有3个子目录:optee、serialboot和trusted,说明有3个版本的可执行文件,optee是针对 OP-TEE的,本教程没使用OP-TEE,所以optee目录和我们没关系。

serialboot看名字就知道是和串行启动有关的,也就是通过串口或者USB烧写系统的时候需要用到serialboot下的可执行文件,之前编写STM32CubeProgrammer所使用的Flashlayout文件(.tsv)的时候用到了一个名为“tf-a-stm32mp157d-atk-serialboot.stm32”的文件,此文件就是 serialboot目录下的。当然,上图中目前还没有“tf-a-stm32mp157d-atk-serialboot.stm32”这个文件。当把TF-A移植到自己开发板上以后就会在serialboot目录下生成我们板子对应的xxx-serialboot.stm32文件

trusted目录下的就是烧写到开发板中的TF-A镜像,进入 trusted目录,如下图所示:
TF-A镜像文件
从上图可以看出,编译出来了很多后缀为.bin、.elf、.ld、.stm32这样的文件, 以
前缀为“tf-a-stm32mp157d-ev1”的文件为例,相关的文件如下图所示:
使用STM32MP157D芯片的EV1开发板对应文件
从上图可以看出,这些文件都是针对使用STM32MP157D芯片的EV1开发板,同理,
其他的文件命名也是类似的,我们只需要选择和我们所使用开发板接近的文件就行了。比如正点原子 STM32MP157开发板使用的主控型号是STM32MP157DAA1,开发板硬件参考了ST官
方的STM32MP157 EVK开发板
,因此我们就需要使用上图中的这些文件,在移植的时候需要参考的对象就是stm32mp157d-ev1

另外,上图中的tf-a-stm32mp157d-ev1.stm32和tf-a-stm32mp157d-ev1-trusted.stm32这两个文件内容一模一样,后者只是前者的重命名版本,目的是为了和上一级optee和serialboot下的文件进行区分,我们在烧写的时候使用tf-a-stm32mp157d-ev1-trusted.stm32即可

在trusted目录下,还有一些其他的文件,比如单独的bl2和bl32对应的可执行文件:bl2.bin和bl32.bin。bl2和bl32编译过程中所有的.c源码文件对应的.o文件也都保存在bl2和bl32文件夹下。

烧写ST官方TF-A镜像

将编译出来的tf-a-stm32mp157d-ev1-trusted.stm32烧写到正点原子开发板EMMC里面,烧写方法在之前的笔记中有所讲解。烧写完成以后打开串口,设置好串口调试软件MobaXterm,设置开发板从EMMC启动,按下复位按键,观察MobaXterm软件接收到的log信息,如下图所示:
运行结果
上图代表着就是运行崩溃了,说明ST官方开发板对应的TF-A不能直接在正点原子的开发板上运行,需要进行修改。

TF-A移植

经过了上述的编译测试,ST官方的TF-A镜像并不能直接在正点原子的开发板上运行,所以需要进行移植操作。

注意,TF-A的移植全部是修改设备树,初学linux(这个文档在针对我,我就是初学者)肯定对设备树 (device tree)不了解,而设备树是一个系统的概念,会在后面的 linux驱动开发里面详解设备树的相关语法!所以初学的朋友直接根据接下来的教程修改就行了,不用深入研究其原理。或者,直接跳过TF-A的移植,直接使用正点原子移植好的。

新建开发板对应的设备树

创建板子对应设备树

设备树英文名字叫做Device tree,用来描述板子硬件信息,比如板子上的CPU有几个核、每个CPU核主频是多少,IIC、SPI这些外设的寄存器范围是多少,IIC接口下都挂了哪些设备等等。设备树文件是一种文本格式的文件,方便阅读与修改,文件后缀为.dts,设备树也有头文件,头文件后缀为.dtsi。和C语言一样,.dts可以引用头文件.dtsi,.dts经过编译以后生成.dtb文件,.dtb就是开发板要使用的。类似于我们将C语言的.c文件编译为.bin文件,然后在开发板上运行,将.dts编译为dtb的工具叫做DTC,并不是我们使用的gcc编译器

打开tf-a-stm32mp-2.2.r1\fdts目录,fdts目录下保存的就是所有开发板的设备树文件,其中就包括了STM32MP1系列的,如下图所示:
TF-A设备树文件
上图中的stm32mp157d-ev1.dts就是STM32MP157D EVK开发板所对应的设备树文件,同理还有STM32MP157其他型号的芯片,比如stm32mp157a、stm32mp157c等。我们以stm32mp157d-ev1.dts为蓝本,添加正点原子STM32MP157开发板对应的设备树文件

创建VScode工程,然后用VScode打开,打开stm32mp157d-ev1.dts文件,文件内容下图所示:
stm32mp157d-ev1.dts文件内容
上图中第8行引用了“stm32mp157d-ed1.dts”这样一个dts文件,注意,在设备树里面可以直接通过include引用另外一个.dts文件,不仅限于.dtsi文件,也就是说**.dts文件也可以作为头文件使用**。

可以看出stm32mp157d-ev1.dts文件非常简洁,主要原因是其引用了stm32mp157d-ed1.dts,主要工作都由 stm32mp157d-ed1.dts文件来完成了。所以可以把蓝本换成stm32mp157d-ed1.dts。复制一份stm32mp157d-ed1.dts,并命名为stm32mp157d-atk.dts,stm32mp157d-atk.dts就是为正点原子 STM32MP157开发板准备的设备树,命令如下:

cd fdts
cp stm32mp157d-ed1.dts stm32mp157d-atk.dts //复制

复制完成以后打开stm32mp157d-atk.dts文件,内容如下图所示:
stm32mp157d-atk.dts文件内容
第8-13行,头文件引用,其中第8-11行引用STM32MP15X芯片相关的dtsi头文件,这些全部保留即可

第12行,非常重要,“stm32mp15xx-edx.dtsi”,是edx系列开发板的通用头文件,适合具体板子有关的,很明显,板子不同其对应的板子头文件也不同。我们同样需要以stm32mp15xx-edx.dtsi为蓝本,创建正点原子开发板对应的板子头文件,一会再创建

第20行,stdout-path表示标准输出,也就是设置TF-A信息输出路径,这里设置为serial0,也就是串行接口0(注意,不是STM32MP157的串口 0),波特率为115200;

第24行,设置serial0对应STM32MP157的串口4,所以 TF-A会使用STM32MP157的串口4作为信息输出接口,在做板子的时候最好选择串口4作为通信接口

最后,需要以stm32mp15xx-edx.dtsi为蓝本,制作正点原子开发板对应的头文件,方法很简单,直接复制一份stm32mp15xx-edx.dtsi,然后将其重命名为“stm32mp157d-atk.dtsi”,命令如下:

cd fdts
cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi

拷贝完成以后就需要修改stm32mp157d-atk.dts,将第12行改为

#include "stm32mp157d-atk.dtsi"

修改以后的stm32mp157d-atk.dts文件内容如下(有缩减):
stm32mp157d-atk.dts文件内容

编译

设备树创建好以后编译一下,在编译之前要先修改以后Makefile.sdk,因此我们前面新建的stm32mp157d-atk.dts并没有添加到编译列表里面,直接编译的话并不会编译此文件。打开Makefile.sdk,在TFA_DEVICETREE配置项中添加“stm32mp157d-atk”,如下图所示:
修改后的TFA_DEVICETREE
修改完成以后保存退出,然后执行如下命令编译一下TF-A:

cd tf-a-stm32mp-2.2.r1/ //进入到 tf-a源码目录下
make -f ../Makefile.sdk all //编译

如果修改没有错误的话就会编译成功,编译完成以后进入build/trusted目录下,此时就会生成以“tf-a-stm32mp157d-atk”开头的相关文件,如下图所示:
编译生成的正点原子开发板TF-A固件
上图就是烧写的TF-A固件,其设备树(dtb)已经替换为上面新建的stm32mp157d-atk.dts了。但是由于并没有对TF-A源码做什么修改,所以tf-a-stm32mp157d-atk-trusted.stm32依旧是不可运行的,错误类型和之前的一样,可以自行烧写测试。

修改设备树电源管理

ST官方STM32MP157开发板用到了一颗PMIC芯片,型号为STPMIC1A,PMIC全称为Power Management IC,也就是集成电源管理芯片。我们在用单片机的时候,只需要给一个3.3V或5V电源即可, 使用起来很方便。但是随着芯片性能的提升,SOC对电源的要求越来越多,比如Cortex-A系列芯片主电源一般要求3.3V,但是芯片内核电压可能需要1.2V,而外扩的DDR3L芯片工作电压是1.35V,DDR3L芯片的端接电压要求0.65V,USB工作电压又要求5V等等,也就是说随着SOC功能越来越强大,所需要的的电源要求也越来越高,最直观的就是电源种类很多。另外,这些电源的上电顺序也是有要求的,也就是说,哪些电源先启动,哪些后启动等。

为此,SOC厂商为了简化硬件设计,都会针对自家的SOC芯片推出专用的PMIC芯片,PMIC芯片就是一个单进多出的电源芯片,比如输入5V,然后可以输出很多路电源,输出的这些电源可以配置输出电压。STPMIC1A就是ST专门为STM32MP1系列设计的专用PMIC,此PMIC芯片性能非常强大:

  • 输入电压 2.8V~5.5V;
  • 4路可调的通用LDO输出;
  • 1路 DDR3端接LDO电源;
  • 1路 USB PHY所使用的LDO电源;
  • 1路 DDR参考电压LDO电源;
  • 4路可调的BUCK开关电源;
  • 1路 5.2V/1.1A的BOOST开关电源;
  • 1路 500mA的USB OTG电源;
  • 1路 500mA/1000mA的通用电源;
  • 此芯片有一个IIC接口,主控通过IIC接口来配置电源芯片,设置每一路输出电源的输出电压,开启时间等。

STPMIC1A很好用但是性价比不高,STPMIC1A在ST官网报价1.9美金 /1K(2020/11/12日),也就是说1000片起的话,价格是1.9美金,换算成人民币就是12.5块钱。但是对于STM32MP157而言用不了这么多路电源,三四路就够了,所以可以采用分离电源,这样的话三四个电源芯片的价格远小于12.5块钱。难点就是分离电源很考验硬件工程师的设计功底,因为处理不同电源上电顺序,好在ST已经提供了分离电源设计手册

总之就是,因为采用ST提供的专用PMIC成本太高,因此大部分STM32MP157核心板都是采用分离电源设计的STPMIC1A是一个IIC器件,因此就涉及到驱动 问题,需要主控通过IIC接口来配置各路电源,所以ST官方提供的TF-A、uboot linux kernel等都会有PMIC驱动。但是正点原子的开发板并没有采用这个PMIC芯片,所以 TF-A默认的电源配置就会出问题,这里就需要我们修改相关的文件,取消掉这个PMIC的相关配置。

打开stm32mp157d-atk.dtsi文件,找到如下所以代码:
在这里插入图片描述
第45行,“i2c4”表示这段代码是和I2C4控制器有关的,在设备树中一个IIC接口下的所有设备都“打包”放到一个节点下,在这里就是描述 I2C4这个 IIC控制器下的所有 IIC器件。ST官方的STM32MP157开发板将STPMIC1A这个PMIC芯片挂到了I2C4下,所以STPMIC这个芯片的相关信息就会在“i2c4”这个节点下进行描述;

第54~281行,这一大段为STPMIC1A这颗芯片的描述信息,第54行是“pmic: stpmic@33”,即使我们没有学习过设备树,但是也能看出这是和PMIC有关的。在这一大段代码中,描述了STPMIC1A各输出电源应该如何配置,比如电压应该是多少,每路电源的功能是什么等

将上图中第54~281行的内容全部删除掉,也就是删除掉STPMIC1A芯片的相关描述,删除以后的 i2c4节点内容如下图所示:
删除pmic后的i2c4节点
由于我们上面把PMIC相关的信息都删除了,但是其他设备的电源信息还是要有的,只是不通过 PMIC来描述了。所以需要我们自己添加一些设备的电源描述信息,在stm32mp157d-atk.dtsi文件里面找到“vin”节点,如下图所示:
vin节点内容
将上图中的vin节点内容全部删除掉,也就是将 17~23行代码删除掉,替换为下面的代码:

vddcore: regulator-vddcore {compatible = "regulator-fixed";regulator-name = "vddcore";regulator-min-microvolt = <1200000>;regulator-max-microvolt = <1350000>;regulator-off-in-suspend;regulator-always-on;
};v3v3: regulator-3p3v {compatible = "regulator-fixed";regulator-name = "v3v3";regulator-min-microvolt = <3300000>;regulator-max-microvolt = <3300000>;regulator-off-in-suspend;regulator-always-on;
};vdd: regulator-vdd {compatible = "regulator-fixed";regulator-name = "vdd";regulator-min-microvolt = <3300000>;regulator-max-microvolt = <3300000>;regulator-off-in-suspend;regulator-always-on;
};vdd_usb: regulator-vdd-usb {compatible = "regulator-fixed";regulator-name = "vdd_usb";regulator-min-microvolt = <3300000>;regulator-max-microvolt = <3300000>;regulator-off-in-suspend;regulator-always-on;
};

第17-24行,描述VDDCORE电源,也就是STM32MP157的内核电源,最小为1.2V,最
大为1.35V;

第26-33行,描述3.3V电源,最小和最大都是3.3V;

第35-42行,描述VDD电源,这是一个3.3V的电源,所以最小和最大都为3.3V;

第44-51行,描述VDD_USB电源,为3.3V,所以最小和最大都为3.3V。

修改完后如下图所示:
修改后电源信息
至此,电源管理修改完成了,不要编译,会报错。因为修改了电源设置,而USB OTG节点还是引用的以前相关电源设置,所以编译会报错,等修改好USB OTG设备节点以后就可以编译了

修改TF卡和EMMC设备树

继续操作stm32mp157d-atk.dtsi这个文件,找到“sdmmc1”和“sdmmc2”这2个节点,节点内容如下图所示:
sdmmc1和sdmmc2原节点内容
将上图中的sdmmc1和sdmmc2节点改为如下所示内容:

&sdmmc1 {pinctrl-names = "default";pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>;st,neg-edge;broken-cd;bus-width = <4>;vmmc-supply = <&v3v3>;status = "okay";
};&sdmmc2 {pinctrl-names = "default";pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;non-removable;st,neg-edge;bus-width = <8>;vmmc-supply = <&v3v3>;vqmmc-supply = <&v3v3>;status = "okay";
};

修改完成以后sdmmc1和sdmmc2如下图所示:
修改后的sdmmc1和sdmmc2节点
同样,不要编译,会报错,因为修改了电源,而USB OTG节点还是引用的以前相关电源设置,所以编译会报错,等修改好USB OTG设备节点以后就可以编译了。

修改USB OTG设备树

最后就是修改一下USB OTG对应的设备树节点,继续操作stm32mp157d-atk.dtsi,找到“usbotg_hs”这个节点,节点默认内容如下图所示:
usbotg_hs原内容
将上图中的usbotg_hs节点改为如下所示内容:

&usbotg_hs {phys = <&usbphyc_port1 0>;phy-names = "usb2-phy";usb-role-switch;status = "okay";
};

最后还需要修改“usbphyc”节点里面的“status”属性值,看起来就是向stm32mp157d-atk.dtsi文件里面添加了一个名为“usbphyc”的节点,内容如下:

&usbphyc {status = "okay";
};

修改完成以后的usbotg_hs和usbphyc这两个节点如下图所示:
修改后的usbotg_hs和usbphyc

编译测试

编译

设备树修改完成以后先编译一下TF-A,但是我们编译的时候默认会编译很多STM32MP1开发板的TF-A镜像,我们可以修改Makefile.sdk固件,只编译正点原子开发板对应的TF-A镜像。打开Makefile.sdk文件,将TFA_DEVICETREE修改为如下图所示内容:
修改后的TFA_DEVICETREE
上图中的TFA_DEVICETREE用于指定需要编译的板子对应的设备树,这里改为之编译stm32mp157d-atk,也就是正点原子开发板对应的设备树,也就是前面我们自己创建的stm32mp157d-atk.dts文件。

修改好以后重新编译TF-A,如下图所示,表示编译成功:
编译成功
上图中提示tf-a-stm32mp157d-atk.bin编译成功,而且也生成了tf-a-stm32mp157d-atk.stm32镜像文件。

烧写测试

使用STM32CubeProgrammer软件将上面编译出来 build/trusted/tf-a-stm32mp157d-atk.stm32烧写到开发板上的EMMC中并运行,运行log信息如下图所示:
TF-A运行log信息
从上图中可以看出TF-A运行成功,其中bl2和bl32(sp_min)都正常运行,bl2和sp_min的编译时间都为2020年11月23号,其中bl2编译时间为 9:18:37,sp_min的编译时间为9:18:48,bl2先编译,SP_MIN后编译。可以看出,bl2其实已经将 uboot加载到了0xc0100000地址处,这是因为拿到的开发板默认已经烧写了出厂系统,所以TF-A可以加载uboot(bl33)

这个时候uboot可能会启动,也可能不会启动,这里先不要管uboot能不能启动。

另外,由于正点原子的STM32MP157开发板出厂已经烧写系统,所以bl2可以加载uboot到DDR上,但是如果用的是全新的核心板,EMMC还没有烧写过任何系统,或者你把EMMC格式化过,因为 EMMC里面没有uboot镜像,所以bl2在加载uboot的时候就会失败,TF-A运行的log信息如下图所示:
TF-A运行错误
从上图中可以看出,TF-A提示没有找到ssbl分区 (ssbl分区用于存放uboot),因为是全新的 EMMC核心板,而烧写的时候也没有在FlashLayout中添加ssbl分区信息,所以会提示找不到ssbl分区,从而导致TF-A启动出问题。解决方法很简单,修改FlashLayout,然后在里面添加一个ssbl分区,但是ssbl分区不烧写任何文件,就相当于新建一个名为“ssbl”的分区打开之前已经创建的FlashLayout文件tf-a.tsv,在最后一行添加如下内容:
添加的ssbl信息
上面一行的“PE”表示不更新ssbl分区,但如果不存在ssbl分区就会进行创建ssbl分区。其实就是新建一个空的ssbl,添加完成后的tf-a.tsv如下图所示:
修改后的tf-a.tsv内容
上图中最后一行就是ssbl分区,**注意0x00080000后面的箭头表示TAB键,这个TAB键是必须要的!**因为最后面还有Binary列的内容,这里我们并没有给出 Binary列的镜像文件名,表示不烧写任何文件,但是位置得留出来,否则烧写的时候STM32CubeProgrammer会 tf-a.tsv语法错误。

修改完成以后使用新的tf-a.tsv来烧写TF-A镜像,烧写完成以后TF-A运行log信息如下图所示:
TF-A运行结果
从上图可以看出,此时没有再提示ssbl分区错误了,但是有另外一个错误,那就是在加载ID=5的镜像的时候加载错误,这个就是uboot镜像。因为全新的EMMC并没有uboot镜像,因此肯定加载不到,除非把uboot镜像也烧写进去,也就是烧写到上面的ssbl分区里面。

修改tf-a.tsv文件,在ssbl分区添加要烧写的uboot镜像即可,这里直接烧写正点原子官方出厂系统的uboot镜像即可,也就是u-boot.stm32,这个文件已经放到了我们烧写目录里面,修改后的tf-a.tsv文件如下图所示:
修改后的tf-a.tsv内容
上图中最后一行的Opt要改为‘P’,也就是更新ssbl分区中的文件,u-boot.stm32要和tf-a.tsv放在同一个目录下。修改完成以后使用新的tf-a.tsv烧写TF-A和uboot镜像到开发板的EMMC里面,烧写完成以后运行TF-A,运行过程的log信息如下图所示:
TF-A运行信息
从上图可以看出,TF-A运行正常,而且因为我们也烧写了uboot镜像,因此uboot也启动了,说明TF-A运行正常。

xxx-serialboot.stm32测试

在之前的TF-A初探中构建的系统烧写目录中,用到了正点原子出厂镜像中的stm32mp157d-atk-serialboot.stm32,前面讲了STM32CubeProgrammer首先通过USB或串口向开发板下载stm32mp157d-atk-serialboot.stm32,名字里面有个“serialboot”,翻译过来就是串行启动,此镜像主要用于初始化DDR,并且提供USB或串口功能,目的是为了进一步将uboot镜像下载到DDR的指定位置,最终通过uboot来向外部Flash设备烧写整个系统镜像

所以需要掌握自行编译stm32mp157d-atk-serialboot.stm32的方法,操作很简单。首先打开 Makefile.sdk,然后将EXTRA_OEMAKE_SERIAL改为如下内容

EXTRA_OEMAKE_SERIAL=$(filter-out STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_SPI_NOR=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1,$(EXTRA_OEMAKE)) STM32MP_UART_PROGRAMMER=1 STM32MP_USB_PROGRAMMER=1

修改完成后如下图所示:
修改后的EXTRA_OEMAKE_SERIAL配置
输入如下命令编译:

cd tf-a-stm32mp-2.2.r1/ //进入到 tf-a源码目录下
make -f ../Makefile.sdk clean //清除以前的编译
make -f ../Makefile.sdk TFA_DEVICETREE=stm32mp157d-atk TF_A_CONFIG=serialboot ELF_DEBUG_ENABLE='1' all //编译

编译完成以后就会在…/build/serialboot目录下生成tf-a-stm32mp157d-atk-serialboot.stm32,如下图所示:
编译生成的tf-a-stm32mp157d-atk-serialboot.stm32
用上图中的tf-a-stm32mp157d-atk-serialboot.stm32替换我们以前使用的正点原子出厂系统中的文件,替换完成以后的烧写目录如下图所示:
images目录
此时上图中的tf-a-stm32mp157d-atk-serialboot.stm32和tf-a-stm32mp157d-atk-trusted.stm32均为我们自行编译的,tf-a-stm32mp157d-atk-trusted.stm32经过测试运行正常,接下来就要测试一下tf-a-stm32mp157d-atk-serialboot.stm32是否能正常烧写系统

直接用STM32CubeProgrammer烧写测试即可,观察是否能正常烧写,烧写完成以后tf-a-stm32mp157d-atk-trusted.stm32是否能够正常启动。

注意!按照本小节讲解的方法编译生成tf-a-stm32mp157d-atk-serialboot.stm32以
后,…/build/trusted和 …/build/optee目录就没了,也就是说此本小节的方法只能编译tf-a-stm32mp157d-atk-serialboot.stm32。一旦编译成功并测试OK以后,就不要再去修改stm32mp157d-atk-serialboot.stm32了。如果想重新编译 tf-a-stm32mp157d-atk-trusted.stm32,那么就按照以前的编译命令即可,不用修改 Makefile.sdk文件!

至此,TF-A移植全部完成!!!

总结

TF-A的移植流程

整个TF-A的移植流程如下:

  • 正点原子的开发光盘中有ST官方TF-A的源码,当然可以官网下载,咱们就直接把他拖过来用就行,就是en.SOURCES-stm32mp1-openstlinux-5-4-dunfell-mp1-20-06-24.tar.xz;
  • 使用tar -xvf解压缩后,进入tf-a-stm32mp-2.2.r1-r0,继续tar -xvf解压缩tf-a-stm32mp-2.2.r1-r0.tar.gz,进入解压后的tf-a-stm32mp-2.2.r1之后,通过如下命令打补丁
for p in `ls -1 ../*.patch`; do patch -p1 < $p; done //打补丁
  • 安装stm32wrapper4dgb,直接拖到Ubuntu之后unzip再make,然后复制到/usr/bin之中就可以了,复制命令如下:
sudo cp stm32wrapper4dbg /usr/bin
  • 在Makefile.sdk,将交叉编译器改为我们目前所使用的,找到CROSS_COMPILE,将其改为arm-none-linux-gnueabihf-
  • 进入tf-a-stm32mp-2.2.r1之后make
make -f ../Makefile.sdk -j8 all //使用 8线程编译
  • 打开tf-a-stm32mp-2.2.r1\fdts目录,复制stm32mp157d-ed1.dts并命名为stm32mp157d-atk.dts
  • 复制stm32mp15xx-edx.dtsi并命名为stm32mp157d-atk.dtsi,后在stm32mp157d-ed1.dts中12行改为
#include "stm32mp157d-atk.dtsi"
  • 正点原子MP157开发板没有PMIC这个电源管理芯片,所以按照教程完成电源的一系列配置,其操作均在stm32mp157d-atk.dtsi文件完成;
  • 配置TF卡和EMMC以及USB OTG设备树;
  • tf-a.tsv中添加uboot.stm32,添加代码如下:
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
  • 自行编译stm32mp157d-atk-serialboot.stm32的方法,在Makefile.sdk中添加:
EXTRA_OEMAKE_SERIAL=$(filter-out STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_SPI_NOR=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1,$(EXTRA_OEMAKE)) STM32MP_UART_PROGRAMMER=1 STM32MP_USB_PROGRAMMER=1
  • 编译serial,命令如下:
make -f ../Makefile.sdk clean //清除以前的编译
make -f ../Makefile.sdk TFA_DEVICETREE=stm32mp157d-atk TF_A_CONFIG=serialboot ELF_DEBUG_ENABLE='1' all //编译
  • 以上编译的三个文件:tf-a-stm32mp157d-atk-serialboot.stm32,u-boot.stm32,tf-a-stm32mp157d-atk-trusted.stm32就此完成,放在同一个文件夹中,并创建一个FlashLayout的.tsv文件完成引导,内容如下:
#Opt Id Name Type Device Offset Binary
- 0x01 fsbl1-boot Binary none 0x0 tf-a/tf-a-stm32mp157d-atk-serialboot.stm32
- 0x03 ssbl-boot Binary none 0x0 uboot/u-boot.stm32
P 0x04 fsbl1 Binary mmc1 boot1 tf-a/tf-a-stm32mp157d-atk-trusted.stm32
P 0x05 fsbl2 Binary mmc1 boot2 tf-a/tf-a-stm32mp157d-atk-trusted.stm32
P 0x06 ssbl Binary mmc1 0x00080000 u-boot.stm32
  • 最后完成开发板接线连接PC,然后通过STM32CubeProgrammer完成烧写。

原理

TF-A在正点原子另一个国产的I.MX6ULL就是没有的,属于是ST公司处于产品的完整性来确保安全加进来的一个ARM可信固件

按照TF-A的原理和源码查看,可以分为bl1、bl2、bl31、bl32以及bl33五个部分,但是在STM32MP1系列芯片中,bl1在ROM内部代码中实现,bl31不是AArch32的,bl33就是uboot,所以其实只有两个部分
STM32MP1 TF-A启动流程

下一步

终于就进入了linux驱动开发的传统学习的uboot内容啦!

相关文章:

正点原子嵌入式linux驱动开发——TF-A移植

经过了之前的学习&#xff0c;除了TF-A的详细启动流程仍待更新&#xff0c;TF-A的使用和其对应的大致启动流程已经进行过了学习。但是当我们实际做产品时&#xff0c;硬件平台肯定会和ST官方的有区别&#xff0c;比如DDR容量会改变&#xff0c;自己的硬件没有使用到官方EVK开发…...

GB28181学习(六)——实时视音频点播(数据传输部分)

GB28181系列文章&#xff1a; 总述&#xff1a;https://blog.csdn.net/www_dong/article/details/132515446 注册与注销&#xff1a;https://blog.csdn.net/www_dong/article/details/132654525 心跳保活&#xff1a;https://blog.csdn.net/www_dong/article/details/132796…...

JMeter接口自动化测试(数据驱动)

之前我们的用例数据都是配置在HTTP请求中&#xff0c;每次需要增加&#xff0c;修改用例都需要打开JMeter重新编辑&#xff0c;当用例越来越多的时候&#xff0c;用例维护起来就越来越麻烦&#xff0c;有没有好的方法来解决这种情况呢&#xff1f;我们可以将用例的数据存放在cs…...

数据结构:二叉树(超详解析)

目录​​​​​​​ 1.树概念及结构 1.1树的概念 1.2树的相关概念 1.3树的表示 1.3.1孩子兄弟表示法&#xff1a; 1.3.2双亲表示法&#xff1a;只存储双亲的下标或指针 两节点不在同一树上&#xff1a; 2.二叉树概念及结构 2.1.概念 2.2.特殊的二叉树&#xff1a; 2…...

【考研数学】高等数学第七模块 —— 曲线积分与曲面积分 | 4. 对坐标的曲面积分(第二类曲面积分)与场论初步

文章目录 二、曲面积分2.2 对坐标的曲面积分&#xff08;第二类曲面积分&#xff09;1. 问题产生 —— 流量2. 对坐标的曲面积分的定义&#xff08;了解&#xff09;3. 对坐标的曲面积分的性质4. 对坐标的曲面积分的计算法&#xff08;1&#xff09; 二重积分法&#xff08;2&a…...

使用Thrift实现跨语言RPC调用

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…...

【QT5-程序控制电源-RS232-SCPI协议-上位机-基础样例【1】】

【QT5-程序控制电源-RS232-SCPI协议-上位机-基础样例【1】】 1、前言2、实验环境3、自我总结1、基础了解仪器控制-熟悉仪器2、连接SCPI协议3、选择控制方式-程控方式-RS2324、代码编写 4、熟悉协议-SCPI协议5、测试实验-测试指令&#xff08;1&#xff09;硬件连接&#xff08;…...

leetcode 1049. 最后一块石头的重量 II、494. 目标和、474. 一和零

1049. 最后一块石头的重量 II 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么粉碎的可能结果…...

Error string: Could not load library

启动Rivz时&#xff0c;报错&#xff1a; Error string: Could not load library (Poco exception libg2o_csparse_extension.so.0.1: cannot open shared object file: No such file or directory) [ERROR] [1696572310.529059051]: Failed to load nodelet [/radar_graph_s…...

pom.xml里的标签

pom.xml 是 Maven 项目的配置文件&#xff0c;其中包含了各种配置信息和依赖管理。下面是一些常见的 pom.xml 中的标签和其作用的简要说明&#xff1a; <project>&#xff1a;根标签&#xff0c;定义了整个项目的基本信息和结构。 <groupId>&#xff1a;指定项目所…...

微服务部署的正确策略

微服务部署挑战 单体应用程序的部署意味着您运行单个&#xff08;通常是大型应用程序&#xff09;的多个相同副本。这主要是通过配置 N 个服务器&#xff08;无论是物理服务器还是虚拟服务器&#xff09;并在每台服务器上运行应用程序的 M 个实例来完成。虽然这看起来非常简单…...

C#中的数组探究与学习

目录 C#中的数组一般分为:一.数组定义:为什么要使用数组?什么是数组?C#一维数组for和foreach的区别C#多维数组C#锯齿数组初始化的意义:适用场景:C#中的数组一般分为: ​①.一维数组。 ②.多维数组,也叫矩形数组。 ③.锯齿数组,也叫交错数组。 一.数组定义: 数组…...

计算机网络八股

1、请你说说TCP和UDP的区别 TCP提供面向连接的可靠传输&#xff0c;UDP提供面向无连接的不可靠传输。UDP在很多实时性要求高的场景有很好的表现&#xff0c;而TCP在要求数据准确、对速度没有硬件要求的场景有很好的表现。TCP和UDP都是传输层协议&#xff0c;都是为应用层程序服…...

Waves 14混音特效插件合集mac/win

Waves14是一款音频处理软件&#xff0c;主要用于音频编辑、混音和母带处理。该软件提供了各种插件&#xff0c;包括EQ、压缩、混响、延迟、失真等&#xff0c;以及一些专业的音频处理工具&#xff0c;如L2限幅器、Linear Phase EQ和多频道扬声器管理。 Mac软件下载&#xff1a;…...

Python python-docx 使用教程

openpyxl是Python下的Word库&#xff0c;它能够很容易的对Word文档进行读取 安装方法&#xff1a;pip install python-docx国内镜像安装&#xff1a;pip install -i https://mirrors.aliyun.com/pypi/simple/ python-docx&#xff08;推荐&#xff0c;安装更快&#xff09;中文…...

Mac上protobuf环境构建-java

参考文献 getting-started 官网pb java介绍 maven protobuf插件 简单入门1 简单入门2 1. protoc编译器下载安装 https://github.com/protocolbuffers/protobuf/releases?page10 放入.zshrc中配置环境变量  ~/IdeaProjects/test2/ protoc --version libprotoc 3.12.1  …...

CocosCreator3.8研究笔记(二十二)CocosCreator 动画系统-动画剪辑和动画组件介绍

国庆假期&#xff0c;闲着没事&#xff0c;在家研究技术~ 大家都知道在Cocos Creator3.x 的版本的动画编辑器中&#xff0c;可以实现不用写一行代码就能实现各种动态效果。 Cocos Creator动画编辑器中主要实现关键帧动画&#xff0c;不仅支持位移、旋转、缩放、帧动画&#xff…...

信看课堂-厘米GNSS定位

我们常常说GPS 定位&#xff0c;不过定位远不止GPS定位&#xff0c;通过本节课程&#xff0c;我们将会了解到&#xff0c;原来GPS只是定位的一种&#xff1a; GNSS概述 不同的GNSS系统使用不同的频段来传输导航信号。以下是一些主要的GNSS系统及其相应的频段&#xff0c;用表…...

2023CCPC网络赛(A E)

2023CCPC网络赛(A E) The 2nd Universal Cup. Stage 3: Binjiang - Dashboard - Contest - Universal Cup Judging System A. Almost Prefix Concatenation 思路&#xff1a;首先考虑如何求出每个位置允许失配一次的LCP长度 &#xff0c; 可以二分哈希求LCP &#xff0c; 即…...

使用 python 检测泛洪攻击的案例

使用 python 检测泛洪攻击的案例 本案例只使用python标准库通过执行命令来监控异常请求, 并封锁IP, 不涉及其他第三方库工具. import os import time from collections import Counter# 1、update 命令, 采集CPU的平均负载 def get_cpu_load():"""uptime 命令…...

SCROLLINFO scrollInfo; 2023/10/5 下午3:38:53

2023/10/5 下午3:38:53 SCROLLINFO scrollInfo;scrollInfo.cbSize = sizeof(SCROLLINFO);scrollInfo.fMask = SIF_ALL;//scrollInfo.nMin = 0; // 最小位置//scrollInfo.nMax = nRowCountToShow; // 最大位置//scrollInfo.nPage = nRowCountToShow; // 页面大小//scrollInf…...

Python--控制台获取输入与正则表达式

前言一、控制台获取输入1.1 字符串输入1.2 整数输入1.3 浮点数输入1.4 布尔值输入1.5 列表输入1.6 汇总 二、正则表达式2.1 匹配数字2.2 模式检查2.3 替换字符2.4 切分字符串2.5 搜索并提取匹配的部分2.6 使用捕获组提取匹配的部分2.7 非贪婪匹配2.8 忽略大小写匹配2.9 使用预定…...

网络基础知识面试题1

VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)...

JavaScript系列从入门到精通系列第十五篇:JavaScript中函数的实参介绍返回值介绍以及函数的立即执行

文章目录 一&#xff1a;函数的参数 1&#xff1a;形参如何定义 2&#xff1a;形参的使用规则 二&#xff1a;函数的返回值 1&#xff1a;函数返回值如何定义 2&#xff1a;函数返回值种类 三&#xff1a;实参的任意性 1&#xff1a;方法可以作为实参 2&#xff1a;将匿…...

js中的原型链

编写思路&#xff1a; 简单介绍构造函数介绍原型对象原型对象、实例的关系&#xff0c;从而引出原型链的基本概念 原型链基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。 1. 什么是构造函数 构造函数本身跟普通函数一样&#xff0c;也不存在定义构造函数…...

一文搞懂APT攻击

APT攻击 1. 基本概念2. APT的攻击阶段3. APT的典型案例参考 1. 基本概念 高级持续性威胁&#xff08;APT&#xff0c;Advanced Persistent Threat&#xff09;&#xff0c;又叫高级长期威胁&#xff0c;是一种复杂的、持续的网络攻击&#xff0c;包含高级、长期、威胁三个要素…...

在pandas中通过一列数据映射出另一列的几种思路和方法

如果一句话中出现某个品牌的关键词&#xff0c;那么就将该品牌进行提取&#xff0c;开始我的做法是写了很多elif&#xff0c;如下&#xff1a; def brand_describe(x):if TRUM in x.upper():return "通快"elif BYSTRONIC in x.upper():return "百超"elif …...

数据分析视角中的商业分析学习笔记

数据分析一大堆&#xff0c;结果却是大家早就知道的结论&#xff1f;是工具和方法出问题了吗&#xff1f;真正原因可能是你的思维有误区。 为什么分析的这么辛苦&#xff0c;得出的结论大家早知道&#xff0c;谁谁都不满意&#xff1f;核心原因有3个&#xff1a; 分析之前&am…...

剑指offer——JZ26 树的子结构 解题思路与具体代码【C++】

一、题目描述与要求 树的子结构_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入两棵二叉树A&#xff0c;B&#xff0c;判断B是不是A的子结构。&#xff08;我们约定空树不是任意一个树的子结构&#xff09; 假如给定A为{8,8,7,9,2,#,#,#,#,4,7}&#xff0c;B为{8,9,2}&…...

NEFU数字图像处理(1)绪论

一、简介 1.1什么是数字图像 图像是三维场景在二维平面上的影像。根据其存储方式和表现形式&#xff0c;可以将图像分为模拟图像和数字图像两大类 图像处理方法&#xff1a;光学方法、电子学方法 模拟图像&#xff1a;连续的图像数字图像&#xff1a;通过对时间上和数值上连续…...

购物网站前台功能/阿里云域名注册官网

以前的需求是将mysql厘米的表和函数转为oracle里面 试过了很多种方法&#xff0c;oracle sqldeveloper,里面加入mysql包&#xff0c;就可以转换&#xff0c;但是有些会转化错误。 这边强烈建议使用Navicat_Premium&#xff0c;基本上都能成功。...

wordpress绝对域名更改/中国今天最新军事新闻

课前声明&#xff1a; 1、本分享仅做学习交流&#xff0c;请自觉遵守法律法规&#xff01; 2、搜索&#xff1a;Kali 与编程&#xff0c;学习更多网络攻防干货&#xff01; 3、Kali 与编程每天准时更新&#xff0c;敬请学习和关注&#xff01; 正文部分 一、背景介绍 局域网自然…...

北京网站seo服务/怎样在百度做广告宣传

前言 上一节RxJava2.0的初学者必备教程(二)讲解了线程调度, 并且举了两个实际中的例子, 其中有一个登录的例子, 不知大家有没有想过这么一个问题, 如果是一个新用户, 必须先注册, 等注册成功之后再自动登录该怎么做呢. 很明显, 这是一个嵌套的网络请求, 首先需要去请求注册, 待…...

在线做h5 的网站/网页是怎么制作的

密码学 密码学&#xff1a;提供了通信安全的基础 ∙\bullet∙ 通信安全包括&#xff1a; – 保密性 – 真实性 – 完整性 – 不可否认性 加密流程 密码分析 ∙\bullet∙密码分析试图破解出加密消息的密钥或明文 ∙\bullet∙密码分析的类型 –密文攻击 已知C1EK(P1),C2EK(P2)…...

网络工程有哪些/关键词优化教程

对话框不是模式就是无模式的。模式对话框&#xff0c;在可以继续操作应用程序的其他部分之前&#xff0c;必须被关闭&#xff08;隐藏或卸载&#xff09;。例如&#xff0c;如果一个对话框&#xff0c;在可以切换到其它窗 体或对话框之前要求先单击“确定”或“取消”&#xff…...

濮阳做网站的公司/电脑优化大师有用吗

445. 两数相加 II 给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。 中等难度。这道题和LeetCode Java刷题笔记—2. 两数相加是类似的题目&#xff0c;区别就是这道题是顺序存储的&#xf…...