一:前期准备

FreeRTOS源码(我用的是FreeRTOS v202107.00)和成功编译的工程模板(越简单越好)。

源码文件夹如图:

工程文件夹如图:

二:完整移植步骤

1.新建工程文件夹,存放FreeRTOS内核文件

在基础工程中,新建一个名为“FreeRTOS”的文件夹,在文件夹目录下再分别新建src、inc、port文件夹:其中,src文件夹用来存放源码,inc文件夹用来存放头文件,port文件夹用来存放移植平台的相关文件。

FreeRTOS/
├── src/        // 存放内核核心.c文件
├── inc/        // 存放内核核心.h文件
└── port/       // 存放移植层相关文件

建好的文件夹如图所示:

2.复制FreeRTOS核心源码到工程目录

其中,inc文件夹包括:

源码路径:FreeRTOSv202107.00\FreeRTOS\Source\include

include文件夹里全部都是FreeRTOS的头文件,将其全部复制到新建的inc文件夹中(不包括readme)。

移植完成的inc文件应如图:

port文件夹包括:

源文件路径1:FreeRTOSv202107.00\FreeRTOS\Source\portable\MemMang

源文件路径2:FreeRTOSv202107.00\FreeRTOS\Source\portable\RVDS\ARM_CM3

复制路径1目录下的“heap_4.c”到port文件夹,路径2目录下的“port.c”和“port.h”两个文件到port文件夹。

复制完成后,port文件夹下仅保留heap_4.c、port.c、port.h三个文件,如图所示:

src文件夹包括:

源文件路径:FreeRTOSv202107.00\FreeRTOS\Source

将Source文件夹下所有的.c文件全部复制到src文件夹中,如图所示:

添加配置文件:

源文件路径:FreeRTOSv202107.00\FreeRTOS\Demo\CORTEX_STM32F103_Keil

在文件夹中的FreerRTOSConfig.h文件到新建的FreeRTOS文件夹中,如图所示:

3.建立工程组

打开工程,新建三个工程分组(FreeRTOS_SRC、FreeRTOS_INC、FreeRTOS_PORT),与FreeRTOS文件夹下的src、inc、port对应,分别用于存放不同类型的文件,避免与STM32标准库文件混淆,同时保持工程结构清晰,建好的组如图所示:

4.将对应文件加入组

添加src文件夹的6个核心c文件(除去stream_buffer之外的六个文件)到FreeRTOS_SRC组。

添加inc文件夹的所有头文件和配置文件FreeRTOSConfig.h到FreeRTOS_INC组。

添加port文件夹的2个c文件(heap_4.c、port.c)到FreeRTOS_PORT组。

全部添加完成应如图所示:

5.添加头文件路径

在工程中,打开“Options for Target”→“C/C++”→“Include Paths”,添加以下头文件路径:

- ./FreeRTOS
- ./FreeRTOS/src
- ./FreeRTOS/inc
- ./FreeRTOS/port

添加完成应如图所示:

6.修改核心文件

FreeRTOSConfig.h(核心配置文件)

完成中断函数的重定义,在文件夹顶部加入下面三行代码:

// 中断重定向(核心,必须重定向)
#define vPortSVCHandler     SVC_Handler
#define xPortPendSVHandler  PendSV_Handler
#define xPortSysTickHandler SysTick_Handler 

stm32f10x_it.c(中断服务函数,避免冲突)

stm32f10x_it.c是STM32的中断服务函数文件,其中SVC_Handler、PendSV_Handler、SysTick_Handler三个中断函数,与FreeRTOS v202107.00的移植层冲突,必须修改,否则编译报错或死机:

打开stm32f10x_it.c,注释掉上面所说三个函数的空定义代码,如图所示:

修改main.c(创建测试任务,验证移植成功)

在main.c中添加头文件,并创建一个简单的LED闪烁任务,用于验证移植是否成功,代码如下:

#include "stm32f10x.h"
#include "Delay.h"
#include "FreeRTOS.h"
#include "task.h"

TaskHandle_t task1Handler;


static void task1(void *arg)
{
	while(1)
	{
		GPIO_ResetBits(GPIOC, GPIO_Pin_13);
		vTaskDelay(500);
		GPIO_SetBits(GPIOC, GPIO_Pin_13);
		vTaskDelay(500);
	}
}
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	xTaskCreate(task1,"task1",100,NULL,2,&task1Handler);
	vTaskStartScheduler();
	
	while(1);
}

编译无报错、无警告,下载到开发板后:

  • LED按设定频率(500ms)闪烁

  • 调试器查看,程序不进入HardFault_Handler死循环

  • 任务调度正常,无死机、无跑飞现象

三:正/盗版芯片的差异(已解决)

目前,有个现象就是盗版芯片(0X2B开头)能正常跑程序现象,正版芯片(0X1B)无法跑,会卡死在HardFault_Handler函数中:

解决办法:不是芯片不兼容,而是堆空间开太大!

STM32F103C8T6 仅有 20KB RAM,堆空间设置过大会直接内存溢出。

FreeRTOSConfig.h堆空间设置正确配置(正版/盗版都能跑)!

#define configTOTAL_HEAP_SIZE  ((size_t)(8 * 1024))

四:坑点

中断优先级配置

STM32F103移植FreeRTOS v202107.00,优先级必须配置为configKERNEL_INTERRUPT_PRIORITY=255、configMAX_SYSCALL_INTERRUPT_PRIORITY=191,优先级分组必须为Group4,不能乱改。

C8T6 堆空间建议不超过 8KB,正版 ST 对内存溢出零容忍,国产芯片相对宽松。

五:常见报错及解决

L6200E 重复定义:stm32f10x_it.c 中 SVC_Handler、PendSV_Handler 未注释。

进入 HardFault:99% 是 configTOTAL_HEAP_SIZE 设置过大,RAM 溢出。

卡在 vTaskStartScheduler:SysTick 未正常工作,检查中断重定向与优先级分组。

六:重点

SVC_Handler、PendSV_Handler必须重定向,由FreeRTOS v202107.00移植层实现,stm32f10x_it.c中必须注释,不能重复实现。

SysTick的两种实现方式(宏重定向/手动调用)不能同时使用,否则会导致中断冲突,v202107.00版本同样适用。

移植过程中,每修改一处配置,就编译一次,逐步排查,不要一次性修改多处,避免无法定位问题;v202107.00版本编译报错与旧版本一致,可按常规方法排查。

FreeRTOS v202107.00版本无需额外修改移植层文件,核心配置与旧版本一致,直接复用本文配置即可,无需额外适配;文件存放需严格遵循src、inc、port的文件夹划分,便于后续维护。

FreeRTOSConfig.h文件需放在inc文件夹下,与其他核心头文件放在一起,避免路径混乱导致配置文件无法识别。

七:源码及写在后面

FreeRTOSConfig.h

/*
 * FreeRTOS V202107.00
 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * http://www.FreeRTOS.org
 * http://aws.amazon.com/freertos
 *
 * 1 tab == 4 spaces!
 */

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H


// 中断重定向(核心,必须重定向)
#define vPortSVCHandler     SVC_Handler
#define xPortPendSVHandler  PendSV_Handler
#define xPortSysTickHandler SysTick_Handler 

/*-----------------------------------------------------------
 * Application specific definitions.
 *
 * These definitions should be adjusted for your particular hardware and
 * application requirements.
 *
 * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
 * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. 
 *
 * See http://www.freertos.org/a00110.html
 *----------------------------------------------------------*/

#define configUSE_PREEMPTION		1
#define configUSE_IDLE_HOOK			0
#define configUSE_TICK_HOOK			0
#define configCPU_CLOCK_HZ			( ( unsigned long ) 72000000 )	
#define configTICK_RATE_HZ			( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES		( 5 )
#define configMINIMAL_STACK_SIZE	( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE		( ( size_t ) ( 8 * 1024 ) )
#define configMAX_TASK_NAME_LEN		( 16 )
#define configUSE_TRACE_FACILITY	0
#define configUSE_16_BIT_TICKS		0
#define configIDLE_SHOULD_YIELD		1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 		0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet		1
#define INCLUDE_uxTaskPriorityGet		1
#define INCLUDE_vTaskDelete				1
#define INCLUDE_vTaskCleanUpResources	0
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 		255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY	15

#endif /* FREERTOS_CONFIG_H */

本文所有代码均在STM32F103C8T6上实测通过,可直接复制到 工程中使用,无需修改任何参数。

本博客仅记录自己的学习进程,无任何商业用途,基于论坛上已经存在的内容结合自己实操过程完成了此博客,自己也做了一些细节验证,在此记录下来作为学习沉淀。如有侵权,联系速删。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐