STM32MP157A MPU配备了对称多处理(SMP)架构的两颗Cortex-A7作为主应用处理器和一颗异构的Cortex-M4协处理器。这样的配置在低功耗物联网与工业控制领域是一种常见的典型MPU配置。这种高低主从处理能力的搭配,用以优化这些应用领域中处理能力、实时性、功耗、资源利用率和架构复杂性之间的平衡。
优点当然是系统平衡,缺点也很突出,那就是相对的系统复杂性。
系统的复杂在两方面体现。一是CA7、各种总线、共享和排他资源访问、多Master通信、中断管理等硬件设计上,二是CA7上的Linux为了兼容各种异构多处理环境而引入的管理框架和它们的配套框架上。当然,CA7裸奔也是可以的,然而“好好的”裸奔的复杂性不比引入Linux简单了。
因此下面的测评会简单的涉及到SoC和Linux以及CM4三方面的协同。
STM32MP157A SoC上首先是对称多处理环境的两颗CA7,然后才是添加了CM4内核的异构多处理环境。两颗CA7经过Linux的SMP支持之后,上层应用仍然作为“进程”模型进行编程即可。片上所有的共享资源分配、资源可见性、资源仲裁与调度等对称多处理环境由Multi-Processor CA7体系结构、AXI总线和Linux操作系统一起提供。
虽然STM32MP157A的总线上CA7可以访问CM4的大部分资源,但是CA7和CM4在运行时分别独占各自的SRAM资源(这不包含用于数据交换的共享SRAM),这样的独占性也就是非对称的存在,再加上CM4和CA7毕竟是很明显的两种不同结构,也就成了所谓的异构多处理环境。更典型的多处理环境是处理器农场和集群。
很早之前操作系统为了让不同的计算虚拟的独享整个系统资源,从而将计算抽象为进程(process),因此发展出进程间通信(IPC)。典型的IPC便是消息、信号量和共享内存。
啰嗦两段话引出操作系统的内容是因为STM32MP157A为了支持异构环境,添加了Hardware Semaphore(HSEM),Inter-processor communication controller(IPCC)和作为数据交换的shared memory(SRAM3)。
再一次的,这些硬件部件和操作系统的概念高度一致。使用上虽然具体技法不同,但是它们要做的事情是一致的:HSEM用于为CA7和CM4提供硬件资源计数和硬件锁,IPCC用于CA7和CM4之间发送消息的通道,SRAM3用于交换数据。因此寄存器细节不再重要了。
以上的SoC部件解决了进程间通信问题。还有一部分是片上资源管理,毕竟没有SMP环境的总线仲裁,CA7和CM4之间要和谐的使用资源还需要一些工作的。
这部分主要由Extended TrustZone® protection controller (ETZPC)完成。大概意思是STM32MP157A的外设分为了三种,一是CA7专用的,一是CA7和CM4都可用的,一是CM4专用的。还有一个TrustZone的安全技术在里面,分为安全和不安全的外设。不同的情况变成了以上三种类型乘以二,总之整的很不easy。很多外设是可以共享的,参见STM32MP1用户手册(Rev 4)的Table 93。ETZPC设置CA7和CM4共享的外设处于何总情况和外设的锁的情况。
总的来说,SoC为CA7和CM4的协调提供了外设资源管理和它们之间的通讯与互斥。
Linux对异构多处理的支持主要有remoteproc(参见内核代码下的Documentation/remoteproc.txt说明),rpmsg(参见内核代码下的Documentation/rpmsg.txt说明),Virtio和dts。
remoteproc是协处理器的管理框架,用来为协处理器加载镜像,开启协处理器运行,停止运行,收集异常日志等。主要提供load,start和stop操作。
rpmsg是主从处理器之间通信的框架,针对STM32MP157A来说它建立在IPCC硬件部件之上。主要是send,recv和消息通知的notify等操作。
Virtio是linux的虚拟io框架,提供虚拟设备支持。这也是为何remoteproc和rpmsg两个功能可以作为device的背景技术。virtoio提供本地资源和handler来虚拟(或实现)一个真实的设备(或新/伪设备)。
dts设备树主要用来指定CA7可以用哪些外设(也就是哪些外设不能用,可以留给CM4)。
总的来说,Linux为异构多处理环境提供了协处理器执行环境的管理和主从处理器之间的通信处理框架(通讯处理,区别于IPCC这种通信机制)。
remoteproc的load操作是建立在elf文件格式的解析之上的。因此为CM4产生的代码不是一般单片机意义上的flash bin(单片机中的flash bin是无格式的二进制代码,所有的可执行格式信息在链接之后被剔除了),CM4的执行文件需要以elf可执行文件的形式存放。Elf对remoteproc来说,它的价值在头部和segment定义(.data,.text等段)。remoteproc还需要为资源分配提供resource_table表,这个表用来定义协处理器的资源使用情况。这个表是以约定的“.resource_table”区段名称存在于elf可执行文件中,同样load操作需要在elf可执行文件中找到这个区段,解析resource_table,然后处理相关资源。
镜像加载之后,remoteproc通过STM32MP1的Reset and clock control (RCC)的0x10C寄存器RCC_MP_GCR中的BOOT_MCU 点亮CM4。
CM4的中断向量表地址是0x0000 0000,这个地址开始的64K是可以被当作一个整体空间使用的。小的CM4程序可以通过连接脚本的控制在这64K里面放置完整的text和data。对于大一些的CM4程序,中断向量表仍然放置在0x0000 0000,text可以放在128K的SRAM1,data可以放在128K的SRAM2,或者把这段连续地址的SRAM当作一个整体内存进行text和data的划分。虽然CM4的SRAM手册上说有384K,但是SRAM3作为共享内存,一般不用于CM4执行环境。
CM4执行起来之后,通过OpenAMP(底层实现是rpmsg,rpmsg的更底层支持是IPCC)进行主从通信与通知。把OpenAMP当作一个msg的send、recv,notify库应该是可以的。
对于小型数据来说rpmsg可以直接交换,对于大型数据通信,ST的建议是交换共享内存的地址。
CM4的加载点有三个。一是通过UBOOT加载,二是通过内核加载,三是系统启动之后通过sysfs加载。当然,首先要确保CA7的DTS把相关的外设预留给了CM4。
UBOOT的自动加载脚本在/boot/boot.scr.uimg,意思是加载/lib/firmware下面默认文件名为“rproc-m4-fw.elf”的CM4固件。这些过程是通过脚本进行控制的,没有什么特殊的地方。
内核加载的形式ST不推荐。
通过sysfs加载是往/sys/class/remoteproc/remoteprocX/firmware发送elf固件,通过echo -n 文件名.elf > 即可,然后echo start >/sys/class/remoteproc/remoteprocX/state,启动CM4协处理器。
更细节的情况可以参考Coprocessor management Linux。
/usr/local/Cube-M4-examples下面有很多例子。
大家对STM32 MCU的操作已经十分熟悉,只是可能对异构多核有些模糊,上面已经梳理了整体概念和过程,跑跑CM4例子这种事情就留给我这种STM32 MCU入门级初学者就行了。
此内容由EEWORLD论坛网友freebsder原创,如需转载或用于商业用途需征得作者同意并注明出处
chenzhufly 发表于 2020-4-6 22:43 还要不要脸了,你也好意思说自己是STM32 MCU入门级初学者。
柱哥,RCSN,qwerghf,54chenjq 都当过我学习STM32 MCU的老师!
商榷:加载cm4描述有误。
1.先要设定boot,
2. 只能从linux加载,硬加载或者软加载
3.有engeering mode和production mode。其中工程模式只有cm4,Linux加载后loop空转,用来单挑cm4。
北方 发表于 2020-4-8 17:04 商榷:加载cm4描述有误。 1.先要设定boot, 2. 只能从linux加载,硬加载或者软加载 3.有engeering ...
无所谓哪里加载,也无所谓先设定之类的要求。
官方wiki说的uboot,kernel(st不推荐),sysfs三个点,这是三种最主要的加载方式。
主要的三种加载方式并不意味着只能唯三的加载方式:更底层的 MCU 只不过是MPU设置 RCC的0x10C寄存器RCC_MP_GCR中的BOOT_MCU 这个动作,把 MCU 的hold状态释放掉,MCU这就启动了,从它的0x0地址访问中断向量表。uboot,kernel,remoteproc(sysfs) 它们做的是把MCU的代码放到 0x0 或者加载到SRAM1,SRAM2等。
机制便是如此。所以我说无所谓,你想咋弄都是你的事情,要不要boot,要不要kernel,都无所谓,总有办法把MCU加载起来。
engeering mode不过是另一个M4,ST不要有太多M4,这里讨论无意义。
本帖最后由 freebsder 于 2020-4-9 14:25 编辑