FreeRTOS内核学习笔记(基于stm32f4)

FreeRTOS内核学习

命名规则

  1. 变量:

    • uint32_t 定义的变量都加上前缀 ul。 u 代表 unsigned 无符号, l 代表 long长整型
    • uint16_t 定义的变量都加上前缀 us。 u 代表 unsigned 无符号,s 代表 short 短整型
    • uint8_t 定义的变量都加上前缀 uc。 u 代表 unsigned 无符号,c 代表 char 字符型
    • int 定义的变量加上前缀 i。i 代表 int
    • stdint.h 文件中未定义的变量类型,在定义变量时需要加上前缀 x.
    • stdint.h 文件中未定义的无符号变量类型,在定义变量时要加上前缀 u
    • 枚举变量会加上前缀 e
    • 指针变量会加上前缀 p
    • **char ** 定义的变量只能用于 ASCII 字符,前缀使用 c
    • **char ** 定义的指针变量只能用于 ASCII 字符串,前缀使用 pc
  2. 函数:

    • 加上了 static 声明的函数,定义时要加上前缀 prv
    • 带有返回值的函数,根据返回值的数据类型,加上相应的前缀,如果没有返回值,即 void 类型,函数的前缀加上字母 v
    • 根据文件名,文件中相应的函数定义时可能会将文件名加到函数命名中,比如 tasks.c 文件中函数vTaskDelete,函数中的 task 就是文件名中的 task。
  3. 宏定义:

    • 根据宏定义所在的文件,文件中的宏定义声明时也将文件名加到宏定义中,比如宏定义configUSE_PREEMPTION 是定义在文件 FreeRTOSConfig.h 里面。 宏定义中的 config 就是文件名中的 config。 另外注意,前缀要小写。
    • 除了前缀,其余部分全部大写,同时用下划线分开。
  4. 缩进:Tab 制表符用于缩进,Tab 一次缩进 4 个字符空间。

  5. 注释:FreeRTOS 中注释不会超过 80 个字符宽度,除非对函数的参数进行注释时。源码中主要是采用/* */
    的形式进行注释,不采用 C++中的双斜杠风格来注释。

堆栈

堆栈的空间均分配在RAM中

堆:cm4中堆向上生长

栈:cm4中栈向下生长

FreeRTOS创建任务使用的栈实际上使用的单片机的堆空间,实际上是在堆中开辟了一个数据结构为栈的空间。

task.c中portSTACK_GROWTH默认为-1,即先分配stack(栈空间)再分配TCB(任务控制块)

任务

任务创建流程:向堆申请任务栈空间和任务控制块,初始化相关链表,将任务加入就绪队列

同一个优先级下,共用一个链表,同一个xLIST_ITEM

函数

  1. vTaskDelete(NULL);

    • 慎用 NULL:调用 vTaskDelete(NULL); 会删除调用它的任务。这在任务完成其工作并希望自我删除时非常有用,但需要谨慎使用,以避免意外删除当前正在运行的任务。
    • 资源回收:虽然任务被删除了,但是它所持有的任何同步原语(如信号量、互斥锁等)不会自动释放。你需要在删除任务之前手动释放这些资源。
    • 删除阻塞任务:如果尝试删除一个处于阻塞状态的任务,那么任务将被删除,但任何等待该任务的同步原语也将被释放。
    • 调度器行为vTaskDelete() 可以影响调度器的行为。例如,如果删除了一个高优先级任务,那么调度器可能会立即调度其他任务。
    • 内存碎片:在某些配置下,频繁创建和删除任务可能会导致内存碎片。在这种情况下,考虑使用静态内存分配或调整内存管理策略。
  2. vApplicationTickHook();

    • 如果要使用需要在FreeRTOSConfig.h中将configUSE_TICK_HOOK 配置为1
    • 触发时机:每次系统时钟节拍中断时
    • SysTick_Handler()中调用,中断频率高,由于它运行在时钟中断上下文中,执行时间应尽量短,以避免影响实时性和其他中断的响应,只能使用"FromISR"的函数
    • 用途:
      • 计时操作:可以用来实现简单的计时功能。例如,周期性地检查某些条件或触发定时操作。
      • 监控功能:在钩子中实现某些运行时监控或统计功能,例如统计系统运行时间或检查某些状态。
      • 外设处理:处理与时钟节拍相关的外设操作(如软件定时器、周期性事件等)。
      • 节拍同步:可以用来同步其他系统组件与 FreeRTOS 的时钟节拍。
  3. vApplicationMallocFailedHook();

    • 如果要使用需要在FreeRTOSConfig.h中将configUSE_MALLOC_FAILED_HOOK 配置为1
    • 触发时机:动态内存分配失败时
    • 用途:
      • 系统重启:在内存分配失败时,可能需要系统重启或进入死循环等待外部干预。
      • 日志记录:可以将内存分配失败的信息写入日志,以便于后续调试。
      • 内存池管理:在内存管理较为复杂的系统中,可以通过此钩子进行内存池的调整或重新配置。
  4. vApplicationIdleHook():

    • 如果要使用需要在FreeRTOSConfig.h中将**configUSE_IDLE_HOOK ** 配置为1

    • 触发时机:空闲任务执行时

    • 用途:

      • 低功耗模式:在嵌入式系统中,空闲状态下常常进入低功耗模式以节省电池。可以在此钩子中调用 CPU 的低功耗指令,如进入休眠模式(例如 __WFI())。
      • 周期性任务:如果系统在空闲时需要执行一些周期性的任务(如状态检查、定时任务等),可以将这些任务放在此钩子中执行。
      • 定期更新或维护:一些不频繁但必须执行的操作,例如刷新显示屏、执行系统自检等,可以放在此钩子中进行。
  5. vApplicationStackOverflowHook();

    • 如果要使用需要在FreeRTOSConfig.h中将configCHECK_FOR_STACK_OVERFLO 配置为1

    • 触发时机:任务栈溢出时

    • 用途:

      • 错误检测和日志记录:栈溢出是程序中的严重错误,可以通过此钩子记录错误信息、进行日志分析,或进行系统状态转储。
      • 防止系统崩溃:栈溢出通常会导致任务行为异常,调用此钩子后,可以采取重启系统、切换到安全模式或者其他恢复措施来防止系统崩溃。
      • 调试工具:在开发阶段,栈溢出钩子可以用于收集调试信息,帮助开发人员识别任务栈的大小配置问题。
  6. vApplicationDaemonTaskStartupHook();

    • 如果要使用需要在FreeRTOSConfig.h中将**configUSE_IDLE_HOOK ** 配置为1
    • 触发时机:当守护任务(通常是系统初始化任务)启动时会调用此钩子。
    • 用途:
      • 系统初始化:用于执行系统的初始化操作,加载必要的配置,进行硬件初始化等。
      • 启动日志:守护任务启动时,可以用此钩子启动系统的日志记录、网络连接等操作。
      • 资源分配:可以用此钩子进行外部资源(如内存、外设等)的配置。
  7. vTaskDelay(),vTaskDelayUntil()函数

    • 调用时,调度器不能处于挂起状态

状态类型

  • 运行状态:任务正在执行,CPU 正在为该任务分配时间。
  • 就绪状态:任务已准备好运行,等待调度器分配 CPU 时间。任务进入就绪状态通常是因为它已经满足了执行的条件,且没有被任何事件阻塞(如等待信号量、消息队列等)。
  • 阻塞状态: 任务因等待某些资源或事件(如信号量、消息队列、时间延迟等)而无法执行。任务不会被调度,直到其等待的事件或资源变得可用。
  • 挂起状态:任务被显式挂起,不会被调度执行。挂起状态与阻塞状态的区别是任务不再等待某个资源或事件,而是被手动暂停了。
  • 删除状态:任务被删除后,其资源(包括任务栈和任务控制块)将被释放。任务进入删除状态意味着它不再被调度,且不再存在。

任务控制块

消息队列

消息队列 是基于先进先出的队列结构,用于任务间传递消息或数据,适合较小的数据包传递,支持消息的发送与接收。

中断

信号量

  • 二值信号量(可以在任务和中断中使用)
  • 计数信号量(可以在任务和中断中使用)
  • 互斥信号量(可以在任务中使用,不可以或避免在中断中使用)

事件组

主要用于多任务间的同步,与信号量不同的是,它可以实现一对多,多对多的同步。

任务通知

使用限制

  1. 任务通知方式仅可以用在只有一个任务等待信号量,消息邮箱或者事件标志组的情况。(点对点)

  2. 仅可在使用 RTOS 任务通知代替 队列的情况下:当某个接收任务可在阻塞状态下等待通知 (因而不花费任何 CPU 时间)时,发送任务不能 在阻塞状态下等待发送完成(在发送不能立刻完成的情况下) 。

  3. 只能发送给任务:通知只能发送给任务,而不能用于中断或其他任务间的同步。

  4. 使用任务通知方式实现的消息邮箱替代消息队列时,发送消息的任务不支持超时等待,即消息队列中的数据已经满

    了,可以等待消息队列有空间可以存新的数据,而任务通知方式实现的消息邮箱不支持超时等待。

  5. 无法解决优先级翻转问题

用例

参考链接

FreeRTOS消息队列、信号量、事件组、任务通知之间的区别_freertos事件和消息队列的区别-CSDN博客

流缓冲区

流缓冲区 专门用于字节流的传递,适合用于处理大量连续数据的流式传输,如音频、视频、传感器数据等,支持更高效的字节数据传输。

软件定时器

低功耗

内存管理

  1. heap_1:提前动态分配一大段内存空间,不管任务用与不用,用多少,内存占用是固定的,禁止动态分配内存,只有pvPortMalloc(),没有vPortFree()!
  2. heap_2:允许释放内存,但不会合并相邻的空闲块,使用Best Fit,可以减少剩余空间,降低外部碎片。同时搜索时间较长,可能导致更多的内部碎片。
  3. heap_3:简单包装了标准 malloc() 和 free(),以保证线程安全。对这两个函数进行了保护机制,采用的方式是操作内存前挂起调度器,完成后再恢复调度器
  4. heap_4:合并相邻的空闲块以避免碎片化。包含绝对地址放置选项,使用First Fit,空闲块链表按照地址大小进行排列,而不是按照碎片大小。。
  5. heap_5:如同 heap_4,能够跨越多个不相邻内存区域的堆。在申请内存前,它会调用vPortDefineHeapRegions,这意味着它允许内存堆跨越多个非连续区域,如果你需要同时使用内部RAM和外部SDRAM,毫无疑问,这种策略非常合适,但是用户需要指定每个内存堆的起始地址和大小。
    • heap_1 不太有用,因为 FreeRTOS 添加了静态分配支持。(FreeRTOS v9.0及以上)
    • heap_2 现在被视为旧版,因为较新的 heap_4 实现是首选。(heap_2 开销小,但是容易产生内存碎片,heap_4 开销大,但是能减少内存碎片)

head_4

  1. heap_4.c使用链表进行了空闲块的管理,heap_4.c使用了链表将空闲的内存块地址进行连接
    • 1)链表使用的空间哪里来呢。答:链表本身使用的空间也是来自这个大数组,链表本身和用申请的空间本身是连在一起的。
    • 2)已经被申请的内存块就不会被链表管理吗?答:回答第一个问题,链表本身使用的空间也是来自这个大数组,链表本身和用申请的空间本身是连在一起的。
  2. heap_4.c对相邻的空闲内存块进行合并处理。
    • 1)空闲块在什么时候进行合并。答:空闲块在内存释放的时候变成空闲块的时候,和申请内存的时候会有新的空闲内存块,然后进行合并。
    • 2)空闲块是如何进行合并的。答:如果两个空闲块都被连接进来,那么只要两个空闲块地址连接在一起就可以进行合并。
    • 3)已经被申请的内存,已经不被链表进行管理,那么释放已经申请的内存是如何找到前面的空闲块的。答:释放内存时的空闲块会遍历所有链表,然后找到当前空闲块的前一个空闲块和后一个空闲块,如果地址重叠可以判定进行空闲块合并。

参考链接

FreeRTOS 堆内存管理 - FreeRTOS™

微型操作系统内核源码详解系列三(0):空间存储及内存管理篇(前置篇)-CSDN博客

FreeRTOS Heap 1_2_3_4_5 比较 - JerryZheng2020 - 博客园

FreeRTOS系列-- heap_4.c内存管理分析_freertos heap合并-CSDN博客

链表

  1. pxDelayedTaskList:延迟任务链表。

  2. pxOverflowDelayedTaskList:溢出后的延迟任务链表。

  3. pxReadyTasksLists:就绪任务链表(按优先级划分)。

  4. xPendingReadyList:等待处理的就绪任务链表。

  5. xSuspendedTaskList:被挂起的任务链表。

  6. xTasksWaitingTermination:等待终止的任务链表。

  7. pxTaskToBeDeleted:待删除任务链表。

  8. pxIdleTaskList:空闲任务链表。

  9. xEventList:等待事件的任务链表。

  10. xTimerList:软件定时器链表。

  11. pxTimerQueue:定时器队列链表。

  12. xMutexHolderList:互斥量持有者链表。

  13. pxQueueList:队列链表。

  14. pxSemaphoreList:信号量链表。

  15. pxTaskList:所有任务的链表。

  16. xTaskStateList:任务状态链表。

杂项

使用结构体时从大到小放置变量更能节省空间

image-20241203230115013

1、不同任务之间,避免在不同任务里面操作同一个外设,除非用户自己手动在底层做了互斥处理。
2、任务和中断之间,都操作同一个外设,一般需要在任务里面设置临界段,也就是开关中断。

FromISR

不能在FreeRTOS不能管理的中断中使用FreeRTOS的API

PendSV

xPortPendSVHandler()在任务切换过程中保存和恢复任务的上下文,调用 vTaskSwitchContext() 进行任务切换

进行任务切换,保存当前任务现场,执行调度,恢复下一个任务现场,执行

PendSV的优势在于它可以像普通中断一样被悬起,当其他中断都执行完毕时,它可以开始工作了,这样就不会打断其他中断了。

PendSV Handler 执行过程中,如果遇到更高优先级的中断被打断,那么 PendSV 之前保存的上下文会保留在栈上。中断服务例程(ISR)会在栈上进行上下文保存与恢复,ISR 处理完毕后,CPU 会根据栈中的上下文返回到 PendSV Handler,继续完成任务切换。

SVC

freeRTOS仅在初始化时用到一次SVC中断

SysTick

作为FreeRTOS的心跳,默认为1khz,使用hal及其他框架需要心跳时需要指定其他定时器作为心跳时钟源

更新任务时钟节拍和链表更新

SysTick 中断发生时,FreeRTOS 会执行一些必要的操作,主要是更新 Tick计数器、检查任务的延时、检查任务是否需要切换、以及触发任务调度等,而实际的任务调度则被推迟到 PendSV 中断 中处理。

【STM32F407开发板用户手册】第10章 STM32F407的FLASH,RAM和栈使用情况(map和htm文件) - 硬汉嵌入式 - 博客园

FreeRTOS 任务栈大小确定及其溢出检测 - Crystal_Guang - 博客园

FreeRTOS - 随笔分类 - 李柱明 - 博客园

FreeRTOS消息队列、信号量、事件组、任务通知之间的区别_freertos事件和消息队列的区别-CSDN博客

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

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

相关文章

使用 EchoAPI 实现 API 断言的全面指南

API 断言是 API 测试中的一个关键部分。通过执行 API 断言,您可以验证 API 响应数据的准确性,从而增强 API 的可靠性和稳定性。在本文中,我们将介绍 API 断言的基础知识,并演示如何通过用户友好的 API 测试工具 Apipost 来轻松执行响应断言。 什么是 API 断言?API 断言是指…

变量与执行

目录变量变量命名规则变量的类型变量的赋值python代码的执行 变量 Python 是一种动态类型语言,这意味着你不需要显式地声明变量的类型,Python 会根据你赋给变量的值自动推断其类型。 变量命名规则 1、字母、数字、下划线:变量名可以包含字母(a-z, A-Z)、数字(0-9)和下划…

结构化程序设计——系统设计思想(输入输出)

一、结构化程序设计概述 结构化程序设计(Structured Programming)是由计算机科学家 Edsger W. Dijkstra 于 20 世纪 60 年代提出的编程方法论。其核心思想是通过 顺序结构、选择结构 和 循环结构 三种基本控制结构,构建出逻辑清晰、易于理解和维护的程序。结构化程序设计强调…

20244111 2024-2025-2 《Python程序设计》实验一报告

20244111 2024-2025-2 《Python程序设计》实验一报告 课程:《Python程序设计》 班级: 2441 姓名: 韩金婕 学号:20244111 实验教师:王志强 实验日期:2025年3月18日 必修/选修: 公选课 1.实验内容熟悉Python开发环境;练习Python运行、调试技能;编写程序,练习变量和类型…

20244226 实验一《Python程序设计》实验报告

20244226 2024-2025-2 《Python程序设计》实验一报告 1.实验内容 课程:《Python程序设计》 班级: 2442 姓名: 张毓格 学号:20244226 实验教师:王志强 实验日期:2025年3月18日 必修/选修: 公选课 1.实验内容 1.熟悉Python开发环境; 2.练习Python运行、调试技能; 3.编…

2025“钉耙编程”中国大学生算法设计春季联赛(2)(2 4 5,补3 6 8)

2025“钉耙编程”中国大学生算法设计春季联赛(2)(2 4 5,补3 6 8) 1002:烂人方法 #include<bits/stdc++.h> #define N 1005 #define mod 998244353 using namespace std; typedef long long ll; string a[] = {"jia","yi","bing",&quo…

.NET周刊【3月第2期 2025-03-09】

国内文章 记一次.NET内存居高不下排查解决与启示 https://www.cnblogs.com/huangsheng/p/18731382 本文讲述了一个ASP.NET Core gRPC服务迁移到Kubernetes后的内存管理问题。服务在K8s上遇到了高内存占用与副本扩展的问题,经过排查发现服务的内存请求设置正确,但未设定上限。…

Agent 智能体创作大赛+参赛小分队召集

与大家分享一个 agent 比赛「智能体全球创作大赛」。你可以用任何趁手的工具打造一个 agent,分享你对人机协作未来的畅想。大赛公告发布出去后,不少社区伙伴都表示有兴趣参与,所以我们决定建一个「RTE 参赛小分队」微信群 ,愿意一起分享想法和讨论技术,一起赶 deadline(3…

HTML打包EXE离线一机一码使用详细教程

近期有些朋友对于HTML打包EXE的网络一机一码验证和离线一机一码验证不太理解,本篇文章主要介绍离线一机一码的使用。相较于需要联网验证的方案,离线版本的优势在于无需连接服务器,通过本地生成的机器码与激活码即可完成授权验证,更适合对数据安全性要求较高,无法联网的项目…

Breach2.1

Breach2.1 信息收集 全端口扫描 ┌──(root㉿kali)-[~/vulnhub/Breach2.1] └─# nmap -sS 192.168.110.151 -p 1-65535 Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-03-18 09:39 CST Stats: 0:00:13 elapsed; 0 hosts completed (0 up), 1 undergoing ARP Ping Scan…

Breach2

Breach2.1 信息收集 全端口扫描 ┌──(root㉿kali)-[~/vulnhub/Breach2.1] └─# nmap -sS 192.168.110.151 -p 1-65535 Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-03-18 09:39 CST Stats: 0:00:13 elapsed; 0 hosts completed (0 up), 1 undergoing ARP Ping Scan…

HTML打包工具EXE工具一机一码激活码计算器小程序版

近期我们收到一些HTML一键打包EXE工具老用户反馈, 他们在使用一机一码离线功能的时候, 遇到如下的问题:外调试时突然需要激活码,手边没电脑急死人!客户现场网络受限,手机能操作就好了每次都要开电脑太麻烦,能移动端解决吗? 解决方案 针对用户集中反馈的"离线激活码…