M-Arch(13)兼容FreeRTOS:让freeRTOS跑起来先

本文介绍了如何将FreeRTOS操作系统移植到STM32和GD32微控制器上,重点讲解了FreeRTOSConfig.h配置文件的关键参数,包括堆栈大小、中断优先级和API函数包含。通过一个简单的任务示例展示了FreeRTOS的基本使用,如任务创建和延时函数。此外,还提到了NVIC中断优先级管理和FreeRTOS对中断的管理策略。
摘要由CSDN通过智能技术生成

前言

回顾下之前的章节:我们在一个简单的定时器 OS 基础上实现了 cortex-M 系列架构的兼容,并基于单片机的基本资源实现了很多实例。

从这个章节开始,我们把 FreeRTOS 移植进来,同时还考虑兼容性。

本文我们将介绍如何移植 FreeRTOS,并基于此实现一个最基本的例子:串口定时打印数据。

关键字:FreeRTOS,STM32,GD32

FreeRTOS 介绍

为什么要用实时操作系统?

软件中的数据交互只有 2 种,一种是轮询,一种是通知。

所谓轮询,就是你每隔 5 分钟去楼下看看快递到了没有,这期间你啥也做不了,只能干等着。

所谓通知,就是快递小哥给你发个短信,“快递到楼下了,快来取”,通知到了再下去,等待期间你该干啥干啥。

用实时操作系统的目的就是为了更高效的利用 CPU 资源。

**另外,**再说,现在物联网这么火,不用实时操作系统怎么行?

为什么选用 FreeRTOS?

开源免费(良心),够简单(就几个 c 文件),够稳定(大家都在用)。

μCOS 要钱 - RT-Thread 要钱 - μClinux 有点难 - NuttX 有点难 - eCOS 用的少 - QNX X86

FreeRTOS 移植

下载

直接去官网:FreeRTOS 官网[1]

下一个 LTS 版本(长期支持版本),大概长这样:

FreeRTOSvyyyymm.xx-LTS.zip
64496a8ffe70128588713d8afe46d7bb.png
FreeRTOS-Kernel目录结构

把这个目录简要说明下:

  • [蓝色]include:头文件

  • [黄色]*.c:几个核心头文件

  • [绿色]portable:移植相关的

portable 目录特别说明,手册上面有,直接贴图

dd60ab2e41c0e2954f92a3ec8adbf127.png
FreeRTOS-Kernel目录结构

其中,MemMang 是内存管理接口,一般用 Heap_4,具体是什么含义,手册上有写,这里不细说。

另外,对应使用 keil 移植 M4 内核,对应的 portable 文件夹为:portable\RVDS\ARM_CM4F。

我们把必须的文件加到我们的工程中,长这样:

48c385721d0da47ed219c1de106f0ba3.png
FreeRTOS移植目录结构

其中,FreeRTOSConfig.h 是配置头文件,几个.c 是核心文件。

FreeRTOS 还有其他扩展,包括 http,json,mqtt 等网络的支持,可以按需下它们的扩展包。

FreeRTOSConfig.h 的配置项很多,官方的参考在:FreeRTOSConfig[2],但是里面内容太多了,可以从 demo 里面 copy 一个现成的过来用。

demo 在 github 上下载:FreeRTOS DEMO[3]

目录是:FreeRTOS\Demo

可参考:FreeRTOS\Demo\CORTEX_STM32F103_Keil

编译

先把最简单的程序弄出来:调试串口打印输出。

代码如下(1000ms 周期打印):

void vTask(void *pvParameters)
{
    while(1)
    {
#ifdef STM32
        printf("[STM32] hello, this is freertos!\r\n");
#endif
#ifdef GD32
        printf("[ GD32] hello, this is freertos!\r\n");
#endif
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

main 函数中(创建任务,开始调度):

/* 3. app */
#ifndef USING_FREE_RTOS

    virtual_timer_init();
    while(1)
    {
        timer0_task();
    }

#else

    xTaskCreate(vTask, "Task1", 50, NULL, 1, NULL);
    vTaskStartScheduler();

#endif

编译一把,OK。

5c608080b1ff00862e88ba3387a9103b.png

当然,最重要的一点,我们要把还有FreeRTOSConfig.h中关键的配置搞清楚。

FreeRTOSConfig.h

/*
 * FreeRTOS V202111.00
 * 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
 *----------------------------------------------------------*/

#include "io.h"

#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 ) 128 )
#define configTOTAL_HEAP_SIZE  ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN  ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS  0
#define configIDLE_SHOULD_YIELD  1

/* 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  ( configMAX_PRIORITIES - 1 )
#define configTIMER_QUEUE_LENGTH  5
#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 0
#define INCLUDE_vTaskSuspend   1
#define INCLUDE_vTaskDelayUntil   1
#define INCLUDE_vTaskDelay    1

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY   255
/* !!!! 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  191 /* equivalent to 0xb0, or priority 11. */

#ifdef USING_FREE_RTOS
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler
#endif

#endif /* FREERTOS_CONFIG_H */
堆栈配置

示例:

#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE  ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN  ( 16 )
configMINIMAL_STACK_SIZE

空闲任务的堆栈大小配置。

configTOTAL_HEAP_SIZE

FreeRTOS 堆栈配置总大小。

需要根据实际项目来配置大小。

configMAX_TASK_NAME_LEN

任务名称的最大长度限制。

tick 配置
#define configCPU_CLOCK_HZ   ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ   ( ( TickType_t ) 1000 )

顾名思义,configCPU_CLOCK_HZ 就是 CPU 的频率,我们可以用系统全局变量来替代:

#define configCPU_CLOCK_HZ   (SystemCoreClock)

configTICK_RATE_HZ 是 tick 的频率,1000 对应的就是 1ms 周期。

还有一个配置是:configSYSTICK_CLOCK_HZ,一般跟 configCPU_CLOCK_HZ 一样就行了,我们可以不管它,在 port.c 中有描述:

#ifndef configSYSTICK_CLOCK_HZ
    #define configSYSTICK_CLOCK_HZ      configCPU_CLOCK_HZ
    /* Ensure the SysTick is clocked at the same frequency as the core. */
    #define portNVIC_SYSTICK_CLK_BIT    ( 1UL << 2UL )
#else

/* The way the SysTick is clocked is not modified in case it is not the same
 * as the core. */
    #define portNVIC_SYSTICK_CLK_BIT    ( 0 )
#endif

需要注意的一点是:

需要考虑把系统原来的 tick 中断函数替换为 freeRTOS 的 tick 中断,具体就是:

#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#define xPortSysTickHandler SysTick_Handler

其中,SysTick_Handler 是 tick 中断,其他两个是异常中断。

考虑兼容性设计,原有框架中涉及 systemTick 的部分需要关闭。

优先级配置

首先,我们需要了解下 NVIC 的基础知识。

NVIC 的全称是 Nested Vectored Interrupt Control,即嵌套向量中断控制器,在 Cortex M3 和 M4 内核的 MCU 中,每个中断的优先级都是 8 bit 的寄存器来表示。

但实际上,厂商一般只用到高 4 bit(对应的配置宏是__NVIC_PRIO_BITS,大家可以在代码中看看这个宏的使用方式),也就是 16 个优先级;这 16 个优先级,又分成 2 bit 抢占式优先级和 2 bit 子优先级。

抢占式优先级高于子优先级;数字越小,优先级越高。

问:为什么要说这个优先级的事?

答:FreeRTOS 要接管(部分)优先级才能把事做好。

为了方便优先级管理,我们可以把 4 bit 优先级都配置为抢占式优先级:

STM32 : NVIC_PriorityGroup_4
GD32 : NVIC_PRIGROUP_PRE4_SUB0

再来看细看下 FreeRTOS 涉及到优先级的配置:

configKERNEL_INTERRUPT_PRIORITY

这个配置定义了 FreeRTOS 用到的 Systick 和 PendSV 中断的优先级,必须配置为最低优先级,也就是:

#define configKERNEL_INTERRUPT_PRIORITY   255

如果未定义的话,在 M3 的 port.c 中会强制定义(M4 中没有):

#ifndef configKERNEL_INTERRUPT_PRIORITY
    #define configKERNEL_INTERRUPT_PRIORITY    255
#endif
configMAX_SYSCALL_INTERRUPT_PRIORITY

这个配置定义了受 FreeRTOS 管理的最高优先级中断。

什么意思呢?

当调用了 FreeRTOS 的关中断后,优先级比这个定义低的中断都会被关闭。

所以,这个值不能设置为 0,在 port.c 中有检查:

#if configMAX_SYSCALL_INTERRUPT_PRIORITY == 0
    #error configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0.  See http: /*www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
#endif

例如:

#define configMAX_SYSCALL_INTERRUPT_PRIORITY  191

hex(191)='0xbf'表示低于 11 的优先级受 FreeRTOS 管理。

configMAX_PRIORITIES
延伸阅读:faultmask,primask 和 basepri

中断屏蔽寄存器。

primask:屏蔽除 NMI 和 HardFalut 外的所有异常和中断。faultmask:屏蔽除 NMI 外的所有异常和中断。basepri:屏蔽优先级低于 basepri 的中断,为 0 时停止屏蔽中断功能。

FreeRTOS 采用的是 basepri 方式,μCOS 采用的是 primask 方式。

API 函数包含配置

其形式是:INCLUDE_函数名

比如,要用 vTaskDelay 函数,则定义如下:

#define INCLUDE_vTaskDelay    1

结果展示

d3c48e04add081f94d28ebbf6023df91.gif

当然,这只是 FreeRTOS 的一个hello world例子,更深层次的还涉及到兼容性设计,FreeRTOS 任务调度、延时方法、信号量以及队列等用法后面再说。

参考资料

[1]

FreeRTOS官网: https://www.freertos.org/

[2]

FreeRTOSConfig: https://www.freertos.org/a00110.html

[3]

FreeRTOS DEMO: https://github.com/FreeRTOS/FreeRTOS

89934cb24778cb13c66d697447b51571.gif 8ba98ae4b1bfae5e792f27229894a1a8.png 8fe545d093c74348ec5241b964fbe059.gif
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值