目录文件裁剪
源文件
FreeRTOS项目必须至少包含以下源文件([compiler] 和 [architecture] 分别是用于创建移植的编译器和移植运行的架构):
- FreeRTOS/Source/tasks.c
- FreeRTOS/Source/queue.c
- FreeRTOS/Source/list.c
- FreeRTOS/Source/portable/[compiler]/[architecture]/port.c
- FreeRTOS/Source/portable/MemMang/heap_x.c 其中 "x" 可以是 1、2、3、4 或 5。
如果包含 port.c 文件的目录也包含程序集语言文件,那么也必须使用程序集语言文件。
可选源文件
- 如果需要软件定时器功能,请在项目中添加 FreeRTOS/Source/timers.c。
- 如果需要事件组功能,请在项目中添加 FreeRTOS/Source/event_groups.c。
- 如果需要流缓冲区或消息缓冲区功能,请在项目中添加 FreeRTOS/Source/stream_buffer.c。
- 如果需要协程功能,请在项目中添加 FreeRTOS/Source/croutine.c(请注意,协程已弃用, 不推荐用于新设计)。
头文件
以下目录必须位于编译器的 include 路径中(必须告知编译器在这些目录中搜索 头文件):
- FreeRTOS/Source/include
- FreeRTOS/Source/portable/[compiler]/[architecture]。
- 无论哪个目录包含要使用的 FreeRTOSConfig.h 文件,请参阅下文"配置文件"段落。
根据移植的不同,也可能需要将相同的目录放在汇编器的 include 路径中。
配置文件
每个项目还需要一个名为 FreeRTOSConfig.h 的文件。 FreeRTOSConfig.h 它为正在构建的应用程序量身定制 RTOS 内核。因此,它是取决于 应用程序的,而不是 RTOS,并且应位于应用程序目录中, 而不是 RTOS 内核源代码目录中。
如果您的项目包含 heap_1、heap_2、heap_4 或 heap_5,则 FreeRTOSConfig.h 的 configTOTAL_HEAP_SIZE 定义将决定 FreeRTOS 堆的大小。如果 configTOTAL_HEAP_SIZE 设置得太高,则您的应用程序将无法建立连接。
FreeRTOSConfig.h 中的 configMINIMAL_STACK_SIZE 定义 设定了闲置任务使用的堆栈大小。如果 configMINIMAL_STACK_SIZE 设置得太低, 则空闲任务将造成栈溢出。建议您找到 使用相同微控制架构的 FreeRTOS 官方演示, 复制其中的 configMINIMAL_STACK_SIZE 设置。FreeRTOS 演示 项目存储在 FreeRTOS/Demo 目录的子目录中。 请注意,一些演示项目的时间距离现在比较久,因此不包含所有可用的 配置选项。
开始裁剪移植
-
把FreeRTOS配置模板FreeRTOS-Kernel\examples\template_configuration\FreeRTOSConfig.h拷贝到FreeRTOS-Kernel\include下。
-
保留选中的文件和文件夹其他的都没用删掉。

-
使用FreeRTOS-Kernel\portable\GCC\ARM_CM0替换FreeRTOS-Kernel\portable\RVDS\ARM_CM0 然后保留选中的文件夹其他删掉。

-
FreeRTOS-Kernel\portable目录下保留刚才替换的文件夹其他删掉。
'
工程添加
工程是直接使用HC模板,直接在模板上添加。


- heap_1------ 最简单,不允许释放内存。
- heap_2------ 允许释放内存,但不会合并相邻的空闲块。
- heap_3------ 简单包装了标准 malloc() 和 free(),以保证线程安全。
- heap_4------ 合并相邻的空闲块以避免碎片化。包含绝对地址放置选项。
- heap_5------ 如同 heap_4,能够跨越多个不相邻内存区域的堆。
注意:
- heap_1 不太有用,因为 FreeRTOS 添加了静态分配支持。
- heap_2 现在被视为旧版,因为较新的 heap_4 实现是首选。
FreeRTOSConfig.h
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* *************************************************************************
* 1. 系统基础配置
* ************************************************************************/
/* 芯片内核时钟频率 - HC32L021 主频配置为 48MHz */
#define configCPU_CLOCK_HZ ( ( unsigned long ) 48000000 )
/* 系统时钟节拍频率 (1000Hz = 1ms中断一次),是RTOS的时间基准 */
#define configTICK_RATE_HZ 1000
/* 最大任务优先级数,数字越大优先级越高 (Cortex-M0+推荐5~8级) */
#define configMAX_PRIORITIES 5
/* 空闲任务最小堆栈大小 (单位:字,1字=4字节),M0+小资源芯片精简配置 */
#define configMINIMAL_STACK_SIZE 64
/* 任务名称最大字符串长度,精简内核可减小内存占用 */
#define configMAX_TASK_NAME_LEN 8
/* 系统节拍计数器位数,32位适合长时间运行,无溢出风险 */
#define configTICK_TYPE_WIDTH_IN_BITS TICK_TYPE_WIDTH_32_BITS
/* 空闲任务是否主动让出CPU:1=开启,提高其他同优先级任务响应速度 */
#define configIDLE_SHOULD_YIELD 1
/* *************************************************************************
* 2. 调度器配置
* ************************************************************************/
/* 1=抢占式调度(高优先级任务打断低优先级),0=协作式调度,FreeRTOS默认开启 */
#define configUSE_PREEMPTION 1
/* 时间片调度:0=关闭,同优先级任务不会轮流执行,适合小资源MCU */
#define configUSE_TIME_SLICING 0
/* 优化任务选择算法:Cortex-M0+不支持硬件优化,必须关闭 */
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
/* 低功耗tickless模式:0=关闭,适合普通应用;低功耗项目可开启 */
#define configUSE_TICKLESS_IDLE 0
/* *************************************************************************
* 3. 内存管理配置
* ************************************************************************/
/* 静态内存分配:0=关闭,不使用静态创建任务/队列,简化开发 */
#define configSUPPORT_STATIC_ALLOCATION 0
/* 动态内存分配:1=开启,使用FreeRTOS内存堆创建任务/队列,推荐新手使用 */
#define configSUPPORT_DYNAMIC_ALLOCATION 1
/* 动态内存堆总大小 (单位:字节),HC32L021小RAM,精简配置1.5KB */
#define configTOTAL_HEAP_SIZE 1536
/* 用户自定义内存堆:0=关闭,使用FreeRTOS自带内存管理 */
#define configAPPLICATION_ALLOCATED_HEAP 0
/* *************************************************************************
* 4. 中断优先级配置 (Cortex-M0+核心)
* ************************************************************************/
/* 内核中断优先级 (PendSV/SysTick),设为最低优先级0,不影响业务中断 */
#define configKERNEL_INTERRUPT_PRIORITY 0
/* 系统调用最高中断优先级,Cortex-M0+仅支持4级优先级,0=最低 */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0
/* API调用最高中断优先级,同上述配置,保持一致避免异常 */
#define configMAX_API_CALL_INTERRUPT_PRIORITY 0
/* *************************************************************************
* 5. 钩子函数(回调函数)配置
* ************************************************************************/
/* 空闲任务钩子:0=关闭,空闲时执行自定义函数,用于低功耗 */
#define configUSE_IDLE_HOOK 0
/* 时钟节拍钩子:1=开启,每1ms执行一次自定义函数 */
#define configUSE_TICK_HOOK 1
/* 内存分配失败钩子:1=开启,内存不足时触发,方便调试 */
#define configUSE_MALLOC_FAILED_HOOK 1
/* 堆栈溢出检测:1=开启,任务堆栈溢出时触发,调试必备 */
#define configCHECK_FOR_STACK_OVERFLOW 1
/* *************************************************************************
* 6. 内核可选功能裁剪
* ************************************************************************/
/* 软件定时器:0=关闭,小资源MCU无需使用 */
#define configUSE_TIMERS 0
/* 事件组:0=关闭,精简内核 */
#define configUSE_EVENT_GROUPS 0
/* 流缓冲区:0=关闭,串口/大量数据传输才使用 */
#define configUSE_STREAM_BUFFERS 0
/* 协程:0=关闭,FreeRTOS废弃功能 */
#define configUSE_CO_ROUTINES 0
/* *************************************************************************
* 7. 硬件外设适配 (HC32L021专用)
* ************************************************************************/
/* MPU内存保护单元:0=关闭,HC32L021无MPU硬件,必须关闭! */
#define configENABLE_MPU 0
/* MPU包装函数:0=关闭,无MPU无需使用 */
#define configUSE_MPU_WRAPPERS_V1 0
/* FPU浮点单元:0=关闭,Cortex-M0+无硬件浮点 */
#define configENABLE_FPU 0
/* TrustZone安全扩展:0=关闭,普通MCU无此功能 */
#define configENABLE_TRUSTZONE 0
/* 仅安全模式运行:0=关闭,无TrustZone无需配置 */
#define configRUN_FREERTOS_SECURE_ONLY 0
/* MVE向量扩展:0=关闭,芯片不支持 */
#define configENABLE_MVE 0
/* 中断处理安装检查:0=关闭,适配GCC端口,解决链接报错 */
#define configCHECK_HANDLER_INSTALLATION 0
/* *************************************************************************
* 8. 任务通信/同步功能
* ************************************************************************/
/* 任务通知:1=开启,轻量级任务同步,替代信号量/队列 */
#define configUSE_TASK_NOTIFICATIONS 1
/* 互斥锁:1=开启,解决多任务资源竞争 */
#define configUSE_MUTEXES 1
/* 递归互斥锁:0=关闭,精简内核 */
#define configUSE_RECURSIVE_MUTEXES 0
/* 计数信号量:1=开启,用于资源计数、同步 */
#define configUSE_COUNTING_SEMAPHORES 1
/* 队列集:0=关闭,精简内核 */
#define configUSE_QUEUE_SETS 0
/* *************************************************************************
* 9. 断言函数(调试专用)
* ************************************************************************/
/* 断言宏:参数不成立时,关闭中断并死循环,快速定位程序BUG */
#define configASSERT( x ) \
if( ( x ) == 0 ) \
{ \
taskDISABLE_INTERRUPTS(); \
for( ; ; ) \
; \
}
/* *************************************************************************
* 10. 可选API函数使能
* ************************************************************************/
#define INCLUDE_vTaskPrioritySet 1 /* 启用 设置任务优先级 API */
#define INCLUDE_uxTaskPriorityGet 1 /* 启用 获取任务优先级 API */
#define INCLUDE_vTaskDelete 1 /* 启用 删除任务 API */
#define INCLUDE_vTaskSuspend 1 /* 启用 挂起任务 API */
#define INCLUDE_xResumeFromISR 1 /* 启用 中断中恢复任务 API */
#define INCLUDE_vTaskDelayUntil 1 /* 启用 绝对延时 API */
#define INCLUDE_vTaskDelay 1 /* 启用 相对延时 API */
#define INCLUDE_xTaskGetSchedulerState 0 /* 关闭 获取调度器状态 API */
#define INCLUDE_xTaskGetCurrentTaskHandle 0 /* 关闭 获取当前任务句柄 API */
#endif /* FREERTOS_CONFIG_H */
R_ARM_THM_JUMP11 编译报错

这里报错的意思是汇编里的跳转指令,能跳的最大距离只有 ±1KB,但要跳的目标函数(vPortSVCHandler_C)在 0xA24 这个位置,超出了芯片允许的跳转范围,硬件做不到,直接报错!
HC32L021 = Cortex-M0+ 内核只支持最简指令集(Thumb-1),普通跳转指令 b 只能跳 ±1024 字节(±1KB)还不支持长跳转指令 b.w。
解决方法是把函数地址放到寄存器里,再用 bx 跳转,想跳多远就跳多远。

c
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" .extern vPortSVCHandler_C \n"
" \n"
" movs r0, #4 \n"
" mov r1, lr \n"
" tst r0, r1 \n"
" beq stacking_used_msp \n"
" \n"
" stacking_used_psp: \n"
" mrs r0, psp \n"
" ldr r3, =vPortSVCHandler_C \n"
" bx r3 \n"
" \n"
" stacking_used_msp: \n"
" mrs r0, msp \n"
" ldr r3, =vPortSVCHandler_C \n"
" bx r3 \n"
" \n"
" .align 4 \n"
);
}
测试下
c
void hello_Task(void *pvParameters)
{
for(;;)
{
printf("hello task\r\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void led_Task(void *pvParameters)
{
for(;;)
{
printf("led task\r\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
int32_t main(void)
{
SysClockConfig();
STK_LedConfig();
GpioConfig();
SpiConfig();
SPI_Enable(SPI);
UartGpioConfig();
LpuartConfig();
xTaskCreate(hello_Task, "hello_Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(led_Task, "hello_Task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
vTaskStartScheduler();
while (1)
{
DDL_Delay1ms(500);
}
}

优雅!