当前位置: 首页 > news >正文

RTOS 低功耗设计原理及实现

RTOS 低功耗设计原理及实现


在这里插入图片描述


文章目录

    • RTOS 低功耗设计原理及实现
    • 👨‍🏫前言
    • 👨‍🔬Tickless Idle Mode 的原理及实现
    • 👨‍🚀Tickless Idle Mode 的软件设计原理
    • 👨‍💻Tickless Idle Mode 的实现
    • 👨‍⚖️结尾


👨‍🏫前言


目前, 越来越多的嵌入式产品在开发中使用 RTOS 作为软件平台, 同时,开发中对低功耗的要求也越来越高, 本文会讨论一下如何在 RTOS 中处理微控制器的低功耗特性。

应用中使用的 RTOS 一般采用基于时间片轮转的抢占式任务调度机制,一般的低功耗设计思路如下:

  • 当 Idle 任务运行时,进入低功耗模式;
  • 在适当的条件下,通过中断或者外部事件唤醒 MCU

但是, 从第二点可以看出,每次当 OS 系统定时器产生中断时,也会将 MCU 从低功耗模式中唤醒,而频繁的进入低功耗模式/从低功耗模式中唤醒会使得 MCU 无法进入深度睡眠,对低功耗设计而言也是不合理的。

在 FreeRTOS 中给出了一种低功耗设计模式 —— Tickless Idle Mode, 这个方法可以让 MCU 更长的时间处于低功耗模式。

🌸🌸🌸🌷🌷🌷💐💐💐🌷🌷🌷🌸🌸🌸

👨‍🔬Tickless Idle Mode 的原理及实现


在这里插入图片描述

上图是任务调度示意图,横轴是时间轴, T1, T2, T3, T4 是 RTOS 的时间片基准,有四个任务分别是 TaskA,TaskB,TaskC,TaskD:

  • Task A,周期性任务
  • Task B, 周期性任务
  • Task C,突发性任务
  • Task D,周期性任务

从图中可以看出在四个任务进行调度之间,会有四次空闲期间(此时 RTOS 会调度 Idle 任务运行, 软件设计的目标应该是尽可能使 MCU 在 Idle 任务运行时处于低功耗模式)。

1️⃣Idle1
Idle 任务运行期间,会产生一次系统时钟滴答,此时会唤醒 MCU,唤醒后 MCU 又会进入低功耗模式, 这次唤醒是无意义的。期望使 MCU 在 Idle1 期间一直处于低功耗模式, 因此适当调整系统定时器中断使得 T1 时不触发系统时钟中断, 中断触发点设置为 Task B 到来时。

2️⃣Idle2
Task C 在系统滴答到达前唤醒 MCU(外部事件),MCU 可以在 Idle2 中可以一直处于低功耗模式;

3️⃣Idle3
与 Idle2 情况相同,但 Idle3 时间很短,如果这个时间很短,那么进入低功耗模式的意义并不大,因此在进入低功耗模式时软件应该添加策略;

4️⃣Idle4
与 Idle1 情况相同。

🐾🐾🐾🐾🐾🐾🐾🐾🐾🐾🐾🐾

👨‍🚀Tickless Idle Mode 的软件设计原理


Tickless Idle Mode 的设计思想在于尽可能地在 MCU 空闲时使其进入低功耗模式。从上述情景中可以看出软件设计需要解决的问题有:

  • 合理地进入低功耗模式(避免频繁使 MCU 在低功耗模式和运行模式下进行不必要的切换);RTOS 的系统时钟源于硬件的某个周期性定时器(Cortex-M 系列内核多数采用 SysTick),RTOS 的任务调度器可以预期到下一个周期性任务(或者定时器任务) 的触发时间,如上文所述,调整系统时钟定时器中断触发时间,可以避免 RTOS 进入不必要的时间中断,从而更长的时间停留在低功耗模式中,此时 RTOS 的时钟不再是周期的而是动态的(在原有的时钟基准时将不再产生中断,即 Tickless)。
  • 当 MCU 被唤醒时,通过某种方式为系统时钟提供补偿。MCU 可能被两种情况所唤醒,动态调整过的系统时钟中断或者突发性的外部事件,无论是哪一种情况,都可以通过运行在低功耗模式下的某种定时器来计算出 MCU 处于低功耗模式下的时间,在 MCU 唤醒后对系统时间进行软件补偿;
  • 软件实现时,要根据具体的应用情景和 MCU 低功耗特性来处理问题。尤其是 MCU 的低功耗特性,不同 MCU 处于不同的低功耗模式下所能使用的外设(主要是定时器) 是不同的, RTOS 的系统时钟可以进行适当的调整。
🌻🌻🌻🌼🌼🌼🌺🌺🌺🌼🌼🌼🌻🌻🌻

👨‍💻Tickless Idle Mode 的实现


这里以 STM32F407 系列的 MCU 为例, 首先需要明确的是 MCU 的低功耗模式, F407 有 3 种低功耗模式:Sleep,Stop, Standby, 在 RTOS 平台时, SRAM 和寄存器的数据不应丢失, 此外需要一个定时器为 RTOS 提供系统时钟, 这里选择 Sleep 模式下进行实现。

在这里插入图片描述

1. 使能

#define configUSE_TICKLESS_IDLE    1

2. 空闲任务(RTOS 空闲时自动调用)

/* Idle 任务 */
void prvIdleTask( void *pvParameters )
{for( ; ; ){...#if ( configUSE_TICKLESS_IDLE != 0 ){TickType_t xExpectedIdleTime;/* 用户策略以决定是否需要进入 Tickless Mode */xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){vTaskSuspendAll(); // 挂起调度器{configASSERT( xNextTaskUnblockTime >= xTickCount );xExpectedIdleTime = prvGetExpectedIdleTime();if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP ){/* 用户函数接口 *//* 1. 进入低功耗模式和如何退出低功耗模式 *//* 2. 系统时间补偿 */portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime );}} (void) xTaskResumeAll(); // 恢复调度器}}#endif /* configUSE_TICKLESS_IDLE */...}
}

3. 低功耗模式处理(根据 MCU 的低功耗模式编写代码)

void vPortSuppressTicksAndSleep( portTickType xExpectedIdleTime )
{unsigned long ulReloadValue, ulCompleteTickPeriods,ulCompletedSysTickDecrements;portTickType xModifiableIdleTime;/* 最长睡眠时间不可以超过定时器的最大定时值 *//* 通过调整定时器的时间基准可以获得更理想的最大定时值 */if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks ){xExpectedIdleTime = xMaximumPossibleSuppressedTicks;}/* 停止 SysTick */portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT;/* 计算唤醒时的系统时间,用于唤醒后的系统时间补偿 */ulReloadValue = portNVIC_SYSTICK_CURRENT_VALUE_REG + ( ulTimerCountsForOneTick * ( xExpectedIdleTime - 1UL ) );if( ulReloadValue > ulStoppedTimerCompensation ){ulReloadValue -= ulStoppedTimerCompensation;}__disable_interrupt();/* 确认下是否可以进入低功耗模式 */if( eTaskConfirmSleepModeStatus() == eAbortSleep ){/* 不可以,重新启动系统定时器 */portNVIC_SYSTICK_LOAD_REG = portNVIC_SYSTICK_CURRENT_VALUE_REG;portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;__enable_interrupt();}else{/* 可以进入低功耗模式 *//* 保存时间补偿,重启系统定时器 */portNVIC_SYSTICK_LOAD_REG = ulReloadValue;portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;/* 进入低功耗模式,可以通过 configPRE_SLEEP_PROCESSING 函数进行低功耗模式下时钟及外设的配置*/xModifiableIdleTime = xExpectedIdleTime;configPRE_SLEEP_PROCESSING( xModifiableIdleTime );if( xModifiableIdleTime > 0 ){__DSB();__WFI();__ISB();}/* 退出低功耗模式 */configPOST_SLEEP_PROCESSING( xExpectedIdleTime );portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT;__disable_interrupt()__enable_interrupt();/*唤醒有两种情况:系统定时器或者外部事件(中断) */if((portNVIC_SYSTICK_CTRL_REG & portNVIC_SYSTICK_COUNT_FLAG_BIT) != 0){/* 系统定时器唤醒,时间补偿 */unsigned long ulCalculatedLoadValue;ulCalculatedLoadValue = ( ulTimerCountsForOneTick - 1UL )( ulReloadValue - portNVIC_SYSTICK_CURRENT_VALUE_REG );if( ( ulCalculatedLoadValue < ulStoppedTimerCompensation ) ||  ( ulCalculatedLoadValue > ulTimerCountsForOneTick ) ){ulCalculatedLoadValue = (ulTimerCountsForOneTick - 1UL);}portNVIC_SYSTICK_LOAD_REG = ulCalculatedLoadValue;ulCompleteTickPeriods = xExpectedIdleTime - 1UL;}else{/* 外部事件(中断)唤醒 */ulCompletedSysTickDecrements = ( xExpectedIdleTime *ulTimerCountsForOneTick ) - portNVIC_SYSTICK_CURRENT_VALUE_REG;ulCompleteTickPeriods = ulCompletedSysTickDecrements /ulTimerCountsForOneTick;portNVIC_SYSTICK_LOAD_REG = ( ( ulCompleteTickPeriods + 1 ) *ulTimerCountsForOneTick ) - ulCompletedSysTickDecrements;}/* 重启 Systick,调整系统定时器中断为正常值 */portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;portENTER_CRITICAL();{portNVIC_SYSTICK_CTRL_REG = portNVIC_SYSTICK_CLK_BIT |portNVIC_SYSTICK_INT_BIT |portNVIC_SYSTICK_ENABLE_BIT;vTaskStepTick( ulCompleteTickPeriods );portNVIC_SYSTICK_LOAD_REG = ulTimerCountsForOneTick - 1UL;}portEXIT_CRITICAL();}
}

👨‍⚖️结尾


STM32 家族中拥有不同的系列,特别是专为低功耗应用设计的 L 系列,为其设计 RTOS 低功耗特性实现时可以有更多的实现方式(例,某种模式下内核停止运行, 此时可以使用外部定时器或者 RTC 来代替 Systick 作为系统定时器)。

在这里插入图片描述

相关文章:

RTOS 低功耗设计原理及实现

RTOS 低功耗设计原理及实现 文章目录 RTOS 低功耗设计原理及实现&#x1f468;‍&#x1f3eb;前言&#x1f468;‍&#x1f52c;Tickless Idle Mode 的原理及实现&#x1f468;‍&#x1f680;Tickless Idle Mode 的软件设计原理&#x1f468;‍&#x1f4bb;Tickless Idle Mo…...

PaddleOCR C++编译出错解决方案

文章目录 前言一、环境准备1、主要环境2、源码下载3、C推理库下载 二、报错信息1.静态库调用错误2.ld returned 1 exit status 总结 前言 最近&#xff0c;想尝试下PaddleOCR的C推理&#xff0c;但是过程不如人所愿&#xff0c;除了很多问题&#xff0c;这里捡重点的说下吧&…...

89、简述RabbitMQ的架构设计

简述RabbitMQ的架构设计 BrokerQueueExchangeRoutingKeyBinding信道架构设计图Broker RabbitMQ的服务节点 Queue 队列,是RabbitMQ的内部对象,用于存储消息。RabbitMQ中消息只能存储在队列中。生产者投递消息到队列,消费者从队列中获取消息并消费。多个消费者可以订阅同一…...

63 | 图像处理

文章目录 Python图像处理什么是图像处理?Python图像处理库安装Pillow库加载和显示图像调整图像大小裁剪图像调整图像亮度、对比度和色彩平衡应用滤镜练习题Python图像处理 什么是图像处理? 图像处理是指使用计算机算法来改变图像的外观或特征。它可以用于许多不同的应用程序…...

Stable Diffusion - 扩展 Roop 换脸 (Face Swapping) 插件的配置与使用

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/131856141 官网&#xff1a;GitHub - roop&#xff0c;参考论文&#xff1a;RobustSwap: A Simple yet Robust Face Swapping Model against Attr…...

opencv实现替换证件照颜色

程序可以实现蓝色底片变为红色底片&#xff08;但有点小bug&#xff09; 修改自&#xff1a;opencv&#xff1a;HSV颜色模型_opencv hsv_君浪的博客-CSDN博客 相关文章&#xff1a;OpenCV Mat数据类型指针ptr的使用_cv::mat ptr_AoboSir的博客-CSDN博客 【OpenCV】HSV颜色识…...

Elasticsearch【全文检索、倒排索引、应用场景、对比Solr、数据结构】(一)-全面详解(学习总结---从入门到深化)

目录 Elasticsearch介绍_全文检索 Elasticsearch介绍_倒排索引 Elasticsearch介绍_Elasticsearch的出现 Elasticsearch介绍_Elasticsearch应用场景 Elasticsearch介绍_Elasticsearch对比Solr Elasticsearch介绍_Elasticsearch数据结构 Elasticsearch介绍_全文检索 Elasti…...

了解 3DS MAX 3D摄像机跟踪设置:第 2 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25&#xff0c;将持续时间设置为 12 秒。单…...

MySQL 判断 JSON 数组是否相等

文章目录 1.问题2.使用 JSON_CONTAINS 与 JSON_LENGTH参考文献 1.问题 JSON&#xff08;JavaScript Object Notation&#xff09;是流行的互联网应用服务之间的数据交换格式。 MySQL 从 5.7 版本开始支持 RFC 7159 定义的 JSON 规范&#xff0c;主要有 JSON 对象 和 JSON 数组…...

uni-app个人中心

一. 介绍uni-app&#xff1a; uni-app 是基于Vue.js框架开发的一个跨平台移动应用开发框架&#xff0c;可以同时支持多个平台&#xff08;如iOS、Android、Web等&#xff09;的应用开发。采用了统一的语法和组件规范&#xff0c;可以大大简化跨平台开发的工作&#xff0c;提高…...

只需3步,使用Stable Diffusion无限生产AI数字人视频

效果演示 先看效果&#xff0c;感兴趣的可以继续读下去。 没有找到可以上传视频的地方&#xff0c;大家打开这个网盘链接观看&#xff1a;https://www.aliyundrive.com/s/CRBm5NL3xAE 基本方法 搞一张照片&#xff0c;搞一段语音&#xff0c;合成照片和语音&#xff0c;同…...

Mysql执行计划字段解释

文章目录 一、前言二、如何查看执行计划三、执行计划各字段解释四、select_type4.1、SIMPLE&#xff08;简单查询&#xff09;4.1.1、简单的单表查询4.1.2、多表连接查询 4.2、PRIMARY&#xff08;主查询&#xff09;4.2.1、包含复杂子查询的外层查询4.2.2、UNION语句中的第一个…...

Linux -- 线程

文章目录 1. 线程概念1.1 概念1.2 理解&#xff08;Linux OS角度&#xff09;1.3 见一见 2. 线程优缺点3. 线程使用3.1 认识线程库3.2 使用3.2.1 线程创建3.2.2 线程等待3.2.3 线程退出3.2.4 线程取消3.2.5 获取线程id3.2.6 线程分离 3.3 理解线程库3.4 证明线程栈3.5 线程局部…...

Android:实时更新时间

心想着也就是更新精确到分钟&#xff0c;不用精确到秒&#xff0c;定时器就没有必要&#xff0c;系统是有广播Intent.ACTION_TIME_TICK可以直接用 动态注册广播 主方法里面调用一下 //要先设置一下当前时间&#xff0c;不然刷新时间会等到1分钟后再刷新 tv_HM.setText(getHM…...

24 鼠标常用事件

鼠标进入&#xff1a;enterEvent鼠标离开&#xff1a;leaveEvent鼠标按下&#xff1a;mousePressEvent鼠标释放&#xff1a;mouseRelaseEvent鼠标移动&#xff1a;mouseMoveEvent 提升为自定义控件MyLabel 代码&#xff1a; //mylabel.h #ifndef MYLABEL_H #define MYLABEL_H#…...

了解 3DS MAX 3D摄像机跟踪设置:第 4 部分

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 1. 项目设置 步骤 1 打开“后效”。 打开后效果 步骤 2 转到合成>新合成以创建新合成。 将“宽度”和“高度”值分别设置为 1280 和 720。将帧速率设置为 25&#xff0c;将持续时间设置为 12 秒。单…...

nginx吞吐量调优

调整worker_processes和worker_connections&#xff1a; worker_processes&#xff1a;设置为服务器的CPU核心数或更高。例如&#xff0c;如果服务器有8个CPU核心&#xff0c;可以将worker_processes设置为8。worker_connections&#xff1a;设置每个worker进程所能处理的最大连…...

Python操作Excel文件,修改Excel样式(openpyxl)

秋风阁-北溪入江流 文章目录 安装依赖库openpyxlopenpyxl的操作加载文件&#xff0c;获取sheet加载文件load_workbook获取sheet 遍历单元格迭代遍历索引遍历 单元格行高和列宽的修改Excel列号与字母的转换Excel行高修改Excel列宽修改 Excel表格文字对齐属性设置修改单元格框线保…...

AutoSAR系列讲解(实践篇)7.6-实验:配置SWCRTE(下)

阅读建议: 实验篇是重点,有条件的同学最好跟着做一遍,然后回头对照着AutoSAR系列讲解(实践篇)7.5-OS原理进阶_ManGo CHEN的博客-CSDN博客理解其配置的目的和意义。本篇是接着AutoSAR系列讲解(实践篇)7.4-实验:配置SWC&RTE_ManGo CHEN的博客-CSDN博客的实验篇接着做…...

【node】使用express+gitee搭建图床,并解决防盗链问题

首先创建一个gitee的项目&#xff0c;详细步骤我就不一一说明 注解&#xff1a;大家记得将这个项目开源&#xff0c;还有记得获取自己的私钥&#xff0c;私钥操作如下&#xff1a; node依赖下载&#xff1a; "axios": "cors": "express"…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...