FreeRTOS源码分析-6 多任务使用要点

news2024/11/17 2:42:06

目录

1 临界段应用

1.1临界段的作用

1.2临界段API

1.3临界段应用

2 临界段原理

2.1FreeRTOS中断管理实现

2.2关开中断实现

2.3临界段实现

3 任务栈大小确定

3.1确定

3.2MKD-htm文件分析

3.3堆栈检测API

4 栈溢出检测应用 

4.1栈溢出检测方案一

4.2栈溢出检测方案二

4.3获取任务状态方案(推荐)

5 CPU使用率

5.1 CPU利用率统计的作用

5.2 CPU利用率统计API 

5.3 CPU利用率统计实现


1 临界段应用

1.1临界段的作用

 不想被打断访问的资源

问:什么是不可重入函数?

比如使用静态全局变量,这时候被系统打断,那么会出问题;还比如malloc,分配到一半,被系统打断。

问:使用硬件资源为什么不希望被打断?
串口、SPI、II2 通信的时候,不希望被打断

问:什么情况下对时序有精准要求的操作不希望被打断?
比如写了一个驱动,延时被打断

1.2临界段API

门限值  ,低于配置宏定义的优先级的中断才会关闭

保证实时性操作不会屏蔽,不允许嵌套

上述两个接口一般不建议这样使用,特殊情况下才使用。

下面两个是任务中提供的临界段

注意事项

  • 不允许加延时
  • 必须成对出现,不能在中断使用

下面是专门在中断中使用的临界段接口函数

 问:为何要返回上次中断屏蔽寄存器的操作值?

因为这个接口支持嵌套,内核在调用,其他任务也可以调用,那么退出中断的时候,要恢复之前临界段的状态,不影响其他任务而产生错误

1.3临界段应用

1、分别修改Usart_Task、DelayTask任务

2、配置延时周期为50ms打印一次运行状态,观察现象,是否出现,资源冲突问题

3、当多任务共同使用串口的时候,如果冲突,如何通过临界段解决共享资源冲突问题

这是未使用临界段的情况

问:出现这个问题的原因?

当高优先级任务就绪态的时候,会抢占低优先级的任务,但是当恢复的时候,usarttask和delaytask相同优先级,会看谁的阻塞时间先到,之后再会返回给UsartTask

问:如何解决?

在printf的时候用临界段包裹一下

2 临界段原理

2.1FreeRTOS中断管理实现

相比STM32的优先级8bit,FreeRTOS没有亚优先级的位段,只有4bit ,对应3

main(void) //---->
    HAL_Init(); //---->
        HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //---->3

 FreeRTOS采用最后一种BASERPRI

门限值是5,>5要屏蔽掉,<5没关系,可以响应
屏蔽 15<<(8-5),因为内核优先级在高4位,所以最低是这么设置屏蔽
屏蔽 5<<(8-5),因为内核优先级在高4位,所以最低是这么设置屏蔽 

2.2关开中断实现

开中断实现

//portENTER_CRITICAL更硬件平台有关系,如果要移植其他平台函数要自己写
//uxCriticalNesting++嵌套增加,使用启动程序的时候用到过变为0。如果第一次检查一下参数
void vPortEnterCritical( void )
{
	portDISABLE_INTERRUPTS();
	uxCriticalNesting++;
}

#define portDISABLE_INTERRUPTS vPortRaiseBASEPRI()

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/*将BASEPRI设置为最大系统调用优先级,以实现critical部分。 */
		msr basepri, ulNewBASEPRI  //basepri赋值为5
		dsb
		isb
	}
}

关中断实现 

#define portENABLE_INTERRUPTS()	vPortSetBASEPRI( 0 )

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
	__asm
	{
		/* Barrier instructions are not used as this function is only used to
		lower the BASEPRI value. */
		msr basepri, ulBASEPRI
	}
}

总结:freeRTOS都是通过门限值来开关中断的。 

2.3临界段实现

进入临界段

如果移植其他平台,这段代码要自己实现,FreeRTOS为我们实现的代码如下

void vTaskEnterCritical( void )
{
    //屏蔽中断寄存器设置为5
	portDISABLE_INTERRUPTS();

	if( xSchedulerRunning != pdFALSE )
	{
        //嵌套功能+1,启动内核时候是0
		( pxCurrentTCB->uxCriticalNesting )++;
        //是否第一次使用
		if( pxCurrentTCB->uxCriticalNesting == 1 )
		{
            //检查
			portASSERT_IF_IN_ISR();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

退出临界段

void vTaskExitCritical( void )
{
	if( xSchedulerRunning != pdFALSE )
	{
		if( pxCurrentTCB->uxCriticalNesting > 0U )
		{
			( pxCurrentTCB->uxCriticalNesting )--;

            //等于0,主要是用于判断是否成对出现
			if( pxCurrentTCB->uxCriticalNesting == 0U )
			{
				portENABLE_INTERRUPTS();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	else
	{
		mtCOVERAGE_TEST_MARKER();
	}
}

中断中进入临界段

带返回值是用来满足嵌套功能

#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )
{
    //设置屏蔽寄存器的值,以及返回值
    uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/* 将目前屏蔽寄存器的值读出来返回*/
		mrs ulReturn, basepri
        /* 将BASEPRI设置为最大系统调用优先级*/
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}

	return ulReturn;
}

中断中退出临界段

如果第一次使用,那么是0,


#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
	__asm
	{
		/*每次退出把值写入中断屏蔽寄存器中 */
		msr basepri, ulBASEPRI
	}
}

总结:

  • 1必须成对出现
  • 2必须不能耗时,否则无法实现

3 任务栈大小确定

3.1确定

其中任务栈PSP,系统栈MSP

以上的分析太繁琐,需要研究函数循环嵌套等,以下方式更简单。

注意:函数指针、中断嵌套是不在分析范围内的

栈溢出检测:针对TOP指针和stack起始地址分析,当然只能在任务切换的时候检测,但是running的时候没法检测。所以FreeRTOS初始化数据为0xa5,末尾16个字节也是0xa5,如果不是0xa5就会栈溢出。

3.2MKD-htm文件分析

 

上例分析: 代码长度22byte,栈空间0byte,栈最大深度72字节,主要调用了Calls5处内容,当然类似printf属于C库大小未能分析准确。

3.3堆栈检测API

方案一、在任务切换时检测任务栈指针是否过界
方案二、任务创建的时候将任务栈所有数据初始化为 0xa5,任务切换时进行任务栈检测的时候会检测末尾的 16 个字节是否都是 0xa5

4 栈溢出检测应用 

4.1栈溢出检测方案一

实验流程

  • 1、打开栈溢出检测方案1
  • 2、修改Usart_Task任务
  • 3、在任务内模拟栈溢出,分析实验结果

开启检测方案一

 模拟溢出,根据满减栈特点,逆序写入0x88

回调函数打印便可知道是否溢出

效果:已经溢出了,打印的时候会有乱码,但是最后又OverFlow标志

4.2栈溢出检测方案二

方案一、二都会有弊端 

其余不变,编译结果

4.3获取任务状态方案(推荐)

功能需求

  • 1、打开任务状态配置
  • 2、修改key_Task任务
  • 3、当检测按键按下时,打印任务状态信息

使能两个宏定义

 定义一个全局buff

 

在按键按下后调用vTasklist接口,并打印

效果

 

 state说明,stack表示剩余堆栈,num任务序号

 如果stack接近0,说明堆栈将用尽,以字为单位。

5 CPU使用率

5.1 CPU利用率统计的作用

发现内存、cpu卡顿的原因


5.2 CPU利用率统计API 

与vTaskList差不多,名称、绝对时间,时间占用率。
注意事项:

  • port相关是和stm32f4要实现的两个宏定义
  • 高精度定时器目的:假如Systick我们设置的是1ms,只有使能10us的定时器,才能去统计1ms的定时周期 一般10倍或20倍 


5.3 CPU利用率统计实现

业务流程:

  • 配置相关宏
  • 使能高精度定时器
  • 定时器中断回调函数
  • FreeRTOS嵌套函数实现
  • 按键触发CPU利用率

配置2个宏定义

 

根据stm32参考手手册配置定时器

 

 

20us的频率,计算公式:84Mhz/85/50=20 

使能TIM6中断

新建全局变量

 

回调函数中计数

 

改写并调用vTaskGetRunTimsStats

 

 实验效果

 

 

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

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

相关文章

各种id转换 kegg id kegg compound id 与HMDB转换

KEGG COMPOUND 数据库 - 简书 (jianshu.com) kegg id号转换为可读 的name &#xff1a;使用KEGGREST #-------------kegg id的entry和Name转换 https://zhuanlan.zhihu.com/p/545494092 #BiocManager::install("KEGGREST") #安装KEGGREST这个包 library(…

Android访问其他程序中的数据——以读取系统联系人为例

首先&#xff0c;需要保证通讯录里面有联系人存在&#xff0c;这里手动新增了两条数据。 activity_main.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"xmln…

SpringBoot创建和使⽤

1.什么是Spring Boot&#xff1f;为什么要学Spring Boot&#xff1f; Spring 的诞⽣是为了简化 Java 程序的开发的&#xff0c;⽽ Spring Boot 的诞⽣是为了简化 Spring 程序开发 的。 Spring Boot 翻译⼀下就是 Spring 脚⼿架&#xff0c;什么是脚⼿架呢&#xff1f;如下图所…

函数(超详解)

函数 1.什么是函数2.C语言中函数的分类2.1 库函数2.1.1如何使用库函数 2.2自定义函数 3.函数的参数3.1实际参数&#xff08;实参&#xff09;3.2形式参数&#xff08;形参&#xff09; 4.函数的调用4.1 传值调用4.2 传址调用4.3 练习 5.函数的嵌套使用和链式访问5.1 嵌套调用5.…

第15章 呈现数据

默认情况下&#xff0c;大多数bash命令会将输出导向STDOUT文件描述符。 数据追加到某个文件用>> 符号来完成。 who命令生成的输出会被追加到test2文件中已有数据的后面。 只重定向错误STDERR文件描述符被设成2。可以选择只重定向错误消息&#xff0c;将该文件描述符值…

day02_springboot综合案例

day02_springboot综合案例 订单操作 查询所有订单 查询所有订单流程 查询订单&#xff0c;要把订单对应的产品也要查出来 Orders实体类 Data public class Orders {private String id;private String orderNum;DateTimeFormat(pattern"yyyy-MM-dd HH:mm")privat…

多线程面试题--线程安全

synchronized关键字的底层原理 基础版 当我们对代码就行反编译&#xff0c;会发现其实synchronized就是monitor Monitor 假如现在有一个线程过来了&#xff0c;要执行当前代码&#xff0c;会执行到synchronized (lock)&#xff0c;lock是一个对象锁。首先会让这个lock对象和m…

Clion开发stm32之微妙延迟(采用nop指令实现)

前言 需要借助逻辑分析仪动态调整参数此次测试的开发芯片为stm32f103vet6 延迟函数 声明 #define NOP_US_DELAY_MUL_CNT 5 /*nop 微妙延迟需要扩大的倍数(根据实际动态修改)*/ void bsp_us_delay_nop(uint32_t us);void bsp_ms_delay_nop(uint32_t ms);定义 void bsp_us_dela…

【深度学习】yolov5以及yolov8的微调后的模型精度对比

文章目录 前言1. 训练1.1 yolov5 的 yolov5m61.2 yolov5 的 yolov5l61.3 yolov8 的训练 结论&#xff1a; 前言 做了一个烟火识别&#xff0c;用了2W张图片&#xff0c;标注包括&#xff1a;fire&#xff0c;smoke 。在coco80类的模型上进行ft&#xff0c; 借此机会进行比较一…

koa2 从0使用mysql2做第一个接口

全局安装Koa命令行工具: npm install -g koa/cli 2. 创建新项目: koa new my-app 这将生成如下目录结构: my-app ├── app.js ├── package.json └── src └── index.js 3. 安装依赖: cd my-app npm install 4. 启动项目: npm start 5.安装mysql2 yarn add…

升级JDK17问题记录

1. 放开标准库的模块访问限制 Jdk9模块后, 有些类访问, 需要通过如下配置打开访问权限 --add-opensjava.base/jdk.internal.miscALL-UNNAMED --add-opensjava.base/java.langALL-UNNAMED --add-opensjava.base/java.utilALL-UNNAMED --add-opensjava.base/java.lang.refle…

加载数据集

批量梯度下降法&#xff08;Batch Gradient Descent&#xff0c;BGD&#xff09;&#xff1a;在更新参数时&#xff0c;BGD根据batch中的所有样本对参数进行更新。&#xff08;计算速度快&#xff09; 随机梯度下降法&#xff08;Stochastic Gradient Descent&#xff0c;SGD&…

实训笔记7.21

实训笔记7.21 7.21一、MapReduce编程代码的打包问题与大数据集群环境中运行问题1.1 MR程序在运行的时候&#xff0c;job提交作业的时候会自动识别我们的运行环境&#xff0c;如果我们是在windows本地运行的话&#xff0c;MR程序识别的环境未LocalRunner这么一个环境&#xff0c…

王道考研数据结构--4.2循环队列

目录 前言 1.循环队列的定义 2.循环队列的结构 3.循环队列的操作 3.1定义循环队列 3.2初始化 3.3入队 3.4出队 3.5遍历&#xff0c;求表长 3.6清空销毁 4.完整代码 前言 日期&#xff1a;2023.7.25 书籍&#xff1a;2024年数据结构考研复习指导&#xff08;王道考研…

MySQL 中一条 SQL 的查询与更新

MySQL 中一条 SQL 的查询与更新 1 SQL 的查询1.1 MySQL 的逻辑架构图1.2 连接器1.3 查询缓存1.4 分析器1.5 优化器1.6 执行器 2 SQL 的更新2.1 redo log&#xff08;重做日志&#xff09;2.2 binlog&#xff08;归档日志&#xff09;2.3 redo log 和 binlog 日志的差异2.4 示例…

【Java SE】类和对象

目录 【1】面向对象的初步认识 【1.1】什么是面向对象 【1.2】面向对象与面向过程 【2】类定义和使用 【2.1】简单认识类 【2.2】类的定义格式 【2.3】练习 【2.3.1】定义一个狗类 【2.3.2】定义一个学生类 【3】类的实例化 【3.1】什么是实例化 【3.2】类和对象的…

Acwing.282 石子合并(动态规划)

题目 设有N堆沙子排成一排&#xff0c;其编号为1&#xff0c;2&#xff0c;3&#xff0c;…&#xff0c;N。 每堆沙子有一定的质量&#xff0c;可以用一个整数来描述&#xff0c;现在要将这N堆沙子合并成为一堆。 每次只能合并相邻的两堆&#xff0c;合并的代价为这两堆沙子的…

应用层协议——http

文章目录 1. HTTP协议1.1 认识URL1.2 urlencode和urldecode1.3 HTTP协议格式1.3.1 HTTP请求1.3.2 HTTP响应1.3.3 外网测试1.3.4 添加html文件1.3.5 HTTP常见Header1.3.6 GET和POST 1.4 HTTP的状态码1.4.1 301和3021.4.2 代码实现 1.5 Cookie1.5.1 代码验证1.5.2 Cookiesession …

【Nodejs】Puppeteer\爬虫实践

puppeteer 文档:puppeteer.js中文文档|puppeteerjs中文网|puppeteer爬虫教程 Puppeteer本身依赖6.4以上的Node&#xff0c;但是为了异步超级好用的async/await&#xff0c;推荐使用7.6版本以上的Node。另外headless Chrome本身对服务器依赖的库的版本要求比较高&#xff0c;c…

海外网红营销合作指南:详解海外合同与协议要点

随着互联网的发展和社交媒体的普及&#xff0c;海外网红营销成为了品牌推广和营销的重要力量。然而&#xff0c;这种跨国合作需要谨慎考虑&#xff0c;签订合适的合同与协议显得尤为重要&#xff0c;以确保各方权益得到保障并促进合作的顺利进行。本文Nox聚星将详细介绍与海外网…