CA888亚洲城集团 OK536x-C 平台 FreeRTOS 应用部署指南

原创 作者 Forlinx 2025-10-29 19:11:00 t536 536开发板 全志t536

本文基于CA888亚洲城集团 OK536x-C 平台官方技术资料、全志科技 T536 芯片规格书整理编写,聚焦 RISCV 核的系统架构、内核初始化流程及自定义应用部署,所有核心逻辑均匹配平台官方定义,数据及技术细节经原厂验证,可作为工程师开发适配的实操参考文档。CA888亚洲城集团 OK536x-C 开发板亮点 采用全志 T536 工业级SoC,四核 Cortex-A55 + 单核 RISC-V 异构架构,A55 主频 1.6 GHz,RISC-V 实时核独立运行 FreeRTOS,整板工业级宽温设计。若您正在寻找“Linux + 实时核”同时落地的量产级方案,OK536x-C 几乎是不二之选。

适用范围

本指南核心适配CA888亚洲城集团 OK536x-C 硬件平台,且基于 Linux5.10 操作系统环境;其他基于 T536 芯片的硬件平台可参考本指南的流程框架,但需注意不同厂家在 GPIO 引脚定义、串口配置、外设驱动适配等硬件设计上的差异,需结合自身平台手册进行修改调整。

系统架构:RISCV 核与 FreeRTOS

OK536x-C 平台的 T536 RISCV 核默认集成 FreeRTOS 实时操作系统,核心技术特性符合 FreeRTOS 官方标准,具体如下:

  • 抢占式调度机制:基于任务优先级调度,高优先级任务可主动中断低优先级任务,保障实时事件响应效率。
  • 模块化可裁剪:支持根据项目需求选择性启用 / 关闭内核模块(如内存管理、内核对象),优化系统资源占用。
  • 轻量化设计:内核代码精简,仅需少量 RAM/ROM 即可运行,适配嵌入式设备资源受限场景。
  • 多任务并发支持:提供标准化任务创建、删除、挂起 / 恢复接口,满足复杂业务逻辑需求。
  • 丰富内核同步通信组件:内置信号量、队列、互斥量、事件组等,实现任务间同步与数据交互。
  • 灵活内存管理策略:支持静态内存分配(编译时确定大小)、动态堆分配(运行时申请),适配不同内存管理需求。

内核初始化流程(含核心代码框架)

T536 RISCV 核的启动初始化围绕三个核心函数 / 任务展开,以下为关键初始化逻辑及代码框架,仅保留 "决定流程成败、需手动关注" 的核心部分,剔除平台固化的底层驱动实现:

4.1 start_kernel 函数:RISCV 核启动入口

函数 void start_kernel(void) 是目前能够找到的最先开始执行的函数,里面对RISCV核以及FreeRTOS系统做了初始化,并开启了一个 void cpu0_app_entry(void \*) 任务,最后打开FreeRTOS调度器,开始运行FreeRTOS。

rtos\lichee\rtos\arch\risc-v\sun55iw6p1\sun55i.c
void start_kernel(void)
{
portBASE_TYPE ret;
#ifdef CONFIG_COMPONENTS_STACK_PROTECTOR
//void stack_protector_init(void);
//stack_protector_init();
#endif
// 初始化Dcache、Icache等
extern void hardware_config(void);
hardware_config();
// 空函数,没有实际作用
systeminit();
// 不执行
#ifdef CONFIG_COMPONENTS_CERTIFICATION_60730
extern int aw_startup_check_entry(void);
#if 0
extern void aw_check_set_test_break_point(unsigned char value);
aw_check_set_test_break_point(1);
#endif
aw_startup_check_entry();
#endif
/* Init heap */
heap_init();
#ifdef CONFIG_COMPONENTS_PM
pm_devops_init();
pm_syscore_init();
#endif
// 和多核处理有关(Open Asymmetric Multi-Processing)
#ifdef CONFIG_AMP_SHARE_IRQ
openamp_share_irq_early_init();
#endif
/* Init hardware devices */
prvSetupHardware();
// 注册multi_console
// 暂时不知道multi_console具体的作用是什么
#ifdef CONFIG_MULTI_CONSOLE
extern int multiple_console_early_init(void);
multiple_console_early_init();
#endif
// 打印启动信息
/* Setup kernel components */
print_banner();
// 设置标准输入输出
setbuf(stdout, 0);
setbuf(stdin, 0);
setvbuf(stdin, NULL, _IONBF, 0);
#ifdef CONFIG_COMPONENT_CPLUSPLUS
/* It should be called after the stdout is ready, otherwise the std:cout can't work */
int cplusplus_system_init(void);
cplusplus_system_init();
#endif
#ifdef CONFIG_ARCH_HAVE_ICACHE
hal_icache_init();
printf("init Icache\n");
#endif
#ifdef CONFIG_ARCH_HAVE_DCACHE
hal_dcache_init();
printf("init Dcache\n");
#endif
#ifdef CONFIG_DRIVERS_HWSPINLOCK
hal_hwspinlock_init();
#endif
#ifdef CONFIG_DRIVERS_WATCHDOG
hal_watchdog_init();
#endif
#ifdef CONFIG_DRIVERS_MSGBOX
hal_msgbox_init();
#endif
start_kernel_flag = 0;
#ifdef CONFIG_COMPONENTS_AMP_HW_WATCHDOG
extern int amp_hw_wdog_init(void);
amp_hw_wdog_init();
#endif
#ifdef CONFIG_COMPONENTS_AMP_TIMESTAMP
extern int amp_timestamp_init(void);
amp_timestamp_init();
#endif
// 添加cpu0_app_entry任务到FreeRTOS内部的任务池中
extern void cpu0_app_entry(void *);
ret = xTaskCreate(cpu0_app_entry, "init-thread-0", 1024, NULL, 31, NULL);
if (ret != pdPASS)
{
printf("Error creating task, status was %d\n", ret);
while (1);
}
// 打开FreeRTOS调度器
vTaskStartScheduler();
}

4.2 cpu0_app_entry 任务:核心业务初始化

cpu0_app_entry 主要做了以下工作:

  • 开启OpenAMP的初始化进程 openamp_init_thread
  • 打开FreeRTOS命令vCommandConsoleStart(0x1000, HAL_THREAD_PRIORITY_CLI, NULL)
rtos\lichee\rtos\projects\t536_e907\demo\src\main.c
svoid cpu0_app_entry(void *param)
{
(void)param;
#ifdef CONFIG_COMPONENTS_PM
pm_init(1, NULL);
#endif
#ifdef CONFIG_COMPONENTS_OPENAMP
void *thread;
thread = hal_thread_create(openamp_init_thread, NULL, "amp_init", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (thread != NULL)
hal_thread_start(thread);
#endif
#ifdef CONFIG_COMPONENT_CLI
vCommandConsoleStart(0x1000, HAL_THREAD_PRIORITY_CLI, NULL);
#endif
#ifdef COMMAND_AUTO_START_MEMTESTER
void *autotest_thread;
autotest_thread = hal_thread_create(auto_memtester_thread, NULL, "auto_memtester", 8 * 1024, HAL_THREAD_PRIORITY_SYS);
if (autotest_thread != NULL)
hal_thread_start(autotest_thread);
#endif
vTaskDelete(NULL);
}

4.3 vCommandConsoleStart 函数:CLI 初始化与任务创建

函数 vCommandConsoleStart 的作用是初始化命令行界面(CLI,Command Line Interface),并且启动对应的任务 prvUARTCommandConsoleTask。CLI使用的串口通过 CONFIG_CLI_UART_PORT 定义来决定。

rtos\lichee\rtos\components\thirdparty\console\UARTCommandConsole.c
void vCommandConsoleStart( uint16_t usStackSize, portBASE_TYPE uxPriority, void * console)
{
#if !defined(CONFIG_DISABLE_ALL_UART_LOG)
/* A UART is used for printf() output and CLI input and output. Note there
is no mutual exclusion on the UART, but the demo as it stands does not
require mutual exclusion. */
TaskHandle_t cli_task = NULL;
prvConfigureUART(console);
vRegisterSampleCLICommands();
portBASE_TYPE ret;
/* Create that task that handles the console itself. */
ret = xTaskCreate(prvUARTCommandConsoleTask, /* The task that implements the command console. */
"CLI", /* Text name assigned to the task. This is just to assist debugging. The kernel does not use this name itself. */
usStackSize, /* The size of the stack allocated to the task. */
NULL, /* The parameter is not used, so NULL is passed. */
uxPriority, /* The priority allocated to the task. */
&cli_task); /* A handle is not required, so just pass NULL. */
if (ret != pdPASS) {
printf("Error creating console task, status was %d\n", (int)ret);
}
#ifdef CONFIG_COMPONENTS_MULTI_CONSOLE
cli_task_set_console(cli_task, console);
#endif
#endif
}

RISCV 核启动信息打印规则

这里分两部分,带有时间戳的是RISCV核和FreeRTOS核的打印信息,不带时间戳的是CLI命令行的打印信息。
[5.800]
[5.800] ************************************************************
[5.802] ** Welcome to T536_E907 FreeRTOS V1.6.0 **
[5.803] ** Copyright (C) 2019-2021 AllwinnerTech **
[5.805] ** **
[5.809] ** starting riscv FreeRTOS **
[5.814] ************************************************************
[5.819]
[5.819]Date:Feb 13 2025, Time:17:50:53
[5.823]init Icache
[5.825]init Dcache
[5.826]AMP timestamp device 0 probe success, count_freq: 24000000Hz
[5.832]amp_hw_wdog_feed_thread enter, feed_interval: 100ms, feed_interval_tick: 100
[5.840]AMP hardware watchdog's new timeout: 2s
[5.844]Begin to feed AMP hardware watchdog!
[5.848]pm_client_init end!!!
FreeRTOS command server.
Type Help to view a list of registered commands.
>[5.858][RV] [AMP_INFO][openamp_platform_init:168]rproc0 init
[5.864][RV] [AMP_INFO][rproc_common_mmap:128]remoteproc mmap pa: 0x60050db0, da: 0xffffffff, size = 0xc8
[5.874][RV] [AMP_INFO][rproc_common_mmap:199]map pa(0x60050db0) to va(0x60050db0)
[5.882][RV] [AMP_INFO][rproc_common_mmap:128]remoteproc mmap pa: 0x42400000, da: 0x42400000, size = 0x40000
[5.892][RV] [AMP_INFO][rproc_common_mmap:199]map pa(0x42400000) to va(0x42400000)
[5.900][RV] [AMP_INFO][rproc_common_mmap:128]remoteproc mmap pa: 0xffffffff, da: 0x42440000, size = 0x1406
[5.911][RV] [AMP_INFO][rproc_common_mmap:199]map pa(0x42440000) to va(0x42440000)
[5.919][RV] [AMP_INFO][rproc_common_mmap:128]remoteproc mmap pa: 0xffffffff, da: 0x42442000, size = 0x1406
[5.929][RV] [AMP_INFO][rproc_common_mmap:199]map pa(0x42442000) to va(0x42442000)
[5.937][RV] [AMP_INFO][openamp_sunxi_create_rpmsg_vdev:365]Wait connected to remote master
[5.946][RV] [AMP_INFO][openamp_sunxi_create_rpmsg_vdev:371]Connecte to remote master Successed
[5.955][RV] [AMP_INFO][openamp_platform_init:219]rproc0 init done
[5.961][RV] [AMP_INFO][openamp_platform_init:168]rproc0 init
[5.968][RV] [AMP_INFO][openamp_platform_init:178]rproc0 already init.
[5.975][RV] [AMP_INFO][openamp_ept_open:388]Waiting for ept('sunxi,rpmsg_ctrl') ready
uart>[5.984][RV] [AMP_INFO][openamp_ept_open:393]ept('sunxi,rpmsg_ctrl') ready! src: 0x400, dst: 0x400
[5.993]rpmsg ctrldev: Start Running...
[5.997][RPBUF_INFO][rpbuf_init_service:154]Waiting for rpbuf ept('rpbuf-service') ready.
[6.005][RV] [AMP_INFO][openamp_platform_init:168]rproc0 init
[6.011][RV] [AMP_INFO][openamp_platform_init:178]rproc0 already init.
[6.018][RV] [AMP_INFO][openamp_ept_open:388]Waiting for ept('sunxi,rpmsg_heartbeat') ready
[6.047][RPBUF_INFO][rpbuf_init_service:160]rpbuf ept('rpbuf-service') ready! src: 0x401, dst: 0x401
cpu>
cpu>

自定义应用部署:GPIO 控制示例

如果需要在RISCV核启动之后,直接运行自己的应用,而不通过CLI去调用,可以在 start_kernel 或者 cpu0_app_entry 中加入自己的应用。这里以启动一个GPIO控制应用为例,介绍如何编写一个简单的GPIO应用,并且将它放到FreeRTOS的任务池中。

注意:代码块中的路径和函数名均为平台特定实现,请勿修改,直接使用即可。

6.1 步骤 1:编写 GPIO 控制任务函数

我们在gpio应用中编写一个简单的测试函数。注意返回值和参数要和示例中保持一致,否则FreeRTOS无法正常创建对应的任务。

rtos\lichee\rtos-hal\hal\test\gpio\test_gpio.c
void hjl_test_gpio_output(void *param)
{
gpio_pin_t pin;
gpio_data_t data;
hal_gpio_pinmux_set_function(239, GPIO_MUXSEL_OUT);
hal_gpio_set_pull(239, GPIO_PULL_UP);
hal_gpio_set_direction(239, GPIO_DIRECTION_OUTPUT);
hal_gpio_set_data(239, 0);
while (1) {
hal_gpio_set_data(239, 0);
hal_sleep(2);
hal_gpio_set_data(239, 1);
hal_sleep(2);
}

6.2 步骤 2:将 GPIO 任务添加到任务池

这里我们直接添加到了start_kernel函数的末尾。由于我们的测试应用并没有涉及到多核通信和AMP的内容,因此这样做是可行的。但如果涉及到了多核通信、AMP或者RPMSG这种操作,建议放到cpu0_app_entry的末尾去实现。
rtos\lichee\rtos\arch\risc-v\sun55iw6p1\sun55i.c
void start_kernel(void)
{
......
extern void cpu0_app_entry(void *);
ret = xTaskCreate(cpu0_app_entry, "init-thread-0", 1024, NULL, 31, NULL);
if (ret != pdPASS)
{
printf("Error creating task, status was %d\n", ret);
while (1);
}
// 添加的自己的测试应用
extern void hjl_test_gpio_output(void *);
ret = xTaskCreate(hjl_test_gpio_output, "gpio_app", 1024, NULL, 31, NULL);
if (ret != pdPASS)
{
printf("Error creating task hjl_test_gpio_output, status was %d\n", ret);
while (1);
}
vTaskStartScheduler();
}

6.3 步骤 3:编译与验证

修改完成后对源码进行全编译并烧录到系统里,按照手册启动RISCV核,可以看到LEDC会开始闪烁,代表应用启动成功。

CA888亚洲城集团OK536x-C开发板实物参考图

相关产品 >

  • FET536-C核心板

    基于全志T536工业级处理器的FET536-C全国产核心板。该核心板的开发设计充分利用了T536处理器的性能优势。T536处理器的主频为1.6GHz,集成了四核Cortex-A55以及64位玄铁E907 RISC-V MCU,能够提供高效的计算能力。此外,T536还支持2TOPS NPU、安全启动、国密算法IP、全通路ECC、AMP、Linux-RT等功能。T536还配备了广泛的连接接口,包括USB、SDIO、UART、SPI、CAN-FD、以太网、ADC(模数转换器)、LocalBus等,以满足不同应用场景的需求

    了解详情
    FET536-C核心板
  • OK536-C开发板

    T536全国产工业级核心板提供配套开发板,采用核心板+底板分体式设计,共320个引脚,T536开发板采用4个80Pin板对板连接器的方式将处理器的功能引脚以最便利的方式引出,并针对不同的功能做了深度优化,T536开发板方便用户二次开发的同时简化用户设计,为您的项目提供良好的评估及设计依据。 了解详情
    OK536-C开发板

推荐阅读 换一批 换一批