μC/OS-III---I笔记13---中断管理
中断管理
先看一下最常用的临界段进入的函数:进入临界段 OS_CRITICAL_ENTER() 退出临界段OS_CRITICAL_EXIT()他们两个的宏是这样的.
在使能中断延迟提交时:
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u /* Deferred ISR Posts ------------------------------ */
/* Lock the scheduler */
#define OS_CRITICAL_ENTER() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr++; \
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0)
/* Lock the scheduler but re-enable interrupts */
#define OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT() \
do { \
OSSchedLockNestingCtr++; \
\
if (OSSchedLockNestingCtr == 1u) { \
OS_SCHED_LOCK_TIME_MEAS_START(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0) /* Scheduling occurs only if an interrupt occurs */
#define OS_CRITICAL_EXIT() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
if (OSIntQNbrEntries > (OS_OBJ_QTY)0) { \
CPU_CRITICAL_EXIT(); \
OS_Sched0(); \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} else { \
CPU_CRITICAL_EXIT(); \
} \
} while (0) #define OS_CRITICAL_EXIT_NO_SCHED() \
do { \
CPU_CRITICAL_ENTER(); \
OSSchedLockNestingCtr--; \
if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { \
OS_SCHED_LOCK_TIME_MEAS_STOP(); \
} \
CPU_CRITICAL_EXIT(); \
} while (0) #else /* Direct ISR Posts -------------------------------- */ 在没有使能中断延迟提交时: #define OS_CRITICAL_ENTER() CPU_CRITICAL_ENTER() #define OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT() #define OS_CRITICAL_EXIT() CPU_CRITICAL_EXIT() #define OS_CRITICAL_EXIT_NO_SCHED() CPU_CRITICAL_EXIT() #endif
先看一下在没有使能中断延迟提交时的临界段进入的函数:进入临界段 CPU_CRITICAL_ENTER() 退出临界段CPU_CRITICAL_EXIT()
他们两个的宏是这样的
#define CPU_CRITICAL_ENTER() do { CPU_INT_DIS(); } while (0)
#define CPU_CRITICAL_EXIT() do { CPU_INT_EN(); } while (0)
另一层宏是
#define CPU_INT_DIS() do { cpu_sr = CPU_SR_Save(); } while (0)
#define CPU_INT_EN() do { CPU_SR_Restore(cpu_sr); } while (0)
接着另一层宏是
CPU_SR_Save
MRS R0, PRIMASK ; Set prio int mask to mask all (except faults)
CPSID I
BX LR
这里关于C语言调用汇编,规定32位的返回值存放到R0,64位的R0存放第32为,R1存放高32位。所以上边的汇编代码第二行实际就是将PRIMASK保存到R0最后返回给变量cpu_sr ,第三行是一个CM3关全局中断的命令,在LR保存了调用CPU_SR_Save()之前的下一条指令PC指针,BX就返回了。
CPU_SR_Restore ;
MSR PRIMASK, R0
BX LR
这里注意调用这个函数时传入了cpu_sr,根据C调用汇编的规定这个变量被存放到R0里,所以第二句就是将cpu_sr 恢复到PRIMASK,由CM3权威指南可以知道,这是一个中断管理的寄存器,写1屏蔽所有中断,只剩下faul和NMI,写0则开启中断;c语言调用汇编时规定,当传递参数少于4个时,从右往左依次存放到R0~R3中,当传入参数多于4个时,多出来的参数会先入栈;
注意在调用进入临界段时常常有这个函数CPU_SR_ALLOC()它的宏是
#define CPU_SR_ALLOC() CPU_SR cpu_sr = (CPU_SR)0
即定义的一个CPU_SR的变量初始化为0;
对于延迟提交使能下的进入临界段代码,就是加了一个调度器嵌套层数OSSchedLockNestingCtr++的操作,它代表了调度器被锁住的嵌套层数,OS_CRITICAL_ENTER直接锁住调度器,OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT()这个宏调用之前一般先关闭中断,接着宏锁住调度器然后锁住调度器,再恢锁调度器前的中断状态(这里不是开中断),在没有使能中断延迟时,会增加中断关闭的时间。解开调度嵌套也有两种
- OS_CRITICAL_EXIT()
- 解开调度时进行任务调度(延迟);
- OS_CRITICAL_EXIT_NO_SCHED()
- 解开调度时不进行任务调度;
这两个函数后应该都根据选项选择是否调用OSSchedule()进行任务调度。且进入调度嵌套和退出嵌套要成对使用负责会导致调度器被一直锁住。锁住调度器是用户无法进行任务切换,也无法将当前任务挂起。
中断在系统中相当于优先级最高的任务,因此对于中断的处理是十分紧急的从CM3的内核中断响应机制就能知道cpu对于中断的相应是追求极致的快速,所以UCOS对于这里也有对应的措施,系统级的一些处理时间比较长的任务不允许在中断中调用,对于一些中断中的提交函数会放到中断延迟提交里完成,把中断级的任务放到任务级从而减少关中断时间,减少对中断的实时性的影响。
中断延迟提交:
当用户在把宏OS_CFG_ISR_POST_DEFERRED使能,使用延迟提交在系统初始化时会自动初始化延迟提交队列然后创建一个延迟提交任务。
OSInit()函数内的延迟提交任务初始化
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
OS_IntQTaskInit(p_err); /* Initialize the Interrupt Queue Handler Task */
if (*p_err != OS_ERR_NONE) {
return;
}
#endif
中断延迟提交的过程就是把要提交的内容先保存起来,然后把系统初始化时创建一个优先级 为0(最高)的延迟提交任务就绪,在中断函数执行完成后就会执行延迟的提交。对于OS_IntQTaskInit(p_err)主要作用就是初始化延迟提交队列,并创建任务。在之前的任务管理章节我们知道一个任务被创建就会加如就绪列表等待调用时就会执行.
void OS_IntQTaskInit (OS_ERR *p_err)
{
OS_INT_Q *p_int_q;
OS_INT_Q *p_int_q_next;
OS_OBJ_QTY i; #ifdef OS_SAFETY_CRITICAL
if (p_err == (OS_ERR *)0) {
OS_SAFETY_CRITICAL_EXCEPTION();
return;
}
#endif
//延迟提交溢出计数清零
OSIntQOvfCtr = (OS_QTY)0u; /* Clear the ISR queue overflow counter */
//延迟提交信息队列的内存不能是空
if (OSCfg_IntQBasePtr == (OS_INT_Q *)0) {
*p_err = OS_ERR_INT_Q;
return;
}
//延迟信息队列的长最小是1
if (OSCfg_IntQSize < (OS_OBJ_QTY)2u) {
*p_err = OS_ERR_INT_Q_SIZE;
return;
}
//延迟提交任务每次运行的最长时间
OSIntQTaskTimeMax = (CPU_TS)0; p_int_q = OSCfg_IntQBasePtr; /* Initialize the circular ISR queue */
p_int_q_next = p_int_q;
p_int_q_next++;
//将信息对垒串成单项链表
for (i = 0u; i < OSCfg_IntQSize; i++) {
p_int_q->Type = OS_OBJ_TYPE_NONE;
p_int_q->ObjPtr = (void *)0;
p_int_q->MsgPtr = (void *)0;
p_int_q->MsgSize = (OS_MSG_SIZE)0u;
p_int_q->Flags = (OS_FLAGS )0u;
p_int_q->Opt = (OS_OPT )0u;
p_int_q->NextPtr = p_int_q_next;
p_int_q++;
p_int_q_next++;
}
//单项链表“圈”操作方便延时提交队列内存的使用
p_int_q--;
p_int_q_next = OSCfg_IntQBasePtr;
p_int_q->NextPtr = p_int_q_next;
OSIntQInPtr = p_int_q_next;
OSIntQOutPtr = p_int_q_next;
//延迟提交队列中要进行提交的内核对象个数
OSIntQNbrEntries = (OS_OBJ_QTY)0u;
//延迟提交队列中要进行提交的内核对象的最大个数
OSIntQNbrEntriesMax = (OS_OBJ_QTY)0u; /* -------------- CREATE THE ISR QUEUE TASK ------------- */
if (OSCfg_IntQTaskStkBasePtr == (CPU_STK *)0) {
*p_err = OS_ERR_INT_Q_STK_INVALID;
return;
} if (OSCfg_IntQTaskStkSize < OSCfg_StkSizeMin) {
*p_err = OS_ERR_INT_Q_STK_SIZE_INVALID;
return;
}
//创建延迟提交任务
OSTaskCreate((OS_TCB *)&OSIntQTaskTCB,
(CPU_CHAR *)((void *)"uC/OS-III ISR Queue Task"),
(OS_TASK_PTR )OS_IntQTask,
(void *)0,
(OS_PRIO )0u, /* This task is ALWAYS at priority '0' (i.e. highest) */
(CPU_STK *)OSCfg_IntQTaskStkBasePtr,
(CPU_STK_SIZE)OSCfg_IntQTaskStkLimit,
(CPU_STK_SIZE)OSCfg_IntQTaskStkSize,
(OS_MSG_QTY )0u,
(OS_TICK )0u,
(void *)0,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)p_err);
} #endif
OS_IntQTaskInit ()
函数内创建的延迟提交任务
void OS_IntQTask (void *p_arg)
{
CPU_BOOLEAN done;
CPU_TS ts_start;
CPU_TS ts_end;
CPU_SR_ALLOC(); p_arg = p_arg; /* Not using 'p_arg', prevent compiler warning */
while (DEF_ON) {
done = DEF_FALSE;
while (done == DEF_FALSE) {
CPU_CRITICAL_ENTER();
//还有内核对象等待提交?
//否
if (OSIntQNbrEntries == (OS_OBJ_QTY)0u) {
//任务删除
OSRdyList[0].NbrEntries = (OS_OBJ_QTY)0u; /* Remove from ready list */
OSRdyList[0].HeadPtr = (OS_TCB *)0;
OSRdyList[0].TailPtr = (OS_TCB *)0;
OS_PrioRemove(0u); /* Remove from the priority table */
CPU_CRITICAL_EXIT();
OSSched();
done = DEF_TRUE; /* No more entries in the queue, we are done */
}
//是
else {
CPU_CRITICAL_EXIT();
ts_start = OS_TS_GET();
//提交信息
OS_IntQRePost();
ts_end = OS_TS_GET() - ts_start; /* Measure execution time of tick task */
if (OSIntQTaskTimeMax < ts_end) {
OSIntQTaskTimeMax = ts_end;
}
CPU_CRITICAL_ENTER();
//提交信息队列出口指向更新
OSIntQOutPtr = OSIntQOutPtr->NextPtr; /* Point to next item in the ISR queue */
OSIntQNbrEntries--;
CPU_CRITICAL_EXIT();
}
}
}
}
函数内先检查提交信息队列是否为空了也就是提交完了,如果 提交完成了就将延迟提交任务从对应优先级的就绪任务列表移除,如果还有信息队列等待提交就继续调用OS_IntQRePost();进行内核对象提交。
void OS_IntQRePost (void)
{
CPU_TS ts;
OS_ERR err; //根据提交对象的类型进行选择内核对象提交函数
switch (OSIntQOutPtr->Type) { /* Re-post to task */
case OS_OBJ_TYPE_FLAG:
#if OS_CFG_FLAG_EN > 0u
(void)OS_FlagPost((OS_FLAG_GRP *) OSIntQOutPtr->ObjPtr,
(OS_FLAGS ) OSIntQOutPtr->Flags,
(OS_OPT ) OSIntQOutPtr->Opt,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_Q:
#if OS_CFG_Q_EN > 0u
OS_QPost((OS_Q *) OSIntQOutPtr->ObjPtr,
(void *) OSIntQOutPtr->MsgPtr,
(OS_MSG_SIZE) OSIntQOutPtr->MsgSize,
(OS_OPT ) OSIntQOutPtr->Opt,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_SEM:
#if OS_CFG_SEM_EN > 0u
(void)OS_SemPost((OS_SEM *) OSIntQOutPtr->ObjPtr,
(OS_OPT ) OSIntQOutPtr->Opt,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_TASK_MSG:
#if OS_CFG_TASK_Q_EN > 0u
OS_TaskQPost((OS_TCB *) OSIntQOutPtr->ObjPtr,
(void *) OSIntQOutPtr->MsgPtr,
(OS_MSG_SIZE) OSIntQOutPtr->MsgSize,
(OS_OPT ) OSIntQOutPtr->Opt,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_TASK_RESUME:
#if OS_CFG_TASK_SUSPEND_EN > 0u
(void)OS_TaskResume((OS_TCB *) OSIntQOutPtr->ObjPtr,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_TASK_SIGNAL:
(void)OS_TaskSemPost((OS_TCB *) OSIntQOutPtr->ObjPtr,
(OS_OPT ) OSIntQOutPtr->Opt,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
break; case OS_OBJ_TYPE_TASK_SUSPEND:
#if OS_CFG_TASK_SUSPEND_EN > 0u
(void)OS_TaskSuspend((OS_TCB *) OSIntQOutPtr->ObjPtr,
(OS_ERR *)&err);
#endif
break; case OS_OBJ_TYPE_TICK:
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
//任务时间片轮换调度任务
OS_SchedRoundRobin(&OSRdyList[OSPrioSaved]);
#endif
//时间任务管理
(void)OS_TaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
(OS_OPT ) OS_OPT_POST_NONE,
(CPU_TS ) OSIntQOutPtr->TS,
(OS_ERR *)&err);
#if OS_CFG_TMR_EN > 0u
//定时器任务提交
OSTmrUpdateCtr--;
if (OSTmrUpdateCtr == (OS_CTR)0u) {
OSTmrUpdateCtr = OSTmrUpdateCnt;
ts = OS_TS_GET(); /* Get timestamp */
(void)OS_TaskSemPost((OS_TCB *)&OSTmrTaskTCB, /* Signal timer task */
(OS_OPT ) OS_OPT_POST_NONE,
(CPU_TS ) ts,
(OS_ERR *)&err);
}
#endif
break; default:
break;
}
}
OS_IntQRePost()
这个函数内就是根据延迟提交的内核对象的类型然后分别调用内核对应的Post函数对内核对象进行提交。从而完成内核对象的延迟提交。
μC/OS-III---I笔记13---中断管理的更多相关文章
- Linux内核学习笔记-2.进程管理
原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...
- 基于μC/OS—III的CC1120驱动程序设计
基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120 嵌入式操作系统 STM32F103ZE ...
- Mongodb Manual阅读笔记:CH4 管理
4 管理 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔 ...
- stm32学习笔记——外部中断的使用
stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- Docker 共有 13 个管理命令和 41 个通用命令,以下是常用 Docker 命令列表
开发人员一直在努力提高 Docker 的使用率和性能,命令也在不停变化.Docker 命令经常被弃用,或被替换为更新且更有效的命令,本文总结了近年来资深专家最常用的命令列表并给出部分使用方法. 目前, ...
- JAVA自学笔记13
JAVA自学笔记13 1.StringBuffer类 1)线程安全的可变字符序列 线程安全(即同步) 2)StringBuffer与String的区别:一个可变一个不可变 3)构造方法: ①publi ...
- linux kernel学习笔记-5内存管理_转
void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...
- Python3+Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)'''from sel ...
- 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理
· 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...
随机推荐
- 参数模型检验过滤器 .NetCore版
最近学习 .NETCore3.1,发现过滤器的命名空间有变化. 除此以外一些方法的名称和使用方式也有变动,正好重写一下. 过滤器的命名空间的变化 原先:System.Web.Http.Filters; ...
- 单台服务器-利用docker搭建Redis哨兵集群模式
前言:只有一台华为云服务器,所以打算创建三个容器来模拟三个服务器了. 一:拉取redis镜像 二:拉取redis.conf文件 放在自定义的目录下:wget -c http://download.re ...
- new() 和 make() 的区别 var arr1 = new([5]int) var arr2 [5]int
Effective Go - The Go Programming Language https://golang.org/doc/effective_go.html#allocation_new A ...
- 从零开始学Java (二)Hello
1.新建Hello.java文件,写入以下内容 1 public class Hello { 2 public static void main(String[] args) { 3 System.o ...
- EF Code First 无法加载指定的元数据资源
是由属于一般出现这个错误是由于App.config里面配置错误,DB First 是不一样的. 配置文件不止一个地方··多查查其他项目有没有.
- editplus 5.0 破解
先安装软件,安装步骤就不解释了,很傻瓜式的,一直下一步就行. 到了最重要的一步,请看仔细了!!! 在两个输入框中分别输入 注册名 Vovan 注册码 3AG46-JJ48E-CEACC-8E6 ...
- 安装sqlserver 的时候 报错:无法通过Windows功能控制面板自动安装或卸载Windows Server 角色和功能。
无法安装以下功能:.NET Framework 3.5(包括.NET2.0和3.0) 无法通过Windows功能控制面板自动安装或卸载Windows Server 角色和功能. 若要安装Windows ...
- Spring听课笔记(专题一)
Spring入门课程:https://www.imooc.com/learn/196 第0章: Spring是为解决企业应用程序开发复杂性而创建的一个Java开源框架,应用非常广泛.业内非常流行的SS ...
- Maven 私服(Nexus)
@[toc](Maven 私服(Nexus)) 1.Nexus 简介 Nexus是Maven仓库管理器,也可以叫Maven的私服.Nexus是一个强大的Maven仓库管理器,它极大地简化了自己内部仓库 ...
- 使用 Shiro,从架构谈起,到框架集成!
使用 Shiro,从架构谈起,到框架集成! 一.架构 1.使用用户的登录信息创建令牌 2.执行登陆动作 3.判断用户 4.两条重要的英文 二.实现Realm 1.缓存机制 2.散列算法与加密算法 3. ...