1. 多核异构核间通信

由于MP157是一款多核异构的芯片,其中既包含高性能的A7核及实时性强的M4内核,那么这两种处理器工作时,怎么互相协调配合呢? 这就涉及到了核间通信概念了。

IPCC (interprocessor communication controller)用于处理器间的数据交换通知。 它提供了一种非阻塞信号机制,并提供原子方式进行信号发布信息检索。 注意,核间通信共享内存缓冲区是在MCU的SRAM中分配的,它不是IPCC外设的一部分

1.1. 外设简述

IPCC外设提供了硬件支持,来管理两个处理器实例之间的处理器间通信每个处理器拥有特定的寄存器区域中断。 有点像硬件信号量功能

IPCC提供了六个双向通道信号每个通道分为两个子通道,每个子通道提供从“发送方”处理器到“接收方”处理器的单向信号:

  • P1_TO_P2子通道(从P1发到P2)

  • P2_TO_P1子通道(从P2发到P1)

子通道中包括如下功能

IPCC支持以下信道的操作模式

间通信模型如下

1.2. 框架简述

IPCC作为核间通信桥梁,它仅承担着通知角色负责消息分发、中断的处理等。

实际上,IPCC外设这个角色只是多核异构核间通信中的一块,在我们使用多核异构核间通信时,往往不仅希望使用到核间的消息通知,还希望能在不同的核心中进行数据的交互比如M4核进行实时的AD数据采集处理,完成后,M4核可通过异构的框架数据呈递给A7核,A7核再进行更复杂应用)。那么在这个需求驱动下,就出现了一些框架相互配合使用的情况了,下面我们就给大家介绍这些内核框架。

1.2.1. RemoteProc framework

远程处理器框架(RPROC、RemoteProc)允许不同的平台/体系结构控制打开电源加载固件关闭电源远程处理器,同时抽象硬件差异。此外,它还提供监视和调试远程协处理器的服务

以MP157为例,其RemoteProc可分为两块,分别是A7核端、M4核端:

remoteproc:这是远程处理器框架的通用部分(在MP157中为A7核端)。

它的作用是:

stm32_rproc:这是远程处理器平台驱动程序(在MP157中为M4核端)。

它的作用是:

ST官方参考资料

Linux RPMsg framework overview – stm32mpu

1.2.2. RPMsg framework

此小节为大家简述有关Linux RPMsg框架的内容。RPMsg框架是一个基于virtio的消息总线,它允许本地处理器与系统上可用的远程处理器通信。

此框架在多核异构中承担的角色下图

Linux RPMsg框架是在virtio框架顶层上实现的消息传送框架,其用于主机和远程处理器进行通信。它基于virtio vring,可通过共享内存向远程CPU发送消息或从远程CPU接收消息。

这些vring是单向的,一个vring专用于发送到远程处理器的消息,另一个vring用于从远程处理器接收的消息。此外,共享缓冲区需要在两个处理器都可见的内存空间创建

当新消息在共享缓冲区中等待时,会使用到另一个框架 Linux Mailbox framework ,该框架将用于通知对应的Core

依靠这些框架,RPMsg框架实现基于不同通道的通信。通道可被文本名称标识,并有一个本地(“源”)的RPMsg地址和一个远程(“目的”)的RPMsg地址

在远程处理器端(MP157则为M4核),也必须使用RPMSG框架。RPMSG框架的实现存在几种解决方案,ST建议使用OpenAMP方案,并在SDK中给出了示例

Github OpenAMP框架 .

简单来说,MP157的A7核与M4核,通过一个标准的RPMsg框架来建立起联系,完成数据传递。

具体原理可以参考

RPMsg-Messaging-Protocol .

RPMsg-Communication-Flow .

Linux内核源码目录给出的rpmsg client示例代码位置如下:

samples/rpmsg/rpmsg_client_sample.c

rpmsg框架Linux内核驱动源码位于:

drivers/rpmsg

ST官方参考资料

Linux remoteproc framework overview – stm32mpu

1.2.3. Mailbox framework

此小节为大家简述有关Linux邮箱框架的内容。邮箱框架涉及异构多核系统的处理器间通信

此框架的结构下图

邮箱框架被用于内核间进行消息或信号交换,常用于主机和协处理器间。邮箱由以下模块组成:

关于此框架的权威描述,在内核文档中的如下目录

Documentation/mailbox.txt

一般而言mailbox controllerclient都由芯片厂商负责实现,因为这依赖于外设。 我们更常关注的,则是mailbox client创建和使用。

ST实现的mailbox client代码位置如下:

drivers/remoteproc/stm32_rproc.c

在内核中还给出了一份mailbox client示例驱动代码代码通过debugfs子系统,将mailbox的操作暴露给了用户空间, 用户可以直接通过debugfs来使用mailbox,进行消息在不同内核中的传递。

mailbox框架的设备描述可参考内核源码文档

Documentation/devicetree/bindings/mailbox/mailbox.txt

一个简单的mailbox client设备树节点,可以参考内核源码目录

Documentation/devicetree/bindings/mailbox/sti-mailbox.txt

内核源码目录给出的mailbox client的示例代码位置如下:

drivers/mailbox/mailbox-test.c

ST官方参考资料

Linux Mailbox framework overview – stm32mpu

1.2.4. 框架小结

前面介绍了三个框架,它们并不是独立工作的,而是相互协调的,彼此关联。 我们可以通过两张图来查看它们之间的关系

以RemoteProc框架为主视角出发:

可以理清三个框架的关系,RemoteProc可以说是骨架,关联到了RPMsg框架、Mailbox框架。

1.3. 设备树插件描述

1.3.1. IPCC设备树节点

设备树节点位于arch/arm/boot/dts/stm32mp157c.dtsi

IPCC设备树节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
ipcc: mailbox@4c001000 {
    compatible = "st,stm32mp1-ipcc";
    #mbox-cells = <1>;
    reg = <0x4c001000 0x400>;
    st,proc-id = <0>;
    interrupts-extended =
        <&amp;intc GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
        <&amp;intc GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
        <&amp;exti 61 1>;
    interrupt-names = "rx", "tx", "wakeup";
    clocks = <&amp;rcc IPCC>;
    wakeup-source;
    power-domains = <&amp;pd_core>;
    status = "disabled";
};

使用节点位于arch/arm/boot/dts/stm32mp157a-basic.dts

使用IPCC设备树节点

1
2
3
&amp;ipcc {
    status = "okay";
};

设备树中的compatible = “st,stm32mp1-ipcc”属性,会匹配到 drivers/mailbox/stm32-ipcc.c 驱动程序,驱动程序中会创建一个mbox controller

1.3.2. A7<–>M4 rproc设备树节点

设备树节点位于arch/arm/boot/dts/stm32mp157c.dtsi

rproc设备树节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
m4_rproc: m4@0 {
    compatible = "st,stm32mp1-rproc";
    #address-cells = <1>;
    #size-cells = <1>;

    ranges = <0x00000000 0x38000000 0x10000>,
            <0x30000000 0x30000000 0x60000>,
            <0x10000000 0x10000000 0x60000>;
    resets = <&amp;rcc MCU_R>;
    reset-names = "mcu_rst";
    st,syscfg-pdds = <&amp;pwr 0x014 0x1>;
    st,syscfg-holdboot = <&rcc 0x10C 0x1>;
    st,syscfg-tz = <&rcc 0x000 0x1>;
    st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
    status = "disabled";

    m4_system_resources {
        compatible = "rproc-srm-core";
        status = "disabled";
    };
};

使用节点位于arch/arm/boot/dts/stm32mp157a-basic.dts

使用rproc设备树节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
&m4_rproc {
    memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
            <&vdev0vring1>, <&vdev0buffer>;
    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
    mbox-names = "vq0", "vq1", "shutdown";
    interrupt-parent = <&exti>;
    interrupts = <68 1>;
    interrupt-names = "wdg";
    wakeup-source;
    recovery;
    status = "okay";
};

设备树中的compatible = “st,stm32mp1-rproc”属性,会匹配到 drivers/remoteproc/stm32_rproc.c 驱动程序,驱动程序中会创建一个mbox client,并基于RemoteProc、RPMsg框架与mbox client进行关联。

1.4. 实验代码简述

这里我们简单讲解一下M4核端的代码和一些概念,更详细的内容则需大家自己研究了。

rpmsg框架下有通信端点的概念,数据在两个端点间传输。端点间的数据传输是rpmsg框架下数据传输最原始的形式, 我们可以在原始的数据传输形式上再做一层封装抽象出一些特定类型的设备。

每个端点注册底层实现,就是一个内核设备的注册(使用的是平台总线模型),故注册的端点设备, 可以利用到驱动的Probe功能(具体实现详见 drivers/rpmsg/rpmsg_core.c 300行后内容)。

在M4端,通过调用openamp库中的 OPENAMP_create_endpoint 函数,并在调用指定参数name(即为设备名称), 即可在内核中注册一个对应的rpmsg框架平台设备,该设备最终可以通过name(设备名称)来匹配到相应的A7端内核驱动:

所以Linux rpmsg框架下使用平台总线模型与端点通讯的方式结合,给一些需要特殊操作的自定设备, 提供了支持的可能。比如异构间的通讯,可以封装串口通讯模型

我们提供的M4内核固件的代码中,注册了两种Linux内核自带的rpmsg框架下, 原生支持的设备模型,这两种设备类型是rpmsg-ttychannel、rpmsg-client-sample:

M4核的代码中,创建上述两个rpmsg设备的代码如下:

在M4核的代码中,还初始化usart3作为M4内核的Log输出串口,我们可以通过串口模块接入开发板上的usart3,来查看M4内核输出的Log。 最终工程代码会被用于生成ELF固件,ELF固件即为程序,会运行在MP157的M4内核上。

综上,通过原生的rpmsg框架设备、 /dev/ttyRPMSGx 节点以及M4内核使用的usart3资源,我们就可以进行简单实验了。 本实验的代码也比较简单这里讲解这么多。

1.5. 实验准备

由于多核异构的框架是与处理器的架构紧密联系在一起的,所以一般这些框架驱动会由芯片厂商为我们提供好。 野火MP157开发板默认开启了这些驱动支持,并且开启了对应的设备树,我们直接进行使用就可以了。

前面我们提到了,M4内核要与A7内核通讯需要共用一个框架,那么M4内核的运行的程序里, 就需要有对应的框架代码,这个为大家提供的工程中已经包含。 最终我们将代码生成的ELF固件,通过A7内核的remoteproc子系统加载到M4内核上, 即可做好前期的准备工作

生成ELF固件的工程代码位于 linux_driverframework_ipccSTM32Cube_FW_MP1_V1.2.0ProjectsSTM32MP157C-EV1ApplicationsOpenAMPOpenAMP_raw 目录下, 感兴趣可自行研究工程可用MDK或CubeIDE打开(在工程目录中由对应文件夹)。

MP157-M4内核的使用可参考:

[野火]Cortex-M4内核开发实战指南-基于STM32MP157

重要

在M4核的代码中,还初始化usart3,实验前请务必将usart3的设备树插件关闭

1.6. 实验操作

M4核的固件我们已经成功编译并放在了/linux_driver/framework_ipcc目录下, 我们将M4核的固件 OpenAMP_raw_CM4.elf 上传至Linux文件系统的 /lib/firmware/ 目录。此目录存放着Linux系统中会使用到的各种固件。

执行如下命令指定M4内核加载的固件,默认root用户下操作:

# 进入remoteproc子系统目录
cd /sys/class/remoteproc/remoteproc0
# 导入M4内核固件名称
echo OpenAMP_raw_CM4.elf > firmware

在同一目录下,执行如下命令启动停止M4内核:

# 启动M4内核
echo start > state
# 停止M4内核
echo stop > state

启动M4内核后信息如下:

M4内核加载固件并启动后,在串口终端打印出了一些信息,我们通过串口模块接入usart3引脚, 再打开串口调试助手设置波特率为115200,可以看到M4固件初始化的usart3作为串口printf出来的信息, 为 [INFO ]M4 send to A7 : hello world! , 并且A7端的驱动也打印出了 rpmsg_client_sample virtio0.rpmsg-client-sample.-1.0: incoming msg 1 (src: 0x0) 说明M4核及A7核驱动正常工作了。

此外,输入lsmod,我们还可以看到演示设备创建后,对应被动态加载的驱动模块, rpmsg_client_sample :

下面,我们进行第二个设备测试,通过前面现象中的LOG,我们可以看到枚举出的tty设备节点 /dev/ttyRPMSG0 节点, 我们就通过该节点测试tty设备的功能输入如下命令

echo "hello M4 core , i'm A7!" > /dev/ttyRPMSG0

实验现象如下所示

上图为A7通过虚拟的tty终端设备,转发到M4内核的消息内容, 最终通过M4核固件的串口Log功能打印出来对应信息

自此,所有实验结束

原文地址:https://blog.csdn.net/liuxd3000/article/details/125858123

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_21568.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注