在线时间185 小时
UID3375312
注册时间2017-6-28
NXP金币6
TA的每日心情 | 开心 2020-12-17 09:04 |
---|
签到天数: 346 天 [LV.8]以坛为家I
金牌会员
- 积分
- 1361
- 最后登录
- 2024-1-15
|
本帖最后由 一代睡神的崛起 于 2020-10-18 21:21 编辑
上一章只给大家讲了一下基于M33的LPC55S69的Core0核一些串口、IIC、SPI通信,大家是不是觉得意犹未尽。没办法被日天兄逼着来更帖子了,这次给大家带来的是基于FreeRTOS的rpmsg双核交互的一个交互评测,希望大家喜欢。
双核通信相比大家都是比较熟悉的了,用得最多的莫过于mailbox了,这得源于其稳定的操作机制。操作系统呢,市场上形形色色的,国内比较著名的就应当属FreeRTOS、UCOS、RT-Thead了。笔者用FreeRTOS比较多,逐飞也出了RT-Thead的开源库,后面笔者也会带着大家一起来移植,这次就先玩着FreeRTOS吧。
一、官网下载FreeRTOS内核源码
首先进入FreeRTOS官网下载源码,因为FreeRTOS是开源的,所以体验也是非常nice的。奉上下载地址:FreeRTOT下载地址。目前最新的FreeRTOS是10.4.1版本,笔者使用的是去年下载的10.2.1版本,不过也是支持NXP的M33架构的。把相应源码加入到程序当中,程序需要以下图中几个文件。
1
把源文件添加上去再把需要的头文件路径包含上去,就把FreeRTOS引入到系统了。这里选择heap4这个堆是为了更好的将过多的碎片内存利用重组,对于一些RAM小的soc这个堆能起到很大的作用。其次就是配置属于自己的FreeRTOS性能属性,这时将视角转到FreeRTOSConfig.h文件中,用户需要配置图中参数。
2
3
4
看到配置到这里你的FreeRTOS就可以差不多可以起飞了。
二、官网下载RPMSG内核源码
小编使用的rpmsg源码是在官方的demo下移植过来的,大家也可以去其官网下载,没下过在此不做过多叙述。同样的需要哪些源码,本次也已图片框选出来:
5
同样的将所需的头文件包含在软件路径中即可。这时候大家有疑问了,双核之间通信不都是依赖邮箱机制么?对的rpmsg也不例外,小编对rpmsg的理解就是基于mailbox做了很多安全机制上的扩展,功能更加完美了。接下来带大家去碰一碰这个邮箱机制。先来看源码:
- void Rpmsg_Config(void)
- {
- #ifdef MCMGR_USED
- volatile uint16_t RPMsgRemoteReadyEventData = 0;
- #endif
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- /* Calculate size of the image */
- uint32_t core1_image_size;
- core1_image_size = get_core1_image_size();
- /* Copy application from FLASH to RAM */
- memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size);
- #endif
- #ifdef MCMGR_USED
- /* Initialize MCMGR before calling its API */
- MCMGR_Init();
- /* Register the application event before starting the secondary core */
- MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, RPMsgRemoteReadyEventHandler,
- (void *)&RPMsgRemoteReadyEventData);
- /* Boot Secondary core application */
- MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, (uint32_t)rpmsg_lite_base, kMCMGR_Start_Synchronous);
- /* Wait until the secondary core application signals the rpmsg remote has been initialized and is ready to
- * communicate. */
- while (APP_RPMSG_READY_EVENT_DATA != RPMsgRemoteReadyEventData)
- {
- };
- my_rpmsg = rpmsg_lite_master_init(rpmsg_lite_base, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
- #else
- my_rpmsg =
- rpmsg_lite_master_init((void *)RPMSG_LITE_SHMEM_BASE, SH_MEM_TOTAL_SIZE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
- #endif
- my_queue = rpmsg_queue_create(my_rpmsg);
- my_ept = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_queue);
- ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, (void *)&remote_addr);
- /* Wait until the secondary core application issues the nameservice isr and the remote endpoint address is known. */
- while (0 == remote_addr)
- {
- };
- }
- void Rpmsg_send_message(char *data,unsigned long size)
- {
- rpmsg_lite_send(my_rpmsg, my_ept, remote_addr, data, size, RL_BLOCK);
- }
- void Rpmsg_receive_message(char *data,int maxlen)
- {
- rpmsg_queue_recv(my_rpmsg, my_queue, (unsigned long *)&remote_addr, data, maxlen, NULL,RL_BLOCK);
- }
复制代码 s是不是觉得非常似曾相识,他的工作机理是首先建立一个邮箱机制,联系两个核的交互。再次建立数据堆栈,将数据准备好当队列做到发送的准备的时候就将数据传输到邮箱通道上,然后一个扭转就转到另一个地址上了,另一个核的地址上同样建立一个邮箱接收站,当接收队列来临的时候就取出数据,就实现了核与核之间的信息传输。是不是非常的简单呢?我们再来看Core1核上的函数:- void Rpmsg_Config(void)
- {
- #ifdef MCMGR_USED
- uint32_t startupData;
- mcmgr_status_t status;
- /* Get the startup data */
- do
- {
- status = MCMGR_GetStartupData(&startupData);
- } while (status != kStatus_MCMGR_Success);
- my_rpmsg = rpmsg_lite_remote_init((void *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
- /* Signal the other core we are ready by triggering the event and passing the APP_RPMSG_READY_EVENT_DATA */
- MCMGR_TriggerEvent(kMCMGR_RemoteApplicationEvent, APP_RPMSG_READY_EVENT_DATA);
- #else
- PRINTF("RPMSG Share Base Addr is 0x%x\r\n", RPMSG_LITE_SHMEM_BASE);
- my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
- #endif /* MCMGR_USED */
- while (!rpmsg_lite_is_link_up(my_rpmsg))
- ;
- my_queue = rpmsg_queue_create(my_rpmsg);
- my_ept = rpmsg_lite_create_ept(my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_queue);
- ns_handle = rpmsg_ns_bind(my_rpmsg, app_nameservice_isr_cb, NULL);
- platform_time_delay(1000);
- rpmsg_ns_announce(my_rpmsg, my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, RL_NS_CREATE);
- #ifdef RPMSG_LITE_MASTER_IS_LINUX
- /* Wait Hello handshake message from Remote Core. */
- rpmsg_queue_recv(my_rpmsg, my_queue, (unsigned long *)&remote_addr, helloMsg, sizeof(helloMsg), NULL, RL_BLOCK);
- #endif /* RPMSG_LITE_MASTER_IS_LINUX */
- }
- void Rpmsg_send_message(char *data,unsigned long size)
- {
- rpmsg_lite_send(my_rpmsg, my_ept, remote_addr, data, size, RL_BLOCK);
- }
- void Rpmsg_receive_message(char *data,int maxlen)
- {
- rpmsg_queue_recv(my_rpmsg, my_queue, (unsigned long *)&remote_addr, data, maxlen, NULL,RL_BLOCK);
- }
复制代码 和发送比较起来差不多,稍微的简单一点,将数据取出来使用进行比对,控制外设进行动作。
6
这个是之前LPC55S69大赛作品程序,由于现在外设被我拆了,所以没有实物给大家演示了,不过这都是作者一一验证过的。通信机制就到这里给大家介绍完了,大家有兴趣可以去官网看看文档更能够帮助大家得心应手的进行移植。
三、彩蛋预设环节,大家互动
下一章节大家是想继续移植RT-Thead还是用Lwip给大家来点猛料(细心的童鞋已近发现了,笔者TCP/IP源码也加入工程了)。目前日天逼我下一章节做cat1、NB-Iot、WIFI模组的联网、连云计划,如果大家有什么兴趣的,可以联系日天胸(NXP管管)或者下方留言,我会根据反馈的力度给大家带来评测。在此谢谢大家花时间看完了。
|
|