中断管理
先看一下最常用的临界段进入的函数:进入临界段 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---中断管理的更多相关文章

  1. Linux内核学习笔记-2.进程管理

    原创文章,转载请注明:Linux内核学习笔记-2.进程管理) By Lucio.Yang 部分内容来自:Linux Kernel Development(Third Edition),Robert L ...

  2. 基于μC/OS—III的CC1120驱动程序设计

    基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120   嵌入式操作系统   STM32F103ZE   ...

  3. Mongodb Manual阅读笔记:CH4 管理

    4 管理 Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作Mongodb Manual阅读笔记:CH3 数据模型(Data Models)Mongodb Manual阅读笔 ...

  4. stm32学习笔记——外部中断的使用

    stm32学习笔记——外部中断的使用 基本概念 stm32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个.比如说,PA0,PB0 ...

  5. uc/os iii移植到STM32F4---IAR开发环境

    也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...

  6. Docker 共有 13 个管理命令和 41 个通用命令,以下是常用 Docker 命令列表

    开发人员一直在努力提高 Docker 的使用率和性能,命令也在不停变化.Docker 命令经常被弃用,或被替换为更新且更有效的命令,本文总结了近年来资深专家最常用的命令列表并给出部分使用方法. 目前, ...

  7. JAVA自学笔记13

    JAVA自学笔记13 1.StringBuffer类 1)线程安全的可变字符序列 线程安全(即同步) 2)StringBuffer与String的区别:一个可变一个不可变 3)构造方法: ①publi ...

  8. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  9. Python3+Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)

    #!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记13(js操作应用:弹出框无效如何处理)'''from sel ...

  10. 并发编程学习笔记(13)----ConcurrentLinkedQueue(非阻塞队列)和BlockingQueue(阻塞队列)原理

    · 在并发编程中,我们有时候会需要使用到线程安全的队列,而在Java中如果我们需要实现队列可以有两种方式,一种是阻塞式队列.另一种是非阻塞式的队列,阻塞式队列采用锁来实现,而非阻塞式队列则是采用cas ...

随机推荐

  1. ElasticSearch Python 基本操作

    创建索引 from elasticsearch import Elasticsearch es = Elasticsearch('192.168.149.96:9200') mappings = { ...

  2. uni-app开发经验分享十三:实现手机扫描二维码并跳转全过程

    最近使用 uni-app 开发 app ,需要实现一个调起手机摄像头扫描二维码功能,官网API文档给出了这样一个demo: // 允许从相机和相册扫码 uni.scanCode({ success: ...

  3. Spring 是如何解决循环依赖的?

    前言 相信很多小伙伴在工作中都会遇到循环依赖,不过大多数它是这样显示的: 还会提示这么一句: Requested bean is currently in creation: Is there an ...

  4. mybatis框架整合及逆向工程

    mybatis框架整合及逆向工程 一.三大框架整合 ​ 整合SSM框架 1.导入pom文件 1.导入spring的pom依赖 <?xml version="1.0" enco ...

  5. .NET 中依赖注入组件 Autofac 的性能漫聊

    Autofac 是一款超赞的 .NET IoC 容器 ,在众多性能测评中,它也是表现最优秀的一个.它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改.它的实现方式是将常 ...

  6. loj10153二叉苹果树

    有一棵二叉苹果树,如果数字有分叉,一定是分两叉,即没有只有一个儿子的节点.这棵树共 N 个节点,标号 1 至 N,树根编号一定为 1. 我们用一根树枝两端连接的节点编号描述一根树枝的位置.一棵有四根树 ...

  7. C# 实现语音聊天

    一.语音聊天说专业点就是即时语音,是一种基于网络的快速传递语音信息的技术,普遍应用于各类社交软件中,优势主要有以下几点: (1)时效性:视频直播会因为带宽问题有时出现延迟高的问题,而语音直播相对来说会 ...

  8. JDBC的操作步骤和实例()

    加载JDBC驱动程序 提供JDBC连接的URL 创建数据库的连接 创建一个Statement 执行SQL语句 处理结果 关闭JDBC对象 实例JdbcUtils 创建一个JDBC程序包含7个步骤: 1 ...

  9. 单体架构、SOA架构、微服务架构

  10. hbase笔记---新版api之对表的操作,指定region创建,普通创建,删除,修改列族信息

    hbase 对于表的相关操作: 实现功能有:指定region创建,普通创建,删除,修改列族信息 package learm.forclass.testclass; import org.apache. ...