Experimental Hybrid Deployment of Heterogeneous Multicore OS on Milk-V DuoS
Background
The CPU of DuoS adopts a multicore design, allowing for the hybrid deployment of multiple operating systems, with the big cores running a Linux system and the small cores running a real-time system, currently FreeRTOS. The V2 version image (whether for RISC-V cores or ARM cores) could not be successfully verified; it is unclear whether the support is incomplete or if modifications are needed, so I did not delve into it for now. Therefore, I switched to the V1 version image for experimentation.Note: The V1 version image only supports RISC-V cores, so the boot switch must be set to the RISC-V side!!!
The image version I tested is:
<span>milkv-duos-sd-v1.1.4.img</span>
Inter-Core Communication Example
Communication between the big core and small core in DuoS is achieved through a mailbox mechanism. The latest V1 version image has added a mailbox driver in the big core’s Linux kernel, and the small core’s FreeRTOS code has also implemented the relevant functionality.
Example Preparation
The application development environment for <span>duo-examples</span> has already been set up in the previous article, and the inter-core communication test program (<span>mailbox-test</span>) has been placed in the <span>duo-examples</span> repository, so it only needs to be compiled -> downloaded -> run.
This example runs as a Linux application on the big core, using the mailbox driver in the big core’s Linux kernel to notify the small core FreeRTOS to control the blue LED on DuoS to light up first, and then turn off after 3 seconds.
Example Compilation
Enter the <span>mailbox-test</span> directory to compile
source envsetup.sh
cd mailbox-test
make
Example Deployment
After successful compilation, transfer the generated <span>mailbox_test</span> test program to the DuoS device via Ethernet or USB network (USB-NCM). For example, using USB network, the IP of DuoS is 192.168.42.1, the username is root, and the password is milkv.
$ scp mailbox_test [email protected]:/root/
Example Testing
Test Preparation: Disable Boot LED Blinking
The default firmware of DuoS with the big core Linux system controls the LED blinking, which is implemented through the boot script. When testing this program, the LED blinking script needs to be disabled. Execute the following command in the DuoS terminal:
mv /mnt/system/blink.sh /mnt/system/blink.sh_backup && sync
This renames the LED blinking script, and after rebooting DuoS, the LED will no longer blink.
Run Test
Since there is no serial connection, I used SSH to connect to DuoS and ran the test in the terminal with <span>./mailbox_test</span>, the output is as follows:
[root@milkv-duo]~# ./mailbox_test
C906B: cmd.param_ptr = 0x4
C906B: cmd.param_ptr = 0x3
It can be observed that the blue LED on DuoS lights up and then turns off.
Since there is no serial connection, the logs may not be comprehensive. From the code, after the big core sends the light-on command to the small core, the small core returns 0x4 (0x00000004) to the big core, and the big core also receives 0x4. However, after sending the light-off command, the small core also returns 0x4 (0x00000004) to the big core, but the value printed on the big core is 0x3. This 0x3 is the parameter before the big core sends the light-off command, which corresponds to the difference between using RTOS_CMDQU_SEND_WAIT and RTOS_CMDQU_SEND:
RTOS_CMDQU_SEND_WAIT Waits for return value
RTOS_CMDQU_SEND No return value
Related Code
<span>mailbox_test</span> Example Related Code:
#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; // 0 : noblock, -1 : block infinite
} resv_t;
typedef struct cmdqu_t cmdqu_t;
/* cmdqu size should be 8 bytes because of mailbox buffer size */
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;
}
More Related Code:
- • Big core mailbox Linux driver:
- •
<span>linux_5.10/drivers/soc/cvitek/rtos_cmdqu/</span> - • Small core FreeRTOS:
- •
<span>freertos/cvitek/driver/rtos_cmdqu/include/rtos_cmdqu.h</span> - •
<span>freertos/cvitek/task/comm/src/riscv64/</span>
References
https://milkv.io/zh/docs/duo/getting-started/rtoscore
Welcome to Follow:
Feel free to add WeChat to join the discussion group:

For more, please click the bottom left corner Read the original text!