FreeRTOS学习(7)

中断管理

ISR和task之间的关系
ISR:interrupt service routine
通常来说ISR是硬件控制的,task是软件控制的.ISR由于其硬件特性,需要被优先处理,其优先级比最高优先级的task都要高.且不支持抢占,进入一个interrupt就要处理完成再回到原位去处理下一个命令

ISR中的程序调用api时应特别注意使用有修饰FromISRs的标识,否则会造成一些硬件错误.在整个中断管理这一章节的核心都是在介绍如何避免在ISR中直接处理数据,转而唤醒task让其处理数据,这样变成了我们之前熟悉的模型了.

xHigherPriorityTaskWoken Parameter

为什么需要这个参数,例程里没给实际展示,最开始读起来有点晕,在于没能理解context switch指的具体内容是什么.其实应该就是指从task到ISR的这个变换导致很多api不再适用了,导致当中断试图调用api的时候,用户并不清楚中断唤醒的那个函数是否真的工作了.现在用这样一个参数来标识,初始化为pdFALSE,当它转化为pdTURE的时候,则说明服务函数成功提升到了最高优先级运行了.

还有两个相关的macro,但其实没啥必要说的,就是一个config的问题,和原理没关系

Deferred Interrupt Processing

这里解释了为什么没有timer的外设中断维持时间越短越好,因为不同于timer的回调函数,ISR和FreeRTOS程序的运行相结合并没有那么理想.所以一般ISR要实现其自己的功能,但是Tasks也得要运行,这样一来效率不就低了吗,于是就有了这个用中断再唤醒一个task,用这个task去干ISR该干的活,从另一个层面去让处理器运行加快.

中断管理这一章节比较劝退的项就在于讲到现在都是在和读者讲道理,没有一些具体的例子,而且中心思想不是那么明确.所以目前先弄懂一点:即所有的管理都有一个中心目标,防止程序卡死;而防止程序卡死的最直接做法就是防止任务进入阻塞态

Binary Semaphore

主要作用就是为了Deferred Interrupt Processing而生的,相当于一个信号的存在,由中断来告诉任务我要运行你了,发送Semaphore出去(Semaphore可以看作是一个队列,此时队列满),任务读取到这个状态就从阻塞态转换到运行态处理中断的进程,Semaphore被接收后取消(队列清空),处理完后进程任务(processing)重新回到阻塞态等待下一个Semaphore.

也有特例,文档提到有些场景使用Semaphore的时候,task也是会"归还"这个Semaphore的

Semaphore的各项api整体用起来比较简单,只说说一个特别的内容,关于发送Semaphore的问题

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, 
 BaseType_t *pxHigherPriorityTaskWoken );
/*
*xSemaphore:典型的句柄
*pxHigherPriorityTaskWoken:参数,防止中断唤醒的函数在运行完以后卡死,导致最高优先级的任务
*一直停在阻塞态内无法恢复到运行态
*/

这样一个中断一个中断的发生的情况是比较简单的,但实际场景中通常是下面的情况

单个中断连续发生两次

此时,上一个中断的processing函数还没有处理完手头上的任务,但Semaphore里面又满了,此时当任务完成后,不进入阻塞态,继续执行任务.

单个中断连续多次发生

从上面两次的情况已经知道,Semaphore只有一个信号,那么就不会再添入新的信号了.那么相当于这个中断事件(event)得不到响应了

那么要怎么解决这种连续中断的问题呢?可以使用环形缓冲区的数据结构

 //先定义一个环形缓冲区
#define BUF_LEN 32
#define NEXT_POS(i) (i+1)&0x1F//这个式子其实就是个高位清零,然后低位与的过程,环形的精髓所在
uint8_t buf[BUF_LEN];
uint32_t uc_r = 0;
uint32_t uc_w = 0;
static int buf_is_empty(void){return uc_r == uc_w;}
static int buf_is_full(void){return NEXT_POS(uc_w)==uc_r;}
static int buf_put(unsigned char val){
    if(buf_is_full())
        return -1;
    buf[uc_w] =val;
    uc_w = NEXT_POS(uc_w);
    return 0;
}
static int buf_get(unsigned char *pval){
    if(buf_is_empty())
        return -1;
    *pval = buf[uc_r];
    uc_r = NEXT_POS(uc_r);
    return 0;
}

这样一来,当中断多次发生的时候,需要Deferred process的内容就被放入了缓冲区中,而任务函数由于中断不断的产生的Semaphore来使得它处于运行态中,可以对中断事件进行有效的响应处理(call)

Counting Semaphores

没啥特别的,只要记住其实Semaphore的结构和queue非常相似即可.只不过这时候不容易将产生的还未响应的中断信号给存起来了,方便后面慢慢读取这样的信号.

Centralized deferred interrupt processing

这是一种用DaemonTask去完成中断服务的思路,那么根据DaemonTask唤醒的机制,不难知道用的肯定不是Semaphore give and get的方式去唤醒,而是用的timer common queue传送的机制,用的是xTimerPendFunctionCallFromISR()api

在ISR中使用队列传递消息

这一方法虽然方便,用的api查阅即可,但是并不建议在高频触发中断的场景下应用.这个其实在裸机中都是不常用的,通常来说传递大量的消息的话,会用DMA(在学下一章前也补上dma的原理方便查阅吧),用中断的方式传消息是一种相当消耗处理器资源的操作.再者就是对数据结构进行优化,打包成一个大体传递其指针也可以.

中断优先级

比较偏ARM架构深层的内容,暂时还不太了解,挖个坑以后再来填吧

填坑:

其实涉及到一个比较复杂的问题,当我们说FreeRTOS管理任务的时候是支持抢占的,但是有没有想过中断有没有被抢占的说法呢?这就涉及到一个中断nest的问题,就是说有多个中断正在请求响应.以后如果开arm架构的坑会考虑讲一下,想了解的话可以参考

https://developer.arm.com/documentation/den0013/d/Interrupt-Handling/External-interrupt-requests/Nested-interrupt-handling

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值