iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等
第六十八章 U-Boot移植
在“第十一章 编译U-Boot”已经对U-Boot进行了编译以及介绍,且对编译出的文件作用做了简单的说明,下面我们对官方提供的源码来进行移植,以此来适配我们自己的开发板。
官方提供的系统源码存放路径为“iTOP-STM32MP157开发板网盘资料汇总\07_系统移植\01_官方源码”下的u-boot-stm32mp-2020.01-r0文件夹。
移植好的系统源码存放路径为“iTOP-STM32MP157开发板网盘资料汇总\07_系统移植\02_移植好的源码\u-boot”。
68.1 源码的导入以及打补丁
将官方提供的系统源码文件夹拷贝到ubuntu上,如下图所示
使用命令“cd u-boot-stm32mp-2020.01-r0/”,进入源码文件夹如下图所示:
然后使用命令“tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz”,对源码的压缩文件进行解压,如下图所示:
解压完成之后,使用命令“ cd u-boot-stm32mp-2020.01”进入tf-a-stm32mp-2.2.r1源码文件如下图所示:
然后我们使用一下命令进行打补丁,打补丁完成如下图所示:
for p in `ls -1 ../*.patch`;do patch -p1 < $p;done
68.2 编译U-Boot源码
68.2.1 增设自己的平台
使用命令“cd u-boot-stm32mp-2020.01”,进入uboot目录,如下图所示:
使用以下命令
cp configs/stm32mp15_trusted_defconfig configs/stm32mp15_itop_trusted_defconfig
创建自己的的默认配置文件,如下图所示:
然后我们使用命令“cd arch/arm/dts/”进入设备树文件存放目录,可以看到ST官方开发板的设备树文件,而我们的板子同样也是参照官方开发板来进行设计的,所以为了方便我们直接通过修改官方开发板的设备树文件来适配我们自己的开发板。
使用以下命令,将官方的设备树文件进行复制并修改文件名,如下图所示
cp stm32mp15xx-dkx.dtsi stm32mp15xx-itop.dtsi
cp stm32mp157a-dk1.dts stm32mp157a-itop.dts
cp stm32mp157a-dk1-u-boot.dtsi stm32mp157a-itop-u-boot.dtsi
使用命令“vim stm32mp157a-itop.dts”进入stm32mp157a-itop.dts文件,将头文件中的
#include "stm32mp15xx-dkx.dtsi"
修改为
#include "stm32mp15xx-itop.dtsi"
修改完成如下图所示:
并将model从STMicroelectronics STM32MP157A-DK1 Discovery Board修改为STMicroelectronics STM32MP157A-iTOP Discovery Board,修改完成如下图所示:
保存退出之后使用以下命令进入stm32mp15xx-itop.dtsi文件夹
vim stm32mp15xx-itop.dtsi
由于官方的DK1开发板内存默认为512MB而我们的内存为1G,所以我们将 memory属性值由
0xc0000000 0x20000000
修改为
0xc0000000 0x40000000
修改完成如下图所示:
并将model从STMicroelectronics STM32MP157A-DK1 Discovery Board修改为STMicroelectronics STM32MP157A-iTOP Discovery Board,修改完成如下图所示:
保存退出之后使用以下命令进入stm32mp15xx-itop.dtsi文件夹
vim stm32mp15xx-itop.dtsi
由于官方的DK1开发板内存默认为512MB而我们的内存为1G,所以我们将 memory属性值由
0xc0000000 0x20000000
修改为
0xc0000000 0x40000000
修改完成如下图所示:
保存退出之后使用以下命令进入stm32mp15xx-itop.dtsi文件夹
vim stm32mp15xx-itop.dtsi
由于官方的DK1开发板内存默认为512MB而我们的内存为1G,所以我们将 memory属性值由
0xc0000000 0x20000000
修改为
0xc0000000 0x40000000
修改完成如下图所示
保存退出之后,使用命令“vim stm32mp157a-itop-u-boot.dtsi”进入stm32mp157a-itop-u-boot.dtsi文件将
#include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi"
修改为
#include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
修改完成如下图所示:
保存退出之后,继续再设备树目录下使用命令“ vim Makefile”对编译配置文件进行修改,打开之后如下图所示:
使用查找命令查找“stm32mp157a-dk1.dtb”,然后在下方添加我们自己的设备树文件
stm32mp157a-itop.dtb \
添加完成之后如下图所示:
保存退出,至此我们自己的平台就增加完成了。
68.2.2 修改Makefile文件
回到uboot源码目录下,如下图所示:
使用命令“vim Makefile ”进入Makefile进行文件的修改,进入文件如下图所示:
然后使用查找命令查找“CROSS_COMPILE ?=”,查找完成如下图所示:
我们在endif下添加以下内容
ARCH = arm
CROSS_COMPILE = arm-none-linux-gnueabihf-
所添加的为我们对应的架构和编译器,添加完成如下图所示:
保存退出。至此我们的Makefile文件就修改完成了。
68.2.3修改Makefile.sdk文件
我们返回上一级目录,可以看到对应的Makefile.sdk文件。如下图所示:
使用命令“vim Makefile.sdk”编辑进入该文件,如下图所示:
这个DEVICE_TREE为最后我们要编译的设备树文件,为了减少编译时间,我们将DEVICE_TREE这一行注释,然后单独加上我们自己的内容,如下:
DEVICE_TREE ?= stm32mp157a-itop
修改完成如下图所示:
保存退出。
68.2.4修改stm32mp1.c文件
首先我们回到uboot源码目录下,如下图所示:
然后我们使用以下命令
vim board/st/stm32mp1/stm32mp1.c
对stm32mp1.c文件进行修改,我们注释掉以下两行内容,注释完成如下图所示:
boot_mode = BOOT_FASTBOOT;
boot_mode = BOOT_STM32PROG;
本修改的原因是使编译出来的uboot镜像具备otg烧写的功能。
68.2.5 编译uboot文件
回到源码目录下使用命令“vim create.sh”创建create.sh文件,并添加以下内容
#!/bin/sh
make stm32mp15_itop_trusted_defconfig
cp .config ../build-trusted/
make distclean
make -f $PWD/../Makefile.sdk all UBOOT_CONFIGS=stm32mp15_itop_trusted_defconfig,trusted,u-boot.stm32
添加完成如下图所示:
保存退出之后使用命令“chmod 777 create.sh ”,给予文件可执行权限,如下图所示:
然后使用命令“./create.sh”来执行该脚本,编译完成如下图所示:
回到上一级目录下,可以看到多出了一个“build-trusted”文件夹,这个文件夹内存放的就是我们编译所得到的文件夹。
进入build-trusted文件夹,u.boot.stm32就是我们最终所要用到的烧写镜像。
这里需要注意的是,在使用STM32CubeProgram软件烧写的时候会烧写两个uboot如下图所示,虽然他们的名字不一样,但他们的来源都是上面编译出来的u-boot.stm32。
首先烧写进去的名为otg-uboot.stm32的用途为辅助STM32CubeProgram烧写,而第二个名为emmc_uboot.stm32或tf_uboot.stm32为我们最终emmc或者TF卡启动所要用到的uboot,这个uboot我们稍后会添加一些环境变量,对此进行一些修改,所以最终的uboot源码编译出的镜像会失去辅助STM32CubeProgram烧写的功能,但对于我们自身并没有影响,我们真正需要的只是最终烧写到EMMC或者TF卡的uboot。
68.2.6 烧写初始uboot镜像
注意由于官方的开发板默认没有配置EMMC,我们本小节使用TF卡进行烧写测试,如果目前手上没有TF卡,可以不进行本小节的测试,但对应的流程需要浏览一下。
将“iTOP-STM32MP157开发板光盘资料\02_开发板烧写工具\02_烧写文件模板”路径下的image文件夹拷贝到ubuntu虚拟机上,拷贝完成如下图所示:
然后我们使用命令“ ls uboot/”命令查看对应的文件夹,可以看到uboot文件夹内的文件正是我们上一小节结束时所讲解的文件,如下图所示:
使用命令将编译出来文件使用以下命令拷贝到uboot文件夹内,对原有的文件进行替换如下图所示(每个人路径并不一样,在此需要注意):
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 ./uboot/otg-uboot.stm32
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 ./uboot/tf_u-boot.stm32
使用命令“stm32.sh”打开烧写软件,如下图所示:
烧写的tsv规则文件我们选择tfcard.tsv如下图所示:
将开发板的拨码开关设置为“0000”,接好otg线之后,对开发板进行上电。在烧写软件之中选中对应的设备USB1,然后进行烧写(具体的烧写过程可以查看第八章STM32MP157烧写系统,在这里没有进行太多的讲解)。在烧写过程之中,也可以看到串口的打印信息,但是会卡在下图所在的地方,提示没有检测到设备,并不会进行后续的烧写
原因是我们在uboot设备树之中并没有进行TF热插拔引脚的修改,官方默认TF卡引脚和我们自己板子的设置引脚并不相同,在uboot源码下使用命令“vim arch/arm/dts/stm32mp15xx-itop.dtsi”,打开我们对应的设备树文件,打开之后如下图所示:
使用查找命令查找“sdmmc”,查找之后如下图所示:
sdmmc1对应的为TF卡,其中cd-gpios为热插拔检测引脚,在这里设置的为Pb7,由下图TF卡原理图可知我们开发板对应的引脚为PC0
所以我们将
cd-gpios = <&gpiob 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
修改为
cd-gpios = <&gpioc 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
修改完成如下图所示:
保存退出之后,按照步骤重新进行编译,编译完成之后再次替换烧写目录下的otg-uboot.stm32、tf_u-boot.stm32,这时候已经可以烧写成功了,烧写完成之后将拨码开关设置为“1010”TF卡启动,启动之后开发发板打印信息如下:
可以看到我们已经成功进入uboot的命令行了,对于以上存在报错的地方我们先不需要管,我们在uboot的命令行输入以下环境变量并保存,如下图所示:
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk0p5 rootwait rw'
setenv bootcmd 'ext4load mmc 0:4 c2000000 uImage;ext4load mmc 0:4 c4000000 stm32mp157a-itop-rgb-070.dtb;bootm c2000000 - c4000000'
saveenv
以上环境变量的作用是将内核与设备树加载进内存中对应的地方,并告诉内核挂载对应分区内的文件系统。保存完成之后,使用“reset”命令重启开发板。启动完成之后如下图所示,证明我们已经成功进入文件系统:
下面我们进行报错的修改。
68.3功能的修改与适配
68.3.1去掉ADC
官方参考板通过 ADC 检测开机电流,如果供电电流不足 3A 则启动失败,所以需要去掉这部分功能,否则就会报下图中显示的错误:
由于 u-boot 期间 ADC 主要功能是检测开机电流,这里直接去掉 ADC 功能即可。
在uboot源码目录下使用命令“make stm32mp15_itop_trusted_defconfig”生成我们开发板自己的.config,然后使用命令“make menuconfig”,进入uboot的功能菜单界面,如下图所示:
将下面对应路径的adc相关设置取消勾选
路径一:
> Command line interface
> Device access commands
[ ] adc - Access Analog to Digital Converters info and data
路径二:
Device Drivers --->
[ ] Enable ADC drivers using Driver Model
保存退出之后,使用命令覆盖我们之前的配置如下图所示:
cp .config ./configs/stm32mp15_itop_trusted_defconfig
然后我们使用命令“./create.sh ”进行编译,生成新的镜像。
根据上一小节相同的步骤,我们使用以下命令覆盖烧写文件的uboot文件夹内的对应文件,如下图所示(注意每个人的路径不一样,所以使用的命令也不尽相同,这里只覆盖了tf_u-boot.stm32原因是我们的otg_u-boot.stm32已经实现了他的otg烧写功能不需要再进行修改):
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 tf_u-boot.stm32
再次烧写之后,发现ADC对应的问题已经没有了,对应的打印信息如下图所示:
剩下的报错只剩下了网络问题,在下一小节中我们将会对网络问提进行适配。
68.3.2 网卡适配
再一次启动开发板,我们可以看到uboot的打印报错信息位“invalid MAC address in OTP 00:00:00:00:00:00”,该报错的意思为,MAC地址不正确,如下图所示:
然后我们在uboot命令行输入以下命令,如下图所示:
env set -f ethaddr 08:90:90:90:90:90
saveenv
reset
重启完成之后,可以看到并没有报错了,如下图所示:
然后我们使用“dhcp”命令来动态获取ip,但是最后会出现“Retry time exceeded; starting again”问题,如下图所示:
原因是我们在uboot的源码中没有对我们的AR8031网卡芯片进行配置,我们回到uboot源码目录下,如下图所示:
然后使用命令“make stm32mp15_itop_trusted_defconfig”生成我们开发板自己的.config,然后使用命令“make menuconfig”,进入uboot的功能菜单界面,如下图所示:
对下面的路径功能进行勾选:
路径1:
> Device Drivers
> Ethernet PHY (physical media interface) support
[*] Atheros Ethernet PHYs support
[*] Fixed-Link PHY
路径2:
> Networking support
[*] Random ethaddr if unset
勾选完成之后,保存退出,使用命令覆盖我们之前的配置如下图所示:
cp .config ./configs/stm32mp15_itop_trusted_defconfig
修改完成默认配置之后我们还需要对网卡的源码进行内容的添加,首先我们使用以下命令进入phy.c文件:
vim drivers/net/phy/phy.c
进入文件之后使用查找命令找到“phy_probe”函数如下图所示:
在“return err;”内容上方添加以下内容:
u16 val;
/*----------------------------------------------*/
/* Ar803x phy SmartEEE feature cause link status generates glitch,
* which cause ethernet link down/up issue, so disable SmartEEE
*/
phy_write(phydev,MDIO_DEVAD_NONE, 0xd, 0x3);
phy_write(phydev,MDIO_DEVAD_NONE, 0xe, 0x805d);
phy_write(phydev,MDIO_DEVAD_NONE, 0xd, 0x4003);
val = phy_read(phydev,MDIO_DEVAD_NONE, 0xe);
phy_write(phydev,MDIO_DEVAD_NONE, 0xe, val & ~(1 << 8));
/* To enable AR8031 output a 125MHz clk from CLK_25M */
phy_write(phydev,MDIO_DEVAD_NONE, 0xd, 0x7);
phy_write(phydev,MDIO_DEVAD_NONE, 0xe, 0x8016);
phy_write(phydev,MDIO_DEVAD_NONE, 0xd, 0x4007);
val = phy_read(phydev,MDIO_DEVAD_NONE, 0xe);
val &= 0xffe3;
val |= 0x18;
phy_write(phydev,MDIO_DEVAD_NONE, 0xe, val);
phy_write(phydev,MDIO_DEVAD_NONE, 0x1d, 0x5);
val = phy_read(phydev,MDIO_DEVAD_NONE, 0x1e);
val |= 0x0100;
phy_write(phydev,MDIO_DEVAD_NONE, 0x1e, val);
//--------------------------------------
添加完成如下图所示:
保存退出。回到uboot源码目录下,然后我们使用以下命令:
vim include/configs/stm32mp1.h
进入stm32mp1.h文件之后,使用查找命令“CONFIG_EXTRA_ENV_SETTINGS”,找到该内容之后如下图所示:
在该定义中,添加以下内容,这样就省去了我们启动之后对mac地址进行设置的步骤,添加完成如下图所示:
"ethaddr=08:90:90:90:90:90\0" \
保存退出,然后我们使用命令“./create.sh ”进行编译,生成新的镜像。
根据上一小节相同的步骤,我们使用以下命令覆盖烧写文件的uboot文件夹内的对应文件,如下图所示(注意每个人的路径不一样,所以使用的命令也不尽相同):
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 tf_u-boot.stm32
烧写成功之后,重启开发板,可以发现我们现在依然没有网卡的相关报错了,然后我们使用“dhcp”命令自动获取ip,可以看到我们的开发板目前已经能获取到对应的ip地址了,如下图所示:
然后我们使用命令
ping 192.168.1.1
可以看到我们的网关已经成功ping通了。至此我们的网卡就适配成功了。
68.3.3 EMMC适配
在源码目录下使用命令“cd arch/arm/dts/”进入设备树文件夹,然后使用命令“vim stm32mp15xx-itop.dtsi”,对stm32mp15xx-itop.dtsi文件夹进行修改,如下图所示:
进图文件夹之后使用搜索命令“/sdmmc1”对sdmmc1进行搜索,搜索定位之后如下图所示:
在sdmmc1内容下方添加以下内容适配EMMC
&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;
no-sd;
no-sdio;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
vqmmc-supply = <&vdd>;
mmc-ddr-3_3v;
status = "okay";
};
添加完成之后如下图所示:
在sdmmc1内容下方添加以下内容适配EMMC
&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;
no-sd;
no-sdio;
st,neg-edge;
bus-width = <8>;
vmmc-supply = <&v3v3>;
vqmmc-supply = <&vdd>;
mmc-ddr-3_3v;
status = "okay";
};
添加完成之后如下图所示:
保存退出之后,我们增加 emmc 映射,使用命令
vim stm32mp157a-itop-u-boot.dtsi
对 stm32mp157a-itop-u-boot.dtsi文件进行修改如下内容:
aliases {
i2c3 = &i2c4;
mmc0 = &sdmmc1;
usb0 = &usbotg_hs;
};
修改为(红色字体为增加内容):
aliases {
i2c3 = &i2c4;
mmc0 = &sdmmc1;
mmc1 = &sdmmc2;
usb0 = &usbotg_hs;
};
然后使用搜索命令搜索 sdmmc1 找到其对应节点,在其节点后添加 sdmmc2 节点的内容添加内容如下图所示:
&sdmmc2 {
u-boot,dm-spl;
}
添加完成如下图所示:
保存退出,回到源码目录下,使用命令“./create.sh”命令进行编译,编译完成之后使用如下命令将生成的uboot镜像覆盖烧写文件夹内uboot文件夹下的文件
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 ./otg-uboot.stm32
cp /home/topeet/work/u-boot-stm32mp-2020.01-r0/build-trusted/u-boot.stm32 ./emmc_u-boot.stm32
这里要注意的是,因为我们添加的是emmc功能所以在这里我们替换的为emmc对应的uboot,又因为我们要烧写到emmc里面,软件需要识别到emmc对应的设备我们才能进行烧写,所以我们需要将otg烧写对应的uboot也要换掉。如下图所示:
然后我们进行镜像的烧写,这里要注意的是,这次我们选择的烧写脚本为emmc.tsv.
烧写完成之后,将拨码开关拨到“0100”,然后启动开发板,在uboot的命令行输入以下内容
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk1p3 rootwait rw'
setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157a-itop-rgb-070.dtb;bootm c2000000 - c4000000'
saveenv
保存完成之后,使用重启命令“reset”重启开发板,启动之后如下如图所示: