在之前的博文 Linux Kernel 之一 完整嵌入式 Linux 环境、构建工具、编译工具链、CPU 体系架构 中说了要一步步搭建整个嵌入式 Linux 运行环境,今天主要学习一下将 Linux 内核适配 STM32F769I-EVAL 开发板。
源码
文中涉及的源代码均放到了我个人的 Github 上:https://github.com/ZCShou/BOARD-STM32F769I-EVAL
。这个仓库中包含了要搭建的完整嵌入式 Linux 环境的所有源代码,后续博文均以该仓库中的源码为基础来学习!
开发环境
我这里使用的基本开发环境依旧是在之前博文中多次说明的 Ubuntu 22.04.1 LTS + Arm GNU Toolchain 11.3.Rel1,对应的 J-link 也依旧是 J-Link_Linux_V764e_x86_64.deb。该环境下需要注意的问题说明如下:
- 由于 Ubuntu 22.04 LTS 默认是标配 OpenSSL 3.x,而旧版 U-Boot 使用的是 OpenSSL 1.x,所以,该环境编译旧版 U-Boot(从 commit e927e21c 开始添加了相关处理) 将出现一堆警告,因此,后续使用 u-boot-v2022.10 这个版本为主:
- Arm GNU Toolchain 10.2-2022.02 存在 BUG,导致编译 U-Boot 报错,不要使用这个版本!
- 新版(Arm GNU Toolchain 10.3 之后的版本)的 Arm GNU Toolchain 在 Linux 上 GDB 需要 Python3.8 支持。然而,Ubuntu 22.04 默认的 Python 是 3.10。直接运行
arm-none-eabi-gdb
报错如下:
解决方法就是直接手动安装 Python3.8 即可。 旧版的 Arm GNU Toolchain 10.3 -2021.10 不需要 Python 支持sudo add-apt-repository ppa:deadsnakes/ppa -y sudo apt install python3.8
我使用的是 VSCode 来查看 U-Boot + Kernel 源代码,为了查看方便,我把不需要的文件进行了隐藏,通过将不需要的文件排除在外,加快搜索等操作的执行,也避免了过多无用结果。以下是我的 VSCode 配置:
{"files.exclude": {"**/.git": true,"**/.svn": true,"**/.hg": true,"**/CVS": true,"**/.DS_Store": true,"u-boot-v2021.10":true,// arch"**/mips": true,"**/powerpc": true,"**/riscv": true,"**/ti": true,"**/x86": true,"**/sandbox": true,"**/arch/{arc,m68k,microblaze,mips,nios2,powerpc,riscv,sandbox,sh,x86,xtensa,um,sparc,s390,parisc,openrisc,nds32,ia64,hexagon,h8300,csky,arm64,alpha}": true,// cpu"**/arch/arm/cpu/{arm11,arm720t,arm920t,arm926ejs,arm946es,arm1136,arm1176,armv7,armv8}": true,// machine"**/arch/arm/mach-[^s]*": true,"**/arch/arm/mach-s[^t]*": true,"**/arch/arm/mach-st[^m]*": true,"**/arch/arm/mach-stm32[$^m]*": true,// dts"**/dts/[^s|^M|^i|^a|^d|^.]*": true,"**/dts/d[^t]*": true,"**/dts/i[^n]*": true,"**/dts/in[^c]*": true,"**/dts/a[^r]*": true,"**/dts/ar[^m]*": true,"**/dts/arm[^v]*": true,"**/dts/s[^t]*": true,"**/dts/st[^m|^-]*": true,"**/dts/stm32[^f]*": true,"**/dts/stm32f[^7]*": true,"**/dts/stm32f7[^6|4|^-]*": true,"**/dts/stm32f769-[^e|d|p]*": true,// configs"**/configs/[^s]*": true,"**/configs/s[^t]*": true,"**/configs/st[^m]*": true,"**/configs/stm[^3]*": true,// "**/configs/stm3[^2]*": true,"**/configs/stm32[^f|^_]*": true,"**/configs/stm32f[^7]*": true,// "**/configs/stm32f7[^6|^4]*": true,// "**/configs/stm32f769-[^e]*": true,// board"**/board/[^s]*": true,"**/board/s[^t]*": true,"**/board/ste": true,"**/board/sto*": true,"**/board/st/st[^m]*": true,"**/board/st/stm32[^f]*": true,// "**/board/st/stm32f[^7]*": true,// "**/board/st/stm32f7[^6|^4]*": true,},"editor.insertSpaces": false
}
运行环境
我使用的嵌入式环境是 STM32F769I-EVAL 板子。STM32F769I-EVAL 板子使用的 STM32F769NI 这个 MCU,STM32F769NI 这款 MCU 采用的是 ARM Cortex-M7 的核心,指令集架构是 ARMv7m。此外,还需要注意,这个板子上的的串口的 RX 默认是断开,需要用短路帽连接起来。
Linux 内核本身提供了对于 STM32 的支持,不过并没有提供 STM32F769I-EVAL 板子对应的设备树文件。配置文件是 ./arch/arm/configs/stm32_defconfig
。不过,这个文件更像是一个 DEMO,其中的有些内容并不符合我们的 STM32F769I-EVAL 开发板,本篇博文的移植主要就是添加对于 STM32F769I-EVAL 板子的支持。
移植过程
绝大多数情况下,移植工作都不是从零开始。Linux Kernel 中默认提供了对于 STM32F769-disco 的支持,STM32F769I-EVAL 的移植完全可以参考它来进行。此外,在博文 U-Boot 之二 移植过程详解、 STM32F769I-EVAL 开发板适配 已经将学习过设备树相关的适配,而 U-Boot 的设备数文件和 Linux 内核中的是基本一致的。
-
增加 STM32F769-eval 设备树文件:
./arch/arm/boot/dts/stm32f769.dtsi
和./arch/arm/boot/dts/stm32f769-eval.dts
。stm32f769.dtsi
是直接复制的stm32f746.dtsi
然后更名的,没有任何修改;stm32f769-pinctrl.dtsi
原来就存在,不需要改动;stm32f769-eval.dts
是直接复制的stm32f769-disco.dts
,然后做了如下更改:
-
将新增的
stm32f769-eval.dts
添加到./arch/arm/boot/dts/Makefile
中,否则编译系统不会编译我们新增的设备树文件。
-
编辑
./arch/arm/mach-stm32/board-dt.c
,在其中增加自己的 MCU 。由于 Linux 本身提供了对于 STM32F769-disco 开发板的支持,因此这里面已经有了STM32F769
,因此,我们board-dt.c
不要更改。
此外,还需要在 MCU 这一级的 Kconfig 文件./arch/arm/mach-stm32/Kconfig
中添加我们的 MCU。同样,由于 Kconfig 中已经存在MAC_STM32F769
了,这里我也不需要更改。此外,这里默认选择了全部 MCU,我修改为只选中STM32F769
。也可以后面在 menuconfig 中手动更改,效果是一样的。
-
将 STM32 的配置添加到 ARM 架构这一级的
./arch/arm/Kconfig
配置系统中。同样,由于 Linux 本身提供了对于 STM32F769-disco 开发板的支持,因此这里面已经有了./arch/arm/mach-stm32/Kconfig
,因此,不需要更改。
这里需要注意,我们的 STM32F769 是没有 mmu 的,因此,实际在./arch/arm/Kconfig-nommu
文件中有很多真多我们的 MCU 的默认配置,这里不需要修改,后面可以直接使用stm32_deconfig
文件中的配置覆盖这些默认配置。
-
将 ARM 架构添加到架构一级的总的 Kconfig 系统
./arch/Kconfig
中。同样,由于 Linux 本身提供了对于 STM32 的支持,这里不需要改动。
-
修改默认的配置文件:
./arch/arm/configs/stm32_defconfig
。在 Linux Kernel 中,所有 STM32 共用这一个配置文件,这个文件中的部分内容并不能适合我们的开发板。如果不想修改这个文件,我们可以直接新建一个stm32f769_defconfig
,主要修改如下:
- 修改 DRAM 的地址和大小
- 取消 XIP,因为 STM32F769 的内部 FLASH 放不开我们的 Image。
之所以在这个配置文件中修改配置是为了不用每次编译都在
ARCH=arm CROSS_COMPILE=arm-none-eabi- make O=build_stm32 menuconfig
进行修改,一劳永逸!
开发板适配
上面的移植仅仅是在 Linux Kernel 中添加了 STM32F769I-EVAL 的支持,接下来还需要根据 STM32F769I-EVAL 的手册修改移植的文件内容,使其完全符合 STM32F769I-EVAL 中各种资源的定义。
注意,Linux Kernel 中的设备树与 U-Boot 中的基本是一致的(U-Boot 的文件就来自于 Linux Kernel),因此,完全可以直接参照在 在博文 U-Boot 之二 移植过程详解、 STM32F769I-EVAL 开发板适配 中的适配过程。甚至直接对比文件复制相关改动即可。
DRAM: 16 MiB
根据 STM32F769I-EVAL 手册说明,DRAM 应该是 32MB,这里显示是 16 MiB,显然是不对的。
STM32F769I-EVAL 手册中说 DRAM 芯片是 IS42S32800G-6BLI,我们需要根据手册,修改 FMC 在设备树文件中有描述。
MMC: no card present
STM32F769-EVAL 开发板上是有 SD 卡的。但是这里显示没有卡。不出意外的话,这里是由于 STM32F769-Disco 与 STM32F769-EVAL 在这方面配置不同导致。下图是两款开发板关于 SD 卡的说明:
从中我们可以看出,两款开发板使用的 SDMMC 并不相同!EVAL 开发板有两个 SD 卡插槽:SD1 -> SDMMC1
,SD2 -> SDMMC2
。而 Discovery 板子只有一个 SD卡插槽:SD -> SDMMC2
。关键在于 SDMMC2 的管脚使用是不一样的!
- EVAL 板子需要我们修改一下板子的硬件,如上图红色框中所示。从修改便捷性来说,我们直接使用 SD2 即可,只需要配置 JP7 即可
- MicroSDcard _detect 引脚需要更改。但是这里有个问题。EVAL 板子中,这个引脚是连接到扩展 IO 的,如何配置到设备树还没处理!不过,我们可以找个临时处理方法:我们借用 PC13 这个引脚,因为正好这个引脚是高电平,正好可以表示 SD 卡插入。
参考
- Linux 官方文档
- https://linux-kernel-labs.github.io/refs/pull/187/merge/lectures/intro.html