stm32l476移植FreeRTOS
1. 环境描述
mcu:stm32l476
IDE:iar for arm(v7)
库:HAL
2. 内容简述
cubemx生成iar程序(带uart),iar下移植FreeRTOS!
3. 操作
1) cubemx生成iar程序
1> 时钟树
2> uart设置
3> led灯io口输出
4> 滴答定时器更改源
由于FreeRTOS使用系统嘀嗒定时器当作心跳,HAL库也使用了这个定时器当作超时计数用,FreeRTOS和HAL库不能同时使用SysTick定时器,所在在这里将HAL库的定时器改为其他的定时器(TIM4)
5> 生成iar代码
2)iar下实现printf重定向
3)移植FreeRTOS
1> FreeRTOS源码下载
官网下载: FreeRTOS
2> 源码移植
iar工程文件下新建文件夹FreeRTOS
FreeRTOS源码:FreeRTOSv202107.00\FreeRTOS\Source下的所有文件复制至iar工程文件下新建的FreeRTOS文件夹
iar工程文件下FreeRTOS文件夹内容修改:portable文件夹下仅保留IAR文件夹、MemMang文件夹
IAR文件夹内容修改:仅保留ARM_CM4F文件夹
3> iar工程添加源码
- 添加文件:
CORE下文件路径:FreeRTOS\FreeRTOS
PORTABLE下文件路径:FreeRTOS\FreeRTOS\portable\MemMang、 FreeRTOS\FreeRTOS\portable\IAR\ARM_CM4F
- 添加头文件路径
4> iar文件修改
打开stm32f1xx_it.c文件,在头部添加FreeRTOS的三个函数导入:
extern void xPortPendSVHandler(void);
extern void xPortSysTickHandler(void);
extern void vPortSVCHandler(void);
在函数SVC_Handler中添加函数调用:
在函数PendSV_Handler中添加函数调用:
在函数SysTick_Handler中添加函数调用:
新建一个名为FreeRTOSConfig.h的文件,保存于FreeRTOS\FreeRTOS\include路径下,这是FreeRTOS的配置文件,贴一个配置:
#ifndef FREERTOS_CONFIG_H__
#define FREERTOS_CONFIG_H__
/*
* 关于本文件宏的详细说明可参考:https://blog.csdn.net/zhzht19861011/article/details/50134883#
*/
// 设置为1使用抢占式,为0使用时间片轮转调度。
#define configUSE_PREEMPTION 1
// 设置为1使能低功耗tickless模式,为0保持系统节拍(tick)中断一直运行。
#define configUSE_TICKLESS_IDLE 0
// 系统时钟主频
#define configCPU_CLOCK_HZ 72000000
// 系统节拍中断的频率,即1s进中断的次数,配置为1000就是一秒进1000次中断,系统节拍就是1s。
#define configTICK_RATE_HZ 1000
// 任务最大优先级,对于STM32来说最大不要超过32
#define configMAX_PRIORITIES 32
// 任务最小栈大小
#define configMINIMAL_STACK_SIZE 64
// FreeRTOR堆空间大小
#define configTOTAL_HEAP_SIZE 8192
// 任务名称最大长度
#define configMAX_TASK_NAME_LEN 16
// 系统节拍计数器的变量类型,即定义portTickType是表示16位变量还是32位变量。
#define configUSE_16_BIT_TICKS 0
// 设置为1允许任务调度,为0不允许(时间片耗尽才让出CPU使用权),该参数抢占式方式下才生效
#define configIDLE_SHOULD_YIELD 1
// 设置是否使用互斥量
#define configUSE_MUTEXES 1
// 设置是否使用递归互斥量
#define configUSE_RECURSIVE_MUTEXES 0
// 设置是否使用计数信号量
#define configUSE_COUNTING_SEMAPHORES 0
// 设置可以记录的队列和信号量的最大数目
#define configQUEUE_REGISTRY_SIZE 10
// 是否使用空闲钩子函数
#define configUSE_IDLE_HOOK 0
// 是否使用TICK嘀嗒钩子函数
#define configUSE_TICK_HOOK 0
// 是否使用栈溢出检查
#define configCHECK_FOR_STACK_OVERFLOW 0
// 是否使用内存申请失败钩子函数
#define configUSE_MALLOC_FAILED_HOOK 0
// 是否使用软件定时器
#define configUSE_TIMERS 1
// 设置软件定时器服务/守护进程的优先级
#define configTIMER_TASK_PRIORITY 3
// 设置软件定时器命令队列的长度
#define configTIMER_QUEUE_LENGTH 10
// 设置软件定时器服务/守护进程任务的堆栈深度
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
// STM32的最低优先级
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
// 能够在中断服务函数中安全调用FreeRTOS API的中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 1
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << 4 )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << 4 )
// 将以下定义设置为1以包含API函数,或设置为0排除API函数
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
#define INCLUDE_pcTaskGetTaskName 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 1
#define INCLUDE_xTimerPendFunctionCall 0
#endif /* FREERTOS_CONFIG_H__ */
修改main.c文件,添加头文件:
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
创建了两个任务,任务一为led灯每间隔500ms闪烁一次,任务二为串口每隔1s打印一次白色星期五:
void led_task(void* arg)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
vTaskDelay(500);
}
}
void print_task(void* arg)
{
while(1)
{
printf("白色星期五!\r\n");
vTaskDelay(1000);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
// xTaskCreate函数参数说明:
// 1、任务入口函数
// 2、任务名称
// 3、堆栈大小,单位word
// 4、传递给任务的参数
// 5、任务优先级
// 6、任务句柄
// 创建任务led灯任务
xTaskCreate(led_task, "led_task", 64, NULL, 3, NULL);
// 创建串口打印任务
xTaskCreate(print_task, "print_task", 128, NULL, 5, NULL);
// 启动任务调度
vTaskStartScheduler();
while (1)
{
}
}
此时编译报错:
解决:
重新编译,未报错!
4. 效果
打开串口软件,下载程序至单片机,查看串口助手每隔一秒接收到"黑色星期五!",且led灯间隔闪烁