河北住房和城乡建设厅网站首页,个人建站网站,在线域名解析ip地址查询,西安网络推广优化培训文章目录 1、简介2、模块MultiProc静态设置#xff08;cfg设置#xff09;动态设置 IPCNotifyMessageQShareRegion 1、简介
IPC: Inter-Processor Communication 处理器间通信#xff0c;指提供多处理器环境中的处理器之间的通信、相同处理器不同线程间的通信。包括数据传递… 文章目录 1、简介2、模块MultiProc静态设置cfg设置动态设置 IPCNotifyMessageQShareRegion 1、简介
IPC: Inter-Processor Communication 处理器间通信指提供多处理器环境中的处理器之间的通信、相同处理器不同线程间的通信。包括数据传递、数据流和链表。
IPC可用于以下通信
在同一处理器上的其他线程在其他处理器上运行的SYS/BIOS线程GPP处理器上运行的SysLink的线程例如Linux
IPC传输分为两种
QMSS队列管理器发送任务和内核之间的数据SRIO IPC发送任务、内核和芯片之间的数据
2、模块
MultiProc
许多IPC模块需要在多处理器环境中识别处理器。MultiProc在一个模块中集中管理处理器id。因为这配置几乎是普遍要求,大多数IPC应用程序需要提供这个模块的配置。MultiProc可以在cfg文件中静态配置也可以在程序中动态配置一般都是用静态配置。 var MultiProc xdc.useModule(‘ti.sdo.utils.MultiProc’); 调用模块相当于是获取一个接口然后用接口进行配置
静态设置cfg设置
/*********在cfg文件中配置************************/
MultiProc.numProcessors 8; //设置系统的核数为8这里的值就是nameList数组的总长度MultiProc.setConfig(null, [CORE0, CORE1, CORE2, CORE3, CORE4, CORE5, CORE6, CORE7]); //设置各个核的名字其ID是根据其名字在setConfig第二个参数数组中的位置BaseID来确定的BaseID默认是0若位置为0则ID就是0其在nameList数组的位置就是0nameList数组和setConfig中的数组不是同一个/**************在一个系统中有两个DSP总共16个这个16个核之间要进行通信可以进行如下设置使得各个核的ID不一样************************/
/*For first C6678 device:*/var MultiProc xdc.useModule(ti.sdo.utils.MultiProc);MultiProc.baseIdOfCluster 0; //设置baseidMultiProc.numProcessors 16;//nameList总共有16个元素MultiProc.setConfig(null, [CORE0, CORE1, CORE2, CORE3,CORE4, CORE5, CORE6, CORE7]);
/***DSP0中的核name占据了nameList的0~7位*****/
/*For second C6678 device:*/var MultiProc xdc.useModule(ti.sdo.utils.MultiProc);MultiProc.baseIdOfCluster 8;//设置baseidMultiProc.numProcessors 16;MultiProc.setConfig(null, [CORE0, CORE1, CORE2, CORE3,CORE4, CORE5, CORE6, CORE7]);
/***DSP1中的核name占据了nameList的8~15位*****/动态设置
MultiProc_getNumProcessors();//获取MultiProc.numProcessors的值
MultiProc_self()//获取当前核的id
MultiProc_getName(id)//根据id获取核的name
MultiProc_getId(name)//根据name获取IDIPC
IPC的启动很简单只需要在函数中调用Ipc_start()就行。该函数只能被调用一次除非返回值是Ipc_E_NOTREADY。它表示ShareRegion 0 无效或者还没有建立所以Ipc_start可能需要再次调用一旦它成功启动后面调用的返回值是Ipc_S_ALREADYSETUP。
IPC的配置是在cfg文件中完成的
var Ipc xdc.useModule(ti.sdo.ipc.Ipc);
Ipc.procSync Ipc.ProcSync_ALL;Ipc.ProcSync_ALL 调用ipc_start还将在内部调用ipc_attach同步所有核应用程序不应该再调用Ipc_attach。如果在一个设备上的所有的IPC核都是同时启动的话可以选择这个同步方式。
Ipc.ProcSync_PAIR ipc_start不会调用ipc_attach,所有此时需要在代码中由应用程序调用ipc_attach
Ipc.ProcSync_NONE Ipc_start将与ProcSync_PAIR工作完全一样,但是ipc_attach不会同步远程的核
核的同步要按照ID号从小到大的顺序进行比如当前核必须先同步核0才能同步核1。两核之间的相互同步必须先满足ID号小的先同步ID号大的比如核2需要等到核1调用了Ipc_attach(2)之后才能调用Ipc_attach(1) 。
Notify
/*注册事件和回调函数进行绑定* param[in] procId 远端的核号* param[in] lineId Line id (大部分系统为0)* param[in] eventId 事件ID 最大31* param[in] fnNotifyCbck 回调函数* param[in] cbckArg 回调函数的参数 */
Int Notify_registerEvent(UInt16 procId, UInt16 lineId, UInt32 eventId,Notify_FnNotifyCbck fnNotifyCbck, UArg cbckArg);
/*发送事件* param[in] procId 目的的核号* param[in] lineId Line id* param[in] eventId 事件ID* param[in] payload 和事件一起发送的数据.是一个int型的数据* param[in] waitClear 如果为TRUE则当前发送的事件会等待上一个相同ID的事件被目标核处理掉如果为FALSE则被挂起的事件中与最近发送的事件的ID相同的事件会被覆盖掉。如果notify设备是通过FIFO传递事件的那么当FIFO满的时候如果为TRUE则会一直等待到FIFO有空间如果为FALSE则会返回Notify_E_FAIL*/
Int Notify_sendEvent(UInt16 procId, UInt16 lineId,UInt32 eventId, UInt32 payload,Bool waitClear);
/****回调函数的形式******************************************************/
Void myFxn2(UInt16 procId, UInt16 lineId, UInt32 eventNo, UArg arg, UInt32 payload)MessageQ
MessageQ同Notify模块一样也是用于多核之间的通信的不过不同的是Notify模块更加侧重于通知其只能传递一个参数而MessageQ却可以传递变长度的消息更侧重于传递消息另外不同线程间的消息是独立的例如对于每个MessageQ来说存在一个读者却可能有多个写者。
MessageQ模块的主要特点
1. 实现了处理期间变长消息的传递所需要传递的消息一般超过32bit
2. 其消息的传递都是通过操作消息队列来实现的
3. 每个消息队列可以有多个写者但只能有一个读者而每个任务(task)可以对多个消息队列进行读写
4. 一个宿主在准备接收消息时必须先创建消息队列而在发送消息前需要打开预定的接收消息队列 HeapBufMP固定大小的内存管理器其分配的所有缓冲区都是一样的当然也可以通过不同HeapBufMP实例来管理不同的大小的缓冲区。 HeapMultiBufMP每个HeapMultiBufMP支持8个不同大小的缓冲区。当一个分配需求被发送HeapMultiBufMP的实例从不同大小的待分配缓冲区中选择一个能满足要求的最小缓冲区。如果待分配缓冲区为空那么这个分配就失败了。 HeapMemMP这是个能分配变长大小的内存管理器。另外HeapMemMP管理共享内存区Shared memory的一个缓冲区。 在cfg文件中开启MessageQ
/****需要HeapBufMP模块来给消息分配空间***************************************/
var MessageQ xdc.useModule(ti.sdo.ipc.MessageQ);
var HeapBufMP xdc.useModule(ti.sdo.ipc.heaps.HeapBufMP);创建MessageQ对象
/***MessageQ不是共享内存只能有一个读者所以要每个核都去创建自己的MessageQ***/
MessageQ_Handle MessageQ_create(String name, const MessageQ_Params *params);消息创建好之后需要给消息分配堆空间。消息其实就是一个结构体。但是其结构体的第一个元素必须是 MessageQ_MsgHeader类型的。
创建一个堆对象
/*因为测试例程只需要发送一个消息就可以了所以HeapBufMP就只分配一个消息块*/
HeapBufMP_Params_init(heapBufParams);
heapBufParams.regionId 0;
heapBufParams.name HEAP_NAME;
heapBufParams.numBlocks 1; //分配的块数
heapBufParams.blockSize sizeof(Msg);//块的大小Msg是创建的消息结构体
heapHandle HeapBufMP_create(heapBufParams);创建好对象后需要给堆对象注册一个id后面给消息分配内存的时候就直接调用ID
/* param[in] heap 要注册id的堆对象*/
/* param[in] heapId 得到的堆ID*/
Int MessageQ_registerHeap(Ptr heap, UInt16 heapId);根据堆ID给堆分配空间
//返回一个msg这个msg就是用来传递消息的。
MessageQ_Msg MessageQ_alloc(UInt16 heapId, UInt32 size);分配完空间得到msg后就可以发送了
/*通过接收核创建消息时注册的名称来打开消息队列并返回消息队列的ID
根据消息队列ID将消息发送给消息队列*/
Int MessageQ_open(String name, MessageQ_QueueId *queueId); //打开队列
Int MessageQ_put(MessageQ_QueueId queueId, MessageQ_Msg msg);//发送消息queueId就是打开消息的时候得到的msg就是堆内存分配的时候返回的。消息接收
Int MessageQ_get(MessageQ_Handle handle, MessageQ_Msg *msg, UInt timeout);ShareRegion
SharedRegion模块是一个共享区域特别是对于多处理器环境下SharedRegion模块就是用于让一个内存区域能被不同处理器共享并操作。这个模块会给每个处理器上创建一个共享内存区域查找表这个查找表保证各个处理器能查看到系统内的所有共享区域。查找表中共享内存区域在所有查找表中的区域ID是一致的在运行时查找表可以通过共享区域ID及共享区域名称来快速查找共享区域
通过cfg配置共享区域
var SharedRegion xdc.useModule(ti.sdo.ipc.SharedRegion);
SharedRegion.numEntries 4; //共享区域的最大个数
SharedRegion.translate true; //是否需要进行地址转换/* Shared Memory base address and length */
var SHAREDMEM 0x88000000;
var SHAREDMEMSIZE 0x00300000;
SharedRegion.setEntryMeta(0,//共享区域的ID号{ base: SHAREDMEM, //共享区域的基地址len: SHAREDMEMSIZE, //共享区域大小ownerProcId: 0, //共享区域所有者的核IDisValid: true, //对于当前核该区域是否有效name: SR0, //区域的名称});1base区域的基地址不同处理器其基地址可以是不同的。
2len区域的长度同一个共享区域在所有处理器的查找表中的长度应该是相同的。
3ownerProcID管理该区域的处理器ID如果存在区域所有者这个区域所有者owner就是创造HeapMemMp实例的而其他核打开这个实例。
4isValid表明该区域在当前核上是否可用判断当前核能否使用此共享区域的。
5cacheLineSize这个值在所有核的查找表中都应该是相同的
6createHeap表明是否需要给当前区域创建一个堆。
7name区域的名称。共享内存的使用
heaphandle (IHeap_Handle)SharedRegion_getHeap(regionId); // 通过区域ID获得共享区域的堆句柄
buf Memory_alloc(heap, size, align, NULL); // 通过堆句柄分配区域内存地址转换
共享内存的地址在各个核上会被映射到不同的地址空间因此我们需要进行地址转换。
/*先将本地分配的共享内存得到一个本地地址转换通过SharedRegion_getSRPtr()将本地地址转换成共享内存地址然后通过MessageQ将共享内存地址发送到其他核。其他核通过SharedRegion_getPtr()来得到共享内存对应的本地地址然后就可以通过本地地址来访问共享内存的内容了*/
SharedRegion_getSRPtr() //根据给定的本地指针及区域ID来获得当前共享区域指针
SharedRegion_getPtr() //根据共享区域指针来获得本地指针能否使用此共享区域的。 5cacheLineSize这个值在所有核的查找表中都应该是相同的 6createHeap表明是否需要给当前区域创建一个堆。 7name区域的名称。 共享内存的使用c
heaphandle (IHeap_Handle)SharedRegion_getHeap(regionId); // 通过区域ID获得共享区域的堆句柄
buf Memory_alloc(heap, size, align, NULL); // 通过堆句柄分配区域内存地址转换
共享内存的地址在各个核上会被映射到不同的地址空间因此我们需要进行地址转换。
/*先将本地分配的共享内存得到一个本地地址转换通过SharedRegion_getSRPtr()将本地地址转换成共享内存地址然后通过MessageQ将共享内存地址发送到其他核。其他核通过SharedRegion_getPtr()来得到共享内存对应的本地地址然后就可以通过本地地址来访问共享内存的内容了*/
SharedRegion_getSRPtr() //根据给定的本地指针及区域ID来获得当前共享区域指针
SharedRegion_getPtr() //根据共享区域指针来获得本地指针