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串口打印
-
接口
+關注
關注
33文章
8500瀏覽量
150839 -
通信
+關注
關注
18文章
5972瀏覽量
135860 -
雙核
+關注
關注
0文章
37瀏覽量
15180
發布評論請先 登錄
相關推薦
評論