前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >M-Arch(13)兼容FreeRTOS:让freeRTOS跑起来先

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

作者头像
滚神大人
发布2022-01-04 15:06:14
9470
发布2022-01-04 15:06:14
举报
文章被收录于专栏:趣Python

前言

回顾下之前的章节:我们在一个简单的定时器 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 版本(长期支持版本),大概长这样:

代码语言:javascript
复制
FreeRTOSvyyyymm.xx-LTS.zip

FreeRTOS-Kernel目录结构

把这个目录简要说明下:

  • [蓝色]include:头文件
  • [黄色]*.c:几个核心头文件
  • [绿色]portable:移植相关的

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

FreeRTOS-Kernel目录结构

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

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

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

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 周期打印):

代码语言:javascript
复制
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 函数中(创建任务,开始调度):

代码语言:javascript
复制
    /* 3. app */
#ifndef USING_FREE_RTOS

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

#else

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

#endif

编译一把,OK。

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

FreeRTOSConfig.h

代码语言:javascript
复制
/*
 * 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 */

堆栈配置

示例:

代码语言:javascript
复制
#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 配置
代码语言:javascript
复制
#define configCPU_CLOCK_HZ   ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ   ( ( TickType_t ) 1000 )

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

代码语言:javascript
复制
#define configCPU_CLOCK_HZ   (SystemCoreClock)

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

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

代码语言:javascript
复制
#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 中断,具体就是:

代码语言:javascript
复制
#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 优先级都配置为抢占式优先级:

代码语言:javascript
复制
STM32 : NVIC_PriorityGroup_4
GD32 : NVIC_PRIGROUP_PRE4_SUB0

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

configKERNEL_INTERRUPT_PRIORITY

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

代码语言:javascript
复制
#define configKERNEL_INTERRUPT_PRIORITY   255

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

代码语言:javascript
复制
#ifndef configKERNEL_INTERRUPT_PRIORITY
    #define configKERNEL_INTERRUPT_PRIORITY    255
#endif
configMAX_SYSCALL_INTERRUPT_PRIORITY

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

什么意思呢?

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

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

代码语言:javascript
复制
#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

例如:

代码语言:javascript
复制
#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 函数,则定义如下:

代码语言:javascript
复制
#define INCLUDE_vTaskDelay    1

结果展示

当然,这只是 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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 趣Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • FreeRTOS 介绍
    • 为什么要用实时操作系统?
      • 为什么选用 FreeRTOS?
      • FreeRTOS 移植
        • 下载
          • 编译
            • FreeRTOSConfig.h
              • 堆栈配置
              • tick 配置
              • 优先级配置
              • 延伸阅读:faultmask,primask 和 basepri
              • API 函数包含配置
          • 结果展示
            • 参考资料
            相关产品与服务
            对象存储
            对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档