以openAMP echo_test demo进行channel扩展,将echo_test和proxy两个模式合并,从而实现可同时进行核间通信和文件读写
OpenAMP软件框架简介:
通常在AMP(非对称多处理)配置中,会采用在不同的处理核上运行不同的软件环境并执行各自的代码程序,各核之间通力合作实现处理器性能的提升。OpenAMP(开源的非对称多处理框架)软件框架为开发AMP系统提供了必要的API函数。
通过共享内存方式,两核可以访问同一块内存,通过中断协调同步。
OpenAMP 提供的demo有3个:
1,echo_test核间数据通信
2,proxy将openAMP提供接口重新封装成对文件操作的接口_open, _read, _write, _close可直接读写linux端的文件
3.矩阵计算,没详细了解
echo_test通信流程:
1.主机端调用remoteproc_init并启动远端
2.远端通过remoteproc_resource_init创建rpmsg,并通知主机RPMsg name
3.主机创建RPMsgchannel并回传给远端name确认消息
4.远端注册channel回调
以echo_test demo为例扩展为双通道,如何保证两端正确接收的:
linux:查询。两个channel对用两个字符设备。不停的读字符设备是否有数据
freeRtos:中断。中断处理中会调用注册的回调函数rpmsg_read_cb,回调函数是与通道绑定的,在回调函数中根据不同channel将数据写入不同的缓冲区,并记下标记,测试用例是用的全局变量,正式应用可改为信号量。
验证通过。
通信模式流程:
创建channel流程:
app(hproc)–>
hil_poll(proc->proc,0);–>
_poll(virtqueue_notification(vring->vq);–>
rpmsg_rx_callback[rdev->channel_created(rp_chnl);]–>
rpmsg_channel_created
获取消息流程:
app(hproc) -->
hil_poll(proc->proc,0); -->
_poll(virtqueue_notification(vring->vq);)–>
rpmsg_rx_callback 【rp_ept->cb(rp_chnl,
(void *)RPMSG_LOCATE_DATA(rp_hdr), rp_hdr->len, rp_ept->priv, rp_hdr->src);】–>
rpmsg_read_cb
proxy模式简介:
- 将openAMP提供接口重新封装成对文件操作的接口_open, _read, _write, _close。
- proxy模式remote串口输出定向到host
如何处理通信模式与读写文件模式同时运行问题
使用双通道模式一个channel来处理消息通信和一个chanel读写文件操作,达到可以同时进行核间通信,又可以CORE1读写core0 的nandflash的目的。消息通信以echo_test为模板进行开发,CORE1读写core0 的nandflash以proxy_app为模板进行扩展。
此方案存在的问题:
从上述的代码处理流程可以看出消息的处理都是软中断hil_poll触发,在rpmsg_rx_callback进行消息处理,而proxy模式则将hil_poll重定向到API中。这就出现了,两者都依赖于软中断hil_poll,所以中断信号来了,而不知道做何处理,到底是进行核间通信哪?还是文件读写哪?
解决方案:
方案1:
在改动尽量小的情况下,由于rpmsg_rx_callback 携带channel和endpoint信息,根据channel进行消息分发
验证结果:proxy模式下相应消息的poll会被通信模式劫持而当做通信消息,导致读写文件等操作无返回。
方案2:
中断扩展,将每个通道有自己独立的中断号。查看代码对中断的处理:中断与cpu shutdown boot有绑定关系,hil(hardware Interface layer)硬件接口层及对上层接口都需要修个,且修改量较大
方案3:中断信息根据channel进行1分2,将proxy重定向的接口重新实现,此方案验证通过。
附验证通过的代码:
static void rpmsg_read_cb(struct rpmsg_channel *rp_chnl, void *data, int len,
void *priv, unsigned long src)
{
(void)priv;
(void)src;
if(!strcmp(rp_chnl->name, RPMSG_CHAN_NAME))
{
memcpy(rpc_data->rpc_response, data, len);
atomic_flag_clear(&rpc_data->sync);
if (rpc_data->rpc_response->id == TERM_SYSCALL_ID) {
/* Application terminate signal is received from the proxy app,
* so let the application know of terminate message.
*/
rpc_data->shutdown_cb(rp_chnl);
}
xSemaphoreGive(xCountSemaphoreforfile);
}
else if(!strcmp(rp_chnl->name, RPMSG_CHAN_NAME2))
{
xIPC_Data.len = len;
memcpy(&(xIPC_Data.data[0]),data,len);
portBASE_TYPE val = xQueueSend( xIPC_Data_Queue, /* The queue being written to. */
(void *)(&xIPC_Data.len), /* The address of the data being sent. */
10UL ); /* The block time. */
if (!val) {
LPERROR("cannot save data\n");
} else {
xSemaphoreGive(xCountSemaphoreforIPC);
//LPRINTF("xCountSemaphoreforIPCGiveNum = %d\n\r",xCountSemaphoreforIPCGiveNum++);
}
}
else
LPRINTF("channel not match between linux and rtos\n");
}
static inline void rpmsg_retarget_wait(struct _rpc_data *rpc)
{
//struct hil_proc *proc = rpc->rpmsg_chnl->rdev->proc;
while (atomic_flag_test_and_set(&rpc->sync)) {
//hil_poll(proc, 0);
xSemaphoreTake( xCountSemaphoreforfile, portMAX_DELAY );
}
}