FreeRTOS总结

堆内存管理

  • 有五种内存分配方式
  • 常用的为heap_4方式

任务管理

  • 任务不能以任何方式实现函数返回,可以在任务的死循环外加上xTaskDelete( )

  • 创建任务:xTaskCreate( )

    1. 任务堆栈的大小,空闲任务的最小是configMINIMAL_STACK_SIZE,其他任务不能比他小
    2. 任务优先级,0~configMAX_PRIORITIES-1 ,数字越小,优先级越低
      1. configMAX_PRIORITIES尽量保证必要最小值 ,越大消耗RAM越多
  • 滴答中断:一般调度器都是基于时间片的抢占系统

    • 滴答中断频率:configTICK_RATE_HZ,要与滴答定时器的频率匹配
    • 典型值为100HZ,即10ms的时间片,但是要注意vTaskDelay函数的延时
    • pdMS_TO_TICKS,使得100HZ的滴答只能延时10ms的整数倍时间,所以我感觉1000HZ也还可以
  • 任务状态

    • 阻塞状态:
      • 时间性事件:例如延时vTaskDelay
      • 同步事件:进入阻塞等待数据到达,例如:队列、二进制和计数量、互斥量、事件组、任务通知等。如果设置10ms,10ms内数据到达,或者超过10ms数据没到达,都会离开阻塞状态
    • 暂停状态:进入暂停唯一方法就是vTaskSuspend,退出方法就是vTaskResume
    • 就绪状态:准备好运行,但是还没运行
  • 阻塞延时:vTaskDelay和vTaskDelayUntil

  • 空闲任务

    • 调度器启动时会自动创建空闲任务,当其他任务都阻塞时也有空闲任务时刻运行
    • 空闲任务钩子:vApplicationIdleHook
      • ***功能:***执行低优先级、后台或连续处理函数;测量空闲处理能力;将处理器置于低功耗模式
      • **注意:**钩子函数绝对不能阻塞和暂停;如果使用了vTaskDelete,空闲任务负责清理被删除任务的资源,还要确保空闲任务不会被饿死
  • 任务优先级:设置任务优先级:vTaskPrioritySet,获取任务优先级:vTaskPriorityGet

  • **任务删除:**vTaskDelete

  • **线程本地存储:**vTaskSetThreadLocalStoragePointer和pvTaskGetThreadLocalStoragePointer,根据任务数组的索引设置和读取数据

  • 调度算法*:***

    • 时间片优先的抢占式调度:用的最多,但注意资源不能被多个任务同时访问,否则可能破坏资源
      • 一个任务优先级高于运行状态任务会抢占运行状态任务
      • 同等优先级任务使用时间片共享处理时间
      • 自动会执行最高优先级就绪态的任务
    • 不含时间片的抢占式调度
      • 调度器转换新任务只有两种可能:高优先级任务就绪抢占,运行状态任务阻塞或者暂停
    • 协同调度
      • 只有运行态任务阻塞或者使用taskYIELD进行任务让步,才会发生切换

队列管理

  • FreeRTOS通过复制实现队列的方式,优点是可以直接发送栈变量到队列,不需要先分配缓冲区存放数据,发送和接收任务完全脱钩,复制实现队列不妨碍引用实现队列。

  • **多任务访问:**队列本身就是对象,可以被任意个任务或者ISR访问

  • 队列读取、写入阻塞:

    • 当任务从队列读取或者写入数据时,可以选择性阻塞时间,当阻塞状态接收到数据或者阻塞时间超时,任务都会转移到就绪状态。
    • 如果有多个任务等待队列数据,只会有一个任务会解除阻塞,最高优先级先解除,相同优先级则等待时间最长的先解除
  • **队列创建:**xQueueCreate

  • **队尾插入:**xQueueSendToBack

  • **队首插入:**xQueueSendToFront

  • **队列接收:**xQueueReceive

  • **数据量查询:**uxQueueMessagesWaiting

  • 从多个来源接收数据:

    • 简单:可以使用队列传输结构体,结构体包含来源和数据
  • 处理大数据和可变大小数据:最好使用队列传输数据的指针

    • 被指向的RAM的所有者必须明确定义
    • 被指向的RAM保持有效
  • **队列集:**能够从多个来源接收数据,但比结构体方法更繁琐效率更低

    • 创建队列集
    • 队列添加队列集
    • 队列集读取数据
  • **队列集创建:**xQueueCreateSet

  • **队列添加队列集:**xQueueAddToSet

  • **队列集读取队列:**xQueueSelectFromSet

  • **队列集移除队列:**xQueueRemoveFromSet

  • ***队列创建邮箱:***邮箱用来指长度为1的队列

    • 队列将数据从一个任务发送到另一个任务,发送者放置数据,接收者读取后移除数据
    • 邮箱将数据从一个任务发送到另一个任务,发送者放置新数据并覆盖原数据,接收者读取数据并不移除
  • **发送并覆盖邮箱数据:**xQueueOverwrite

  • **接收并不移除数据:**xQueuePeek

软件定时器

  • **软件定时器回调函数形式:**void ATimerCallback(TimerHandle_t xTimer)
    • 回调函数应该短小精悍,不能阻塞
    • 可以多个定时器使用同一回调函数,但是需要在函数里判断定时器句柄
    • 也可以每个定时器使用不同回调函数
  • **定时器周期:**指从启动软件定时器到执行软件定时器回调函数之间的时间
    • 一次性定时器:只执行一次回调函数
    • 自动重载:到期后自动重启,回调函数周期执行
    • 到期时间是从发送“启动定时器”命令到定时器命令队列的时间开始计算,而不是守护任务从命令队列收到“启动定时器”命令的时间开始计算的
  • 定时器状态:
    • 休眠:休眠的定时器存在,可以通过句柄调用,回调函数不会执行
      • xTimerCreate创建后就是休眠状态
      • 运行转休眠,
    • 运行:到规定的周期时间,自动执行回调函数
      • 调用xTimerStart,xTimerReset,xTimerChangePeriod都可以转换为运行态
  • RTOS守护任务
    • 在调度器启动时自动创建,优先级和栈大小由常量设置
    • 软件定时器API将命令从调用函数发送到守护任务,在守护任务的“定时器命令队列”上
    • 守护任务的调度:只有当守护任务为能够运行的最高优先级时,才会处理命令和执行定时器回调函数
    • 发送到定时器命令队列的命令包含时间戳,确保启动的定时器是从发送“启动定时器”命令到定时器命令队列的时间开始计算
  • **创建软件定时器:**xTimerCreate
  • 启动软件定时器:xTimerStart
  • **停止定时器:**xTimerStop
  • **删除定时器:**xTimerDelete
  • **定时器ID:**是一个标签值,可以随意使用,创建软件定时器时,会给ID分配初始值
    • vTimerSetTimerID,创建定时器时,会为软件定时器分配一个标识符 (ID), 此函数更改此标识符。
    • pvTimerGetTimerID,返回分配给软件计时器的 ID
  • **更改软件定时器周期:**xTimerChangePeriod
  • **重置软件定时器:**xTimerReset

中断管理

  • 任务是软件功能,和运行的硬件无关。中断是硬件功能,最低优先级的中断可以抢断最高优先级任务,反之则不可以。

  • 专门用于ISR的API函数,在名称后添加FromISR,不要在ISR中调用没有后缀的函数

  • **使用单独中断安全函数的缺点:**有需要在ISR中调用第三方函数,但第三方函数用了正常的FreeRTOS API函数

    • 将中断处理推迟给任务,就可以在任务中调用
    • 如果有的话,将API改为FromISR结尾的函数
  • xHigherPriorityTaskWoken参数

    • 中断结束时,会回到打断处继续执行,但如果中断期间,有了更高优先级任务就绪,就应该执行更高优先级任务,而不是返回原点继续执行。如果不管的话,更高优先级任务将保持就绪状态,直到不在中断时的下一次调度器运行。

      • 切换更高优先级任务不会在中断内自动发生,设置了xHigherPriorityTaskWoken变量通知应该上下文切换
      • FromISR结尾的函数有xHigherPriorityTaskWoken变量,用于此目的,taskYIELD函数是在任务中请求任务切换的函数。
      • portYIELD_FROM_ISR是taskYIELD函数的中断版本
    • 示例代码如下:

      void vTimerISR( void * pvParameters )
      {BaseType_t xHigherPriorityTaskWoken = pdFALSE;xHigherPriorityTaskWoken = pdFALSE;xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );/* Yield if xHigherPriorityTaskWoken is true.  The actual macro used here is port specific. */portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
      }
      
  • 推迟中断处理

    • 中断所需的其他处理工作通常可以在任务中运行,所以可以将中断的工作推迟到任务
    • 以下情况强烈建议推迟到任务
      • 中断所需的处理并不简单
      • 任务处理能方便执行ISR内部无法执行的操作
      • 中断处理不确定,不知道处理工作需要多长时间
  • 二进制信号量:能够有效使任务和中断同步,可以认为使长度为1的队列

    • 设置推迟任务的优先级确保,该任务可以抢占系统其他任务

    • 在ISR实现中调用portYIELD_FROM_ISR,确保ISR返回到推迟中断处理任务

    • 创建二值信号量: xSemaphoreCreateBinary

    • **释放信号量:**xSemaphoreGive

    • **获取信号量:**xSemaphoreTake

  • **计数信号量:**可用于资源管理,计数事件

    • **创建计数信号量:**xSemaphoreCreateCounting
    • **释放信号量:**xSemaphoreGive
    • **获取信号量:**xSemaphoreTake
  • **推迟工作到守护任务:**xTimerPendFunctionCallFromISR()

  • 中断程序使用队列:

    • 使用xQueueSendToFront和xQueueSendToBack的ISR版本
    • 数据到达频率很高,队列效率不高
    • 更高效且适合生产代码方法:
      • 直接内存访问DMA
      • 接收到的字符复制到线程安全的RAM缓冲区
      • 直接在ISR内处理接收到的字符,队列只发送处理结果
  • 中断嵌套

    • 数字优先级和逻辑优先级:数字是分配给中断优先级的数字,逻辑是描述该中断相较于其他中断的优先级
    • configMAX_SYSCALL_INTERRUPT_PRIORITYD,低于此优先级中断可以被管理
    • configKERNEL_INTERRUPT_PRIORITY,设置滴答中断的优先级,最低优先级
    • 对时间精度要求非常严格的功能,可以考虑使用高于configMAX_SYSCALL_INTERRUPT_PRIORITYD的优先级
    • 必须始终configKERNEL_INTERRUPT_PRIORITY设置为尽可能最低的中断优先级
    • configMAX_SYSCALL_INTERRUPT_PRIORITYD的数值要注意,如cortex-m不允许设置为0

资源管理

  • 资源访问导致数据损坏的例子:A任务打印hello,A打印到he,B任务抢占A,打印abort,最终结果就是heabortllo。这是不正确的。

  • **函数重入:**函数可以安全的在多个任务调用,或既可以从中断也可以在任务使用,那么函数就是重入,也称作线程安全。每个任务都维护自己的栈和硬件寄存器值,除了访问栈上的数据或保存至寄存器的数据外,不访问其他数据,就是重入函数。

  • **相互排斥:**任务之间共享的资源进行访问时,必须使用相互排斥进行管理。使资源不被共享,被单一程序访问。

  • **临界区:**taskENTER_CRITICAL和taskEXIT_CRITICAL成对使用。FROM_ISR版本的taskENTER_CRITICAL会有返回值,返回值要传递给taskEXIT_CRITICAL。

    • 工作原理是禁用中断,即禁用所有可以管理的中断
    • 临界区必须短小,否则对中断响应产生不利响应
    • 临界区的嵌套是安全的,Freertos中两个宏定义是改变中断使能状态唯一合法方式
  • **暂停调度器:**如果临界区代码过长,可以使用暂停调度器,但恢复调度器操作较慢

    • vTaskSuspendAll,暂停调度器
    • xTaskrResumeAll,恢复调度器
  • **互斥量:**特殊的二进制信号量,获取后必须归还,归还后别的任务才能获取,否则可能死锁。

    • 创建互斥量:xSemaphoreCreateMutex
    • 获取互斥量:xSemaphoreTake
    • 释放互斥量:xSemaphoreGive
  • 互斥量和优先级密切相关的概念

    • **优先级反转:**优先级高的任务等待优先级低的任务释放互斥量,仔细思考资源访问尽量避免。
    • **优先级继承:**为了解决互斥量产生的优先级反转,rtos会将持有者的优先级提高至与等待互斥量的任务优先级相同,即继承优先级,归还后优先级恢复原状。不能在中断中使用互斥量
    • **死锁:**两个任务都在等待对方持有的资源而无法继续,充分考虑系统,识别并消除。
    • **递归互斥量:**当任务获取了互斥量,但执行过程中有函数继续获取互斥量,导致自己锁死自己。
      • 使用递归互斥量来避免,可以被同一任务多次获取,接着执行调用归还后,才能归还。类似成对使用。
      • 创建递归互斥量:xSemaphoreCreateRecursiveMutex
      • 获取递归互斥量:xSemaphoreTakeRecursive
      • 释放递归互斥量:xSemaphoreGiveRecursive
  • 互斥量和任务调度

    • 不同优先级任务获取同一互斥量,优先级高的任务先进入运行状态。

    • 如果A,B任务优先级相同,A先获取了互斥量,等到时间片结束切换B,接着回A,释放互斥量,再等到时间片结束,B才能运行

      • 推荐的更平等处理时间的例子

      • // 记录时间
        Xtime = xTaskGetTickCount();
        // 释放互斥量
        xSemaphoreGive
        // 滴答计数变化时,调用切换
        if(xTaskGetTickCount() != Xtime)
        {taskYIELD();
        }
        
  • 守门人任务:指对任务拥有唯一所有权的任务,其他需要访问资源的任务只能通过守门人任务。

    • 方法简单,基本没有反转和死锁风险

事件组

  • 事件组的特性:

    • 允许任务阻塞状态下等待一个或多个事件组合发生
    • 事件组会解除所有在等待同一个事件或事件组合的任务的阻塞
    • 通常可以用一个事件组代替多个二进制信号量
  • 事件组标志是一个布尔值,每一位都代表一个事件是否发生

    • configUSE_16_BIT_TICKS为1,则事件组为16位,但其中的高八位保留,即包含8个可用事件位
    • configUSE_16_BIT_TICKS为0,则事件组为32位,但其中的高八位保留,即包含24个可用事件位
  • **事件组创建:**xEventGroupCreate

  • **事件组位设置:**xEventGroupSetBits

  • **读取事件组位:**xEventGroupWaitBits

  • **多任务事件组相互同步:**xEventGroupSync

任务通知

  • 任务通知允许任务之间交互,不要单独的通信对象。通过任务通知,任务或ISR可以直接向接收任务发送事件。

  • 通常用来替代二值信号量

  • 优势与劣势:

    • 任务通知比队列、信号量等操作快得多
    • 所需RAM也要小的多
    • 无法向ISR发送事件和数据
    • 无法启用多个接收任务
    • 无法缓冲多个数据项
    • 无法向多个任务广播
    • 无法在阻塞状态等待发送完成
  • **发送任务通知:**xTaskNotify

  • **发送任务通知的简单版:**xTaskNotifyGive

  • **接收任务通知:**xTaskNotifyWait

  • **接收任务通知的简单版:**ulTaskNotifyTake

低功耗支持

  • **与节能有关的宏:**portSUPPRESS_TICKS_AND_SLEEP

开发者支持

  • **断言:**cofigASSERT
  • **任务状态信息快照:**uxTaskGetSystemState,比较重要的信息主要有
    • 到目前为止分配给任务的总运行时间
    • 任务剩余的最小堆栈空间量
  • **提供可读的任务信息ASCII表格:**vTaskList
    • 很耗费CPU,仅用于调试阶段
  • **将运行时统计信息格式化为可读表格:**vTaskGetRunTimeStats
    • 很耗费CPU,仅用于调试阶段
    • 还需要实现一个计数器

故障排除

  • 演示工程添加任务导致演示工程崩溃
    • 延时工程的堆空间很精确,没有足够的堆空间
  • 中断使用API导致应用崩溃
    • 使用FROM_ISR结尾的API函数
  • 有时应用程序在中断服务程序中崩溃
    • 中断是否导致了栈溢出
  • 调度器启动第一个任务时崩溃
    • 有些处理器启动调度器哦i之前必须处于特权模式
    • 确保移植没问题,中断处理程序没问题
  • 应用程序在调度器启动前崩溃
    • 启动前不允许上下文切换
  • 调度器暂停或者临界区调用API函数,导致应用程序崩溃
    • 调度器暂停不能调用API函数
    • 临界区内不能调用API函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/135250.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【自然语言处理】利用python创建简单的聊天系统

一,实现原理 代码设计了一个简单的客户端-服务器聊天应用程序,建立了两个脚本文件(.py文件),其中有一个客户端和一个服务器端。客户端和服务器之间通过网络连接进行通信,客户端发送消息,服务器端接收消息并…

git clone单个文件/文件夹、wget下载单文件

文章目录 1. 暂时没找到方法用git命令方便地clone单个文件/文件夹2. 通过wget手动下载单个文件 1. 暂时没找到方法用git命令方便地clone单个文件/文件夹 复杂,未测试 https://www.cnblogs.com/impw/p/15629514.html 2. 通过wget手动下载单个文件 在github/gitee网…

acwing 795前缀和

输入一个长度为 n� 的整数序列。 接下来再输入 m� 个询问,每个询问输入一对 l,r�,�。 对于每个询问,输出原序列中从第 l� 个数到第 r� 个数的和。 输入格式 第一行包含两个整数 …

django+drf+vue 简单系统搭建 (2) - drf 应用

按照本系统设置目的,是为了建立一些工具用来处理简单的文件。 1. 准备djangorestframework 关于drf的说明请参见:Django REST Framework教程 | 大江狗的博客 本系列直接使用drf的序列化等其他功能。 安装 conda install djangorestframework conda i…

VSCode使用插件Github Copilot进行AI编程

演示示例 函数封装 根据上下文 根据注释 详情请看GitHub Copilot 安装插件 在VS Code中安装插件 GitHub Copilot 登录账号 点击VS code左下角账户图标,点击【Sign in】,会自动在浏览器打开Github登录页,登录具有 Github Copilot 服务的…

数据结构 编程1年新手视角的平衡二叉树AVL从C与C++实现③

对应地,我们可以将insert函数中省略的操作补上 if(getBalance(node)2){ if(getBalance(node->left)1){ noderightRotate(node); //对应LL型 } else if(getBalance(node->left)-1{ node->left leftRotate(node->left); //对应LR型 noderightRotate(n…

微信 商家转账到零钱 二

本来想手写&#xff0c;但是有sdk 就没必要这么麻烦。 composer地址&#xff1a;wechatpay/wechatpay - Packagist 微信官网sdk,给的是github&#xff0c;打不开。 <?php require_once vendor/autoload.php; defined(ROOT_PATH) or define(ROOT_PATH, ./); use WeChatPa…

网工内推 | 上市公司,云平台运维,IP认证优先,13薪

01 上海新炬网络信息技术股份有限公司 招聘岗位&#xff1a;云平台运维工程师 职责描述&#xff1a; 1、负责云平台运维&#xff0c;包括例行巡检、版本发布、问题及故障处理、平台重保等&#xff0c;保障平台全年稳定运行&#xff1b; 2、参与制定运维标准规范与流程&#x…

混沌系统在图像加密中的应用(基于哈密顿能量函数的混沌系统构造1.1)

混沌系统在图像加密中的应用&#xff08;基于哈密顿能量函数的混沌系统构造1.1&#xff09; 前言一、基于广义哈密顿系统的一类混沌系统构造1.基本动力学特性分析2.数值分析 待续 前言 本文的主题是“基于哈密顿能量函数的混沌系统构造”&#xff0c;哈密顿能量函数是是全文研…

案例 - 拖拽上传文件,生成缩略图

直接看效果 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>拖拽上传文件</title>&l…

PTA_乙级_1002

思路&#xff1a;不仅超出int还超出Longlong,直接用string类型定义n&#xff0c;for循环来遍历每一位字符然后转换成数字进行累加&#xff0c;再用to_string把数字和转换成字符串&#xff0c;再用for循环把数字和的每一位定位到pinyin字符串数组上输出 #include <iostream&…

单链表的创建定义

(无头结点)单链表 #define NULL 0typedef struct LNode {int data; //每个结点存放一个数据元素struct LNode *next; //指针指向下一结点 }LNode,*LinkList;//初始化一个空单链表 bool InitList(LinkList &L){L NULL; //空表&#xff0c;暂时没有…

人工智能(AI)是一种快速发展的技术,其未来发展前景非常广阔。

人工智能&#xff08;AI&#xff09;是一种快速发展的技术&#xff0c;其未来发展前景非常广阔。以下是一些关于AI未来的可能发展方向和就业前景的详细说明&#xff1a; 1.机器学习工程师&#xff1a;机器学习是AI的核心技术之一&#xff0c;它涉及到从数据中自动学习模式并进…

使用Python爬虫被封ip的解决方案

在使用 Python 程序进行网络爬虫开发时&#xff0c;可能会因为下面原因导致被封IP或封禁爬虫程序&#xff1a; 1、频繁访问网站 爬虫程序可能会在很短的时间内访问网站很多次&#xff0c;从而对目标网站造成较大的负担和压力&#xff0c;这种行为容易引起目标网站的注意并被封…

Leetcode71简化路径

代码&#xff1a; class Solution {public String simplifyPath(String path) {String[] names path.split("/");Deque<String> stack new ArrayDeque<String>();for(String name: names){if(name.equals("..")){if(!stack.isEmpty()){stac…

C语言【趣编程】我们怎样便捷输出空心的金字塔

目录 1问题&#xff1a; 2解题思路&#xff1a; 3代码如下&#xff1a; 4代码运行结果如下图所示&#xff1a; 5总结&#xff1a; r如若后续有不会的问题&#xff0c;可以和我私聊&#xff1b; 1问题&#xff1a; 2解题思路&#xff1a; 方法&#xff1a;找规律&#xff0…

Flask(Jinja2) 服务端模板注入漏洞(SSTI)

Flask&#xff08;Jinja2&#xff09; 服务端模板注入漏洞(SSTI) 参考 https://www.freebuf.com/articles/web/260504.html 验证漏洞存在 ?name{{7*7}} 回显49说明漏洞存在 vulhub给出的payload: {% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__…

【uniapp+vue3/vue2】ksp-cropper高性能图片裁剪工具,详解

效果图&#xff1a; 1、ksp-cropper是hbuilder插件市场中的一款插件&#xff0c;兼容vue2和vue3 ksp-cropper插件安装地址&#xff0c;直接点击跳转 2、插件用法相对简单 &#xff08;1&#xff09;只要url有值就会显示插件&#xff0c;为空就会隐藏插件 &#xff08;2&#…

【FI】FB02中Coding Block字段如何设置为可修改

本文基于S/4 HANA 2022 关于FB02下会计凭证行上的可更改字段的控制&#xff0c;以前以为只受“凭证明细行更变规则”&#xff08;OB32&#xff09;的影响。 今天碰到了Coding Block字段的情况&#xff0c;它不受OB32的影响&#xff0c;而是受表TCOBX控制。 如何确认该字段是Cod…

树专题 —— 二叉搜索树和中序遍历

大家好&#xff0c;我是 方圆。我准备把树写成一个专题&#xff0c;包括二叉搜索树、前序、中序、后序遍历以及红黑树&#xff0c;我也想试试能不能将红黑树写好。 本篇是关于二叉搜索树&#xff0c;也是所有后续学习的基础&#xff0c;其中会涉及前序、中序、后序遍历&#x…