IPC,Inter-Processor Communication是SYS/BIOS处理核间通信的组件:
IPC的几种应用方式:
1.最小使用(Minimal use)
这种情况是通过核间的通知机制(notification)来实施的,而一个通知所携带的信息是非常小的(一般是32bits),所以称为最小使用。这种方式一般是用于处理核间的简单同步,却无法处理复杂的消息传递。
这种情况下,需要利用到Notify模块的APIs函数,比如通过Notify_sendEvent()函数给某个特定核传递一个事件,我们可以给特定事件动态注册反馈函数。由于一个通知(notification)所携带的信息是极少的,所以只能给处理器发送一个事件号,而这个事件号所代表的反馈函数决定之后的动作。另外一些数据以函数参数方式,也可以被送出。

2.增加数据通路(Add data passing)
这种情况是在前面的最小使用机制下,在核间增加了一个传递链表元素的数据通路,这个链表的实施一般是使用共享内容并通过门(gates)来管理同步。
3.增加动态分配(Add dynamic allocation)
这种情况下,增加了从堆中动态分配链表元素的功能。
这种情况在上种情况下,增加了一个Heap*MP模块,这个模块主要用于从堆中给链表动态分配内存。

4.强大但易用的消息机制(Powerful but easy-to-use messaging)
这种情况下利用MessageQ模块来传递消息。
除了Notify通知机制,还可以利用MessageQ来实现更为复杂的核间通信,在这种情况下,只需要配置MultiProc和SharedRegion模块就可以了,而Ipc_start()函数将自动为我们实现上面灰色模块的配置。

最小使用(Minimal use)情况举例
打开CCS自带例程


选中Group,点击运行:


结果分析

1.各核打印:

这段是在main()中出现的结果,每个核都会执行各自的main():
System_printf("main: MultiProc id = %d\n", MultiProc_self()); System_printf("main: MultiProc name = %s\n", MultiProc_getName(MultiProc_self()));
2.各核注册事件,并表明其反馈函数:
status = Notify_registerEvent(srcProc, INTERRUPT_LINE, EVENTID, (Notify_FnNotifyCbck)cbFxn, NULL);
核0执行同时释放信号量,在核0释放信号量semHandle之前,其他核都处理等待信号量释放中

核0通过给核1发送事件,触发反馈函数,在反馈函数中semHandle归一,注意这个激活的信号量是在核1中的
status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq, TRUE);
激活核1的信号量后,核0打印结果,并等待其信号量的结果,所有核的信号量都初始为0:
System_printf("tsk1_func: Sent request #%d to %s\n", seq, MultiProc_getName(dstProc));
/* wait forever on a semaphore, semaphore is posted in callback */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
以下是总共八个核,分别执行了NUMLOOPS次(这里设置的是10次)

下一个核信号被激活,开始执行:
/* wait forever on a semaphore, semaphore is posted in callback */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); System_printf("tsk1_func: Received request #%d from %s\n", seq, MultiProc_getName(recvProcId));
同时通过反馈函数将当前核的下一个核激活:
status = Notify_sendEvent(dstProc, INTERRUPT_LINE, EVENTID, seq, TRUE);
完成发送事件:
System_printf("tsk1_func: Sent request #%d to %s\n", seq, MultiProc_getName(dstProc));
退出任务循环,同时退出当前核的BIOS:

多核IPC的配置
3.设置同步的核数
4.核间的连接方法Ipc_attach()及Ipc_detach()
Ipc_attach(#coreID),#coreID表示需要连接的核ID号,如Ipc_attach(0)表示连接核0。
不过需要注意的是:
while(Ipc_attach(#coreID)<0) { Task_sleep(1); }
Ipc_detach()的使用方法同Ipc_attach()是类似的,不过它的功能是解除连接。
主从核之间的通信
2.修改源文件为:
#include <xdc/std.h>
/* -----------------------------------XDC.RUNTIME module Headers */ #include <xdc/runtime/System.h>
/* ----------------------------------- IPC module Headers */ #include <ti/ipc/MultiProc.h> #include <ti/ipc/Notify.h> #include <ti/ipc/Ipc.h>
/* ----------------------------------- BIOS6 module Headers */ #include <ti/sysbios/knl/Semaphore.h> #include <ti/sysbios/knl/Task.h> #include <ti/sysbios/BIOS.h>
/* ----------------------------------- To get globals from .cfg Header */ #include <xdc/cfg/global.h>
#define INTERRUPT_LINE 0
/* Notify event number that the app uses */
#define EVENTID 10
/* Number of times to run the loop */
#define NUMLOOPS 3 UInt32 times = 0; UInt16 recvnumes = 0; #define masterProc 0
#define sloverProc1 1
#define sloverProc2 2
#define sloverNum 2
/* * ======== cbFxn ======== * This function was registered with Notify. It is called when any event is * sent to this processor. */ Void cbFxn(UInt16 procId, UInt16 lineId, UInt32 eventId, UArg arg, UInt32 payload) { /* The payload is a sequence number. */
if(procId!=masterProc) // 主核注册函数
{ recvnumes++; // 接收从核的数目
if(recvnumes==sloverNum) // 当收到全部从核回复的信息
{ recvnumes=0; Semaphore_post(semHandle); } } else { times = payload; // 执行次数
Semaphore_post(semHandle); } } /* * ======== tsk0_func ======== * Sends an event to the next processor then pends on a semaphore. * The semaphore is posted by the callback function. */ Void tsk0_func(UArg arg0, UArg arg1) { Int i = 1; Int status; if (MultiProc_self() == masterProc) { while (i <= NUMLOOPS) { /* 这里可以添加主核需要执行的任务代码*/
/* Send an event to the next processor */ status = Notify_sendEvent(sloverProc1, INTERRUPT_LINE, EVENTID, i, TRUE); status = Notify_sendEvent(sloverProc2, INTERRUPT_LINE, EVENTID, i, TRUE); /* Continue until remote side is up */
if (status < 0) { continue; } System_printf("MasterCore Sent Event to SloverCores in %d\n", i); /* Wait to be released by the cbFxn posting the semaphore */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); // 主核等待所有从核完成其工作返回
System_printf("MasterCore Received Event from All SloverCores in %d\n",i); /* increment for next iteration */ i++; } } else { while (times < NUMLOOPS) { /* wait forever on a semaphore, semaphore is posted in callback */ Semaphore_pend(semHandle, BIOS_WAIT_FOREVER); // 等待主核通知开始执行任务
System_printf("SloverCore%d Received Event from MasterCore in %d\n", MultiProc_self(),times); /* 这里可以添加从核执行的任务*/
/* Send an event to the next processor */ status = Notify_sendEvent(masterProc, INTERRUPT_LINE, EVENTID, times, TRUE); if (status < 0) { System_abort("sendEvent to MasterCore failed\n"); } System_printf("SloverCore%d sent Event from MasterCore in %d\n", MultiProc_self(),times); } } System_printf("Test completed\n"); BIOS_exit(0); } /* * ======== main ======== * Synchronizes all processors (in Ipc_start), calls BIOS_start, and registers * for an incoming event */ Int main(Int argc, Char* argv[]) { Int status; status = Ipc_start(); if (status < 0) { System_abort("Ipc_start failed\n"); } /* 这里主要根据主核和从核的角色分别添加连接任务:主核同两个从核都有连接,而从核只与主核有链接 在添加核间连接后,分别给核间连接注册事件 */
if(MultiProc_self()==masterProc) { while(Ipc_attach(sloverProc1)){ Task_sleep(1); }// 完成从核1的连接
while(Ipc_attach(sloverProc2)){ Task_sleep(1); }// 完成从核2的连接
status = Notify_registerEvent(sloverProc1, INTERRUPT_LINE, EVENTID, (Notify_FnNotifyCbck)cbFxn, NULL); if (status < 0) { System_abort("Notify_registerEvent for sloverCore1 failed\n"); }// 完成从核1的事件注册
status = Notify_registerEvent(sloverProc2, INTERRUPT_LINE, EVENTID, (Notify_FnNotifyCbck)cbFxn, NULL); if (status < 0) { System_abort("Notify_registerEvent for sloverCore2 failed \n"); }// 完成从核2的事件注册
} else{ while(Ipc_attach(masterProc)) { Task_sleep(1); }// 完成主核0的连接
status = Notify_registerEvent(masterProc, INTERRUPT_LINE, EVENTID, (Notify_FnNotifyCbck)cbFxn, NULL); if (status < 0) { System_abort("Notify_registerEvent for masterCore0 failed\n"); }// 完成主核0的事件注册
} BIOS_start(); return (0); }
仿真调试的结果:

从结果上看,当从核分别收到了来自主核的事件时,同时开始任务,当从核任务全部完成后,主核才开始其任务。
