STM32F4基礎工程移植FreeRTOS

本篇目標:基於上一篇的基礎工程(stm32f4_first_demo)上,移植freertos,建立移植工程(stm32f4_freertos)。

資料準備:


Freertos源文件目錄說明

.
├─FreeRTOS                          //只展示了會用到的子文件夾
│  ├─Demo
│  │  └─CORTEX_M4F_STM32F407ZG-SK   //應用示例,會用到文件夾下的FreeRTOSConfig.h文件
│  ├─License
│  └─Source                         //源代碼文件夾
│      ├─include                    //頭文件
│      └─portable                   //移植相關文件
│          ├─GCC
│          │  └─ARM_CM4F            //在stm32cubeide(gcc)環境下的stm32移植文件
│          ├─MemMang                //內存管理文件
│          └─RVDS
│              └─ARM_CM4F           //在keil環境下的stm32移植文件
└─FreeRTOS-Plus                     //其他freertos應用文件

ps:上述是freertos源文件目錄,一些用不到的目錄做了一些過濾,主要關注這幾個目錄文件就可以了:

  • source 文件目錄,目錄下的 .c 文件爲freertos的核心文件。
  • ARM_CM4F 文件夾下是對應各種stm32的移植文件。
  • MemMang 文件夾下是內存管理文件,一般場景都選擇 heap_4,具體可以在後面分析的時候看。
  • FreeRTOSConfig.h 用於配置 freertos ,可以在demo工程中copy一個然後結合自己的情況修改。

Freertos源文件移植改動

這部分主要涉及的是 freertos 部分的改動。

  1. 我們創建一個 stm32_port 文件夾專門來存放移植相關的配置文件,這樣可以更好的模塊化。
    在這裏插入圖片描述

  2. 複製 MemMang 文件夾到 stm32_port 下,實際用到的是 heap_4.c 文件。

  3. keil環境複製 portable目錄下的 RVDS 文件夾到 stm32_port 下;stm32cubeide複製 portable目錄下的 GCC 文件夾到 stm32_port 下。

  4. 複製 demo 工程中 CORTEX_M4F_STM32F407ZG-SK 文件夾下的 FreeRTOSConfig.h 到 stm32_port 下。
    在這裏插入圖片描述
    以上是修改建立直觀的移植目錄,接下來就是代碼修改,修改 FreeRTOSConfig.h 相關配置項:

// 1. ------------------------------------------------------
//源--45行
#ifdef __ICCARM__
	#include <stdint.h>
	extern uint32_t SystemCoreClock;
#endif
// 修改後:增加不同編譯環境的配置
#if defined (__ICCARM__) || defined (__CC_ARM) || defined (__GNUC__)
	#include <stdint.h>
	extern uint32_t SystemCoreClock;
#endif

// 2. ------------------------------------------------------
// 源--51、52、64、66行,修改宏定義爲0,暫時不需要使用到這些鉤子函數
#define configUSE_IDLE_HOOK				0//1
#define configUSE_TICK_HOOK				0//1
#define configCHECK_FOR_STACK_OVERFLOW	0//2
#define configUSE_MALLOC_FAILED_HOOK	0//1

// 3. ------------------------------------------------------
// 源--124行,註釋宏定義,該中斷函數我們自己實現
//#define xPortSysTickHandler SysTick_Handler

上面是修改的內容,貼一份實際修改後的配置文件:

/*
 * FreeRTOS Kernel V10.3.1
 * 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

/*-----------------------------------------------------------
 * 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
 *----------------------------------------------------------*/

/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined (__ICCARM__) || defined (__CC_ARM) || defined (__GNUC__)
	#include <stdint.h>
	extern uint32_t SystemCoreClock;
#endif

#ifndef USE_OS
#define USE_OS
#endif

#define configUSE_PREEMPTION			1
#define configUSE_IDLE_HOOK				0
#define configUSE_TICK_HOOK				0
#define configCPU_CLOCK_HZ				( SystemCoreClock )
#define configTICK_RATE_HZ				( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES			( 5 )
#define configMINIMAL_STACK_SIZE		( ( unsigned short ) 130 )
#define configTOTAL_HEAP_SIZE			( ( size_t ) ( 75 * 1024 ) )
#define configMAX_TASK_NAME_LEN			( 10 )
#define configUSE_TRACE_FACILITY		1
#define configUSE_16_BIT_TICKS			0
#define configIDLE_SHOULD_YIELD			1
#define configUSE_MUTEXES				1
#define configQUEUE_REGISTRY_SIZE		8
#define configCHECK_FOR_STACK_OVERFLOW	0
#define configUSE_RECURSIVE_MUTEXES		1
#define configUSE_MALLOC_FAILED_HOOK	0
#define configUSE_APPLICATION_TASK_TAG	0
#define configUSE_COUNTING_SEMAPHORES	1
#define configGENERATE_RUN_TIME_STATS	0

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

/* Software timer definitions. */
#define configUSE_TIMERS				1
#define configTIMER_TASK_PRIORITY		( 2 )
#define configTIMER_QUEUE_LENGTH		10
#define configTIMER_TASK_STACK_DEPTH	( configMINIMAL_STACK_SIZE * 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	1
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay				1

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
	/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4        /* 15 priority levels */
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			0xf

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! 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 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
	
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }	
	
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
// #define xPortSysTickHandler SysTick_Handler


/* user config code 額外定義了常用優先級的宏定義 */
#define RTOS_PRIORITY_HIGHEST       (10)
#define RTOS_PRIORITY_LEVEL_1ST     (9)
#define RTOS_PRIORITY_LEVEL_2ST     (8)
#define RTOS_PRIORITY_LEVEL_3ST     (7)
#define RTOS_PRIORITY_LEVEL_4ST     (6)
#define RTOS_PRIORITY_LEVEL_5ST     (5)

#endif /* FREERTOS_CONFIG_H */



stm32f4移植改動

這一部分爲涉及到stm32的代碼,主要就是我們自己實現的 SysTick_Handler 中斷。

  1. 在 stm32_port 文件夾下創建 stm_config.c ,用於涉及 stm32 部分的代碼與初始化接口。

  2. 實現 SysTick_Handler 中斷函數:

    void SysTick_Handler(void)
    {
        extern void xPortSysTickHandler( void );
        /* USER CODE END SysTick_IRQn 0 */
        #if (INCLUDE_xTaskGetSchedulerState == 1 )
        if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
        {
        #endif /* INCLUDE_xTaskGetSchedulerState */
            xPortSysTickHandler();
        #if (INCLUDE_xTaskGetSchedulerState == 1 )
        }
        #endif /* INCLUDE_xTaskGetSchedulerState */
    }
    

初始化Freertos並搭建應用任務

至上,移植工作已經做完了,但是需要把配置好的 freertos 用起來,所以少不了初始化與應用任務的建立。

  1. 在 stm_config.c 實現以下內容:

    #include "FreeRTOS.h"
    #include "task.h"
    
    static TaskHandle_t xTask_creat;
    
    /**
      * @note   This function is used to creat app task and delect self.
      * @brief  None
      * @param  *p
      * @retval None
      */
    static void creat_task(void *p)
    {
        log_d("%s", __FUNCTION__);
        int cnt = 0;
    
        /* creat app task in this 在這裏創建應用任務 */
        taskENTER_CRITICAL();
    
        //user_main(NULL);     //調用自己的應用函數接口
    
        taskEXIT_CRITICAL();
        /* creat app task in this 在這裏創建應用任務 */
    
    #if 1
        /* delay task 延時退出,並刪除本任務 */
        while(1){
            log_d("this is creat task:idle-%d", cnt++);
            vTaskDelay(1000);
    
            if (cnt >= 10){
                break;
            }
        }
    #endif
    
        log_d("delete creat task");
    
        vTaskDelete(xTask_creat);
    }
    
    /**
      * @note   This function is used to creat app task and delect self.
      * @brief  None
      * @param  *p
      * @retval None
      */
    int rtos_init(void)
    {
        /* stm32 NVIC config */
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
        BaseType_t xReturn = pdPASS;
    
        log_i("Freertos v10.3.1 start ");
    
        /* first creat task in this 創建rtos第一個任務,用於創建其他任務 */
        xReturn = xTaskCreate(  (TaskFunction_t )creat_task,
                                (const char *   )"creat_task",
                                (unsigned short )1024,
                                (void *         )NULL,
                                (UBaseType_t    )RTOS_PRIORITY_LEVEL_5ST,
                                (TaskHandle_t * )&xTask_creat);
    
        if (pdPASS != xReturn){
            return -1;
        }
    
        /* start task 開啓任務調度 */
        vTaskStartScheduler();
    
        return xReturn;
    }
    
  2. 在 main函數中調用封裝好的初始化接口 rtos_init 即可。

    //main函數調用示例
    int main(void)
    {
        /* stm32系統配置 */
        Sys_Config();
    
        extern int rtos_init(void);
        rtos_init();
    
        log_e("never get here");
    
        while(1)
        {
        }
    }
    

同樣貼上 stm_config.c 的全部代碼:

/**
  *****************************************************************************
  * @file    : stm_config.c
  * @author  : Tuu
  * @version : 1.0.0
  * @date    : 2020-04-01
  * @brief   : stm32f407 freertos config file
  ******************************************************************************
  * @lasteditors  : Tuu
  * @lasteditTime : 2020-06-02
  ******************************************************************************
  * @atten   : Copyright (C) by Tuu Inc
  *
  *****************************************************************************
  */

/* Includes -------------------------------------------------------------------*/
#include "config.h"

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


/* Defines --------------------------------------------------------------------*/


/* Variables ------------------------------------------------------------------*/
static TaskHandle_t xTask_creat;

/* Functions ------------------------------------------------------------------*/
extern void user_main(void *p);

/**
  * @note   This function is used to creat app task and delect self.
  * @brief  None
  * @param  *p
  * @retval None
  */
static void creat_task(void *p)
{
    log_d("%s", __FUNCTION__);
    int cnt = 0;

    /* creat app task in this 在這裏創建應用任務 */
    taskENTER_CRITICAL();

    user_main(NULL);

    taskEXIT_CRITICAL();
    /* creat app task in this 在這裏創建應用任務 */

#if 1
    /* delay task 延時退出,並刪除本任務 */
    while(1){
        log_d("this is creat task:idle-%d", cnt++);
        vTaskDelay(1000);

        if (cnt >= 10){
            break;
        }
    }
#endif

    log_d("delete creat task");

    vTaskDelete(xTask_creat);
}

/**
  * @note   This function is used to creat app task and delect self.
  * @brief  None
  * @param  *p
  * @retval None
  */
int rtos_init(void)
{
    /* stm32 NVIC config 必須配置成分組4 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

    BaseType_t xReturn = pdPASS;

    log_i("Freertos v10.3.1 start ");

    /* first creat task in this 創建rtos第一個任務,用於創建其他任務 */
    xReturn = xTaskCreate(  (TaskFunction_t )creat_task,
                            (const char *   )"creat_task",
                            (unsigned short )1024,
                            (void *         )NULL,
                            (UBaseType_t    )RTOS_PRIORITY_LEVEL_5ST,
                            (TaskHandle_t * )&xTask_creat);

    if (pdPASS != xReturn){
        return -1;
    }

    /* start task 開啓任務調度 */
    vTaskStartScheduler();

    return xReturn;
}

/* systick */
#if 1
void SysTick_Handler(void)
{
    extern void xPortSysTickHandler( void );
    /* USER CODE END SysTick_IRQn 0 */
    #if (INCLUDE_xTaskGetSchedulerState == 1 )
    if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
    #endif /* INCLUDE_xTaskGetSchedulerState */
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState == 1 )
    }
    #endif /* INCLUDE_xTaskGetSchedulerState */
}
#endif


/************************ (C) COPYRIGHT Tuu ********END OF FILE****************/



實際運行

上面基本的移植,初始化 freertos 的工作基本完成了,可以編譯燒錄運行看一下效果:(可以根據自己的環境打開 stm32f4_freertos 中的工程來運行看看)
在這裏插入圖片描述

在這裏插入圖片描述

在這裏插入圖片描述


小結

做個小結,移植 freertos 涉及到的幾個方面:

  1. 與移植硬件相關的 portable 文件,有能力的同學可以自己編寫,像stm32比較大衆的有現有的文件,可以直接拿來使用,如上移植。
  2. 內存管理默認情況下都使用 heap_4.c 文件,在特殊多內存管理的時候纔會用到 heap_5.c等。
  3. 修改 FreeRTOSConfig.h 的配置,將剛開始不必要的HOOK宏定義去除,只編譯基本的功能。
  4. 自己定義 SysTick_Handler 函數,方便後續拓展,以及完成初始化創建任務的代碼。

ps:爲什麼要重新創建一個 stm_config.c 文件?因爲將所有有關 freertos 移植的文件以及與硬件相關的代碼都放在了 stm32_port 文件夾下,這樣後續跨平臺移植的時候,修改該文件夾下和硬件相關的內容即可,不需要大動工程與框架,保證後續應用移植開發的方便性。

想要不基於上面的基礎工程,移植到自己的 stm32f4 工程當中,只需要將 thirdlib 文件夾下的 FreeRTOSv10.3.1 拷貝到自己的工程中,然後調用初始化 rtos_init 即可。


如有其它移植上面的問題自己問我哦~後續會對移植相關及freertos部分源碼進行解析,深入理解纔可以更好的運用。

Tuu

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章