2、FreeRTOS移植

一、前言

本文是基于FreeRTOS操作系统的移植,使用到的芯片是STM32F407ZET6平台上,移植环境使用的是MDK5.32版本,首先要准备一个裸机工程源码,我这里随便选择了一个 正点原子 探索者的串口例程,选择的是hal库,其实标准库也是一样的。为什么我一定要手动移植呢,如果用stm32cubemx生成的话,达不到学习的效果,里面什么都配置好了,对学习的帮助很少,所以才会复习的时候选择自己手动移植。

二、裸机代码修改

​ 原子哥的代码自己写了delay的函数,我们先注释delay_init,因为hal的Hal_Delay()和外设驱动超时机制用的是SysTick中断,但是这个中断我们需要给Freertos使用,所以需要用其他定时器替换。

1、注释 delay_init()

2、修改 main函数里面 串口相关的代码

int main(void)
{
    
    
		u8 len;	
		u16 times=0;

		HAL_Init();                    	//初始化HAL库    
		Stm32_Clock_Init(336,8,2,7);  	//设置时钟,168Mhz
		//delay_init(168);               	//初始化延时函数
		uart_init(115200);              //初始化USART
		LED_Init();						//初始化LED	
		KEY_Init();                     //初始化按键
	
    while(1)
    {
    
    
			printf("Hello is ok\r\n");
			HAL_Delay(1000);
//       if(USART_RX_STA&0x8000)
//		{					   
//			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
//			printf("\r\n您发送的消息为:\r\n");
//			HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000);	//发送接收到的数据
//			while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);		//等待发送结束
//			printf("\r\n\r\n");//插入换行
//			USART_RX_STA=0;
//		}else
//		{
    
    
//			times++;
//			if(times%5000==0)
//			{
    
    
//				printf("\r\nALIENTEK 探索者STM32F407开发板 串口实验\r\n");
//				printf("正点原子@ALIENTEK\r\n\r\n\r\n");
//			}
//			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
//			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
//			delay_ms(10);   
//		} 
    }
}

3、修改 HAL_InitTick()函数

因为这个函数是维护hal库用的,

SystickHAL库中作用:

1.外设驱动程序的超时判断;
2.HAL_Delay()函数的时基;

进入 main()—>HAL_Init()—> HAL_InitTick(TICK_INT_PRIORITY);
我们需要换成其他的定时器,这里我们选择定时器1,因为HAL_InitTick() 是应用____weak____修饰的弱函数,我们可以直接重定义,找一个地方写一个HAL_InitTick()

image-20220727151245558

重新写的代码就不要用____weak____了 不能再___weak___ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) 所在文件下重定义,这个是因为(weak)的作用,我选择在stm32f4xx_it.c下面

#include "stm32f4xx_hal_tim.h"
#include "stm32f4xx_hal.h"
TIM_HandleTypeDef        htim1;
extern uint32_t uwTickPrio; /* Invalid PRIO */

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    
    

	
	RCC_ClkInitTypeDef    clkconfig;
  uint32_t              uwTimclock = 0U;

  uint32_t              uwPrescalerValue = 0U;
  uint32_t              pFLatency;
  HAL_StatusTypeDef     status;

  /* Enable TIM1 clock */
  __HAL_RCC_TIM1_CLK_ENABLE();

  /* Get clock configuration */
  HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);

  /* Compute TIM1 clock */
  uwTimclock = 2*HAL_RCC_GetPCLK2Freq();

  /* Compute the prescaler value to have TIM1 counter clock equal to 1MHz */
  uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U);

  /* Initialize TIM1 */
  htim1.Instance = TIM1;

  /* Initialize TIMx peripheral as follow:
  + Period = [(TIM1CLK/1000) - 1]. to have a (1/1000) s time base.
  + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock.
  + ClockDivision = 0
  + Counter direction = Up
  */
  htim1.Init.Period = (1000000U / 1000U) - 1U;
  htim1.Init.Prescaler = uwPrescalerValue;
  htim1.Init.ClockDivision = 0;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

  status = HAL_TIM_Base_Init(&htim1);
  if (status == HAL_OK)
  {
    
    
    /* Start the TIM time Base generation in interrupt mode */
    status = HAL_TIM_Base_Start_IT(&htim1);
    if (status == HAL_OK)
    {
    
    
    /* Enable the TIM1 global Interrupt */
        HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
      /* Configure the SysTick IRQ priority */
      if (TickPriority < (1UL << __NVIC_PRIO_BITS))
      {
    
    
        /* Configure the TIM IRQ priority */
        HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, TickPriority, 0U);
        uwTickPrio = TickPriority;
      }
      else
      {
    
    
        status = HAL_ERROR;
      }
    }
  }
	
}

当然这样修改了 还是不行的,你这样下载进去会卡死在B .

image-20220727151917287

单步调试程序卡在 HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);就进不去了,这个是因为打开了timer1中断,还没有写入定时器1的中断函数。

image-20220727151714426

4、添加定时器1中断

那么现在我们写一下定时器的中断 在stm32f4xx_it.c 里面去添加

/**
  * @brief This function handles TIM1 update interrupt and TIM10 global interrupt.
  */
void TIM1_UP_TIM10_IRQHandler(void)
{
    
    
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */
	 HAL_IncTick();
  /* USER CODE END TIM1_UP_TIM10_IRQn 0 */
    HAL_TIM_IRQHandler(&htim1);
  /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */

  /* USER CODE END TIM1_UP_TIM10_IRQn 1 */
}


5、取消sysick中断的SysTick_Handler

如果不取消会有不可估计的bug

image-20220727170616463

6、实验systick 移植现象

现在我们下载代码,看看能不能1s打印一次数据,ok!移植成功,现在要移植freertos

image-20220727154450528

三、Freertos移植

1、Freertos 下载

获取源码可以直接到FreeRTOS的官网获取,官网:https://www.freertos.org/ 。

image-20220727155946682

下载会有点慢 我已经准备好了

链接:https://pan.baidu.com/s/12ao3oX2q53fDGA8HkCygjw?pwd=5djt
提取码:5djt
–来自百度网盘超级会员V4的分享

image-20220727160054781

2、 FreeRTOS目录结构

我们解压出来后,就得到了FreeRTOS的源码了,里面包含了所需要的全部源码资料。这里对FreeRTOSv10.4.0版本的源码目录结构简单介绍一下。解压出来后,目录结构如下图

image-20220727160754509


├─FreeRTOS
│  ├─Demo               // 集成开发环境完整的Demo模板
│  ├─License            // 许可证相关
│  └─Source             // FreeRTOS的源码,非常重要,移植就是使用该目录里面的源码了
│      ├─include        // 源码的头文件
│      └─portable       // 不同硬件平台相关的代码
│            ├─MemMang  // FreeRTOS内存管理方案,我们选择其中一个文件即可
│            │     heap_1.c
│            │     heap_2.c
│            │     heap_3.c
│            │     heap_4.c
│            │     heap_5.c
│   		 ├─RVDS		// ARM架构相关的代码,我们在里面选择其中的CM3架构目录即可 
│            └─其他     // 其他架构、开发平台相关的代码
│      croutine.c       // 协线程(协程)文件,和任务类似,在系统资源比较缺乏下使用
│      event_groups.c   // 事件标志组
│      list.c           // 列表结构描述,在内核整体控制上都使用了列表格式数据处理,一切数据结构的基础
│      queue.c          // 队列,任务和任务之间的通讯处理
│      tasks.c          // 所有任务相关函数
│      timers.c         // 软件定时器,以任务形式存在
│      stream_buffer.c  // 流缓冲区文件,该文件是v10.0.0新增的,v9.0.0没有
|─FreeRTOS-Plus         // FreeRTOS生态相关的文件,基本用不到
|-tools					// 使用python和js编写的一些脚本和工具 都用不到
......					// 剩下的都是一些文档 我们也用不了

3、在裸机工程里面新建一个FreeRTOS文件夹

image-20220727162810745

4、复制核心文件

移动FreeRTOS工程下面的Source文件先移动到裸机下面的FreeRTOS文件夹下面

image-20220727163025487

5、FreeRTOS\portable 文件夹修剪

只留下这三个文件夹(其他的是其他编译器的 我们只需要keil的)

image-20220727163249357

6、工程添加文件

把刚刚移植的文件添加到工程里面 选择heap4.c的内存管理方式和我们单片机的m4内核

image-20220727164013765

7、添加头文件编译

把头文件添加进入工程里面编译

image-20220727164314745

image-20220727165004093

8、解决没有FreeRTOSConfig.h

编译以后,看到没有FreeRTOSConfig.h

image-20220727165035237

这个文件,FreeRTOS 例程里面的预定义很少,不全,这里我贴出原子哥写的


/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.

    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?

    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.

    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.

    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
*/


#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "sys.h"
#include "usart.h"
//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

/***************************************************************************************************************/
/*                                        FreeRTOS基础配置配置选项                                              */
/***************************************************************************************************************/
#define configUSE_PREEMPTION					1                       //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING					1						//1使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION	1                       //1启用特殊方法来选择下一个要运行的任务
                                                                        //一般是硬件计算前导零指令,如果所使用的
                                                                        //MCU没有这些硬件指令的话此宏应该设置为0!
#define configUSE_TICKLESS_IDLE					0                       //1启用低功耗tickless模式
#define configUSE_QUEUE_SETS					1                       //为1时启用队列
#define configCPU_CLOCK_HZ						(SystemCoreClock)       //CPU频率
#define configTICK_RATE_HZ						(1000)                  //时钟节拍频率,这里设置为1000,周期就是1ms
#define configMAX_PRIORITIES					(32)                    //可使用的最大优先级
#define configMINIMAL_STACK_SIZE				((unsigned short)130)   //空闲任务使用的堆栈大小
#define configMAX_TASK_NAME_LEN					(16)                    //任务名字字符串长度

#define configUSE_16_BIT_TICKS					0                       //系统节拍计数器变量数据类型,
                                                                        //1表示为16位无符号整形,0表示为32位无符号整形
#define configIDLE_SHOULD_YIELD					1                       //为1时空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configUSE_TASK_NOTIFICATIONS            1                       //为1时开启任务通知功能,默认开启
#define configUSE_MUTEXES						1                       //为1时使用互斥信号量
#define configQUEUE_REGISTRY_SIZE				8                       //不为0时表示启用队列记录,具体的值是可以
                                                                        //记录的队列和信号量最大数目。
#define configCHECK_FOR_STACK_OVERFLOW			0                       //大于0时启用堆栈溢出检测功能,如果使用此功能
                                                                        //用户必须提供一个栈溢出钩子函数,如果使用的话
                                                                        //此值可以为1或者2,因为有两种栈溢出检测方法。
#define configUSE_RECURSIVE_MUTEXES				1                       //为1时使用递归互斥信号量
#define configUSE_MALLOC_FAILED_HOOK			0                       //1使用内存申请失败钩子函数
#define configUSE_APPLICATION_TASK_TAG			0                       
#define configUSE_COUNTING_SEMAPHORES			1                       //为1时使用计数信号量

/***************************************************************************************************************/
/*                                FreeRTOS与内存申请有关配置选项                                                */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请
#define configTOTAL_HEAP_SIZE					((size_t)(20*1024))     //系统所有总的堆大小

/***************************************************************************************************************/
/*                                FreeRTOS与钩子函数有关的配置选项                                              */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK						0                       //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK						0                       //1,使用时间片钩子;0,不使用

/***************************************************************************************************************/
/*                                FreeRTOS与运行时间和任务状态收集有关的配置选项                                 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS	        0                       //为1时启用运行时间统计功能
#define configUSE_TRACE_FACILITY				1                       //为1启用可视化跟踪调试
#define configUSE_STATS_FORMATTING_FUNCTIONS	1                       //与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
                                                                        //prvWriteNameToBuffer(),vTaskList(),
                                                                        //vTaskGetRunTimeStats()
                                                                        
/***************************************************************************************************************/
/*                                FreeRTOS与协程有关的配置选项                                                  */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES 			        0                       //为1时启用协程,启用协程以后必须添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES         ( 2 )                   //协程的有效优先级数目

/***************************************************************************************************************/
/*                                FreeRTOS与软件定时器有关的配置选项                                            */
/***************************************************************************************************************/
#define configUSE_TIMERS				        1                               //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        //软件定时器优先级
#define configTIMER_QUEUE_LENGTH		        5                               //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH	        (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小

/***************************************************************************************************************/
/*                                FreeRTOS可选函数配置选项                                                      */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState          1                       
#define INCLUDE_vTaskPrioritySet		        1
#define INCLUDE_uxTaskPriorityGet		        1
#define INCLUDE_vTaskDelete				        1
#define INCLUDE_vTaskCleanUpResources	        1
#define INCLUDE_vTaskSuspend			        1
#define INCLUDE_vTaskDelayUntil			        1
#define INCLUDE_vTaskDelay				        1
#define INCLUDE_eTaskGetState			        1
#define INCLUDE_xTimerPendFunctionCall	        1

/***************************************************************************************************************/
/*                                FreeRTOS与中断有关的配置选项                                                  */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4                  
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15                      //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/***************************************************************************************************************/
/*                                FreeRTOS与中断服务函数有关的配置选项                                          */
/***************************************************************************************************************/
#define xPortPendSVHandler 	PendSV_Handler
#define vPortSVCHandler 	SVC_Handler
#define xPortSysTickHandler		SysTick_Handler
#endif /* FREERTOS_CONFIG_H */


8、修改stm32f4xx_it.c

xPortPendSVHandler()

vPortSVCHandler()

xPortSysTickHandler()

这三个中断需要给FreeRTOS 使用和hal库冲突了,我们屏蔽hal库的这三个中断函数

image-20220727170751972

9、编译有错误(1)

…\FreeRTOS\queue.c(2762): error: #268: declaration may not appear after executable statement in block

​ QueueRegistryItem_t * pxEntryToWrite = NULL;

image-20220727170848061

10、解决办法(1)

在Keil的魔术棒中C/C++选项卡下选择C99mode,该模式下能通过以下省略参数的语句,

image-20220727170915115

11、还有错误(2)

…\FreeRTOS\portable\RVDS\ARM_CM4F\port.c(482): error: A1586E: Bad operand types (UnDefOT, Constant) for operator (

image-20220727171054700

12、解决错误(2)

定位问题

image-20220727171147636

往上找

image-20220727171225372

最终问题找到

image-20220727171302107

最后发现 6<<(8-4U)

4U unsigned int 4

解决方法 U去掉

13、因此编译至此通过,移植也就到此结束了。

工程下载

https://download.csdn.net/download/mayuxin1314/86263318

image-20220727171349642

猜你喜欢

转载自blog.csdn.net/mayuxin1314/article/details/126019667
今日推荐