Milk-V DuoS之异构多核OS混合部署实验
背景
DuoS 的 CPU 采用多核设计,所以可以多OS混合部署,大核上跑 Linux 系统,小核上跑的是实时系统,当前是 FreeRTOS。
V2 版本镜像(不管是RISC-V 核还是 ARM 核)无法验证成功,不知道是支持不完善还是需要修改啥,暂时没有去深究。
所以后面换成了V1 版本镜像的来实验。
注:V1 版本镜像只支持 RISCV 核,所以需要将启动切换开关拨到RISCV这边!!!
我这里测试的镜像版本是:milkv-duos-sd-v1.1.4.img
核间通信样例
DuoS 大核与小核间通信是通过 mailbox 机制实现的,V1 版本最新的镜像已经在大核的 Linux 内核中添加了 mailbox 驱动,小核 FreeRTOS 代码中也实现了相关功能。
样例准备
前面上一篇已经搭建好的 duo-examples 应用开发环境,该核间通信测试程序(mailbox-test)已经放到了 duo-examples 这个仓库中, 所以只需要编译->下载->运行即可。
该样例是运行在大核上的一个 Linux 应用程序,通过大核 Linux 内核中的 mailbox 驱动,来通知小核 FreeRTOS 控制 DuoS 上的蓝色 LED 先点亮,3秒后再灭掉。
样例编译
进入 mailbox-test 目录编译
source envsetup.sh
cd mailbox-test
make
样例部署
编译成功后将生成的 mailbox_test 测试程序通过网口或者 USB网络(USB-NCM) 等方式传送到 DuoS 设备中,比如 USB 网络方式,DuoS 的 IP 为 192.168.42.1,用户名是 root,密码是 milkv
$ scp mailbox_test root@192.168.42.1:/root/
样例测试
测试准备:关闭开机LED 闪烁
DuoS 的默认固件大核 Linux 系统会控制 LED 闪烁,这个是通过开机脚本实现的,在测试该程序的时候,需要将 LED 闪烁的脚本禁用,在 DuoS 的终端中执行:
mv /mnt/system/blink.sh /mnt/system/blink.sh_backup && sync
也就是将 LED 闪烁脚本改名,重启 DuoS 后,LED 就不会闪了。
运行测试
这里没有接串口,使用 SSH 连接的 DuoS,在终端中运行 ./mailbox_test 测试,输出如下:
[root@milkv-duo]~# ./mailbox_test
C906B: cmd.param_ptr = 0x4
C906B: cmd.param_ptr = 0x3
可以看到 DuoS 上的蓝色 LED 先亮后灭的现象。
因为未接串口,可能看到的日志不够全面,从代码来看,大核绐小核发送亮灯指令后,小核有回送 0x4(0x00000004) 绐大核,大核上也收到了 0x4,而发灭灯指令后,小核也有返回 0x4(0x00000004) 绐大核,但大核端打印的值是 0x3, 结合代码看,这个 0x3 是大核发送灭灯指令前的参数,这也正是使用 RTOS_CMDQU_SEND_WAIT 和 RTOS_CMDQU_SEND 两个参数的差异:
RTOS_CMDQU_SEND_WAIT 等待返回值
RTOS_CMDQU_SEND 没有返回值
相关代码
mailbox_test样例相关代码:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
enum SYSTEM_CMD_TYPE {
CMDQU_SEND = 1,
CMDQU_SEND_WAIT,
CMDQU_SEND_WAKEUP,
};
#define RTOS_CMDQU_DEV_NAME "/dev/cvi-rtos-cmdqu"
#define RTOS_CMDQU_SEND _IOW('r', CMDQU_SEND, unsigned long)
#define RTOS_CMDQU_SEND_WAIT _IOW('r', CMDQU_SEND_WAIT, unsigned long)
#define RTOS_CMDQU_SEND_WAKEUP _IOW('r', CMDQU_SEND_WAKEUP, unsigned long)
enum SYS_CMD_ID {
CMD_TEST_A = 0x10,
CMD_TEST_B,
CMD_TEST_C,
CMD_DUO_LED,
SYS_CMD_INFO_LIMIT,
};
enum DUO_LED_STATUS {
DUO_LED_ON = 0x02,
DUO_LED_OFF,
DUO_LED_DONE,
};
struct valid_t {
unsigned char linux_valid;
unsigned char rtos_valid;
} __attribute__((packed));
typedef union resv_t {
struct valid_t valid;
unsigned short mstime;
} resv_t;
typedef struct cmdqu_t cmdqu_t;
struct cmdqu_t {
unsigned char ip_id;
unsigned char cmd_id : 7;
unsigned char block : 1;
union resv_t resv;
unsigned int param_ptr;
} __attribute__((packed)) __attribute__((aligned(0x8)));
int main()
{
int ret = 0;
int fd = open(RTOS_CMDQU_DEV_NAME, O_RDWR);
if(fd <= 0)
{
printf("open failed! fd = %d\n", fd);
return 0;
}
struct cmdqu_t cmd = {0};
cmd.ip_id = 0;
cmd.cmd_id = CMD_DUO_LED;
cmd.resv.mstime = 100;
cmd.param_ptr = DUO_LED_ON;
ret = ioctl(fd , RTOS_CMDQU_SEND_WAIT, &cmd);
if(ret < 0)
{
printf("ioctl error!\n");
close(fd);
}
sleep(1);
printf("C906B: cmd.param_ptr = 0x%x\n", cmd.param_ptr);
sleep(3);
cmd.cmd_id = CMD_DUO_LED;
cmd.param_ptr = DUO_LED_OFF;
ret = ioctl(fd , RTOS_CMDQU_SEND, &cmd);
if(ret < 0)
{
printf("ioctl error!\n");
close(fd);
}
sleep(1);
printf("C906B: cmd.param_ptr = 0x%x\n", cmd.param_ptr);
close(fd);
return 0;
}
更多相关代码:
-
大核 mailbox Linux 驱动:
linux_5.10/drivers/soc/cvitek/rtos_cmdqu/
-
小核 FreeRTOS:
freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h
freertos/cvitek/task/comm/src/riscv64/
参考
https://milkv.io/zh/docs/duo/getting-started/rtoscore