AWorksLP 對外設(shè)進行了高度抽象化,為同一類外設(shè)提供了相同的接口,應(yīng)用程序可以輕松跨平臺。本文以MR6750?平臺為例,介紹AWorksLP ?雙核通信的基本用法。
?簡介
通信信箱MBX 有2 套寄存器訪問接口,接口A 和接口B。A 和B 接口都具有一套TX FIFO 寄存器、RX FIFO
寄存器、控制寄存器和狀態(tài)寄存器。用戶從A 接口的發(fā)送端TX 發(fā)送的數(shù)據(jù),可以在B 接口的接收端RX 接收 到。同理,A 接口的接收端RX 可以接收到B 接口發(fā)送端TX 發(fā)送的數(shù)據(jù)。
雙核燒錄的用法請參考《AWorksLP樣例詳解(MR6750)——雙核燒錄》
雙核調(diào)試的用法請參考《AWorksLP樣例詳解(MR6750)——雙核調(diào)試》
? 雙核通信
1. MBX信箱
{SDK}demosmulti-coreopenamp路徑下為openamp的例程。雙核通信需要使用信箱在gui上勾選對應(yīng)的信箱接口,hart0和hart1需勾選同一個信箱的兩個不同接口。例如hart0勾選了mbx0a、則hart1需勾選mbx0b。
圖1 mbx設(shè)備
2.?OpenAMP
OpenMP是由OpenMP Architecture Review Board牽頭提出的,并已被廣泛接受,用于共享內(nèi)存并行系統(tǒng)的多處理器程序設(shè)計的一套指導(dǎo)性編譯處理方案。
3.?例程
#if CONFIG_AW_OPENAMP_MASTER
aw_local int rx_callback (struct rpmsg_endpoint *ept, void *data,
? ? ? ? ? ? ? ?size_t len, uint32_t src, void *priv)
{
? ?aw_kprintf("[Master receive]: %sn", data);
? ?return 0;
}
#else
aw_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]: %sn", 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;
}
/* 處理其它設(shè)備發(fā)送過來的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是發(fā)送, 從機反之
? ? ? ? */
#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]: %sn", 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);
? ?}
}
由于篇幅原因本文僅截取部分關(guān)鍵代碼。
-
- 在rpmsg_demo中使用aw_open打開信箱、使用aw_openamp_init并注冊__mail_box_notify函數(shù);在__mail_box_notify函數(shù)中發(fā)送相應(yīng)的標記、使用aw_openamp_remoteproc_init函數(shù)注冊__aworks_rproc_ops,參數(shù)中是各運行階段的函數(shù)接口;使用aw_openamp_create_ept函數(shù)注冊rx_callback接收回調(diào)函數(shù),當作為主核時打印從核發(fā)送的數(shù)據(jù),當作為從核時將收到的數(shù)據(jù)發(fā)送回去;使用aw_openamp_ep_poll_task_start函數(shù)創(chuàng)建一個任務(wù),任務(wù)的函數(shù)入口為__openamp_task,在__openamp_task函數(shù)中根據(jù)讀到的標記做相應(yīng)的處理。
使用aw_openamp_wait_ept_ready函數(shù)等待從機準備好。
在while循環(huán)中主核使用aw_openamp_send函數(shù)循環(huán)的發(fā)送數(shù)據(jù)、從核在rx_callback回調(diào)函數(shù)中將主核發(fā)送的數(shù)據(jù)發(fā)送回去、串口打印如下圖。
圖2?串口打印