1. 项目概述:为什么是STM32MP135D?
如果你最近在关注嵌入式Linux的开发板,尤其是那些既想玩转Linux应用,又想保留实时控制能力的场景,那么ST(意法半导体)的STM32MP1系列大概率已经进入了你的视野。而STM32MP135D,可以说是这个家族里为“入门”和“成本敏感”量身打造的一个明星型号。我拿到这块板子(这里指基于STM32MP135D的核心板或开发套件)也有一段时间了,从最初对着数据手册发懵,到成功点亮第一个自定义应用,中间踩了不少坑,也总结了不少心得。这篇指南,就是想把这段从零开始的折腾过程,掰开揉碎了讲清楚,让你能避开我走过的弯路,快速上手。
简单来说,STM32MP135D是一颗典型的异构多核处理器。它内部包含了一个主频可达650MHz的Arm® Cortex®-A7核心,用来运行Linux这样的富操作系统,处理复杂的网络、图形界面和文件系统;同时,它还集成了一个主频可达209MHz的Arm® Cortex®-M4核心,这个核心就专攻实时控制,比如精准的PWM输出、高速ADC采集,或者运行RTOS(实时操作系统)。这种“A核+M核”的架构,让它既能胜任智能家居网关、工业HMI(人机界面)这种需要友好交互和连接能力的任务,又能同时控制电机、采集传感器数据,一颗芯片搞定过去可能需要两颗甚至三颗芯片才能完成的工作,对于精简产品设计、降低BOM成本非常有吸引力。
市面上叫“入门指南”的资料很多,但很多要么是官方手册的翻译,步骤跳跃;要么只讲A核Linux,忽略了M核的玩法。我这篇指南的目标是“全景式入门”,不仅会带你完成最基础的开发环境搭建、系统烧录,还会深入到双核通信、独立调试等实际项目必然会遇到的环节。你会发现,从让板子“跑起来”,到让两个核心“对话起来”,每一步都有需要注意的细节。
2. 开发环境搭建与工具链选型
工欲善其事,必先利其器。玩转STM32MP135D,第一步不是急着接线,而是要把“战场”——也就是你的开发主机环境——给布置好。这里的选择会直接影响你后续开发的效率。
2.1 操作系统与主机的选择
首先,强烈建议使用Linux作为开发主机系统。Ubuntu LTS版本(如20.04, 22.04)是兼容性最广、社区支持最好的选择。Windows当然也可以,但需要通过WSL2(Windows Subsystem for Linux)来获得一个接近原生Linux的环境。直接在Windows上搞,你会遇到各种路径、权限和编译工具的问题,徒增烦恼。
注意:如果你坚持用Windows,请务必安装WSL2并选择一个Ubuntu发行版。接下来的所有命令行操作,都将在WSL2的Ubuntu终端中进行。虚拟机方案也可以,但性能会有损耗,特别是涉及大量编译时。
为什么是Linux?因为ST官方提供的核心开发工具——STM32CubeProgrammer、编译工具链、以及构建系统如OpenSTLinux或Yocto Project——其脚本和生态都是围绕Linux/Unix环境设计的。在Linux下,一切都会顺畅得多。
2.2 关键软件工具安装
你需要安装的软件主要分为三类:烧录工具、编译工具、源码构建工具。
1. STM32CubeProgrammer:这是ST官方的多功能烧录和配置工具。它不仅能通过USB、UART或ST-LINK给板子烧写固件(包括TF-A、U-Boot、内核、根文件系统),还能访问芯片的OTP(一次性可编程)区域,配置安全启动等高级功能。去ST官网下载Linux版本的.tar.gz包,解压后运行里面的./SetupSTM32CubeProgrammer-*.linux安装脚本即可。安装后,记得将安装目录下的bin文件夹路径添加到系统的PATH环境变量中,这样就能在终端直接调用STM32CubeProgrammer命令了。
2. 交叉编译工具链:你的电脑(x86_64架构)无法直接编译出能在板子(Arm Cortex-A7架构)上运行的代码。所以需要一个“交叉”工具链。对于A核的Linux应用开发,我们使用gcc-arm-*。ST官方推荐使用Linaro或Arm官方提供的工具链。一个省心的选择是直接从Arm开发者网站下载arm-none-linux-gnueabihf这个工具链。下载后解压,同样将其bin目录加入PATH。
验证安装:在终端输入arm-none-linux-gnueabihf-gcc --version,如果能正确输出版本信息,说明工具链就绪。
3. 构建系统:OpenSTLinux 或 Yocto这是入门阶段最复杂,但也最重要的一环。STM32MP135D的完整系统镜像(包括所有启动固件、内核、设备树、根文件系统)不是单个文件,而是通过一个构建系统自动生成的。ST提供了基于Yocto Project定制的发行版——OpenSTLinux。你需要获取它的源码仓库(Manifest),然后通过repo工具同步。
# 1. 安装 repo 工具 mkdir -p ~/bin curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo chmod a+x ~/bin/repo export PATH=~/bin:$PATH # 2. 创建并进入工作目录 mkdir stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17 cd stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17 # 3. 初始化 repo 并同步代码 (这是一个例子,具体版本和链接请参考ST官网最新文档) repo init -u https://github.com/STMicroelectronics/oe-manifest.git -b refs/tags/openstlinux-5.10-dunfell-mp1-21-11-17 repo sync -j4这个过程会下载数十GB的代码,耗时很长,请确保网络通畅。同步完成后,你就拥有了一个可以定制、编译完整Linux系统的环境。
4. 其他实用工具:
screen或minicom:用于通过串口连接开发板,查看启动日志和进行命令行交互。这是你与板子沟通的主要窗口。git:版本管理,必不可少。gcc和make:用于编译一些本地主机工具。
2.3 硬件连接准备
以常见的STM32MP135D开发套件为例,你需要准备:
- Type-C数据线:用于给板子供电和USB通信(烧录和调试)。
- USB转TTL串口线:这是最重要的调试线!连接板子的UART串口(通常是PA9/PA10或PB6/PB7)到你电脑的USB口。波特率通常设置为115200。
- MicroSD卡和读卡器:用于制作启动卡。这是最常用的启动方式。
- 网线:如果你想通过网络(NFS、SSH)与板子交互,需要连接板子的以太网口。
- ST-LINK调试器(可选但推荐):用于M核的代码调试和烧录,以及A核的深度调试。
连接好后,打开串口终端(如screen /dev/ttyUSB0 115200),给板子上电,你应该能看到如海浪般涌出的启动日志。如果什么都没看到,请检查串口线连接、端口号和波特率。
3. 系统镜像构建与烧录实战
环境准备好了,接下来就是“做饭”——构建系统镜像,并把它“装盘”——烧录到存储设备中。这是让板子活起来的关键一步。
3.1 理解启动流程与镜像构成
在动手编译前,有必要了解一下STM32MP135D从上电到进入Linux系统的“心路历程”。这决定了我们最终要生成哪些文件:
- FSBL (First Stage Bootloader):芯片ROM代码从启动设备(如SD卡)加载的第一段程序。在ST的体系中,这部分由TF-A (Trusted Firmware-A)承担。它负责初始化最基础的硬件(如DDR),建立安全环境,并加载下一阶段。
- SSBL (Second Stage Bootloader):这就是我们熟悉的U-Boot。它负责更全面的硬件初始化,加载设备树(Device Tree),并从存储设备或网络中加载Linux内核。
- Linux Kernel:操作系统核心,带有所需的驱动。
- Device Tree Blob (dtb):一个描述板级硬件资源(哪个引脚是什么功能,外设地址在哪)的数据文件。内核依赖它来正确驱动硬件。对于STM32MP135D,你需要一个匹配你具体板卡设计的
.dtb文件。 - Root Filesystem:根文件系统,包含Linux运行所需的所有命令、库和应用程序。
OpenSTLinux构建系统会帮我们一次性生成所有这些组件。
3.2 使用OpenSTLinux构建镜像
进入之前同步好的源码目录,初始化构建环境:
cd <your-openstlinux-directory> source layers/meta-st/scripts/envsetup.sh这个脚本会提示你选择“机器”(Machine),对于STM32MP135D,通常选择stm32mp135d-dk(如果你用的是官方DK开发板)或类似的配置。然后选择“发行版”(Distribution),比如openstlinux-weston(带Wayland/Weston图形界面)或openstlinux-eglfs(无桌面,直接使用EGLFS图形后端)。
接下来,开始构建:
bitbake st-image-weston这个命令会启动Yocto的构建过程。st-image-weston是一个目标镜像配方,它会自动解析所有依赖,从内核、U-Boot到根文件系统,全部编译一遍。这是最耗时的步骤,在性能一般的电脑上可能需要数小时。首次构建会下载大量软件包,请确保磁盘空间充足(建议预留100GB以上)。
构建成功后,你需要的所有镜像文件都在build-openstlinuxweston-stm32mp1/tmp-glibc/deploy/images/stm32mp135d-dk/目录下。关键文件包括:
tf-a-stm32mp135d-dk.stm32:TF-A镜像u-boot-stm32mp135d-dk.stm32:U-Boot镜像core-image-minimal-stm32mp135d-dk.bootfs.tar.xz:内核、设备树等启动文件压缩包core-image-minimal-stm32mp135d-dk.rootfs.tar.xz:根文件系统压缩包st-image-weston-stm32mp135d-dk.wic.gz:一个完整的、可以直接写入SD卡的磁盘镜像(包含所有分区)。
对于新手,我强烈推荐直接使用.wic.gz文件,它是最简单的烧录方式。
3.3 多种烧录方式详解
方式一:使用STM32CubeProgrammer通过USB烧录(适用于开发阶段)这种方式需要板子处于“烧录模式”。通常通过拨动板上的启动开关(Boot0),让芯片从系统存储器(System Memory)启动,里面存有ST的出厂USB DFU(设备固件升级)程序。
- 板子断电,设置启动开关为DFU模式。
- 通过USB线连接板子的USB-OTG口到电脑。
- 打开STM32CubeProgrammer,选择“USB”连接方式,点击连接。如果驱动正确,会显示设备已连接。
- 在“烧录”页面,选择你编译好的
tsv文件(OpenSTLinux构建目录下通常有一个flashlayout.tsv),这个文件定义了哪个镜像文件烧写到存储设备的哪个分区。然后点击“Download”即可。 这种方式可以直接烧写到板载eMMC或SD卡,非常方便。
方式二:直接烧写SD卡镜像(最通用)如果你有.wic.gz文件,这就非常简单了。
- 将MicroSD卡插入电脑读卡器。
- 使用
lsblk命令确认SD卡在系统中的设备名(例如/dev/sdb,务必确认无误,写错盘符会清空你的硬盘!)。 - 解压并烧写:
gunzip -c st-image-weston-stm32mp135d-dk.wic.gz | sudo dd of=/dev/sdb bs=1M status=progress conv=fsync - 烧写完成后,安全弹出SD卡,插入板子的SD卡槽,设置启动开关为SD卡启动,上电。
方式三:手动分区与部署(深入理解)你也可以不用.wic,而是手动对SD卡分区,然后分别放入各个组件。这有助于理解分区结构:
- 用
fdisk对SD卡分区。通常需要:一个小的FAT32分区(约64M)用于存放TF-A、U-Boot、内核和设备树;一个大的EXT4分区用于根文件系统。 - 将
tf-a-*.stm32和u-boot-*.stm32通过dd命令写入SD卡开头的特定扇区(偏移量由你的板子决定,参考手册)。 - 挂载FAT32分区,将
zImage(内核)和*.dtb文件拷贝进去。 - 挂载EXT4分区,解压
rootfs.tar.xz到该分区。
烧录完成后,连接串口,上电,你应该能看到TF-A和U-Boot的启动信息,最后成功进入Linux登录提示符(如stm32mp135d-dk login:)。恭喜,你的Linux世界已经成功启动了!
4. 双核开发基础与通信初探
系统跑起来只是第一步。STM32MP135D的精髓在于双核协同。接下来,我们看看如何让Cortex-M4这个“小兄弟”动起来,并让它和Cortex-A7这个“老大哥”对话。
4.1 Cortex-M4固件的开发与加载
M核的程序开发,其实和你玩普通的STM32单片机(如STM32F4)非常相似。你可以使用熟悉的STM32CubeIDE。
- 创建工程:在STM32CubeIDE中,选择STM32MP135D作为目标芯片。关键一步是配置工程为“Cortex-M4”核心。IDE会自动生成针对M核的初始化代码。
- 资源分配:这是双核开发的核心矛盾。芯片上的外设(如GPIO、定时器、ADC、I2C等)需要明确分配给A核还是M核使用,不能冲突。分配是通过设备树(Device Tree)和资源管理器(如Linux侧的
remoteproc框架)来完成的。通常,在Linux的设备树源文件(.dts)中,会将某些外设节点标记为status = “disabled”;,或者将其归属到m4_rproc节点下,表示这些资源预留给M核。你需要在M核的代码中,只使用那些分配给你的外设。 - 编译与生成:编译M核工程,会得到一个
.elf文件(包含调试信息)和一个.bin或.hex文件(纯二进制镜像)。
如何把这个固件加载到M核并运行呢?有两种主流方式:
方式A:由U-Boot加载(静态分配)将M核的.bin文件打包进Linux的根文件系统。在U-Boot启动时,通过环境变量命令,将这块二进制数据从存储设备(如SD卡)加载到指定的DDR内存地址,然后启动M核。这种方式简单,但M核固件更新需要重新打包根文件系统。
在U-Boot命令行或bootcmd中:
load mmc 0:4 ${loadaddr} /lib/firmware/m4_firmware.bin cp.b ${loadaddr} 0x10000000 ${filesize} bootaux 0x10000000方式B:由Linux运行时加载(动态加载)这是更灵活、更现代的方式。利用Linux内核的remoteproc和rpmsg框架。你需要:
- 将M核固件(
.elf文件)放入根文件系统的/lib/firmware/目录下,例如命名为m4_firmware.elf。 - 在设备树中正确配置
m4_rproc节点,并指定固件路径:firmware = “m4_firmware.elf”;。 - 在Linux系统启动后,通过操作
sysfs接口来启动和停止M核:
启动后,使用# 启动M核 echo start > /sys/class/remoteproc/remoteproc0/state # 停止M核 echo stop > /sys/class/remoteproc/remoteproc0/statecat /sys/class/remoteproc/remoteproc0/state可以查看状态(running或offline)。这种方式允许你在系统运行时动态加载和更新M核固件。
4.2 双核通信机制:RPMSG
两个核心物理上独立,如何交换数据?ST提供了基于共享内存(Shared Memory)和处理器间中断(IPI)的RPMSG(Remote Processor Messaging)框架。你可以把它理解成双核之间的“消息队列”。
基本原理:在DDR中划出一块内存区域作为“邮箱”(Mailbox)或“通道”(VirtIO队列)。A核和M核都能访问这块区域。当一方想发送消息时,就将数据写入共享内存,然后通过一个硬件中断(IPI)“踢”一下对方,告诉对方“有你的信”。接收方收到中断后,从共享内存读取数据。
开发流程:
- M核侧:在STM32CubeIDE中,你可以使用ST提供的
OpenAMP库(集成在HAL包中)。它封装了RPMSG的初始化和通信API。你需要在M核代码中初始化一个RPMSG通道,并定义好通道的名字(例如“rpmsg-openamp-demo-channel”)和回调函数。当收到A核消息时,回调函数会被触发。 - A核侧:在Linux用户空间,你可以使用
rpmsg-char驱动。加载驱动后,会在/dev/下生成一个字符设备文件(如/dev/rpmsg0)。A核上的应用程序就可以像读写普通文件一样,用open(),read(),write(),ioctl()等系统调用来与这个设备文件交互,从而实现与M核的通信。
一个简单的例子:M核程序循环读取ADC,然后将数值通过RPMSG发送给A核;A核上一个简单的C程序打开/dev/rpmsg0,读取数据并打印出来。这就实现了一个典型的“M核采集,A核处理/显示”的协作模式。
实操心得:双核通信的调试是难点。务必先从最简单的“回声测试”(Echo)开始:A核发什么,M核原样发回来。确保通信链路通畅后,再增加业务逻辑。同时,要仔细检查设备树中关于共享内存区域(
vdev0vring0,vdev0vring1,vdev0buffer)的配置,地址和大小必须和M核代码中的定义严格一致,否则通信必然失败。
5. 外设驱动开发与调试技巧
当基本的双核通信跑通后,你会面临更实际的问题:如何驱动具体的硬件外设?这里既有A核Linux下的驱动,也有M核裸机或RTOS下的驱动。
5.1 Linux内核驱动开发入门
在A核的Linux环境下,驱动开发遵循标准的Linux设备驱动模型。对于STM32MP135D,大部分常见外设(如USB、以太网、SDMMC、I2C、SPI、UART)的驱动都已经由ST或社区维护在内核中了。你的工作主要是通过设备树(Device Tree)来启用和配置它们。
设备树是关键:设备树(.dts文件)是一种描述硬件的数据结构。内核通过解析它来知道“这个板子上有什么设备,挂在哪个总线上,用什么参数”。例如,使能一个I2C接口并连接一个触摸屏:
&i2c1 { pinctrl-names = "default"; pinctrl-0 = <&i2c1_pins_a>; status = "okay"; clock-frequency = <100000>; touchscreen@38 { compatible = "edt,edt-ft5x06"; reg = <0x38>; interrupt-parent = <&gpiof>; interrupts = <5 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&gpioe 15 GPIO_ACTIVE_LOW>; }; };你需要做的,就是根据你的实际硬件连接,修改或添加这样的设备树节点。修改后,需要重新编译设备树(bitbake linux-stm32mp -c devshell进入环境后手动编译,或整体重新构建),并将新的.dtb文件部署到启动分区。
对于内核中没有的驱动,你需要自己编写。这属于更高级的主题,通常需要创建一个内核模块(.ko文件),实现file_operations结构体中的open、read、write、ioctl等函数,并向内核注册你的设备。
5.2 M核裸机/RTOS驱动与调试
在M核侧,驱动开发更接近传统单片机。你可以使用STM32CubeMX生成初始化代码,或者直接使用STM32CubeHAL库。重点在于资源隔离。
- 时钟与电源:确保A核(通过Linux)和M核不会同时去配置同一个时钟域或电源域,否则会导致系统不稳定。通常,这些系统级的资源由A核的Linux统一管理。M核在启动前,需要A核为其配置好时钟和电源。这就是为什么推荐使用
remoteproc动态加载的原因,因为Linux的remoteproc驱动会在启动M核前做好这些准备工作。 - 外设独占:如果一个定时器分配给了M核,在Linux的设备树中就必须将其
status设为disabled,或者从aliases中移除,防止Linux内核试图去初始化它。 - 调试:调试M核的最佳工具是ST-LINK配合STM32CubeIDE或OpenOCD。你需要将ST-LINK的SWD接口连接到板子的调试口。在STM32CubeIDE中,可以像调试普通STM32一样设置断点、单步执行、查看变量和寄存器。特别注意:当A核也在运行时,调试M核可能会受干扰。有时需要在调试前,先在U-Boot或Linux中暂停A核(例如进入U-Boot后不执行
boot命令),然后再连接调试器。
5.3 系统级调试与性能分析
- 串口日志:永远是你最可靠的朋友。确保内核的
printk日志级别足够(通过dmesg或/proc/sys/kernel/printk调整),以便看到驱动加载和运行的详细信息。 - 网络调试:为板子配置好网络(有线或无线),使用
ssh登录,比串口终端方便太多。你还可以通过网络挂载NFS根文件系统,实现主机和开发板之间的文件实时共享,极大提升应用开发效率。 - 性能工具:Linux下有很多强大的性能分析工具。
top/htop看进程,vmstat/iostat看系统IO,perf可以进行性能剖析。对于M核,可以在代码中插入时间戳来计算函数执行时间。 - 示波器和逻辑分析仪:当软件调试无法解决问题时(比如时序问题、信号完整性问题),硬件仪器是终极武器。用它们来测量GPIO波形、I2C/SPI通信时序,往往能快速定位问题根源。
6. 常见问题排查与避坑指南
这里汇总了我自己在折腾STM32MP135D过程中遇到的一些典型问题及其解决方法,希望能帮你节省大量时间。
6.1 系统无法启动
现象:上电后串口无任何输出。
- 检查1:电源和启动开关。确认供电电压和电流足够,启动开关拨到了正确的位置(SD卡启动或eMMC启动)。
- 检查2:串口连接。确认TX/RX线没有接反,波特率是否为115200,电脑端串口软件配置是否正确。
- 检查3:镜像文件。确认烧录的镜像是否针对你的具体板卡(
stm32mp135d-dk和stm32mp135d-xxx可能不同)。尝试使用官方预编译的镜像测试,以排除自己编译出错的可能。 - 检查4:SD卡或eMMC。尝试换一张SD卡,或者用STM32CubeProgrammer重新完整烧写eMMC。
现象:卡在U-Boot阶段,提示“
Wrong Ram size”或“DRAM init failed”。- 原因:DDR初始化失败。这是最常见的问题之一。
- 解决:这几乎总是设备树(dtb)选错了。STM32MP135D可能有不同大小的DDR配置(比如256MB,512MB)。你必须使用与你的板载DDR芯片型号和大小完全匹配的设备树文件。仔细查阅你的板子原理图和数据手册,确认DDR型号,然后在U-Boot启动时,通过
env print fdtfile查看当前加载的设备树,并通过setenv fdtfile correct-board.dtb来修改。
6.2 双核通信失败
现象:
remoteproc启动M核失败,sysfs状态一直为offline或报错。- 检查1:固件路径和文件名。确认
/lib/firmware/目录下的.elf文件名与设备树中firmware属性指定的名字完全一致(包括后缀)。 - 检查2:资源冲突。检查设备树中,是否将M核要用的外设(如GPIO、定时器、DMA通道)正确地分配给了M核(例如,在
m4_rproc节点下声明,或者在A核侧设为disabled)。使用dmesg | grep -i remoteproc查看内核日志,通常会有详细的错误信息。 - 检查3:共享内存地址。确认设备树中定义的
vdev0vring0、vdev0vring1、vdev0buffer的地址范围,与M核固件代码中(通常在openamp_conf.h或类似文件中)定义的VRING_ADDR等宏的地址完全一致。哪怕有一个字节的偏差,通信都无法建立。
- 检查1:固件路径和文件名。确认
现象:RPMSG通道可以建立,但收发数据异常(丢包、乱码)。
- 检查1:缓冲区大小。确保发送的数据长度不超过RPMSG通道的缓冲区大小(默认可能只有512字节)。如果需要传输大量数据,需要设计分片传输协议。
- 检查2:同步问题。A核和M核的处理速度可能不同。确保你的应用层协议有足够的流控或确认机制,避免生产者过快淹没消费者。
6.3 外设无法使用
现象:在Linux下找不到I2C设备(
i2cdetect看不到)。- 检查1:设备树引脚复用(Pinctrl)。确认设备树中该I2C控制器对应的
pinctrl-0引用了正确的引脚配置组(pinctrl节点),并且这些引脚没有被其他功能占用。 - 检查2:时钟使能。确认设备树中该I2C控制器的父节点(比如
i2c1)的clocks属性正确,且status为okay。 - 检查3:物理连接。用万用表或示波器检查I2C总线的SCL和SDA线上是否有正确的上拉电压,设备地址是否正确。
- 检查1:设备树引脚复用(Pinctrl)。确认设备树中该I2C控制器对应的
现象:M核控制的PWM输出无波形。
- 检查1:时钟配置。M核的时钟默认可能较低,需要检查并配置相关定时器的时钟源和分频器。
- 检查2:引脚复用。在M核的CubeMX配置或代码中,必须将对应的GPIO设置为正确的复用功能(AF)。
- 检查3:A核干扰。再次确认该定时器对应的引脚在Linux设备树中已被禁用,防止Linux内核在启动时将其初始化为其他功能(如普通GPIO输入)。
6.4 构建与编译问题
- 现象:
bitbake构建失败,报错找不到某个包或下载失败。- 解决:Yocto构建需要从网络下载大量源码包。失败通常是网络问题。可以尝试配置代理,或者使用国内的镜像源。另一个常见原因是磁盘空间不足,请确保构建目录所在分区有充足空间。
- 现象:交叉编译简单的Hello World程序失败,提示找不到头文件或库。
- 解决:确保你的编译命令使用了正确的交叉编译工具链前缀:
arm-none-linux-gnueabihf-gcc。并且,如果你需要链接开发板根文件系统里的库,可能需要通过-I和-L选项指定sysroot路径,这通常可以在OpenSTLinux的SDK安装后获得。
- 解决:确保你的编译命令使用了正确的交叉编译工具链前缀:
折腾STM32MP135D的过程,是一个典型的“先难后易”的过程。初期会被庞大的系统、复杂的工具链和双核概念所困扰,但一旦你打通了环境搭建、系统构建、双核通信这条主线,后面很多工作都是在这条主线上的扩展和深化。它给了你一个在单芯片上探索Linux应用和实时控制的绝佳平台,无论是用于产品原型开发,还是用于学习嵌入式Linux和异构计算,价值都非常高。我的建议是,不要试图一次性掌握所有东西,跟着这篇指南,先让板子跑起来,再让两个核心说上话,然后基于一个具体的、小小的项目目标(比如用M核读取温度传感器,A核通过Web界面显示),去逐个攻克遇到的技术点,这样学习起来最有成就感,也最扎实。