OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5067|回复: 1

《STM32MP157嵌入式Linux驱动开发指南》第十三章 U-boot移植

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4666
金钱
4666
注册时间
2019-5-8
在线时间
1224 小时
发表于 2021-6-16 11:48:31 | 显示全部楼层 |阅读模式
1)实验平台:正点原子STM32MP157开发板
2)  章节摘自【正点原子】《STM32MP157嵌入式Linux驱动开发指南》
3)购买链接:https://item.taobao.com/item.htm?&id=629270721801
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyzmp157.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子STM32MP157技术交流群:691905614  
O1CN01abYcZO23XsL4ETed4_!!230947266.png
原子哥在线教育平台.jpg

152443zfu1nrzhhhh6wuc8.png
第十三章 U-boot移植



uboot的移植并不是说我们完完全全的从零开始将 uboot 移植到我们现在所使用的开发板或者开发平台上。这个对于我们来说基本是不可能的,这个工作一般是半导体厂商做的,半导体厂商负责将uboot移植到他们的芯片上,因此半导体厂商都会自己做一个开发板,这个开发板就叫做原厂开发板,比如大家学习STM32的时候听说过的discover开发板就是ST自己做的。半导体厂商将uboot移植到自己的原厂开发板上,测试好以后就会将这个uboot发布出去,这就是大家常说的原厂BSP包。我们一般做产品的时候就会参考原厂的开发板做硬件,然后在原厂提供的BSP包上做修改,将uboot或者linux kernel移植到我们的硬件上。这就是uboot移植的一般流程:
1、在uboot中找到参考的开发平台,一般是原厂的开发板。
2、参考原厂开发板移植uboot到我们所使用的开发板上。
正点原子STM32MP157开发板参考的是ST官方的STM32MP157 EVK开发板做的硬件,因此我们在移植uboot的时候就可以以ST官方的STM32MP157 EVK开发板为蓝本。


13.1 ST官方的U-boot编译测试
13.1.1 ST官方uboot源码打补丁
        1、获取到ST官方uboot源码
        首先肯定要获取到ST官方的uboot源码,这个已经在6.1.1小节获取到了,进入到对应的uboot源码目录,命令如下:
  1. cd /home/zuozhongkai/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0                                //进入ST官方uboot源码
复制代码

        ST官方uboot源码如图13.1.1.1所示:
第十三章 U800.png

图13.1.1.1 ST官方uboot源码

        从图13.1.1.1可以看出,ST官方的uboot源码跟TF-A的源码包文件夹内容格式基本一样,包括了补丁文件.patch、Makefile.sdk和uboot源码压缩包,只是uboot有多个.patch补丁文件,打补丁的时候这些.patch都要用到。
下一步肯定是解压图13.1.1.1中u-boot-stm32mp-2020.01-r0.tar.gz这个真正的源码包压缩包,解压命令如下:
  1. tar -vxf u-boot-stm32mp-2020.01-r0.tar.gz
复制代码

        解压完成以后就会得到一个名为“u-boot-stm32mp-2020.01”的uboot源码文件夹,如图13.1.1.2所示:
第十三章 U1129.png

图13.1.1.2 解压得到uboot源码

        2、打补丁
        上面已经解压出来了uboot的源码文件,接下来就要对其打补丁,进入到上面解压出来的u-boot-stm32mp-2020.01目录,然后执行相应的打补丁命令:
  1. cd u-boot-stm32mp-2020.01/                                        //进入uboot源码目录
  2. for p in `ls -1 ../*.patch`;do patch -p1 < $p;done        //打补丁
复制代码

打补丁结果如图13.1.1.3所示:
第十三章 U1362.png

图13.1.1.3 打补丁结果

        打完补丁以后的u-boot-stm32mp-2020.01目录就是我们要移植的uboot源码,但是图13.1.1.3中的u-boot-stm32mp-2020.01目录路径有点长,不适合阅读和编译。所以我们新建一个名为“my_uboot”的目录来保存我们要移植的uboot源码,然后将ST官方的uboot源码拷贝到“my_uboot”目录下,命令如下:
  1. cd /home/zuozhongkai/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/u-boot-stm32mp-2020.01-r0/u-boot-stm32mp-2020.01
  2. cp * /home/zuozhongkai/linux/atk-mp1/uboot/my_uboot/ -rf        //拷贝到my_uboot目录下
复制代码

        拷贝完成以后的my_uboot目录如图13.1.1.4所示:
第十三章 U1826.png

图13.1.1.4 拷贝过来的uboot源码

        最后就是创建vscode工程,方便我们移植和阅读。
13.1.2 编译ST官方uboot源码
        上一小节已经准备好了ST官方uboot源码,存放到了my_uboot目录下,本小节我们来编译一下这个uboot源码。
        1、修改Makefile
        和10.2.1小节一样,首先修改一下uboot源码的Makefile文件,也可以不修改,但是在编译的时候需要多输入一些参数,为了偷懒,还是修改一下。修改方法已经在10.2.1小节讲解过了,就是在Makefile文件里面添加ARCH和CROSS_COMPILE这两个变量的值,如图10.1.2.1所示:
第十三章 U2125.png

图10.1.2.1 设置ARCH和CROSS_COMPILE变量值

        ST官方uboot肯定适配了官方的STM32MP1 EVK开发板,我们就编译EVK开发板对应的uboot,编译完成以后将得到的uboot可执行文件烧写到正点原子的STM32MP1开发板中,看看能不能运行,不能的话就要修改uboot相应的文件,这就是uboot的移植。编译命令如下:
  1. make stm32mp15_trusted_defconfig
  2. make DEVICE_TREE=stm32mp157d-ev1 all -j8
复制代码

        编译完成以后如图13.1.2.2所示:
第十三章 U2398.png

图13.1.2.2 uboot编译成功

        编译完成以后就会得到uboot可执行文件,如图13.1.2.3所示:
第十三章 U2456.png

图13.1.2.3 uboot可执行文件

        从图13.1.2.3可以看出,uboot编译成功,生成了u-boot.bin和u-boot.stm32,u-boot.bin包含了设备树(dtb),也就是将uboot镜像和设备树打包在了一起。其中u-boot.stm32是在u-boot.bin前面添加了256字节头部信息的可执行文件,是要烧写到开发板里面的。
13.1.3 烧写测试
        上一小节我们编译出了ST官方EVK开发板对应的u-boot.stm32,本节我们将其烧写到我们的开发板中,看看能不能启动。这里烧写就要注意一下了,不能直接用图13.1.2.3小节中的u-boot.stm32文件替换以前images目录下的u-boot.stm32。前面说了STM23CubeProgrammer烧写原理就是先向开发板的DDR里面下载一个完整的uboot进去,然后用这个uboot来烧写系统。所以我们必须保证这个下载到DDR里面的uboot是工作正常的,但是我们刚刚编译出来的uboot可执行文件肯定是有问题的,所以下载到DDR中的uboot必须用正点原子提供的,烧写到EMMC里面的是我们刚刚编译的,这两个uboot要区分开。
        将图13.1.2.3中的u-boot.stm32重命名为my-u-boot.stm32,一定要重命名!然后将重命名以后的my-u-boot.stm32放到images目录下。我们还需要修改一下Flashlayouts文件,修改一下烧写到EMMC里面的uboot名字,如图13.1.3.1所示:
第十三章 U3120.png

图13.1.3.1 修改后的Flashlayouts文件

        一切准备好以后就可以烧写了,烧写完成以后从EMMC启动,此时会发现,开发板一直在重启!其中uboot的启动过程如图13.1.3.2所示:
第十三章 U3221.png

图13.1.3.2 uboot启动过程

        从图13.1.3.2可以看出一下几个重要的信息:
        ①、uboot能运行,也就是说ST官方EVK开发板的uboot可以直接在正点原子的开发板上运行,但是运行会出错!
        ②、uboot版本为2020.01,编译日期为2020年12月1日,10:33:15,说明就是刚刚我们自己编译的uboot。
        ②、出现了“stpmic1_read: failed to read register”错误,前面讲解TF-A的时候已经说了,ST官方EVK开发板使用了电源管理芯片STPMIC1A,所以uboot运行的时候会初始化这个PMIC芯片,但是正点原子开发板并没有使用这个PMIC芯片,所以就会报STPMIC错误!
        接下来就是一步步的修改uboot,至到其正常工作,也就是所谓的uboot移植。
13.2 在U-boot中添加自己的开发板
13.2.1 创建默认配置文件
首先创建自己所使用开发板对应的默认配置文件,我们在第一次编译uboot的时候先执行:
make stm32mp15_trusted_defconfig
上面命令的意思就是先使用默认配置文件配置一下uboot,stm32mp15_trusted_defconfig这个文件保存了默认配置选项。默认配置文件创建方法很简单,既然正点原子开发板参考了ST官方的EVK开发板,那么默认配置文件也可以直接参考官方的EVK开发板。在uboot的源码目录下,运行以下命令:
  1. cd configs                //进入uboot的configs目录
  2. cp stm32mp15_trusted_defconfig stm32mp15_atk_trusted_defconfig        //拷贝
复制代码

        此时在uboot的configs目录下就存在一个名为“stm32mp15_atk_trusted_defconfig”的默认配置文件,这个默认配置文件就是给我们开发板使用的。
13.2.2 创建默认配置设备树
另外我们还要创建自己所使用开发板对应的设备树,方法也很简单,直接复制ST官方EVK开发板对应的设备树,在uboot的源码目录下,运行以下命令:
  1. cd arch/arm/dts/                                                        //进入uboot设备树目录
  2. cp stm32mp157d-ed1.dts stm32mp157d-atk.dts        //复制.dts
  3. cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi        //复制.dtsi
  4. cp stm32mp157a-ed1-u-boot.dtsi stm32mp157d-atk-u-boot.dtsi        //复制.dtsi
复制代码

        打开stm32mp157d-atk.dts文件,要修改一下其中的一个头文件引用,stm32mp157d-atk.dts默认头文件引用如下:
示例代码13.2.2.1 stm32mp157d-atk.dts文件
  1. 1  // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
  2. 2  /*
  3. 3   * Copyright (C) STMicroelectronics 2019 - All Rights Reserved
  4. 4   * Author: Alexandre Torgue <<a href="mailto:alexandre.torgue@st.com">alexandre.torgue@st.com</a>> for STMicroelectronics.
  5. 5   */
  6. 6  /dts-v1/;
  7. 7  
  8. 8  #include "stm32mp157.dtsi"
  9. 9  #include "stm32mp15xd.dtsi"
  10. 10 #include "stm32mp15-pinctrl.dtsi"
  11. 11 #include "stm32mp15xxaa-pinctrl.dtsi"
  12. 12 #include "stm32mp157-m4-srm.dtsi"
  13. 13 #include "stm32mp157-m4-srm-pinctrl.dtsi"
  14. 14 #include "stm32mp15xx-edx.dtsi"
复制代码

         注意,第14行引用的是stm32mp15xx-edx.dtsi这个设备树头文件,我们要将其改为上面创建的stm32mp15d-atk.dtsi,修改以后如图13.2.2.1所示:
第十三章 U5035.png

图13.2.2.1 修改后的stm32mp157d-atk.dts

13.2.3 修改电源管理设置
打开13.2.2小节创建的stm32mp157d-atk-u-boot.dtsi这个文件。前53行的内容如下所示:
示例代码13.2.3.1 stm32mp157d-atk-u-boot.dtsi文件
  1. 1  // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  2. 2  /*
  3. 3   * Copyright : STMicroelectronics 2018
  4. 4   */
  5. 5  
  6. 6  #include <dt-bindings/clock/stm32mp1-clksrc.h>
  7. 7  #include "stm32mp15-u-boot.dtsi"
  8. 8  #include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi"
  9. 9  
  10. 10 / {
  11. 11  aliases {
  12. 12      i2c3 = &i2c4;
  13. 13      mmc0 = &sdmmc1;
  14. 14      mmc1 = &sdmmc2;
  15. 15  };
  16. 16
  17. 17  config {
  18. 18      u-boot,boot-led = "heartbeat";
  19. 19      u-boot,error-led = "error";
  20. 20      u-boot,mmc-env-partition = "ssbl";
  21. 21      st,fastboot-gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
  22. 22      st,stm32prog-gpios = <&gpioa 14 GPIO_ACTIVE_LOW>;
  23. 23  };
  24. 24
  25. 25  led {
  26. 26      red {
  27. 27                  label = "error";
  28. 28                  gpios = <&gpioa 13 GPIO_ACTIVE_LOW>;
  29. 29                  default-state = "off";
  30. 30                  status = "okay";
  31. 31              };
  32. 32          };
  33. 33 };
  34. 34
  35. 35 #ifndef CONFIG_STM32MP1_TRUSTED
  36. 36 &clk_hse {
  37. 37          st,digbypass;
  38. 38 };
  39. 39
  40. 40 &i2c4 {
  41. 41          u-boot,dm-pre-reloc;
  42. 42 };
  43. 43
  44. 44 &i2c4_pins_a {
  45. 45          u-boot,dm-pre-reloc;
  46. 46          pins {
  47. 47              u-boot,dm-pre-reloc;
  48. 48          };
  49. 49 };
  50. 50
  51. 51 &pmic {
  52. 52          u-boot,dm-pre-reloc;
  53. 53 };
复制代码

把示例代码13.2.3.1中的的21~22行、26~31行和51~53行都删除,删除以后如图13.2.3.1所示:
第十三章 U6332.png

图13.2.3.1 修改以后的stm32mp157d-atk-u-boot.dtsi文件

        
接着修改stm32mp157d-atk.dtsi文件,找到如下所示代码:
示例代码13.2.3.2 stm32mp157d-atk.dtsi代码段
  1. 90  &adc {
  2. 91 /* ANA0, ANA1 are dedicated pins and don't need pinctrl:
  3. only in6. */
  4. 92      pinctrl-0 = <&adc1_in6_pins_a>;
  5. 93      pinctrl-names = "default";
  6. 94      vdd-supply = <&vdd>;
  7. 95      vdda-supply = <&vdda>;
  8. 96      vref-supply = <&vdda>;
  9. 97      status = "disabled";
  10. 98      adc1: adc@0 {
  11. 99          st,adc-channels = <0 1 6>;
  12. 100         /* 16.5 ck_cycles sampling time */
  13. 101         st,min-sample-time-nsecs = <400>;
  14. 102         status = "okay";
  15. 103     };
  16. 104 };
  17. 105
  18. 106 &cpu0{
  19. 107     cpu-supply = <&vddcore>;
  20. 108 };
  21. 109
  22. 110 &crc1 {
  23. 111     status = "okay";
  24. 112 };
  25. 113
  26. 114 &dac {
  27. 115     pinctrl-names = "default";
  28. 116     pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>;
  29. 117     vref-supply = <&vdda>;
  30. 118     status = "disabled";
  31. 119     dac1: dac@1 {
  32. 120         status = "okay";
  33. 121     };
  34. 122     dac2: dac@2 {
  35. 123         status = "okay";
  36. 124     };
  37. 125 };
  38. 126
  39. 127 &dma1 {
  40. 128     sram = <&dma_pool>;
  41. 129 };
  42. ......
  43. 142
  44. 143 &i2c4 {
  45. 144     pinctrl-names = "default", "sleep";
  46. 145     pinctrl-0 = <&i2c4_pins_a>;
  47. 146     pinctrl-1 = <&i2c4_pins_sleep_a>;
  48. 147     i2c-scl-rising-time-ns = <185>;
  49. 148     i2c-scl-falling-time-ns = <20>;
  50. 149     clock-frequency = <400000>;
  51. 150     status = "okay";
  52. 151     /* spare dmas for other usage */
  53. 152     /delete-property/dmas;
  54. 153     /delete-property/dma-names;
  55. 154
  56. 155     pmic: stpmic@33 {
  57. 156         compatible = "st,stpmic1";
  58. 157         reg = <0x33>;
  59. 158         interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>;
  60. 159         interrupt-controller;
  61. 160         #interrupt-cells = <2>;
  62. 161         status = "okay";
  63. 162
  64. 163         regulators {
  65. 164             compatible = "st,stpmic1-regulators";
  66. 165             buck1-supply = <&vin>;
  67. 166             buck2-supply = <&vin>;
  68. 167             buck3-supply = <&vin>;
  69. 168             buck4-supply = <&vin>;
  70. 169             ldo1-supply = <&v3v3>;
  71. 170             ldo2-supply = <&v3v3>;
  72. 171             ldo3-supply = <&vdd_ddr>;
  73. 172             ldo4-supply = <&vin>;
  74. 173             ldo5-supply = <&v3v3>;
  75. 174             ldo6-supply = <&v3v3>;
  76. 175             vref_ddr-supply = <&vin>;
  77. 176             boost-supply = <&vin>;
  78. 177             pwr_sw1-supply = <&bst_out>;
  79. 178             pwr_sw2-supply = <&bst_out>;
  80. 179
  81. 180             vddcore: buck1 {
  82. 181                 regulator-name = "vddcore";
  83. 182                 regulator-min-microvolt = <1200000>;
  84. 183                 regulator-max-microvolt = <1350000>;
  85. 184                 regulator-always-on;
  86. 185                 regulator-initial-mode = <0>;
  87. 186                 regulator-over-current-protection;
  88. 187             };
  89. ......
  90. 278              vbus_sw: pwr_sw2 {
  91. 279                 regulator-name = "vbus_sw";
  92. 280                 interrupts = <IT_OCP_SWOUT 0>;
  93. 281                 regulator-active-discharge = <1>;
  94. 282              };
  95. 283         };
  96. 284
  97. 285         onkey {
  98. 286             compatible = "st,stpmic1-onkey";
  99. 287             interrupts = <IT_PONKEY_F 0>, <IT_PONKEY_R 0>;
  100. 288             interrupt-names = "onkey-falling", "onkey-rising";
  101. 289             power-off-time-sec = <10>;
  102. 290             status = "okay";
  103. 291         };
  104. 292
  105. 293         watchdog {
  106. 294             compatible = "st,stpmic1-wdt";
  107. 295             status = "disabled";
  108. 296         };
  109. 297     };
  110. 298 };
复制代码

将示例代码13.2.3.2中90~104行的adc节点、114~125行的dac节点以及143~298行的i2c4节点全部删除掉,删除以后如图13.2.3.2所示:
第十三章 U9818.png

图13.2.3.2 修改后的stm32mp157d-atk.dtsi代码段

        继续修改stm32mp157d-atk.dtsi文件,找到如下所示代码:
示例代码13.2.3.3 stm32mp157d-atk.dtsi代码段
  1. 58 led {
  2. 59          compatible = "gpio-leds";
  3. 60                  blue {
  4. 61              label = "heartbeat";
  5. 62              gpios = <&gpiod 9 GPIO_ACTIVE_HIGH>;
  6. 63              linux,default-trigger = "heartbeat";
  7. 64              default-state = "off";
  8. 65          };
  9. 66 };
  10. 67
  11. 68 sd_switch: regulator-sd_switch {
  12. 69                 compatible = "regulator-gpio";
  13. 70          regulator-name = "sd_switch";
  14. 71          regulator-min-microvolt = <1800000>;
  15. 72          regulator-max-microvolt = <2900000>;
  16. 73          regulator-type = "voltage";
  17. 74          regulator-always-on;
  18. 75
  19. 76          gpios = <&gpiof 14 GPIO_ACTIVE_HIGH>;
  20. 77          gpios-states = <0>;
  21. 78          states = <1800000 0x1 2900000 0x0>;
  22. 79 };
复制代码

        上述代码是led和sd_switch节点信息,将这两个节点都删除掉,这两个节点删除以后如图13.2.3.3所示:
第十三章 U10585.png

图13.2.3.3 删除以后的stm32mp157d-atk.dtsi代码段

        最后我们需要向stm32mp157d-atk.dtsi文件的根节点‘/’下添加自己的电源管理配置,将下面的代码添加到图13.2.3.3中的58行处:
示例代码13.2.3.4 要添加的电源管理配置节点
  1. 1  vddcore: regulator-vddcore {
  2. 2       compatible = "regulator-fixed";
  3. 3       regulator-name = "vddcore";
  4. 4       regulator-min-microvolt = <1200000>;
  5. 5       regulator-max-microvolt = <1350000>;
  6. 6       regulator-always-on;
  7. 7       regulator-boot-on;
  8. 8  };
  9. 9  
  10. 10 v3v3: regulator-3p3v {
  11. 11     compatible = "regulator-fixed";
  12. 12     regulator-name = "v3v3";
  13. 13     regulator-min-microvolt = <3300000>;
  14. 14     regulator-max-microvolt = <3300000>;
  15. 15     regulator-always-on;
  16. 16     regulator-boot-on;
  17. 17 };
  18. 18
  19. 19 v1v8_audio: regulator-v1v8-audio {
  20. 20     compatible = "regulator-fixed";
  21. 21     regulator-name = "v1v8_audio";
  22. 22     regulator-min-microvolt = <1800000>;
  23. 23     regulator-max-microvolt = <1800000>;
  24. 24     regulator-always-on;
  25. 25     regulator-boot-on;
  26. 26 };
  27. 27
  28. 28 vdd: regulator-vdd {
  29. 29     compatible = "regulator-fixed";
  30. 30     regulator-name = "vdd";
  31. 31     regulator-min-microvolt = <3300000>;
  32. 32     regulator-max-microvolt = <3300000>;
  33. 33     regulator-always-on;
  34. 34     regulator-boot-on;
  35. 35 };
  36. 36
  37. 37 vdd_usb: regulator-vdd-usb {
  38. 38     compatible = "regulator-fixed";
  39. 39     regulator-name = "vdd_usb";
  40. 40     regulator-min-microvolt = <3300000>;
  41. 41     regulator-max-microvolt = <3300000>;
  42. 42     regulator-always-on;
  43. 43     regulator-boot-on;
  44. 44 };
复制代码

        上述代码定义了5个电源节点,分别为:vddcore、v3v3、v1v8_audio、vdd和vdd_usb,至此,电源管理相关配置已经设置好了。
13.2.4 修改TF卡和EMMC配置
继续修改stm32mp157d-atk.dtsi文件,找到sdmmc1和sdmmc2这两个节点,将这两个节点改为如下所示内容:
示例代码13.2.4.1 修改后的sdmmc1和sdmmc2节点
  1. 1  &sdmmc1 {
  2. 2      pinctrl-names = "default", "opendrain", "sleep";
  3. 3      pinctrl-0 = <&sdmmc1_b4_pins_a>;
  4. 4      pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
  5. 5      pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
  6. 6      st,neg-edge;
  7. 7      broken-cd;
  8. 8      bus-width = <4>;
  9. 9      vmmc-supply = <&v3v3>;
  10. 10     status = "okay";
  11. 11 };
  12. 12
  13. 13 &sdmmc2 {
  14. 14     pinctrl-names = "default", "opendrain", "sleep";
  15. 15     pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>;
  16. 16     pinctrl-1 = <&sdmmc2_b4_od_pins_a &sdmmc2_d47_pins_a>;
  17. 17     pinctrl-2 = <&sdmmc2_b4_sleep_pins_a &sdmmc2_d47_sleep_pins_a>;
  18. 18     non-removable;
  19. 19     st,neg-edge;
  20. 20     bus-width = <8>;
  21. 21     vmmc-supply = <&v3v3>;
  22. 22     keep-power-in-suspend;
  23. 23     status = "okay";
  24. 24 };
复制代码

        修改以后如图13.2.4.1所示:
第十三章 U12959.png

图13.2.4.1 修改后的sdmmc1和sdmmc2

13.2.5 编译uboot
        接下来我们先编译一下uboot,在编译之前先在stm32mp157d-atk.dtsi文件中找到usbotg_hs节点,此节点默认内容如下所示:
示例代码13.2.5.1 usbotg_hs节点
  1. 222 &usbotg_hs {
  2. 223     vbus-supply = <&vbus_otg>;
  3. 224 };
复制代码

此节点定义了USB_OTG的电源配置,ST官方开发板的USB_OTG电源也是通过PMIC配置的,所以USB_OTG电源配置也要修改,但是这里我们要先测试一下当前修改后的uboot能不能运行,因此先不改USB_OTG电源,所以先将示例代码13.2.5.1中的usbotg_hs节点屏蔽掉,防止编译报错,屏蔽以后如图13.2.5.1所示:
第十三章 U13330.png

图13.2.5.1 屏蔽usbotg_hs节点

        在编译uboot之前要先让编译器知道我们要编译哪个配置文件,打开arch/arm/dts/Makefile文件,找到“dtb-$(CONFIG_STM32MP15x)”配置项,然后在此配置项中加入“stm32mp157d-atk.dtb”,添加完以后如图13.2.5.2所示:
第十三章 U13496.png

图13.2.5.2 添加stm32mp157d-atk.dtb

图13.2.5.2中第847行里就是告诉“Makefile”把我们刚新建的stm32mp157d-atk.bts编译成对应的dtb文件。以前编译uboot都是自己输入一条一条命令编译,我们可以创建一个shell脚本,将所有的编译命令都写到这个shell脚本里面,然后每次的时候只需要执行一下这个shell脚本即可。在 uboot 源码根目录下新建一个名为 stm32mp157d_alientek.sh 的 shell 脚本,在这个shell脚本里面输入如下内容:
示例代码13.2.5.2 stm32mp157d_alientek.sh文件
  1. 1   #!/bin/bash
  2. 2
  3. 3   make distclean
  4. 4   make stm32mp15_atk_trusted_defconfig
  5. 5   make DEVICE_TREE=stm32mp157d-atk all -j12
复制代码

第3行清零uboot。
第4行使用stm32mp15_atk_trusted_defconfig来配置uboot。
第5行编译uboot,设备树为stm32mp157d-atk.dts。
给予stm32mp157d_alientek.sh可执行权限,然后运行脚本来完成编译,命令如下:
  1. chmod 777 stm32mp157d_alientek.sh                 //给予可执行权限,一次即可
  2. ./stm32mp157d_alientek.sh                                 //运行脚本编译 uboot
复制代码

编译成功会出现如图13.2.5.3所示信息:
第十三章 U14188.png

图13.2.5.3 uboot编译成功

        从图13.2.5.3可以看出,stm32mp157d-atk.dts已经编译成功,生成了对应的stm32mp157d-atk.dtb文件,u-boot.stm32就是我们一会要烧写测试的,我们要先将其重命名为my-u-boot.stm32,然后再烧写进去。
        烧写完成以后uboot启动过程如图13.2.5.4所示:
第十三章 U14370.png

图13.2.5.4 uboot启动过程

        从图13.2.5.4可以看出,uboot启动成功,并且进入了命令行模式,并且命令行也可以正常操作,那么是不是说明uboot已经移植成功了呢?不一定,uboot有没有移植成功取决于当前uboot能不能满足我们的要求,如果不满足就说明还没移植成功。
        当前uboot的网络、USB_OTG也不能正常工作,所以我们还需要接着修改。
13.2.6 网络设备树的修改
        从图13.5.2.4可以看到“Net:   No ethernet found.”这一行,这样行的意思就是没有找到网络,说明uboot下的网路驱动有问题。原因是当前设备树并没有网络相关节点,我们只需要将网络相关节点加进去就可以了。打开stm32mp157d-atk.dtsi文件,将如下所示的ethernet0节点加添加到最后面:
示例代码13.2.6.1 ethernet0节点
  1. 1  eernet0 {
  2. 2          status = "okay";
  3. 3          pinctrl-0 = <eernet0_rgmii_pins_a>;
  4. 4          pinctrl-1 = <eernet0_rgmii_pins_sleep_a>;
  5. 5          pinctrl-names = "default", "sleep";
  6. 6          phy-mode = "rgmii-id";
  7. 7          max-speed = <1000>;
  8. 8          phy-handle = <&phy0>;
  9. 9  
  10. 10         mdio0 {
  11. 11                 #address-cells = <1>;
  12. 12                 #size-cells = <0>;
  13. 13                 compatible = "snps,dwmac-mdio";
  14. 14                 phy0: ethernet-phy@0 {
  15. 15                         reg = <0>;
  16. 16                 };
  17. 17         };
  18. 18 };
复制代码

        添加完成以后如图13.2.6.1所示:
第十三章 U15355.png

图13.2.6.1 添加进来的ethernet0节点

        网络节点已经添加到设备树里面了,重新编译uboot并烧写,uboot启动过程如图13.2.6.2所示:
第十三章 U15437.png

图13.2.6.2 uboot启动信息

从图13.2.6.2中可以看到 “ethernet@5800a00 address not set.”字样,说明已经找到了网络外设并且网络外设已经启动,但是还是会报“No ethernet found.”错误,这是因为uboot启动的时候获取不到MAC地址,我们只需要设置一些地址相关的环境变量即可,前面讲解uboot的网络相关命令的时候已经讲过了,命令如下:
  1. setenv ipaddr 192.168.1.250                        //开发板 IP 地址
  2. setenv ethaddr 00:04:9f:04:d2:35                //开发板网卡 MAC 地址
  3. setenv gatewayip 192.168.1.1                        //开发板默认网关
  4. setenv netmask 255.255.255.0                //开发板子网掩码
  5. setenv serverip 192.168.1.249                //服务器地址,也就是 Ubuntu 地址
  6. saveenv
复制代码

设置好地址相关环境变量以后就可以在uboot中使用网络了,用网线将开发板上的网络接口与电脑或者路由器连接起来,保证开发板和电脑在同一个网段内,通过 ping 命令来测试一下网络连接,命令如下:
ping 192.168.1.249
结果如图13.2.6.3所示:
第十三章 U16005.png

图13.2.6.3 ping命令测试

从图13.2.6.3中可以看到“host 192.168.1.249 is alive”这句,表明ping主机成功,说明网络工作正常。
13.2.7 USB OTG设备树修改
        1、添加usb_phy_tuning子节点
在这一小节里,我们就给uboot添加USB_OTG功能,操作stm32mp157d-atk.dtsi这个文件,在根节点“/”下添加名为“usb_phy_tuning”的子节点,节点内容如下:
示例代码13.2.7.1 usb_phy_tuning节点
  1. 1  usb_phy_tuning: usb-phy-tuning {
  2. 2        st,hs-dc-level = <2>;
  3. 3        st,fs-rftime-tuning;
  4. 4        st,hs-rftime-reduction;
  5. 5        st,hs-current-trim = <15>;
  6. 6        st,hs-impedance-trim = <1>;
  7. 7        st,squelch-level = <3>;
  8. 8        st,hs-rx-offset = <2>;
  9. 9       st,no-lsfs-sc;
  10. 10 };
复制代码

        添加完成以后如图13.2.7.1所示:
第十三章 U16581.png

图13.2.7.1 新添加的usb_phy_tuning子节点

        2、添加STUSB1600 I2C子节点
        正点原子STM32MP157开发板上的USB OTG接口类型为Type-C,使用STUSB1600芯片来实现此接口功能,STUSB1600有一个I2C接口,此I2C接口用来配置芯片,因此我们还需要在设备树中添加STUSB1600相关的I2C节点内容。将如下内容添加到stm32mp157d-atk.dtsi的最后面:
示例代码13.2.7.2 stusb1600芯片i2c节点
  1. 1  &i2c1 {
  2. 2      pinctrl-names = "default", "sleep";
  3. 3      pinctrl-0 = <&i2c1_pins_a>;
  4. 4      pinctrl-1 = <&i2c1_pins_sleep_a>;
  5. 5      i2c-scl-rising-time-ns = <100>;
  6. 6      i2c-scl-falling-time-ns = <7>;
  7. 7      status = "okay";
  8. 8      /delete-property/dmas;
  9. 9      /delete-property/dma-names;
  10. 10
  11. 11     stusb1600@28 {
  12. 12         compatible = "st,stusb1600";
  13. 13         reg = <0x28>;
  14. 14         interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
  15. 15         interrupt-parent = <&gpiog>;
  16. 16         pinctrl-names = "default";
  17. 17         pinctrl-0 = <&stusb1600_pins_a>;
  18. 18         status = "okay";
  19. 19         vdd-supply = <&vin>;
  20. 20
  21. 21         connector {
  22. 22             compatible = "usb-c-connector";
  23. 23             label = "USB-C";
  24. 24             power-role = "dual";
  25. 25             power-opmode = "default";
  26. 26
  27. 27             port {
  28. 28                 con_usbotg_hs_ep: endpoint {
  29. 29                     remote-endpoint = <&usbotg_hs_ep>;
  30. 30                 };
  31. 31             };
  32. 32         };
  33. 33     };
  34. 34 };
复制代码

       由于STUSB1600是挂在STM32MP157的I2C1接口下,因此示例代码13.2.7.2是向I2C1节点追加内容,完成以后如图13.7.2.2所示:
第十三章 U17911.png

图13.7.2.2 stusb1600节点

3、添加usb接口相关节点
        继续向stm32mp157d-atk.dtsi文件添加USB接口相关节点内容,内容如下:
示例代码13.2.7.3 usb接口节点
  1. 1  &usbh_ehci {
  2. 2      phys = <&usbphyc_port0>;
  3. 3      status = "okay";
  4. 4  };
  5. 5  
  6. 6  &usbotg_hs {
  7. 7      phys = <&usbphyc_port1 0>;
  8. 8      phy-names = "usb2-phy";
  9. 9      usb-role-switch;
  10. 10     status = "okay";
  11. 11
  12. 12     port {
  13. 13         usbotg_hs_ep: endpoint {
  14. 14             remote-endpoint = <&con_usbotg_hs_ep>;
  15. 15         };
  16. 16     };
  17. 17 };
  18. 18
  19. 19 &usbphyc {
  20. 20     status = "okay";
  21. 21 };
复制代码

        上述代码中有三个节点usbh_ehci、usbotg_hs和usbphyc,其中usbotg_hs默认就有,我们在前面将其屏蔽掉了,完成以后如图13.2.7.3所示:
第十三章 U18498.png

图13.2.7.3 USB接口节点

4、在stm32mp157d-atk-u-boot.dtsi文件中添加usbotg_hs节点
        最后,我们需要在stm32mp157d-atk-u-boot.dtsi文件里面添加usbotg_hs节点,节点内容如下所示:
示例代码13.2.7.4 usbotg_hs节点
  1. 1 &usbotg_hs {
  2. 2     u-boot,force-b-session-valid;
  3. 3     hnp-srp-disable;
  4. 4     /* TEMP: force peripheral for USB OTG */
  5. 5     dr_mode = "peripheral";
  6. 6 };
复制代码

        结果如图13.2.7.4所示:
第十三章 U18827.png

图13.2.7.4 stm32mp157d-atk-u-boot.dtsi下的usbotg_hs节点

        至此,uboot下的USB OTG就已经修改完成,重新编译uboot并烧写,然后使用ums命令测试,看看能不能将EMMC模拟成U盘,挂载到电脑上,命令如下:
做到这里,保存修改的文件,编译和拷贝。把STM32MP157D-ATK开发板的USB_OTG接口连接到电脑里,重启开发板,接着运行以下命令:
  1. ums 0 mmc 1
复制代码

        如果电脑上出现如图13.2.7.5所示的磁盘,说明USB OTG工作成功。
第十三章 U19082.png

图13.2.7.5 uboot下开发板模拟U盘

        由于笔者在编写本章节教程的时候使用的全新的核心板,因此EMMC上只有一个分区,所以在电脑上就只有一个U盘,如果EMMC上有多个分区的话就会出现多个U盘,一切以实际情况为准。
13.2.8 使能boot和bootd命令
        ST官方uboot默认并没有使能boot和bootd这两个命令,这两个命令的实现源文件为cmd/bootm.c,bootm.c下有如图13.2.8.1所示内容:
第十三章 U19300.png

图13.2.8.1 boot和bootd命令具体实现

        从图13.2.8.1可以看出,如果要使能boot和bootd这两个命令,必须定义宏CONFIG_CMD_BOOT。打开include/configs/stm32mp1.h,然后在后面添加如下宏定义:
示例代码13.2.8.1 CONFIG_CMD_BOOTD宏
  1. #define CONFIG_CMD_BOOTD    /* 使能boot和bootd命令 */
复制代码

        如图13.2.8.2所示:
第十三章 U19525.png

图13.2.8.3 添加CONFIG_CMD_BOOTD宏

        重新编译uboot并烧写启动,输入命令:
  1. ? boot
复制代码

或者
  1. ? bootd
复制代码

        如果boot和bootd使能的话就会打印出相应的命令使用方法,如图13.2.8.4所示:
第十三章 U19643.png

图13.2.8.4 boot和bootd帮助信息

13.2.9 LCD驱动修改
        uboot也是支持LCD显示的,但是要进行相应的设置,主要是设置屏幕背光、屏幕时序参数这些,这些直接在设备树里面修改即可。打开stm32mp157d-atk.dts文件,在里面添加LCD相关节点信息,首先在根节点“/”下添加panel_backlight和panel_rgb这两个节点,节点内容如下:
示例代码13.2.9.1 新添加节点信息
  1. 1  panel_backlight: panel-backlight {
  2. 2      compatible = "gpio-backlight";
  3. 3      gpios = <&gpiod 13 GPIO_ACTIVE_HIGH>;
  4. 4      default-on;
  5. 5      status = "okay";
  6. 6   };
  7. 7  
  8. 8  panel_rgb: panel-rgb {
  9. 9      compatible = "simple-panel";
  10. 10     pinctrl-names = "default", "sleep";
  11. 11     pinctrl-0 = <<dc_pins_b>;
  12. 12     pinctrl-1 = <<dc_pins_sleep_b>;
  13. 13     backlight = <&panel_backlight>;
  14. 14     status = "okay";
  15. 15
  16. 16          port {
  17. 17              panel_in_rgb: endpoint {
  18. 18                          remote-endpoint = <<dc_ep0_out>;
  19. 19                 };
  20. 20             };
  21. 21
  22. 22          display-timings {
  23. 23              native-mode = <&timing0>; /* 时序信息 */
  24. 24              timing0: timing0 {                                        /* 7寸1024*600分辨率 */
  25. 25                          clock-frequency = <51200000>;         /* LCD 像素时钟,单位 Hz */
  26. 26                          hactive = <1024>;                               /* LCD X 轴像素个数 */
  27. 27                          vactive = <600>;                                /* LCD Y 轴像素个数 */
  28. 28                          hfront-porch = <160>;                           /* LCD hfp 参数 */
  29. 29                          hback-porch = <140>;                            /* LCD hbp 参数 */
  30. 30                          hsync-len = <20>;                               /* LCD hspw 参数 */
  31. 31                          vback-porch = <20>;                            /* LCD vbp 参数 */
  32. 32                          vfront-porch = <12>;                            /* LCD vfp 参数 */
  33. 33                          vsync-len = <3>;                                /* LCD vspw 参数 */
  34. 34                     };
  35. 35          };
  36. 36 };
复制代码

        第1~6行,panel_backlight为LCD的背光控制节点,主要指定LCD背光IO所使用的引脚,正点原子的STM32MP157开发板LCD背光引脚为PD13。
第8~38行,panel_rgb为RGB LCD节点,指定了LTDC接口所使用的IO、屏幕时序参数等。第11~12行指定LTDC接口的IO,ltdc_pins_b和ltdc_pins_sleep_b定义在stm32mp15-pinctrl.dtsi文件中。第22~35行的display-timings是非常重要的LCD时序参数,不同的屏幕其时序参数不同,这里演示的是正点原子7寸1024*600分辨率的。正点原子有4款RGB接口屏幕,分别为4.3寸480*272和 800*480分辨率、7寸800*480和1024*600分辨率,这款屏幕时序参数如表13.2.9.1所示:
屏幕型号        参数        值        单位
ATK4342        水平显示区域        480        tCLK
        HSPW(thp)        1        tCLK
        HBP(thb)        40        tCLK
        HFP(thf)        5        tCLK
        垂直显示区域        272        th
        VSPW(tvp)        1        th
        VBP(tvb)        8        th
        VFP(tvf)        8        th
        像素时钟        9        MHz
ATK4384        水平显示区域        800        tCLK
        HSPW(thp)        48        tCLK
        HBP(thb)        88        tCLK
        HFP(thf)        40        tCLK
        垂直显示区域        480        th
        VSPW(tvp)        3        th
        VBP(tvb)        32        th
        VFP(tvf)        13        th
        像素时钟        31        MHz
ATK7084        水平显示区域        800        tCLK
        HSPW(thp)        1        tCLK
        HBP(thb)        46        tCLK
        HFP(thf)        210        tCLK
        垂直显示区域        480        th
        VSPW(tvp)        1        th
        VBP(tvb)        23        th
        VFP(tvf)        22        th
        像素时钟        33.3        MHz
ATK7016        水平显示区域        1024        tCLK
        HSPW(thp)        20        tCLK
        HBP(thb)        140        tCLK
        HFP(thf)        160        tCLK
        垂直显示区域        600        th
        VSPW(tvp)        3        th
        VBP(tvb)        20        th
        VFP(tvf)        12        th
        像素时钟        51.2        MHz
表13.2.9.1 RGB LCD屏幕时间参数
        正点原子其他3款RGB屏幕的时序参数如下所示:
示例代码13.2.9.2 其他3款LCD时序参数
  1. 1  /* 4.3寸480*272分辨率 */
  2. 2  display-timings {
  3. 3    native-mode = <&timing0>;                         /* 时序信息 */
  4. 4    timing0: timing0 {
  5. 5          clock-frequency = <9200000>;         /* LCD 像素时钟,单位 Hz */
  6. 6          hactive = <480>;                                 /* LCD X 轴像素个数 */
  7. 7          vactive = <272>;                                 /* LCD Y 轴像素个数 */
  8. 8          hfront-porch = <8>;                         /* LCD hfp 参数 */
  9. 9          hback-porch = <4>;                         /* LCD hbp 参数 */
  10. 10         hsync-len = <41>;                                 /* LCD hspw 参数 */
  11. 11         vback-porch = <2>;                         /* LCD vbp 参数 */
  12. 12         vfront-porch = <4>;                         /* LCD vfp 参数 */
  13. 13         vsync-len = <10>;                                 /* LCD vspw 参数 */
  14. 14  };
  15. 15 }
  16. 16      
  17. 17 /* 4.3寸800*480分辨率 */
  18. 18 display-timings {
  19. 19     native-mode = <&timing0>;                 /* 时序信息 */
  20. 20     timing0: timing0 {
  21. 21          clock-frequency = <31000000>; /* LCD 像素时钟,单位 Hz */
  22. 22          hactive = <800>;                        /* LCD X 轴像素个数 */
  23. 23          vactive = <480>;                        /* LCD Y 轴像素个数 */
  24. 24          hfront-porch = <40>;                    /* LCD hfp 参数 */
  25. 25          hback-porch = <88>;                     /* LCD hbp 参数 */
  26. 26          hsync-len = <48>;                       /* LCD hspw 参数 */
  27. 27          vback-porch = <32>;                     /* LCD vbp 参数 */
  28. 28          vfront-porch = <13>;                    /* LCD vfp 参数 */
  29. 29          vsync-len = <3>;                        /* LCD vspw 参数 */
  30. 30      };
  31. 31 }
  32. 32 /* 7寸800*480分辨率 */
  33. 33 display-timings {
  34. 34     native-mode = <&timing0>;                 /* 时序信息 */
  35. 35     timing0: timing0 {
  36. 36          clock-frequency = <51200000>; /* LCD 像素时钟,单位 Hz */
  37. 37          hactive = <800>;                        /* LCD X 轴像素个数 */
  38. 38          vactive = <480>;                        /* LCD Y 轴像素个数 */
  39. 39          hfront-porch = <210>;                   /* LCD hfp 参数 */
  40. 40          hback-porch = <46>;                     /* LCD hbp 参数 */
  41. 41          hsync-len = <1>;                        /* LCD hspw 参数 */
  42. 42          vback-porch = <23>;                     /* LCD vbp 参数 */
  43. 43          vfront-porch = <22>;                    /* LCD vfp 参数 */
  44. 44          vsync-len = <1>;                        /* LCD vspw 参数 */
  45. 45      };
  46. 46 }
复制代码

        第2~15行为4.3寸480*272分辨率的LCD时序参数,第18~31行为4.3寸800*480分辨率的LCD时序参数,第33~46行为7寸800*480分辨率的LCD时序参数。大家根据自己所使用的屏幕选择合适的屏幕时序参数。
添加完成以后如图13.2.9.1所示:
第十三章 U24220.png

图13.2.9.1 panel_backlight和panel_rgb节点

        最后还需要在stm32mp157d-atk.dts文件里面向ltdc节点追加一些内容,内容如下:
示例代码13.2.9.3 ltdc节点
  1. 1  <dc {
  2. 2                  status = "okay";
  3. 3              pinctrl-names = "default";
  4. 4            port {
  5. 5                       #address-cells = <1>;
  6. 6                   #size-cells = <0>;
  7. 7   
  8. 8           ltdc_ep0_out: endpoint@0 {
  9. 9                    reg = <0>;
  10. 10                      remote-endpoint = <&panel_in_rgb>;
  11. 11                 };
  12. 12        };
复制代码

  添加完成以后如图13.2.9.2所示:
第十三章 U24632.png

图13.2.9.3 ltdc节点

        修改完成以后编译uboot,得到新的uImage和stm32mp157d-atk.dtb设备树,关于uboot下LCD的测试方法稍后会讲解。
13.3 U-boot测试
13.3.1 自烧写测试
        前面说了很多次STM32CubeProgrammer是如何烧写系统的,核心就是先向DDR里面下载一个uboot镜像,然后启动此uboot,使用uboot里面的相关命令进行烧写。本章前面都是使用正点原子出厂u-boot.stm32来烧写我们移植的uboot,本小节就用我们移植好的u-boot来烧写自身,也就是自烧写测试。这里就再也不需要my-u-boot.stm32了,直接使用我们前面编译得到的u-boot.stm32替换掉images目录下的正点原子出厂u-boot.stm32。然后修改FlashLayout,如图13.3.1.1所示:
第十三章 U25023.png

图13.3.1.1 修改后的FlashLayout

        修改完成以后重新烧写测试,此时首先下载到DDR中的u-boot.stm32镜像也是我们自己编译得到了,也就是用我们自己编译的uboot来烧写自身。检测方法很简单,就是看能不能正常烧写。
13.3.2 从EMMC启动Linux
从EMMC启动也就是将编译出来的Linux镜像文件uImage和.dtb设备树文件保存在EMMC中,uboot从EMMC中读取这两个文件并启动,这个是我们产品最终的启动方式。首先EMMC里面要先存放Linux镜像文件uImage和.dtb设备树,但是我们前面新建的FlashLayout文件并没有烧写uImage和.dtb,所以我们需要修改一下FlashLayout文件,加入uImage和.dtb烧写命令。由于我们还没有移植Linux系统,所以uImage和.dtb就先使用正点原子出厂系统提供的,路径为:开发板光盘8、系统镜像2、出厂系统镜像1、STM32CubeProg烧录固件包atk-image-bootfs.ext4。atk-image-bootfs.ext4是ext4格式的打包文件,因为STM32CubeProgrammer软件要求将uImage和.dtb打包在一起,格式为ext4。atk-image-bootfs.ext4里面的文件如图13.3.2.1所示:
第十三章 U25609.png

图13.3.2.1 atk-image-bootfs.ext4文件

        从图13.3.2.1可以看出,正点原子出厂的atk-image-bootfs.ext4里面还是有不少文件,其中我们最关心的就是uImage和.dtb设备树。后面讲解Linux系统移植的时候会讲解如何将uImage和.dtb打包成ext4格式。
        复制一份atk-image-bootfs.ext4到images文件夹,然后打开FlashLayout文件(tf-a.tsv),添加下面一行:
示例代码13.3.2.1 linux系统烧写命令
P     0x21    boot     System  mmc1   0x00280000  atk-image-bootfs.ext4
        修改完成以后如图13.3.2.2所示:
第十三章 U25959.png

图13.3.2.2 修改后的FlashLayout

        修改完成以后烧写到开发板中并重启,首先使用ext4ls命令查看一下EMMC的分区2里面有没有uImage和.dtb文件,命令如下:
ext4ls mmc 1:2
结果如图13.3.2.3所示:
第十三章 U26085.png

图13.3.2.3 EMMC分区2文件

        这里我们只需要用到图13.3.2.3中的uImage和stm32mp157d-atk.dtb这两个文件,设置bootcmd环境变量从EMMC里面读取系统文件,然后再启动,这个在前面讲解BOOT命令的时候已经讲过了如何操作,命令如下:
  1. setenv bootcmd 'ext4load mmc 1:2 c2000000 uImage;ext4load mmc 1:2 c4000000 stm32mp157d-atk.dtb;bootm c2000000 - c4000000'
  2. saveenv
  3. boot
复制代码

        设置好以后uboot就会按照bootcmd环境变量的内容加载系统并启动,如图13.3.2.4所示:
第十三章 U26412.png

图13.3.2.4 系统启动流程

        注意!只有出现图13.3.2.4中的“Booting Linux on physical CPU 0x0”这一行就说明uboot引导Linux内核成功!
13.3.3 从网络启动Linux系统
从网络启动Linux系统的唯一目的就是为了调试!不管是为了调试Linux系统还是Linux下的驱动。每次修改Linux系统文件或者Linux下的某个驱动以后都要将其烧写到EMMC中去测试,这样太麻烦了。我们可以设置Linux从网络启动,也就是将Linux镜像文件和根文件系统都放到Ubuntu下某个指定的文件夹中,这样每次重新编译Linux内核或者某个Linux驱动以后只需要使用cp命令将其拷贝到这个指定的文件夹中即可,这样就不用需要频繁的烧写 EMMC,这样就加快了开发速度。我们可以通过nfs或者tftp从Ubuntu中下载uImage和设备树文件,根文件系统的话也可以通过nfs挂载,不过本小节我们不讲解如何通过nfs挂载根文件系统,这个在讲解根文件系统移植的时候再讲解。这里我们使用tftp从Ubuntu中下载 uImage 和设备树文件,前提是要将uImage和设备树文件放到Ubuntu下的tftp目录中。
设置bootcmd环境变量,设置如下:
  1. setenv bootcmd 'tftp c2000000 uImage;tftp c4000000 stm32mp157d-atk.dtb;bootm c2000000 - (有空格) c4000000'
  2. saveenv
  3. boot
复制代码

        设置好以后,uboot先从tftp服务器下载uImage和stm32mp157d-atk.dtb这两个文件,然后启动,如图13.3.3.1所示:
第十三章 U27152.png

图13.3.3.1 uboot网络启动linux成功

13.3.4 LCD测试
        1、烧写过程显示测试
        uboot下LCD测试有两种方法,第一种大家应该已经看到了,那就是用STM32CubeProgrammer烧写系统的时候会在LCD上显示烧写过程,如图13.3.4.1所示:
第十三章 U27294.png

13.3.4.1 uboot烧写过程

        2、bmp命令显示测试
        另外我们可以使用uboot下的bmp命令在LCD上显示一张bmp图片,bmp命令如图13.3.4.2所示:
第十三章 U27383.png

图13.3.4.2 bmp命令

        从图13.3.4.2可以看出,有bmp info和bmp display两个命令:
①、bmp info命令
命令格式如下:
  1. bmp info <imageAddr>  
复制代码

bmp info命令用于显示BMP图片信息,imageAddr就是BMP图片在RAM中的起始地址。
②、bmp display命令
bmp display命令用于显示bmp图片,imageAddr是要显示的BMP图片在RAM中的起始地址,[x,y]用于指定BMP图片左上角在屏幕上的显示坐标。
        大家准备一个BMP格式的图片,注意这个BMP图片是有要求的,不是随便拿个图片过来就能显示的:
①、图片的分辨率不能超过当前所使用的LCD分辨率,比如我现在使用的LCD分辨率为1024*600,因此要显示的图片分辨率就不能超过1024*600。
②、图片的色深应该和LCD驱动格式一致,比如STM32MP1的uboot中LCD驱动默认为16BPP色深的RGB565格式,因此BMP图片必须是16位的RGB565格式,否则显示会出问题!一般的图片都是32位色深的,所以我们需要借助其他软件将其改为RGB565格式,这里以Photoshop为例(自行安装Photoshop CC软件),给大家简单讲一下如何将32位BMP图片转为RGB565格式的16位图片。首先使用PS打开需要转换格式的BMP图片,如图13.3.4.3所示:
第十三章 U27997.png

图13.3.4.3 PS打开图片

        点击“文件->存储为(A)……”,打开如图13.3.4.4所示界面:
第十三章 U28052.png

图13.3.4.4 保存设置

        在图13.3.4.4中设置好图片名字,保存类型一定要选择BMP,设置好以后点击右下角的“保存”按钮,然后打开保存设置对话框,如图13.3.4.5所示:
第十三章 U28146.png

图13.3.4.5 BMP图片选项设置

        点击图13.3.4.5中的“高级模式”,打开以后如图13.3.4.6所示:
第十三章 U28207.png

图13.3.4.6 BMP高级模式

        在图13.3.4.6中选择16位“R5 G6 B5”这个模式,也就是RGB565,然后点击右上角的“确定”按钮即可,此时就会在我们前面设置的文件夹里面生成一个16位RGB565格式的BMP图片。
16位RGB565格式的BMP图片准备好以后就可以显示了,首先将要显示的BMP图片放到ubuntu的TFTP服务器目录下,我们通过网络将BMP图片下载到板子的DDR中,然后再用bmp命令显示。命令如下:
  1. tftp c0000000 test.bmp                //下载bmp图片
  2. bmp info c0000000                        //显示图片信息
复制代码

        图片信息如图13.3.4.7所示:
第十三章 U28511.png

图13.3.4.7 图片信息

        从图13.3.4.7可以看出,当前BMP图片分辨率为1024*600,每个像素16位,也就是16BPP,当前LCD分辨率为1024*600,输入如下命令在LCD上显示图片:
  1. bmp display c0000000 0 0        //显示bmp图片
复制代码

        结果如图13.3.4.8所示:
第十三章 U28668.png

图13.3.4.8 bmp图片显示

13.4 bootcmd和bootargs环境变量
13.4.1 bootcmd环境变量
bootcmd在前面已经说了很多次了,bootcmd保存着uboot默认命令,uboot倒计时结束以后就会执行bootcmd中的命令。这些命令一般都是用来启动Linux内核的,比如读取EMMC或者NAND Flash中的Linux内核镜像文件和设备树文件到DRAM中,然后启动Linux内核。可以在uboot启动以后进入命令行设置bootcmd环境变量的值。如果EMMC或者NAND中没有保存bootcmd的值,那么uboot就会使用默认的值,板子第一次运行uboot的时候都会使用默认值来设置bootcmd环境变量。打开文件include/env_default.h,在此文件中有如下所示内容:
示例代码13.4.1.1 默认环境变量
  1. 13  env_t embedded_environment __UBOOT_ENV_SECTION__(environment) = {
  2. 14      ENV_CRC,    /* CRC Sum */
  3. 15  #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
  4. 16      1,      /* Flags: valid */
  5. 17  #endif
  6. 18      {
  7. 19  #elif defined(DEFAULT_ENV_INSTANCE_STATIC)
  8. 20  static char default_environment[] = {
  9. 21  #else
  10. 22  const uchar default_environment[] = {
  11. 23  #endif
  12. 24  #ifndef CONFIG_USE_DEFAULT_ENV_FILE
  13. 25  #ifdef  CONFIG_ENV_CALLBACK_LIST_DEFAULT
  14. 26      ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
  15. 27  #endif
  16. 28  #ifdef  CONFIG_ENV_FLAGS_LIST_DEFAULT
  17. 29      ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
  18. 30  #endif
  19. 31  #ifdef  CONFIG_USE_BOOTARGS
  20. 32      "bootargs=" CONFIG_BOOTARGS         "\0"
  21. 33  #endif
  22. 34  #ifdef  CONFIG_BOOTCOMMAND
  23. 35      "bootcmd="  CONFIG_BOOTCOMMAND      "\0"
  24. 36  #endif
  25. 37  #ifdef  CONFIG_RAMBOOTCOMMAND
  26. 38      "ramboot="  CONFIG_RAMBOOTCOMMAND       "\0"
  27. 39  #endif
  28. 40  #ifdef  CONFIG_NFSBOOTCOMMAND
  29. 41      "nfsboot="  CONFIG_NFSBOOTCOMMAND       "\0"
  30. 42  #endif
  31. 43  #if defined(CONFIG_BOOTDELAY)
  32. 44      "bootdelay="    __stringify(CONFIG_BOOTDELAY)   "\0"
  33. 45  #endif
  34. 46  #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
  35. 47      "baudrate=" __stringify(CONFIG_BAUDRATE)    "\0"
  36. 48  #endif
  37. 49  #ifdef  CONFIG_LOADS_ECHO
  38. 50      "loads_echo="   __stringify(CONFIG_LOADS_ECHO)  "\0"
  39. 51  #endif
  40. 52  #ifdef  CONFIG_ETHPRIME
  41. 53      "ethprime=" CONFIG_ETHPRIME         "\0"
  42. 54  #endif
  43. 55  #ifdef  CONFIG_IPADDR
  44. 56      "ipaddr="   __stringify(CONFIG_IPADDR)  "\0"
  45. 57  #endif
  46. 58  #ifdef  CONFIG_SERVERIP
  47. 59      "serverip=" __stringify(CONFIG_SERVERIP)    "\0"
  48. 60  #endif
  49. 61  #ifdef  CONFIG_SYS_AUTOLOAD
  50. 62      "autoload=" CONFIG_SYS_AUTOLOAD     "\0"
  51. 63  #endif
  52. 64  #ifdef  CONFIG_PREBOOT
  53. 65      "preboot="  CONFIG_PREBOOT          "\0"
  54. 66  #endif
  55. 67  #ifdef  CONFIG_ROOTPATH
  56. 68      "rootpath=" CONFIG_ROOTPATH         "\0"
  57. 69  #endif
  58. 70  #ifdef  CONFIG_GATEWAYIP
  59. 71      "gatewayip="    __stringify(CONFIG_GATEWAYIP)   "\0"
  60. 72  #endif
  61. 73  #ifdef  CONFIG_NETMASK
  62. 74      "netmask="  __stringify(CONFIG_NETMASK) "\0"
  63. 75  #endif
  64. 76  #ifdef  CONFIG_HOSTNAME
  65. 77      "hostname=" CONFIG_HOSTNAME "\0"
  66. 78  #endif
  67. 79  #ifdef  CONFIG_BOOTFILE
  68. 80      "bootfile=" CONFIG_BOOTFILE         "\0"
  69. 81  #endif
  70. 82  #ifdef  CONFIG_LOADADDR
  71. 83      "loadaddr=" __stringify(CONFIG_LOADADDR)    "\0"
  72. 84  #endif
  73. 85  #ifdef  CONFIG_CLOCKS_IN_MHZ
  74. 86      "clocks_in_mhz=1\0"
  75. 87  #endif
  76. 88  #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
  77. 89      "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0"
  78. 90  #endif
  79. 91  #ifdef  CONFIG_ENV_VARS_UBOOT_CONFIG
  80. 92      "arch="     CONFIG_SYS_ARCH         "\0"
  81. 93  #ifdef CONFIG_SYS_CPU
  82. 94      "cpu="      CONFIG_SYS_CPU          "\0"
  83. 95  #endif
  84. 96  #ifdef CONFIG_SYS_BOARD
  85. 97      "board="    CONFIG_SYS_BOARD        "\0"
  86. 98      "board_name="   CONFIG_SYS_BOARD        "\0"
  87. 99  #endif
  88. 100 #ifdef CONFIG_SYS_VENDOR
  89. 101     "vendor="   CONFIG_SYS_VENDOR       "\0"
  90. 102 #endif
  91. 103 #ifdef CONFIG_SYS_SOC
  92. 104     "soc="      CONFIG_SYS_SOC          "\0"
  93. 105 #endif
  94. 106 #endif
  95. 107 #if defined(CONFIG_BOOTCOUNT_BOOTLIMIT) && (CONFIG_BOOTCOUNT_BOOTLIMIT > 0)
  96. 108     "bootlimit="    __stringify(CONFIG_BOOTCOUNT_BOOTLIMIT)"\0"
  97. 109 #endif
  98. 110 #ifdef  CONFIG_EXTRA_ENV_SETTINGS
  99. 111     CONFIG_EXTRA_ENV_SETTINGS
  100. 112 #endif
  101. 113     "\0"
  102. 114 #else /* CONFIG_USE_DEFAULT_ENV_FILE */
  103. 115 #include "generated/defaultenv_autogenerated.h"
  104. 116 #endif
  105. 117 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
  106. 118     }
  107. 119 #endif
  108. 120 };
复制代码

        从示例代码13.3.4.1的第13行可以看出,embedded_environment是个env_t类型的变量,保存在environment 段里面,env_t类型如下:
示例代码13.3.4.2 env_t结构体
  1. 102 typedef struct environment_s {
  2. 103     uint32_t    crc;                /* CRC32 over data bytes    */
  3. 104 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
  4. 105     unsigned char   flags;           /* active/obsolete flags ENVF_REDUND_ */
  5. 106 #endif
  6. 107     unsigned char   data[ENV_SIZE]; /* Environment data     */
  7. 108 } env_t;
复制代码

        env_t结构体中的crc为CRC值,flags是标志位,data数组就是环境变量值。示代码13.3.4.1中指定了很多环境变量的默认值,比如bootcmd的默认值就是CONFIG_BOOTCOMMAND,bootargs的默认值就是CONFIG_BOOTARGS。我们可以直接在stm32mp1.h文件中通过设置宏CONFIG_BOOTCOMMAND来设置bootcmd的默认值。
13.4.2 bootargs环境变量
bootargs保存着uboot传递给Linux内核的参数,比如指定Linux内核所使用的console、指定根文件系统所在的分区等,如下面bootargs环境变量值:
  1. console=ttySTM0,115200 root=/dev/mmcblk2p3 rootwait rw
  2.         1、console
复制代码

console用来设置linux终端(或者叫控制台),也就是通过什么设备来和Linux进行交互,是串口还是LCD屏幕?如果是串口的话应该是串口几等等。一般设置串口作为Linux终端,这样我们就可以在电脑上通过MobaXterm来和linux交互了。这里设置console为ttySTM0,因为linux启动以后STM32MP1的串口4在linux下的设备文件就是/dev/ttySTM0,在Linux下,一切皆文件。
ttySTM0后面有个“,115200”,这是设置串口的波特率,console=ttySTM0,115200综合起来就是设置ttySTM0(也就是串口4)作为Linux的终端,并且串口波特率设置为115200。
2、root
root用来设置根文件系统的位置,root=/dev/mmcblk2p3用于指明根文件系统存放在mmcblk2设备的分区3中。正点原子的STM32MP1核心板启动linux以后会存在/dev/mmcblk1、/dev/mmcblk2、/dev/mmcblk1p1、/dev/mmcblk1p2、/dev/mmcblk2p1、/dev/mmcblk2p2和/dev/mmcblk2p3这样的文件,其中/dev/mmcblkx(x=0~n)表示mmc设备,而/dev/mmcblkxpy(x=0~n,y=1~n)表示mmc设备x的分区y。在STM32MP1开发板中/dev/mmcblk2表示EMMC,而/dev/mmcblk2p3表示EMMC的分区3。
        root后面有“rootwait rw”,rootwait表示等待mmc设备初始化完成以后再挂载,否则的话mmc设备还没初始化完成就挂载根文件系统会出错的。rw表示根文件系统是可以读写的,不加rw的话可能无法在根文件系统中进行写操作,只能进行读操作。
3、rootfstype
        此选项一般配合root一起使用,rootfstype用于指定根文件系统类型,如果根文件系统为ext格式的话此选项无所谓。如果根文件系统是yaffs、jffs或ubifs的话就需要设置此选项,指定根文件系统的类型。        
        bootargs常设置的选项就这三个,后面遇到其他选项的话再讲解。

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

7

主题

27

帖子

0

精华

初级会员

Rank: 2

积分
163
金钱
163
注册时间
2013-2-21
在线时间
28 小时
发表于 2021-10-22 12:25:46 | 显示全部楼层
有大神知道stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24往后的新版uboot编译没有uboot.stm32这文件是什么原因吗。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 10:34

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表