在线时间4 小时
UID3370303
注册时间2017-6-14
NXP金币63
该用户从未签到
高级会员

- 积分
- 695
- 最后登录
- 2019-12-4
|
作为一名接触arm一年的新人,不得不说从来没接触过双核,所以在学习这个事后也就遇到了很多简单却又根本的问题。所以我从原理开始求索,尝试慢慢理解双核的机制和通信方式。相信肯定有人会跟我一样第一次接触双核,希望我的学习过程能够帮到大家。
开发环境:IAR
首先在硬件上,肯定只有一个最初的启动地址,官网例程将m0和m4的代码分成两份,首先编译烧录m0,然后烧录m4,从m4处启动和关闭m0.
这是m4工程下的代码:
- #define CORE1_BOOT_ADDRESS (void *)0x20010000 //定义了前面烧录的m0代码的地址core1是m0,代表slave
- #if defined(__CC_ARM)
- extern uint32_t Image$CORE1_REGION$Base;
- extern uint32_t Image$CORE1_REGION$Length;
- #define CORE1_IMAGE_START &Image$CORE1_REGION$Base
- #elif defined(__ICCARM__)
- extern unsigned char core1_image_start[]; //声明了一个数组,用来存储m0,使得m0的代码加载进内存
- #define CORE1_IMAGE_START core1_image_start
- #endif
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- uint32_t get_core1_image_size(void); //得到m0程序的大小
- #endif
- void delay(void);
- /*******************************************************************************
- * Code
- ******************************************************************************/
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- uint32_t get_core1_image_size()
- {
- uint32_t core1_image_size; //通过地址计算出代码长度
- #if defined(__CC_ARM)
- core1_image_size = (uint32_t)&Image$CORE1_REGION$Length;
- #elif defined(__ICCARM__)
- #pragma section = "__sec_core"
- core1_image_size = (uint32_t)__section_end("__sec_core") - (uint32_t)&core1_image_start;
- #endif
- return core1_image_size;
- }
- #endif
复制代码 现在基本上已经看出,是将m0的代码烧进flash的固定位置,这个位置在iar的icf中有定义。然后以m4的代码为入口,在m4代码中将m0的代码从存储中加载进一个数组,从而进入内存得以启动。接下来是main里面的代码:
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- /* Calculate size of the image - not required on LPCExpresso. LPCExpresso copies image to RAM during startup
- * automatically */
- uint32_t core1_image_size;
- core1_image_size = get_core1_image_size(); //在此处得到了m0程序的大小
- PRINTF("Copy Secondary core image to address: 0x%x, size: %d\n", CORE1_BOOT_ADDRESS, core1_image_size);//官方例程的提示;
- /* Copy Secondary core application from FLASH to RAM. Primary core code is executed from FLASH, Secondary from RAM
- * for maximal effectivity.*/
- memcpy(CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size); //复制进数组。
- #endif
复制代码 上面的所有过程完成了将m0加载进内存,使其可执行成为可能。
- MCMGR_Init(); //多核心管理初始化,里面其实只是初始化了mailbox时钟,mailbox是双核间通信用的,关于其使用的协议细节我还在学习中。
- /* Boot Secondary core application */
- PRINTF("Starting Secondary core.\n");
- MCMGR_StartCore(kMCMGR_Core1, CORE1_BOOT_ADDRESS, 1, kMCMGR_Start_Synchronous); //把数组的地址传入,启动m0内核!!
复制代码 关于上面的最后一行代码,对核心进行启动,第一个参数kMCMGR_Core1是一个enum的代码编号,1是m0,0是m4,第二个参数是数组地址,第三个参数其实是在启动m0内核时传给m0的数据,m0可以接受到这个数据并进行一系列的操作。最后一个参数指定了核心的工作状态,同步还是异步,因为以前没有接触过,所以对这个不太了解,通过检索大概内容就是,同步是多个核心以相同频率同时运行,异步是可以以不同的频率运行然后轮换运行,我所说的不一定对,这个地方我觉得原理应该很有趣。说的不对要是有人指正就很棒了!
m4的代码先看到这,接下来看一下m0的代码:
可以看到main函数之前并没有像m4一样做额外处理
- int main(void)
- {
- uint32_t startupData, i; //该变量用来接收上面传进来的那个1
- /* Define the init structure for the output LED pin*/
- gpio_pin_config_t led_config = {
- kGPIO_DigitalOutput, 0,
- };
- /* Initialize MCMGR before calling its API */
- MCMGR_Init(); //同样要初始化mailbox时钟
-
- /* Get the startup data */
- MCMGR_GetStartupData(kMCMGR_Core1, &startupData); //这就是得到启动时传入进来的数据,原理是什么?是他们共享的那部分数据,后面说
- /* Make a noticable delay after the reset */
- /* Use startup parameter from the master core... */
- for (i = 0; i < startupData; i++)
- delay();
- /* Init board hardware.*/
- /* enable clock for GPIO */
- CLOCK_EnableClock(kCLOCK_Gpio0);
- CLOCK_EnableClock(kCLOCK_Gpio1);
- BOARD_InitPins_Core1();
- /* Configure LED */
- LED_INIT();
- /* Signal the other core we are ready */
- MCMGR_SignalReady(kMCMGR_Core1); //更新准备信号
- while (1)
- {
- delay();
- LED_TOGGLE();
- }
- }
复制代码 关于共享的数据:
lpc54114_cm4的头文件里有些内容,具体踪迹我还在找,因为我也是在摸索嘛,且摸且写。到最后无非是两个工程定位到同一个地址。
把这个工程看完吧,回到m4:
定义了按键和关闭启动内核==。
整个工程就这样结束了,MCMGR相关的所有函数其实到最后都指向mailbox,接下来就摸索一下mailbox!
任务二未完待续。分析代码来学习是我的习惯,若能帮像我一样的初学者稍微理清一下思路,那再好不过。
|
|