AWorksLP 样例详解(MR6750)——双核通信

描述

AWorksLP 对外设进行了高度抽象化,为同一类外设提供了相同的接口,应用程序可以轻松跨平台。本文以MR6750 平台为例,介绍AWorksLP  双核通信的基本用法。

 

接口  简介

 

通信信箱MBX 有2 套寄存器访问接口,接口A 和接口B。A 和B 接口都具有一套TX FIFO 寄存器、RX FIFO

寄存器、控制寄存器和状态寄存器。用户从A 接口的发送端TX 发送的数据,可以在B 接口的接收端RX 接收到。同理,A 接口的接收端RX 可以接收到B 接口发送端TX 发送的数据。

双核烧录的用法请参考《AWorksLP样例详解(MR6750)——双核烧录》

双核调试的用法请参考《AWorksLP样例详解(MR6750)——双核调试》


接口  双核通信

1. MBX信箱

{SDK}\demos\multi-core\openamp路径下为openamp的例程。双核通信需要使用信箱在gui上勾选对应的信箱接口,hart0和hart1需勾选同一个信箱的两个不同接口。例如hart0勾选了mbx0a、则hart1需勾选mbx0b。

接口

图1 mbx设备

2. OpenAMP

OpenMP是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受,用于共享内存并行系统的多处理器程序设计的一套指导性编译处理方案。

3. 例程

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

#if CONFIG_AW_OPENAMP_MASTERaw_local int rx_callback (struct rpmsg_endpoint *ept, void *data,                size_t len, uint32_t src, void *priv){    aw_kprintf("[Master receive]: %s\n", data);    return 0;}#elseaw_local int rx_callback (struct rpmsg_endpoint *ept, void *data,                size_t len, uint32_t src, void *priv){    char sendbuf[512];
   aw_kprintf("[Slave receive]: %s\n", data);    aw_snprintf(sendbuf, sizeof(sendbuf), "%s ACK", data);    if (rpmsg_send(&__resmgr_ept, sendbuf, strlen(sendbuf) + 1) < 0) {        aw_kprintf("[Slave send]: error!\n");    }    return 0;}#endif

aw_local int __mail_box_notify(void *priv, uint32_t id){    uint32_t tmp;
#if CONFIG_AW_OPENAMP_MASTER    /* master to remote */    if (id == VRING1_ID) {        /* send msg */        tmp = EPT_SEND_MSG_FLAG;    } else { /* remote to master */        /* send ack */        tmp = EPT_SEND_ACK_FLAG;    }#else    if (id == VRING1_ID) {        /* send ack */        tmp = EPT_SEND_ACK_FLAG;    } else {        /* send msg */        tmp = EPT_SEND_MSG_FLAG;    }#endif
   aw_write(__g_mbx_fd, &tmp, 4);    return 0;}

/* 处理其它设备发送过来的MBX */aw_local void __openamp_task(void *p_arg){
   struct rpmsg_virtio_device *p_dev = (struct rpmsg_virtio_device *)p_arg;
   aw_kprintf("Entry OpenAMP task!\n");
   while(1) {        uint32_t tmp;
       aw_read(__g_mbx_fd, &tmp, 4);
       /*         * 默认Master VRING0是接收, VRING1是发送, 从机反之         */#if CONFIG_AW_OPENAMP_MASTER        if (tmp == EPT_SEND_MSG_FLAG) {
           /* 接收到来自从机的消息 */            rproc_virtio_notified(p_dev->vdev, VRING0_ID);        } else {
           /* 接收到来自从机的ACK */            rproc_virtio_notified(p_dev->vdev, VRING1_ID);        }#else
       if (tmp == EPT_SEND_MSG_FLAG) {            rproc_virtio_notified(p_dev->vdev, VRING1_ID);        } else {            rproc_virtio_notified(p_dev->vdev, VRING0_ID);        }#endif    }}
void rpmsg_demo(){    int ret = 0;#if CONFIG_AW_OPENAMP_MASTER    int i = 0;    int RPMsgRole = 0;#else    int RPMsgRole = 1;#endif
   __g_mbx_fd = aw_open(CONFIG_MBX_CHOOSE, AW_O_RDWR, 0);
   ret = aw_openamp_init(&rpmsg_dev, RPMsgRole, NULL, __mail_box_notify);
#if CONFIG_AW_OPENAMP_MASTER    /* 启动固件 */    ret = aw_openamp_remoteproc_init(&__aworks_rproc_ops);    if (ret) {        aw_kprintf("Start processor fail!\n");    }#endif
   if (ret) {        aw_kprintf("OpenAMP init error!\n");        while(1);    }
   aw_openamp_create_ept(&rpmsg_dev,                          &__resmgr_ept,                           "rpmsg-client-sample",                           0xFFFFFFFF,                           rx_callback, NULL);
   aw_openamp_ep_poll_task_start(&rpmsg_dev);    aw_openamp_wait_ept_ready(&__resmgr_ept);
   while(1) {
#if CONFIG_AW_OPENAMP_MASTER        char sendbuf[512];        aw_snprintf(sendbuf, sizeof(sendbuf), "AWorks %d", i);        aw_kprintf("[Master send]: %s\n", sendbuf);        if (aw_openamp_send(&__resmgr_ept, sendbuf, strlen(sendbuf) + 1) < 0) {            aw_kprintf("[Master send]: error!\n");        }        i++;#else        aw_kprintf("Salve is alive!\n");#endif        aw_mdelay(100);    }}

由于篇幅原因本文仅截取部分关键代码。

  • 在rpmsg_demo中使用aw_open打开信箱、使用aw_openamp_init并注册__mail_box_notify函数;
  • 在__mail_box_notify函数中发送相应的标记、使用aw_openamp_remoteproc_init函数注册__aworks_rproc_ops,参数中是各运行阶段的函数接口;
  • 使用aw_openamp_create_ept函数注册rx_callback接收回调函数,当作为主核时打印从核发送的数据,当作为从核时将收到的数据发送回去;
  • 使用aw_openamp_ep_poll_task_start函数创建一个任务,任务的函数入口为__openamp_task,在__openamp_task函数中根据读到的标记做相应的处理。

使用aw_openamp_wait_ept_ready函数等待从机准备好。

在while循环中主核使用aw_openamp_send函数循环的发送数据、从核在rx_callback回调函数中将主核发送的数据发送回去、串口打印如下图。接口

图2 串口打印

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分