请选择 进入手机版 | 继续访问电脑版
查看: 1738|回复: 0

[分享] 逐飞LPC55S69 IOT开发板之双核通讯的一些想法和测试

[复制链接]
  • TA的每日心情

    2024-2-5 12:06
  • 签到天数: 627 天

    [LV.9]以坛为家II

    94

    主题

    1628

    帖子

    2

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    4429

    热心会员

    最后登录
    2024-2-5
    发表于 2020-12-23 16:31:32 | 显示全部楼层 |阅读模式
    LPC55S69这款MCU除了用的M33的内核,还有个最大的特点就是双核:Core0和core1。两者的区别就是core1不能运用MPU(内存保护单元),FPU(浮点运算单元),DSP,ETM(嵌入式追踪宏单元)和TrustZone这几个几乎都是跟数据相关的部分,而core0可以使用。其他的外设两者通用。这就注定了core0更倾向于做算法,而core1更倾向于控制外设。
    M1.png
    那他们之间如何通讯呢?我们不妨想一下:如果我在MCU里面定义一块RAM,RAM空间分为2块,一块是存储给core0信息的,一块是存储给core0信息的,两个核均可以访问这块RAM。这样当core0想给core1发送消息是,就往定义的RAM core1处写下,当core1读到这个位置的信息是就能知道core0发的信息了,反之亦然。就这样两个核就愉快的通讯了。这样想法其实就是NXP双核通讯的最初原型。
    当然LPC55S69 core0和core1z之间通讯,没我们这么简单,但大概思路还是这个。它定义了一个叫mailbox的寄存器:
    M2.png
    每个核都拥有中断标志,设置中断寄存器数值,清除中断寄存器数值这3个含义的地址。
    这样我们双核的通讯流程就清晰了:
    CORE0-->CORE1方向:
    CORE0往core1对应的设置中断寄存器里面写入对应的数值,并且把core1对应的中断标志置1。
    Core1接收到中断,然后读取core1对应的设置中断寄存器里面数值,并保存下来或者做成相应,然后通过清除中断寄存器清除数据。
    反之亦然。
    当然具体寄存器里面读到的数据代表什么事件或者含义,就要自己定义了。
    废话不多说,我们测试下官方的双核通讯例程:
    思路很简单,就是core0往core1里面写数据,core1接收数据后加1,再发给core0,core0接收数据后再加1 发给core1,如此循环。
    core1的代码:
    1. /*
    2. * Copyright (c) 2016, Freescale Semiconductor, Inc.
    3. * Copyright 2016-2018 NXP
    4. * All rights reserved.
    5. *
    6. * SPDX-License-Identifier: BSD-3-Clause
    7. */

    8. #include "board.h"
    9. #include "fsl_mailbox.h"

    10. #include "fsl_common.h"
    11. #include "pin_mux.h"
    12. #include "fsl_power.h"
    13. /*******************************************************************************
    14. * Definitions
    15. ******************************************************************************/
    16. #define PRIMARY_CORE_MAILBOX_CPU_ID   kMAILBOX_CM33_Core0
    17. #define SECONDARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core1

    18. #define START_EVENT 1234

    19. /*******************************************************************************
    20. * Prototypes
    21. ******************************************************************************/

    22. /*******************************************************************************
    23. * Variables
    24. ******************************************************************************/
    25. volatile uint32_t g_msg;

    26. /*******************************************************************************
    27. * Code
    28. ******************************************************************************/
    29. void MAILBOX_IRQHandler()
    30. {
    31.     g_msg = MAILBOX_GetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID);
    32.     MAILBOX_ClearValueBits(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
    33.     g_msg++;
    34.     MAILBOX_SetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, g_msg);
    35. }

    36. /*!
    37. * @brief Main function
    38. */
    39. int main(void)
    40. {
    41.     /* Init board hardware.*/
    42.     /* set BOD VBAT level to 1.65V */
    43.     POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
    44.     BOARD_InitPins_Core1();

    45.     /* Initialize Mailbox */
    46.     MAILBOX_Init(MAILBOX);

    47.     /* Enable mailbox interrupt */
    48.     NVIC_EnableIRQ(MAILBOX_IRQn);

    49.     /* Let the other side know the application is up and running */
    50.     MAILBOX_SetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, (uint32_t)START_EVENT);

    51.     while (1)
    52.     {
    53.         __WFI();
    54.     }
    55. }
    复制代码
    很简单,就是开启mailbox及它的中断,然后向core0发送了哟个已经开始的标志。然后中断中就是到数据就加1并反返回去。

    core2代码:
    1. /*
    2. * Copyright (c) 2016, Freescale Semiconductor, Inc.
    3. * Copyright 2016-2018 NXP
    4. * All rights reserved.
    5. *
    6. * SPDX-License-Identifier: BSD-3-Clause
    7. */

    8. #include "fsl_debug_console.h"
    9. #include "board.h"

    10. #include "fsl_mailbox.h"

    11. #include "fsl_common.h"
    12. #include "pin_mux.h"
    13. #include "fsl_power.h"
    14. /*******************************************************************************
    15. * Definitions
    16. ******************************************************************************/
    17. #define PRIMARY_CORE_MAILBOX_CPU_ID   kMAILBOX_CM33_Core0
    18. #define SECONDARY_CORE_MAILBOX_CPU_ID kMAILBOX_CM33_Core1

    19. /* Address of RAM, where the image for core1 should be copied */
    20. #define CORE1_BOOT_ADDRESS 0x20033000

    21. #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
    22. extern uint32_t Image$CORE1_REGION$Base;
    23. extern uint32_t Image$CORE1_REGION$Length;
    24. #define CORE1_IMAGE_START &Image$CORE1_REGION$Base
    25. #elif defined(__ICCARM__)
    26. extern unsigned char core1_image_start[];
    27. #define CORE1_IMAGE_START core1_image_start
    28. #elif (defined(__GNUC__)) && (!defined(__MCUXPRESSO))
    29. extern const char m0_image_start[];
    30. extern const char *m0_image_end;
    31. extern int m0_image_size;
    32. #define CORE1_IMAGE_START ((void *)m0_image_start)
    33. #define CORE1_IMAGE_SIZE  ((void *)m0_image_size)
    34. #endif
    35. #define START_EVENT 1234
    36. /*******************************************************************************
    37. * Prototypes
    38. ******************************************************************************/

    39. #ifdef CORE1_IMAGE_COPY_TO_RAM
    40. uint32_t get_core1_image_size(void);
    41. #endif

    42. void start_secondary_core(uint32_t sec_core_boot_addr);

    43. /*******************************************************************************
    44. * Variables
    45. ******************************************************************************/
    46. volatile uint32_t g_msg = 1;
    47. /* For the flow control */
    48. volatile bool g_secondary_core_started = false;

    49. /*******************************************************************************
    50. * Code
    51. ******************************************************************************/

    52. #ifdef CORE1_IMAGE_COPY_TO_RAM
    53. uint32_t get_core1_image_size(void)
    54. {
    55.     uint32_t core1_image_size;
    56. #if defined(__CC_ARM) || defined(__ARMCC_VERSION)
    57.     core1_image_size = (uint32_t)&Image$CORE1_REGION$Length;
    58. #elif defined(__ICCARM__)
    59. #pragma section = "__sec_core"
    60.     core1_image_size = (uint32_t)__section_end("__sec_core") - (uint32_t)&core1_image_start;
    61. #elif defined(__GNUC__)
    62.     core1_image_size = (uint32_t)m0_image_size;
    63. #endif
    64.     return core1_image_size;
    65. }
    66. #endif

    67. void start_secondary_core(uint32_t sec_core_boot_addr)
    68. {
    69.     /* Boot source for Core 1 from flash */
    70.     SYSCON->CPUCFG |= SYSCON_CPUCFG_CPU1ENABLE_MASK;
    71.     SYSCON->CPBOOT = SYSCON_CPBOOT_CPBOOT(sec_core_boot_addr);

    72.     int32_t temp = SYSCON->CPUCTRL;
    73.     temp |= 0xc0c48000;
    74.     SYSCON->CPUCTRL = temp | SYSCON_CPUCTRL_CPU1RSTEN_MASK | SYSCON_CPUCTRL_CPU1CLKEN_MASK;
    75.     SYSCON->CPUCTRL = (temp | SYSCON_CPUCTRL_CPU1CLKEN_MASK) & (~SYSCON_CPUCTRL_CPU1RSTEN_MASK);
    76. }

    77. /* When the secondary core writes to the primary core mailbox register it causes call of this irq handler,
    78.    in which the received value is read, incremented and sent again to the secondary core */
    79. void MAILBOX_IRQHandler()
    80. {
    81.     if (!g_secondary_core_started)
    82.     {
    83.         if (START_EVENT == MAILBOX_GetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID))
    84.         {
    85.             g_secondary_core_started = true;
    86.         }
    87.         MAILBOX_ClearValueBits(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
    88.     }
    89.     else
    90.     {
    91.         g_msg = MAILBOX_GetValue(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID);
    92.         MAILBOX_ClearValueBits(MAILBOX, PRIMARY_CORE_MAILBOX_CPU_ID, 0xffffffff);
    93.         PRINTF("Read value from the primary core mailbox register: %d\r\n", g_msg);
    94.         g_msg++;
    95.         PRINTF("Write to the secondary core mailbox register: %d\r\n", g_msg);
    96.         MAILBOX_SetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, g_msg);
    97.     }
    98. }

    99. /*!
    100. * @brief Main function
    101. */
    102. int main(void)
    103. {
    104.     /* Init board hardware.*/
    105.     /* set BOD VBAT level to 1.65V */
    106.     POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false);
    107.     /* attach main clock divide to FLEXCOMM0 (debug console) */
    108.     CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH);

    109.     BOARD_InitPins_Core0();
    110.     BOARD_BootClockPLL150M();
    111.     BOARD_InitDebugConsole();

    112.     PRINTF("Mailbox interrupt example\r\n");

    113.     /* Init Mailbox */
    114.     MAILBOX_Init(MAILBOX);

    115.     /* Enable mailbox interrupt */
    116.     NVIC_EnableIRQ(MAILBOX_IRQn);

    117. #ifdef CORE1_IMAGE_COPY_TO_RAM
    118.     /* Calculate size of the image */
    119.     uint32_t core1_image_size;
    120.     core1_image_size = get_core1_image_size();
    121.     PRINTF("Copy CORE1 image to address: 0x%x, size: %d\r\n", CORE1_BOOT_ADDRESS, core1_image_size);

    122.     /* Copy application from FLASH to RAM */
    123.     memcpy((void *)CORE1_BOOT_ADDRESS, (void *)CORE1_IMAGE_START, core1_image_size);
    124. #endif

    125.     /* Start the secondary core */
    126.     start_secondary_core(CORE1_BOOT_ADDRESS);

    127.     /* Wait for start and initialization of secondary core */
    128.     while (!g_secondary_core_started)
    129.         ;

    130.     PRINTF("Write to the secondary core mailbox register: %d\r\n", g_msg);
    131.     /* Write g_msg to the secondary core mailbox register - it causes interrupt on the secondary core */
    132.     MAILBOX_SetValue(MAILBOX, SECONDARY_CORE_MAILBOX_CPU_ID, g_msg);

    133.     while (1)
    134.     {
    135.         __WFI();
    136.     }
    137. }
    复制代码
    它的事就多一些,一开始打开串口,打开mailbox并开启中断,把core1生成的代码拷贝到相应的FLASH地址里面。然后启动core1,等待core1开始的信号。然后发送一个数值给core1,然后在中断里收到数值加1并反返回去。
    思路很清晰,当然这个例子比较简单,我们在core1里面定义一些事件(比如打开LED啥的,然后事件对应一个标号),core0发送这个标号,core1接收到,就可以响应具体的事件了。
    先编译core1程序,让它生成BIN文件,然后编译core0程序,然后运行过程,运行中,它会把core1的bin文件复制到FLASH对应地址里面。这样我们就
    真正要下载到MCU的其实就是core0的程序。
    查看串口输出:
    XXX2.png
    好,达到了我们预期的结果。
    那么我们在看看core0程序里面写入的core1 bin复制的地址是否跟我们core1程序的分散加载文件一致呢:
    CORE1里面的分散加载文件
    QQQ1.png
    文件内容。看到地址:
    QQQ2.png
    core0程序里面的copy的首地址:
    QQQ3.png
    显然是一样的,那下次更改地址是不是心里就有数了呢。
    好了双核通讯就到这了。小白水文,大神勿喷!谢谢大家!


    哎...今天够累的,签到来了~
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-3-29 10:34 , Processed in 0.112619 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表