STM32标准库移植FreeRTOS(以F407为例)

STM32标准库移植FreeRTOS(以F407为例)

前言

尝试过CubeMX直接生成HAL库+FreeRTOS;也尝试过CubeMX生成HAL库+手动移植FreeRTOS;正点原子也有手动HAL+手动FreeRTOS;
这里想要记录一下标准库+手动移植FreeRTOS


下载FreeRTOS源码

可以直接在浏览器搜索 “ FreeRTOS ” 下载,或者直接点此条博客的绑定资源。
在这里插入图片描述

新建新建stm32标准库空白工程模板

这个根据自己的已有模板创建使用,这里不做讲解。

移植

  • 在工程文件夹内建立《FreeRTOS》文件夹,将 资料\FreeRTOS源码\FreeRTOSv9.0.0\FreeRTOS\Source里的文件全部拷入其中
    在这里插入图片描述
    在这里插入图片描述

  • 删除工程 stm32标准库工程模板\FreeRTOS\portable 里的文件,仅保留keil》《MemMang 》《RVDS》三个文件夹(或者在前一步拷贝的时候仅拷贝这三个文件夹)
    在这里插入图片描述

  • 打开工程,点开箱子图标新建两个Group名为《 FreeRTOS_Core 》《 FreeRTOS_Port

  • 在《 FreeRTOS_Core 》中添加源码《FreeRTOS》文件夹里面的 五个.c文件

stm32标准库工程模板\FreeRTOS\ croutine.c
stm32标准库工程模板\FreeRTOS\ event_groups.c
stm32标准库工程模板\FreeRTOS\ list.c
stm32标准库工程模板\FreeRTOS\ queue.c
stm32标准库工程模板\FreeRTOS\ task.c
stm32标准库工程模板\FreeRTOS\ timers.c

在这里插入图片描述

  • 在 《 FreeRTOS_Port 》中添加源码《FreeRTOS》文件夹里面的 两个.c文件

stm32标准库工程模板\FreeRTOS\portable\MemMang\ heap_4.c
stm32标准库工程模板\FreeRTOS\portable\RVDS\ARM_CM4F\ port.c

在这里插入图片描述

  • 进入工程内的stm32f4xx_it.c文件
    注释 这三个函数或者 改成条件宏定义

    // void SysTick_Handler(void){
    //};

    //void PendSV_Handler(void){
    //};

    //void SVC_Handler(void){
    //};

在这里插入图片描述

  • 拷贝 资料\FreeRTOS源码\FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h 的.h配置文件到stm32标准库工程模板\FreeRTOS\include中,并将其添加进工程中(可以放进user的group里)

在这里插入图片描述

  • 点开FreeRTOSConfig.h文件
    将以下宏定义置0

    configUSE_IDLE_HOOK 0
    configUSE_TICK_HOOK 0
    configCHECK_FOR_STACK_OVERFLOW 0
    configUSE_MALLOC_FAILED_HOOK 0

在这里插入图片描述

  • 找到__NVIC_PRIO_BITS的宏定义(可在整个project中直接搜索),如果是 4U改为4

在这里插入图片描述

  • 点开FreeRTOSConfig.h文件
    将:
		/* Ensure stdint is only used by the compiler, and not the assembler. */
		#ifdef __ICCARM__
			#include <stdint.h>
			extern uint32_t SystemCoreClock;
		#endif

改为:(否则报错SystemCoreClock未定义)

		#if defined (__ICCARM__) || defined (__CC_ARM) || defined (__GNUC__) 
			#include <stdint.h>
			extern uint32_t SystemCoreClock;
		#endif

在这里插入图片描述

  • 点开魔术棒 在C/C++下的 Include Paths 添加路径

.\FreeRTOS\include
.\FreeRTOS\portable\RVDS\ARM_CM4F

在这里插入图片描述

  • 编译通过

点灯试验

  • 在main.c添加头文件 :

#include “FreeRTOS.h”
#include “task.h”

  • 在main函数外上面定义任务
	#define START_TASK_PRIO			1
	#define START_STK_SIZE			120
	void start_task(void * pvParameters);  //任务函数
	TaskHandle_t StartTask_Handler;		//任务句柄	 
 
 
	#define TASK1_TASK_PRIO			2
	#define TASK1_STK_SIZE			120
	void task1_task(void * pvParameters);
	TaskHandle_t Task1Task_Handler;		//任务句柄	 
 
	#define TASK2_TASK_PRIO			3
	#define TASK2_STK_SIZE			120 
	void task2_task(void * pvParameters);
	TaskHandle_t Task2Task_Handler;		//任务句柄

  • 在main函数内部初始化外设创建初始任务
    注意优先级分组为4,全为抢占优先级,去除main函数内的while函数
	xTaskCreate((TaskFunction_t	) start_task,
				(char*			) "start_task",
				(uint16_t		) START_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) START_TASK_PRIO,
				(TaskHandle_t*	) &StartTask_Handler);
	vTaskStartScheduler();          //开启任务调度
  • 在main函数外下面写任务函数
void start_task(void * pvParameters)
	{
		//创建Task1
		taskENTER_CRITICAL();               /* 进入临界区 */
		xTaskCreate((TaskFunction_t	) task1_task,
				(char*			) "task1_task",
				(uint16_t		) TASK1_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) TASK1_TASK_PRIO,
				(TaskHandle_t*	) &Task1Task_Handler);
				
		//创建Task2
		xTaskCreate((TaskFunction_t	) task2_task,
				(char*			) "task2_task",
				(uint16_t		) TASK1_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) TASK2_TASK_PRIO,
				(TaskHandle_t*	) &Task2Task_Handler);
		vTaskDelete(StartTask_Handler); //NULL
		 taskEXIT_CRITICAL();                /* 退出临界区 */	
}


 
	void task1_task(void * pvParameters){
		
		while(1){

		}
	}
 
	void task2_task(void * pvParameters){
	
		while(1){

		}
	}
  • 编译下载

main函数

#include "stm32f4xx.h"                  // Device header
#include "delay.h"
#include "usart.h"
#include "LED.h"

#include "FreeRTOS.h"
#include "task.h"

#define START_TASK_PRIO			1
#define START_STK_SIZE			120
void start_task(void * pvParameters);  //任务函数
TaskHandle_t StartTask_Handler;		//任务句柄	 


#define TASK1_TASK_PRIO			2
#define TASK1_STK_SIZE			120
void task1_task(void * pvParameters);
TaskHandle_t Task1Task_Handler;		//任务句柄	 

#define TASK2_TASK_PRIO			3
#define TASK2_STK_SIZE			120 
void task2_task(void * pvParameters);
TaskHandle_t Task2Task_Handler;		//任务句柄
	
	
int main(){
	delay_init(168);
	uart_init(9600);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);	
	printf("Start !\r\n");

	LED_Init();
	
	xTaskCreate((TaskFunction_t	) start_task,
				(char*			) "start_task",
				(uint16_t		) START_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) START_TASK_PRIO,
				(TaskHandle_t*	) &StartTask_Handler);
	    vTaskStartScheduler();          //开启任务调度

}


	void start_task(void * pvParameters)
	{
		//创建Task1
		taskENTER_CRITICAL();               /* 进入临界区 */
		xTaskCreate((TaskFunction_t	) task1_task,
				(char*			) "task1_task",
				(uint16_t		) TASK1_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) TASK1_TASK_PRIO,
				(TaskHandle_t*	) &Task1Task_Handler);
				
		//创建Task2
		xTaskCreate((TaskFunction_t	) task2_task,
				(char*			) "task2_task",
				(uint16_t		) TASK1_STK_SIZE,
				(void * 		) NULL,
				(UBaseType_t	) TASK2_TASK_PRIO,
				(TaskHandle_t*	) &Task2Task_Handler);
		vTaskDelete(StartTask_Handler); //NULL
		taskEXIT_CRITICAL();                /* 退出临界区 */	
	}


 
	void task1_task(void * pvParameters){
		
		while(1){
			
			LED1(1);
			vTaskDelay(1000);//延时函数
			LED1(0);
			vTaskDelay(1000);

		}
	}
 
	void task2_task(void * pvParameters){
	
		while(1){
			
			LED2(1);
			vTaskDelay(1000);
			LED2(0);
			vTaskDelay(1000);
		}
	}

delay函数实现(不会引起任务调度)

  • 包含头文件

#include “FreeRTOS.h”
#include “task.h”

  • 重新定义SysTick_Handler函数
extern void xPortSysTickHandler(void);
/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks : 延时的节拍数  
 * @retval    无
 */  
void SysTick_Handler(void)
{

    /* OS 开始跑了,才执行正常的调度处理 */
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}
  • 进入FreeRTOSConfig.h 文件
    注释掉(避免重定义,因为刚刚在delay函数里已经定义过了)

// #define xPortSysTickHandler SysTick_Handler

  • 重新实现delay_init 、 delay_us、 delay_ms 函数

delay函数

#include "delay.h"
#include "sys.h"
// 	 

#include "FreeRTOS.h"
#include "task.h"

static uint32_t g_fac_us = 0;       /* us延时倍乘数 */
extern void xPortSysTickHandler(void);

/**
 * @brief     systick中断服务函数,使用OS时用到
 * @param     ticks : 延时的节拍数  
 * @retval    无
 */  
void SysTick_Handler(void)
{

    /* OS 开始跑了,才执行正常的调度处理 */
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}



/**
 * @brief     初始化延迟函数
 * @param     sysclk: 系统时钟频率, 即CPU频率(rcc_c_ck), 180MHz
 * @retval    无
 */  
void delay_init(uint16_t sysclk)
{
  /* 如果需要支持OS */
    uint32_t reload;

    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);	/* SYSTICK使用外部时钟源,频率为HCLK */
    g_fac_us = sysclk;                                  /* 不论是否使用OS,g_fac_us都需要使用 */
  /* 如果需要支持OS. */
    reload = sysclk;                                    /* 每秒钟的计数次数 单位为M */
    reload *= 1000000 / configTICK_RATE_HZ;            	/* 根据delay_ostickspersec设定溢出时间,reload为24位
                                                         * 寄存器,最大值:16777216,在180M下,约合0.0932s左右  */
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;          /* 开启SYSTICK中断 */
    SysTick->LOAD = reload;                             /* 每1/delay_ostickspersec秒中断一次 */
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;           /* 开启SYSTICK */
}



/**
 * @brief     延时nus
 * @param     nus: 要延时的us数
 * @note      注意: nus的值,不要大于93206us(最大值即2^24 / g_fac_us @g_fac_us = 180)
 * @retval    无
 */ 
void delay_us(uint32_t nus)
{
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;        /* LOAD的值 */
    ticks = nus * g_fac_us;                 /* 需要的节拍数 */
    told = SysTick->VAL;                    /* 刚进入时的计数器值 */
    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            if (tnow < told)
            {
                tcnt += told - tnow;        /* 这里注意一下SYSTICK是一个递减的计数器就可以了 */
            }
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;
            if (tcnt >= ticks) 
            {
                break;                      /* 时间超过/等于要延迟的时间,则退出 */
            }
        }
    }
        
} 

/**
 * @brief     延时nms
 * @param     nms: 要延时的ms数 (0< nms <= 65535) 
 * @retval    无
 */
void delay_ms(uint16_t nms)
{
    uint32_t i;
    for (i=0; i<nms; i++)
    {
        delay_us(1000);
    }
}




  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值