小猫爪:AWR294x学习笔记02-AWR294x之DPM,IPC和Mailbox
1 前言
这一章稍来微介绍一下AWR294x的核间通信,即DPM,IPC以及Mailbox。
2 结构关系
首先得搞清楚DPM,IPC和Mailbox三者关系,如下图:
其中Mailbox很好理解,它其实就是一个专门实现核间通信的硬件外设;而IPC也很容易理解,它其实就是Mailbox的驱动软件;至于DPM它则是基于IPC搭建的一个可执行的软件架构,基于DPM则可以很轻松的实现核间通信管理。
3 MailBox简介
MailBox是AWR294x的一个硬件外设,它的原理也是非常的简单,其结构如下图:
通信原理为:每两个核之间都有两块专属RAM,其实一块用来核A读,核B写,而另外一块则是核A写,核B读,因为AWR294x里面有三个独立运行的核,所以这样的RAM共有6块。如果一个核需要给另外一个核发送信息的时候,那么发送核只需要在两个核的专属RAM中事先准备好需要传输的数据,然后再主动发送一个可以触发接收核RECEIVER中断的信号告知接收核有新数据需要读取,接收核读取完RAM中的数据后,则发送一个可以触发发送核Acknowledgment中断的信号告知发送核消息已读取,至此一次完整的核间通信完成。
4 IPC简介
IPC其实就是MailBox的底层驱动,,打开mmWave的SDK包,可以发现IPC分为了ipc_notify和ipc_rpmsg,其中ipc_notify实现了发送信号量,而ipc_rpmsg则是在ipc_notify的基础上实现了发送数据包。
在这里就不多说什么了,感兴趣的小伙伴可以去翻看一下源码了解一下。
5 DPM详解
DPM(Data Path Manager)是一个完整的软件架构,或者说是一个软件服务,只需要将其移植进软件中,就可以在这个软件架构上实现我们想要的功能,接下来看看它的架构是怎样的。
5.1 三种工作模式
首先DPM规定了其工作的三种模式,分别是Local Domian,Remote Domain,Distributed Domain,这三种的区别在于其在DPM架构中为控制端还是执行端。每个核可以给本身发送命令,也可以给其他核发送命令,当然也可以接收命令并执行,可以向另一个核发送命令的一端称为控制端,而接收另外一个核的命令并执行的一端被称为执行端。
5.1.1 Local Domain
这种模式下,只有一个核具有DPM服务,如下所示:
如上图,DPM工作在Local Domain模式下,MSS端本身不仅作为控制端,也作为执行端,MSS端只能给自己发送命令,并且自己解析命令并执行。在这个模式下,并没有第二个核来参与。
5.1.2 Remote Domain
这种模式下,需要两个核来运行DPM服务,举个例子如下:
如上图,DPM工作在Remote Domain模式下,MSS端作为控制端,而DSS端作为执行端,此时MSS端可以给DSS发送命令,而DSS作为执行端,接收MSS的命令并执行。
5.1.3 Distributed Domain
这种模式下,需要两个核来运行DPM服务,举个例子如下:
如上图,DPM工作在Distributed Domain模式下,MSS端作为控制端的同时也作为执行端,而DSS端也是同样如此,两者互相发送和接收MSS的命令并执行。
5.2 DPM流程的实现
那DPM建立了一个什么样的软件机制来实现核间通信的呢?
DPM服务本身具有一个操作解释器,不管是控制端还是执行端,为了完成一次行为都需要发起或者接收一个或者多个操作,然后去执行,比如说有初始化操作,开始服务操作以及停止服务操作等。为此DPM定义了一个操作队列,DPM在运行时会根据目的需求往这个操作队列里面插入操作元素从而来发起操作,然后DPM就会从队列中读取操作并执行。DPM中定义了如下操作类型:
操作类型 | 描述 | 操作端 |
---|---|---|
DPM_MessageId_START | 启动DPM服务 | 控制端和执行端分别发起和执行 |
DPM_MessageId_STOP | 停止DPM服务 | 控制端和执行端分别发起和执行 |
DPM_MessageId_DPC_CFG | DPC配置,可自定义子类型,通常用其从控制端向执行端传输信息 | 控制端发起,执行端执行 |
DPM_MessageId_BSS_FAULT | CPU/ESM错误报告 | 控制端发起,执行端执行 |
DPM_MessageId_DPC_ASSERT | ASSERT报告 | 控制端和执行端分别发起和执行 |
DPM_MessageId_RESULT | 结果反馈,执行端执行操作后向控制端反馈执行结果 | 执行端发起和控制端执行 |
DPM_MessageId_DPC_INFO | 输出DPC信息 | 控制端和执行端分别发起和执行 |
DPM_MessageId_RESPONSE | 操作响应,控制端和执行端执行操作后的响应 | 控制端和执行端分别发起和执行 |
如果想要实现一个行为的话就需要单个或者多个操作相互组合才能实现,这样说可能比较抽象,接下来举个非常通用的例子就是,如果想实现从MSS端给DSS端发送命令或者数据的功能,那么在DPM中是怎样的一个过程呢?首先需要使用DPC配置操作来传输数据或者命令,流程如下图:
5.3 DPM的函数
DPM可供外部调用的函数如下:
名称 | 描述 |
---|---|
DPM_execute | 操作解释器,从操作队列中获取操作并执行,需周期性调用,操作队列为空时,其内的信号量堵塞 |
DPM_ioctl | 发起操作,包括DPC_CFG,DPC_CFG,BSS_FAULT,DPC_INFO,按需调用 |
DPM_start | 启动DPM服务,start-up时调用一次 |
DPM_sendResult | 用于执行端向控制端发送执行结果 |
DPM_relayResult | 用于执行端向控制端发送执行结果,只能在Distributed Domain模式中使用 |
DPM_stop | 停止DPM服务 |
DPM_notifyExecute | post信号量,让DPM_execute执行一次,其实是执行执行端的executeFxn |
DPM_synch | 完成DPM同步,start-up时在DPM_init后调用一次 |
DPM_init | 初始化DPM,start-up时调用一次 |
DPM_deinit | 复位DPM相关配置 |
所以结合DPM的函数,以非Local Domain模式为例,DPM运行Flow如下:
5.4 DPM的应用
经过上面的介绍,已经对DPM的软件架构已经有了一定的理解,接下就是怎样在DPM的软件架构中实现我们的应用。首先列举出TI的DPM的例子中对DPM初始化时的代码如下:
/*****************************************************************************
* DPM Instance1:
* - The DPM Instance is responsible for executing the LL & ML Profiles on the
* MSS and DSS so this is a multiple domain instance.
*****************************************************************************/
memset ((void *)&dpmInitCfg, 0, sizeof(DPM_InitCfg));
/* Initialize the LL Processing Init Argument: */
initArg = LL_INIT_ARGUMENT;
/* Setup the configuration: */
dpmInitCfg.arg = (void *)&initArg;
dpmInitCfg.argSize = sizeof(initArg);
dpmInitCfg.ptrProcChainCfg = &gLLProfileCfg;
dpmInitCfg.instanceId = LL_DPM_INSTANCE_ID;
dpmInitCfg.domain = DPM_Domain_DISTRIBUTED;
dpmInitCfg.reportFxn = DPMTest_llReportFxn;
/* Initialize the DPM Module: */
gDPMTestMCB.llDPMHandle = DPM_init (&dpmInitCfg, &errCode);
if (gDPMTestMCB.llDPMHandle == NULL)
{
test_print ("Error: Unable to initialize the DPM Module [Error: %d]\n", errCode);
MCPI_setFeatureTestResult ("DPM Distributed Domain Initialization", MCPI_TestResult_FAIL);
return;
}
对于DPM初始化结构体中的元素如下:
项目 | Value |
---|---|
domain | 指定DPM的工作模式,Local,Remoted,Distributed |
instanceId | ID,用来区分不同的DPM服务 |
arg | 初始化处理链的参数 |
argSize | 处理链初始化结构体大小 |
ptrProcChainCfg | 处理链配置指针 |
reportFxn | DPM事件callback函数 |
在上面的表格中出现了一个名词叫做处理链(processing chain),这个东西其实就是执行端基于DPM架构建立的执行应用,是执行端对执行行为的具象化,当控制端发出控制命令后,执行端就需要使用处理链对控制端的命令进行执行。
对于一个完整的DPM应用来说,有两个元素的具象化至关重要,分别是ptrProcChainCfg和reportFxn,其中reportFxn相关于DPM的回调函数,当DPM执行完一个操作后都会使用该回调函数报告,对照着源码这个还是很好理解的。
而另外一个则是ptrProcChainCfg元素,它是一个完整处理链的具象化,处理链是执行端特有的,只有当前核在DPM的角色为执行端,那么才需要具象化这个元素。那么一个完整的处理链需要实现哪些函数呢?查看ptrProcChainCfg的定义如下:
类型 | 名称 | 描述 |
---|---|---|
DPM_ProcChainInitFx | initFxn | 初始化处理链相关配置,在DPM_init中被调用 |
DPM_ProcChainStartFxn | startFxn | 开始处理链,在DPM_start发起启动DPM服务操作后被调用 |
DPM_ProcChainExecuteFxn | executeFxn | 处理链执行函数, 执行端调用DPM_notifyExecute后在DPM_execute中被调用,并返回处理结果 |
DPM_ProcChainIoctlFxn | ioctlFxn | 当控制端发出DPM_ioctl后触发DPC_CFG操作后,执行端接收DPC_CFG操作命令被调用 |
DPM_ProcChainStopFxn | stopFxn | 停止处理链,DPM_stop发起停止DPM服务操作后被调用 |
DPM_ProcChainDeinitFxn | deinitFxn | 复位处理链配置,在DPM_deinit中被调用 |
DPM_ProcChainInjectDataFxn | injectDataFxn | 注入数据操作执行函数,在DPM_ioctl触发DPM_CMD_INJECT_DATA类型命令时被调用 |
DPM_ProcChainChirpAvailableCallbackFxn | chirpAvailableFxn | chirp event 回调函数,在DPM_chirpISR中断中被调用 |
DPM_ProcChainFrameStartCallbackFxn | frameStartFxn | frame event 回调函数,在DPM_frameStartISR中断中被调用 |
以上所有处理链的函数并不是完全都是需要的,有些函数是专门针对雷达ADC事件的,如果你只想通过DPM实现简单的核间通讯,只需要完成其中几个函数即可,这些可参考mmWave SDK中的DPM的样例函数,位置处于C:\ti\mmwave_mcuplus_sdk_04_02_00_03\mmwave_mcuplus_sdk_04_02_00_03\ti\control\dpm\test。