目录
DSP 开发例程: 单镜像多核引导
此例程实现在 EVM6678L 开发板上将单镜像应用程序进行多核引导, 核0-核4 分别控制一个LED 闪烁, 并通过串口打印日志信息. 例程源码可从我的 gitee 仓库上克隆或下载. 点击 DSP 开发教程(0): 汇总查看其他例程说明.
新建工程
此示例工程直接在 logbuf_print_to_uart 工程基础上修改.
- 选中 logbuf_print_to_uart 工程, 右键选择 Copy 或 使用快捷键
Ctrl+C
复制工程.
- 在工程浏览视图中, 右键选择 Paste 或使用快捷键
Ctrl+V
粘贴工程.
在弹出的 Copy Project 对话框中 修改工程名为: multicore_boot , 点击 OK .
- 删除 multicore_boot 工程中的 Debug 目录, 右键选择 Build Project, 编译此工程.
源码编辑
multicore_boot.c
新建名为 multicore_boot.c的源文件, 文件内容如下:
c
#include <ti/csl/csl_bootcfgAux.h>
#define CORE_0_MAGIC_ADDR (0X1087FFFC)
extern unsigned int _c_int00(void);
void multicore_boot()
{
unsigned int i;
CSL_BootCfgUnlockKicker();
// 拷贝 core0 L2SRAM 数据到其他核心
for (i = 1; i < 8; i++)
{
memcpy((void *)(CSL_DSP0_L2_SRAM_REGS+0x01000000*i), (void *)CSL_DSP0_L2_SRAM_REGS, 0x70000);
*(volatile unsigned int *)(CORE_0_MAGIC_ADDR + 0x01000000*i) = (unsigned int)_c_int00;
CSL_BootCfgGenerateInterDSPInterrupt(i, 0);
}
CSL_BootCfgLockKicker();
}
multicore_boot()
函数由核0执行, 实现以下功能:
- 将核0的 L2SRAM 中的内容复制到其他核心的 L2SRAM中;
- 向其他核心发送 IPC中断, 唤醒其他核心.
config.h
新建名为 config.h 的头文件, 在其中输入如下内容:
c
#ifndef CONFIG_H_
#define CONFIG_H_
#define PLATFORM_UART_HW_SEM 4
#define PLATFORM_LED_HW_SEM 5
#endif /* CONFIG_H_ */
其中, 定义了两个宏, 分别用于多核在 UART 和 LED 外设资源抢占时, 使用哪个硬件信号量进行资源保护.
os.c
修改 os_systemFlush()
函数, 在执行System_flush()
前后加入硬件信号量的请求和释放.
c
void os_systemFlush()
{
if (logger0)
myLoggerBuf_flush(logger0);
if ((CSL_semAcquireDirect (PLATFORM_UART_HW_SEM)))
{
System_flush();
CSL_semReleaseSemaphore (PLATFORM_UART_HW_SEM);
}
}
main.c
修改 EVM_init()
函数, 调用 multicore_boot()
函数实现多核引导. 平台初始化和多核引导只由核0 完成.
c
void EVM_init()
{
platform_init_flags init_flags;
platform_init_config init_config;
if (platform_get_coreid() == 0)
{
// plaform initialize
memset(&init_flags, 1, sizeof(platform_init_flags));
init_flags.phy = 0;
memset(&init_config, 0, sizeof(platform_init_config));
if (platform_init(&init_flags, &init_config) != Platform_EOK)
{
printf("Platform failed to initialize, errno = 0x%x \n", platform_errno);
while(1);
}
platform_uart_init();
multicore_boot();
}
}
修改 task_ledFlash()
函数, 在调用 platform_led()
函数前后加入硬件信号量的请求和释放.
c
Void task_ledFlash(UArg a0, UArg a1)
{
int i = 1;
int id = platform_get_coreid();
Log_info0("enter task_ledFlash().");
if (id < 4)
{
while(1)
{
while ((CSL_semAcquireDirect (PLATFORM_LED_HW_SEM)) == 0);
platform_led(id, PLATFORM_LED_ON, PLATFORM_USER_LED_CLASS);
CSL_semReleaseSemaphore (PLATFORM_LED_HW_SEM);
Log_info2("LED %d ON at %d times.", id, i);
Task_sleep(500);
while ((CSL_semAcquireDirect (PLATFORM_LED_HW_SEM)) == 0);
platform_led(id, PLATFORM_LED_OFF, PLATFORM_USER_LED_CLASS);
CSL_semReleaseSemaphore (PLATFORM_LED_HW_SEM);
Log_info2("LED %d OFF at %d times.", id, i);
Task_sleep(500);
i++;
}
}
}
保存对上述文件的修改.
测试
此处我使用 IBL-TFTP 引导方式对核0进行应用程序的加载和引导. 你也可以使用其他的引导方式. 请参考:EVM6678L 开发教程: IBL-TFTP 引导 elf 文件
下图是EVM6678L开发板串口终端打印的日志信息. 多个核心的日志时间戳不一定按时间先后顺序排列
同时应该可以看到开发板上的四个LED灯以1秒周期闪烁.