在线时间372 小时
UID3135871
注册时间2016-10-9
NXP金币20
TA的每日心情 | 怒 2024-2-5 12:06 |
---|
签到天数: 627 天 [LV.9]以坛为家II
版主
- 积分
- 4429
- 最后登录
- 2024-2-5
|
LPC55S69这款MCU除了用的M33的内核,还有个最大的特点就是双核:Core0和core1。两者的区别就是core1不能运用MPU(内存保护单元),FPU(浮点运算单元),DSP,ETM(嵌入式追踪宏单元)和TrustZone这几个几乎都是跟数据相关的部分,而core0可以使用。其他的外设两者通用。这就注定了core0更倾向于做算法,而core1更倾向于控制外设。
那他们之间如何通讯呢?我们不妨想一下:如果我在MCU里面定义一块RAM,RAM空间分为2块,一块是存储给core0信息的,一块是存储给core0信息的,两个核均可以访问这块RAM。这样当core0想给core1发送消息是,就往定义的RAM core1处写下,当core1读到这个位置的信息是就能知道core0发的信息了,反之亦然。就这样两个核就愉快的通讯了。这样想法其实就是NXP双核通讯的最初原型。
当然LPC55S69 core0和core1z之间通讯,没我们这么简单,但大概思路还是这个。它定义了一个叫mailbox的寄存器:
每个核都拥有中断标志,设置中断寄存器数值,清除中断寄存器数值这3个含义的地址。
这样我们双核的通讯流程就清晰了:
CORE0-->CORE1方向:
CORE0往core1对应的设置中断寄存器里面写入对应的数值,并且把core1对应的中断标志置1。
Core1接收到中断,然后读取core1对应的设置中断寄存器里面数值,并保存下来或者做成相应,然后通过清除中断寄存器清除数据。
反之亦然。
当然具体寄存器里面读到的数据代表什么事件或者含义,就要自己定义了。
废话不多说,我们测试下官方的双核通讯例程:
思路很简单,就是core0往core1里面写数据,core1接收数据后加1,再发给core0,core0接收数据后再加1 发给core1,如此循环。
core1的代码:
- /*
- * Copyright (c) 2016, Freescale Semiconductor, Inc.
- * Copyright 2016-2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include "board.h"
- #include "fsl_mailbox.h"
- #include "fsl_common.h"
- #include "pin_mux.h"
- #include "fsl_power.h"
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- #define PRIMARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core0
- #define SECONDARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core1
- #define START_EVENT 1234
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- /*******************************************************************************
- * Variables
- ******************************************************************************/
- volatile uint32_t g_msg;
- /*******************************************************************************
- * Code
- ******************************************************************************/
- void MAILBOX_IRQHandler()
- {
- g_msg = MAILBOX_GetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID);
- MAILBOX_ClearValueBits(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
- g_msg++;
- MAILBOX_SetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, g_msg);
- }
- /*!
- * @brief Main function
- */
- int main(void)
- {
- /* Init board hardware.*/
- /* set BOD VBAT level to 1.65V */
- POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
- BOARD_InitPins_Core1();
- /* Initialize Mailbox */
- MAILBOX_Init(MAILBOX);
- /* Enable mailbox interrupt */
- NVIC_EnableIRQ(MAILBOX_IRQn);
- /* Let the other side know the application is up and running */
- MAILBOX_SetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, (uint32_t)START_EVENT);
- while (1)
- {
- __WFI();
- }
- }
复制代码 很简单,就是开启mailbox及它的中断,然后向core0发送了哟个已经开始的标志。然后中断中就是到数据就加1并反返回去。
core2代码:
- /*
- * Copyright (c) 2016, Freescale Semiconductor, Inc.
- * Copyright 2016-2018 NXP
- * All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include "fsl_debug_console.h"
- #include "board.h"
- #include "fsl_mailbox.h"
- #include "fsl_common.h"
- #include "pin_mux.h"
- #include "fsl_power.h"
- /*******************************************************************************
- * Definitions
- ******************************************************************************/
- #define PRIMARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core0
- #define SECONDARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core1
- /* Address of RAM, where the image for core1 should be copied */
- #define CORE1_BOOT_ADDRESS 0x20033000
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- 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[];
- #define CORE1_IMAGE_START core1_image_start
- #elif (defined(__GNUC__)) && (!defined(__MCUXPRESSO))
- extern const char m0_image_start[];
- extern const char *m0_image_end;
- extern int m0_image_size;
- #define CORE1_IMAGE_START ((void *)m0_image_start)
- #define CORE1_IMAGE_SIZE ((void *)m0_image_size)
- #endif
- #define START_EVENT 1234
- /*******************************************************************************
- * Prototypes
- ******************************************************************************/
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- uint32_t get_core1_image_size(void);
- #endif
- void start_secondary_core(uint32_t sec_core_boot_addr);
- /*******************************************************************************
- * Variables
- ******************************************************************************/
- volatile uint32_t g_msg = 1;
- /* For the flow control */
- volatile bool g_secondary_core_started = false;
- /*******************************************************************************
- * Code
- ******************************************************************************/
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- uint32_t get_core1_image_size(void)
- {
- uint32_t core1_image_size;
- #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
- 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;
- #elif defined(__GNUC__)
- core1_image_size = (uint32_t)m0_image_size;
- #endif
- return core1_image_size;
- }
- #endif
- void start_secondary_core(uint32_t sec_core_boot_addr)
- {
- /* Boot source for Core 1 from flash */
- SYSCON->CPUCFG |= SYSCON_CPUCFG_CPU1ENABLE_MASK;
- SYSCON->CPBOOT = SYSCON_CPBOOT_CPBOOT(sec_core_boot_addr);
- int32_t temp = SYSCON->CPUCTRL;
- temp |= 0xc0c48000;
- SYSCON->CPUCTRL = temp | SYSCON_CPUCTRL_CPU1RSTEN_MASK | SYSCON_CPUCTRL_CPU1CLKEN_MASK;
- SYSCON->CPUCTRL = (temp | SYSCON_CPUCTRL_CPU1CLKEN_MASK) & (~SYSCON_CPUCTRL_CPU1RSTEN_MASK);
- }
- /* When the secondary core writes to the primary core mailbox register it causes call of this irq handler,
- in which the received value is read, incremented and sent again to the secondary core */
- void MAILBOX_IRQHandler()
- {
- if (!g_secondary_core_started)
- {
- if (START_EVENT == MAILBOX_GetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID))
- {
- g_secondary_core_started = true;
- }
- MAILBOX_ClearValueBits(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
- }
- else
- {
- g_msg = MAILBOX_GetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID);
- MAILBOX_ClearValueBits(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
- PRINTF("Read value from the primary core mailbox register: %d\r\n", g_msg);
- g_msg++;
- PRINTF("Write to the secondary core mailbox register: %d\r\n", g_msg);
- MAILBOX_SetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, g_msg);
- }
- }
- /*!
- * @brief Main function
- */
- int main(void)
- {
- /* Init board hardware.*/
- /* set BOD VBAT level to 1.65V */
- POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
- /* attach main clock divide to FLEXCOMM0 (debug console) */
- CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);
- BOARD_InitPins_Core0();
- BOARD_BootClockPLL150M();
- BOARD_InitDebugConsole();
- PRINTF("Mailbox interrupt example\r\n");
- /* Init Mailbox */
- MAILBOX_Init(MAILBOX);
- /* Enable mailbox interrupt */
- NVIC_EnableIRQ(MAILBOX_IRQn);
- #ifdef CORE1_IMAGE_COPY_TO_RAM
- /* Calculate size of the image */
- uint32_t core1_image_size;
- core1_image_size = get_core1_image_size();
- PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", CORE1_BOOT_ADDRESS, core1_image_size);
- /* Copy application from FLASH to RAM */
- memcpy((void *)CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size);
- #endif
- /* Start the secondary core */
- start_secondary_core(CORE1_BOOT_ADDRESS);
- /* Wait for start and initialization of secondary core */
- while (!g_secondary_core_started)
- ;
- PRINTF("Write to the secondary core mailbox register: %d\r\n", g_msg);
- /* Write g_msg to the secondary core mailbox register - it causes interrupt on the secondary core */
- MAILBOX_SetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, g_msg);
- while (1)
- {
- __WFI();
- }
- }
复制代码 它的事就多一些,一开始打开串口,打开mailbox并开启中断,把core1生成的代码拷贝到相应的FLASH地址里面。然后启动core1,等待core1开始的信号。然后发送一个数值给core1,然后在中断里收到数值加1并反返回去。
思路很清晰,当然这个例子比较简单,我们在core1里面定义一些事件(比如打开LED啥的,然后事件对应一个标号),core0发送这个标号,core1接收到,就可以响应具体的事件了。
先编译core1程序,让它生成BIN文件,然后编译core0程序,然后运行过程,运行中,它会把core1的bin文件复制到FLASH对应地址里面。这样我们就
真正要下载到MCU的其实就是core0的程序。
查看串口输出:
好,达到了我们预期的结果。
那么我们在看看core0程序里面写入的core1 bin复制的地址是否跟我们core1程序的分散加载文件一致呢:
CORE1里面的分散加载文件
文件内容。看到地址:
core0程序里面的copy的首地址:
显然是一样的,那下次更改地址是不是心里就有数了呢。
好了双核通讯就到这了。小白水文,大神勿喷!谢谢大家!
|
|