【GD32E503评测】IAR环境移植FreeRTOSV202012.00
[复制链接]
本帖最后由 superstar_gu 于 2021-1-27 09:49 编辑
2.5 GD32E503V-EVAL开发板移植FreeRTOS系统
2.5.1 概况
开发板:GD32E503V-EVAL开发板,板载GD32E503VET6,Cortex-M33内核, 512K FLASH,512K RAM, 128K PSRAM
电脑系统:WIN10
编辑器:IAR v8.32.1
2.5.2 FreeRTOS系统内核源码
FreeRTOS内核源码下载链接如下:
https://freertos.org/a00104.html
最新版本为V202012.00,解压缩,FreeRTOS文件夹如下:
Source文件夹包含FreeRTOS内核的源代码,移植FreeRTOS就需要这部分源代码。
2.5.3 LED程序
以LED亮灯程序作为模板,移植FreeRTOS系统。本次测试以开发板例程GPIO_Running_LED作为基础程序,调试并测试完毕。
2.5.4 FreeRTOS移植
1) 在GPIO_Running_LED工程文件夹下新建“src”文件夹,用于保存FreeRTOS中的核心源文件。我们将FreeRTOS内核的源代码下属源程序复制到“src”文件夹内。
2) 在GPIO_Running_LED工程文件夹下新建“inc”文件夹,用于保存FreeRTOS中的一些头文件。我们将FreeRTOS内核的源代码下属“include”文件夹内容复制到“inc”文件夹内。
3) 在GPIO_Running_LED工程文件夹下新建“port”文件夹,用于RTOS硬件接口层。我们将\FreeRTOS\Source\portable\IAR\ARM_CM33\non_secure文件夹内容复制到“port”文件夹内。
说明下,GD32E503V为ARM Cortex-M33架构,且编辑器平台为IAR,所以选择用ARM_CM33文件夹。
4) FreeRTOSConfig.h文件是FreeRTOS的工程配置文件,因为FreeRTOS是可以裁剪的实时操作内核,应用于不同的处理器平台,用户可以通过修改这个FreeRTOS内核的配置头文件来裁剪FreeRTOS的功能,所以我们把它拷贝一份放在user这个文件夹下面。将FreeRTOS内核的源代码下属FreeRTOS\Demo\CORTEX_STM32L152_IAR文件夹FreeRTOSConfig.h复制到“inc”文件夹内。
5) 至此FreeRTOS内核的源代码提取完成。
2.5.5 准备工作
1) 在工程GPIO_Running_LED工程新建分组“FreeRTOS”,将文件夹“inc”“port”“src”放置到该分组文件中
2) 添加头文件路径
3) 修改FreeRTOSConfig.h
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
FreeRTOSConfig.h该头文件对裁剪整个FreeRTOS所需的功能的宏均做了定义,有些宏定义被使能,有些宏定义被失能。
把configUSE_IDLE_HOOK、configUSE_TICK_HOOK、configCHECK_FOR_STACK_OVERFLOW、configUSE_MALLOC_FAILED_HOOK这几个宏定义设为0。
/* 置1:使用空闲钩子(Idle Hook类似于回调函数);置0:忽略空闲钩子
* * 空闲任务钩子是一个函数,这个函数由用户来实现,
* FreeRTOS规定了函数的名字和参数:void vApplicationIdleHook(void ),
* 这个函数在每个空闲任务周期都会被调用
* 对于已经删除的RTOS任务,空闲任务可以释放分配给它们的堆栈内存。
* 因此必须保证空闲任务可以被CPU执行
* 使用空闲钩子函数设置CPU进入省电模式是很常见的
* 不可以调用会引起空闲任务阻塞的API函数
*/
#define configUSE_IDLE_HOOK 0 /*change from 1 to 0*/
/* 置1:使用时间片钩子(Tick Hook);置0:忽略时间片钩子
* * 时间片钩子是一个函数,这个函数由用户来实现,
* FreeRTOS规定了函数的名字和参数:void vApplicationTickHook(void )
* 时间片中断可以周期性的调用
* 函数必须非常短小,不能大量使用堆栈,
* 不能调用以”FromISR" 或 "FROM_ISR”结尾的API函数
*/
/*xTaskIncrementTick函数是在xPortSysTickHandler中断函数中被调用的。因此,vApplicationTickHook()函数执行的时间必须很短才行*/
#define configUSE_TICK_HOOK 0 /*change from 1 to 0*/
/*
* 大于0时启用堆栈溢出检测功能,如果使用此功能
* 用户必须提供一个栈溢出钩子函数,如果使用的话
* 此值可以为1或者2,因为有两种栈溢出检测方法 */
#define configCHECK_FOR_STACK_OVERFLOW 0 /*change from 2 to 0*/
//使用内存申请失败钩子函数
#define configUSE_MALLOC_FAILED_HOOK 0 /*change from 1 to 0*/
注释掉时间状态相关宏定义
/* Run time stats related macros. */
/*#define configGENERATE_RUN_TIME_STATS 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats()
#define portALT_GET_RUN_TIME_COUNTER_VALUE( ulCountValue ) \
{ \
TIM_Cmd( TIM6, DISABLE ); \
ulCountValue = ( ( ulTIM6_OverflowCount << 16UL ) | ( unsigned long ) TIM6->CNT ); \
TIM_Cmd( TIM6, ENABLE ); \
}
*/
4) 修改gd32e50x_it.c
SysTick中断服务函数,FreeRTOS所有跟时间相关的事情都在里面处理,SysTick就是FreeRTOS的一个心跳时钟,驱动着FreeRTOS的运行,就像人的心跳一样,假如没有心跳,我们就相当于“死了”,同样的,FreeRTOS没有了心跳,那么它就会卡死在某个地方,不能进行任务调度,不能运行任何的东西,因此我们需要实现一个FreeRTOS的心跳时钟,FreeRTOS帮我们实现了SysTick的启动的配置:在port.c文件中已经实现vPortSetupTimerInterrupt()函数,并且FreeRTOS通用的SysTick中断服务函数也实现了:在port.c文件中已经实现xPortSysTickHandler()函数,所以移植的时候只需要我们在gd32e50x_it.c文件中实现我们对应平台上的SysTick_Handler()函数即可。FreeRTOS为开发者考虑得特别多,PendSV_Handler()与SVC_Handler()这两个很重要的函数都帮我们实现了,在在port.c文件中已经实现xPortPendSVHandler()与vPortSVCHandler()函数,防止我们自己实现不了,那么在gd32e50x_it.c中就需要我们注释掉PendSV_Handler()与SVC_Handler()这两个函数了。
屏蔽掉SVC_Handler、PendSV_Handler、SysTick_Handler三个函数。
/*
void SVC_Handler(void)
{
}
*/
/*
void PendSV_Handler(void)
{
}
*/
/*
void SysTick_Handler(void)
{
delay_decrement();
}
*/
工程中把HAL库与FreeRTOS共用Systic,所以在FreeRTOS的xPortSysTickHandler函数中添加HAL_IncTick函数的执行。
5) 创建任务(Main.c)
(1) 在main.c中包含有关于FreeRTOS的.h文件
/* FreeRTOS header file */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "croutine.h"
(2) 创建任务句柄和入口函数
/* create tast handle */
static TaskHandle_t AppTask_Handle = NULL;
/* AppTask function*/
static void AppTaskCreate(void);
static void vTaskLED(void* parameter)
{
while (1)
{
/* turn on LED1 */
gpio_bit_set(GPIOC, GPIO_PIN_0);
/* insert 200 ms delay */
delay_1ms(200);
/* turn on LED2 */
gpio_bit_set(GPIOC, GPIO_PIN_2);
/* insert 200 ms delay */
delay_1ms(200);
/* turn on LED3 */
gpio_bit_set(GPIOE, GPIO_PIN_0);
/* insert 200 ms delay */
delay_1ms(200);
/* turn on LED4 */
gpio_bit_set(GPIOE, GPIO_PIN_1);
/* insert 200 ms delay */
delay_1ms(200);
/* turn off LEDs */
gpio_bit_reset(GPIOC, GPIO_PIN_0 | GPIO_PIN_2);
gpio_bit_reset(GPIOE, GPIO_PIN_0 | GPIO_PIN_1);
/* insert 200 ms delay */
delay_1ms(200);
}
}
(3) 创建并启动调度器
/* 创建AppTaskCreate任务 */
xReturn = xTaskCreate((TaskFunction_t )vTaskLED, /* 任务入口函数 */
(const char* )"vTaskLED",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL,/* 任务入口函数参数 */
(UBaseType_t )1, /* 任务的优先级 */
(TaskHandle_t* )&AppTask_Handle);/* 任务控制块指针 */
2.5.6 总结
编译后下载程序,观察到板子上LD1开始闪烁,任务创建并成功运行。
GD32E503VET6为Cortex-M33架构,新版本FREERTOS新增了时间状态相关宏定义,若时间充裕可以研究,一般可以注释掉.
|