Simply try running FreeRTOS on Milk-V Duo's small core

Simple Attempt to Run FreeRTOS on Milk-V Duo

It’s been a while since my last update, but I noticed that the official SDK for running FreeRTOS on the small core was released. It’s the weekend, so I decided to pull the latest code from Git and give it a try.

1. How to Add RTOS Task Code?
First, I took a quick look at the code, and in the SDK, there’s a file called cvitek under FreeRTOS. I opened the task folder and found two files: comm and main. I opened main.c and found the main_cvirtos() function, which is the entry point for FreeRTOS.

int main(void)
{
  pre_system_init();
  printf("CVIRTOS Build Date:%s  (Time :%s) \n", __DATE__, __TIME__);
#ifndef __riscv
  mmu_enable();
  printf("enable I/D cache & MMU done\n");
#endif
  /* Configure the hardware ready to run the demo. */
  prvSetupHardware();
#if ( configUSE_TRACE_FACILITY == 1 )
  vTraceEnable(TRC_START);
#endif
  post_system_init();

#ifdef CVIRTOS
  {
    main_cvirtos(); // Entry point
  }
#else
#error "Not correct running definition"
#endif

  /* Don't expect to reach here. */
  return 0;
}

So, where is main_cvirtos()? Continuing to navigate, I found it in the common folder at the path task/comm/src/riscv64. The source code is straightforward.

void main_cvirtos(void)
{
  printf("create cvi task\n");
  /* Start the tasks and timer running. */
  // This is where you can add your code!
  /* If all is well, the scheduler will now be running, and the following
    line will never be reached.  If the following line does execute, then
    there was either insufficient FreeRTOS heap memory available for the idle
    and/or timer tasks to be created, or vTaskStartScheduler() was called from
    User mode.  See the memory management section on the FreeRTOS web site for
    more details on the FreeRTOS heap http://www.freertos.org/a00111.html.  The
    mode from which main() is called is set in the C start up code and must be
    a privileged mode (not user mode). */
  printf("cvi task end\n");

  for (;;)
    ;
}

You can add your source code here following FreeRTOS API.

2. Simple Attempt: Let’s Create a FreeRTOS Version of “Hello, World!”
Since the official SDK already includes a UART0 driver, you can use printf directly. I modified common_main.c as follows:

/* Standard includes. */
#include <stdio.h>

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "mmio.h"
#include "delay.h"

/* cvitek includes. */
#include "printf.h"
#include "rtos_cmdqu.h"
#include "cvi_mailbox.h"
#include "intr_conf.h"
#include "top_reg.h"
#include "memmap.h"
#include "comm.h"
#include "cvi_spinlock.h"

//#define __DEBUG__

#ifdef __DEBUG__
#define debug_printf printf
#else
#define debug_printf(...)
#endif

/****************************************************************************
 * Function prototypes
 ****************************************************************************/
void my_task_test();
/****************************************************************************
 * Global parameters
 ****************************************************************************/

/* mailbox parameters */
volatile struct mailbox_set_register *mbox_reg;
volatile struct mailbox_done_register *mbox_done_reg;
volatile unsigned long *mailbox_context; // mailbox buffer context is 64 Bytess

/****************************************************************************
 * Function definitions
 ****************************************************************************/

DEFINE_CVI_SPINLOCK(mailbox_lock, SPIN_MBOX);

void main_cvirtos(void)
{
  printf("create cvi task\n");

  xTaskCreate(my_task_test, "my_task", 1024 * 8, NULL, 1, NULL);
  
  vTaskStartScheduler();

  /* Start the tasks and timer running. */

  /* If all is well, the scheduler will now be running, and the following
    line will never be reached.  If the following line does execute, then
    there was either insufficient FreeRTOS heap memory available for the idle
    and/or timer tasks to be created, or vTaskStartScheduler() was called from
    User mode.  See the memory management section on the FreeRTOS web site for
    more details on the FreeRTOS heap http://www.freertos.org/a00111.html.  The
    mode from which main() is called is set in the C start up code and must be
    a privileged mode (not user mode). */
  printf("cvi task end\n");

  for (;;)
    ;
}

void my_task_test()
{
  int index = 0;
  for (;;) {
    printf("test the RTOS: %d\r\n", index);
    vTaskDelay(100);
    index++;
  }
}

After recompiling and connecting to UART0, I used the official baseboard. Upon powering up, I found that FreeRTOS was running correctly. Since the UART resource is shared with Linux, you can see that the UART is continuously in use.

You can see that even when Linux is running on the big core, FreeRTOS on the small core continues to print numbers. After the Linux system is started, FreeRTOS keeps running.

3. Challenges and Solutions

  1. You need to modify the FreeRTOS config to disable configUSE_TICK_HOOK. Otherwise, you’ll encounter errors.
  2. I initially thought it would work like ESP32 IDF development, where you could write the task program without starting the scheduler. However, I found that it wouldn’t run unless you started the scheduler at the end.

That’s it! If you’re interested, give it a try!

1 Like

Hi,
Thank you for sharing this example.
Can I use FreeRTOS to drive an LCD to show a Splash screen until Linux core started?
Or what is the best approach?