RTT小师弟 · 2021年06月10日

【rtthread学习笔记系列】第二篇:中断

一、中断的概念
1.1 rtthread中断处理过程

rtthread将中断分为三个过程:前导程序、中断服务程序、后续程序。

前导程序:保存cpu中断现场,m3核该部分由硬件完成,关于保存现场的寄存器有 PSR、 PC、 LR、 R12、 R3-R0。之后通知内核处理中断。
中断服务程序:在中断触发后要执行的用户操作。
后续程序:通知内核中断处理完成,恢复cpu现场。

1.2 中断栈

rtthread会在中断的前期处理中切换栈指针到预先留出的中断栈空间,等中断退出时恢复用户的栈指针。
1.3 中断低半部处理

低半部处理用于处理耗时长的操作,举一种使用信号量完成低半部的例子:线程demo_nw_thread阻塞在等待nw_bh_sem,在中断服务程序中释放nw_bh_sem信号让demo_nw_thread线程处理中断的低半部。

rt_sem_t nw_bh_sem;

/ 数 据 读 取、 分 析 的 线 程 /
void demo_nw_thread(void *param)
{

/* 首 先 对 设 备 进 行 必 要 的 初 始 化 工 作 */
device_init_setting();
/*.. 其 他 的 一 些 操 作..*/
/* 创 建 一 个 semaphore 来 响 应 Bottom Half 的 事 件 */
nw_bh_sem = rt_sem_create("bh_sem", 0, RT_IPC_FLAG_FIFO);
while(1)
{
    /* 最 后, 让 demo_nw_thread 等 待 在 nw_bh_sem 上 */
    rt_sem_take(nw_bh_sem, RT_WAITING_FOREVER);
    /* 接 收 到 semaphore 信 号 后, 开 始 真 正 的 Bottom Half 处 理 过 程 */
    nw_packet_parser (packet_buffer);
    nw_packet_process(packet_buffer);
}

}

int main(void)
{

rt_thread_t thread;
/* 创 建 处 理 线 程 */
thread = rt_thread_create("nwt",demo_nw_thread, RT_NULL, 1024, 20, 5);
if (thread != RT_NULL)
rt_thread_startup(thread);

}

void demo_nw_isr(int vector, void *param)
{

/* 当 network 设 备 接 收 到 数 据 后, 陷 入 中 断 异 常, 开 始 执 行 此 ISR */
/* 开 始 Top Half 部 分 的 处 理, 如 读 取 硬 件 设 备 的 状 态 以 判 断 发 生 了 何 种 中 断 */
nw_device_status_read();
/*.. 其 他 一 些 数 据 操 作 等..*/
/* 释 放 nw_bh_sem, 发 送 信 号 给 demo_nw_thread, 准 备 开 始 Bottom Half */
rt_sem_release(nw_bh_sem);
/* 然 后 退 出 中 断 的 Top Half 部 分, 结 束 device 的 ISR */

}

二、中断api

要使用中断,首先需要装载一个中断,当中断触发时,就会进入中断处理函数处理。

可以通过rt_hw_interrupt_mask屏蔽指定中断号的中断,避免再次触发的中断对本次中断处理的影响。
rtthread提供全局中断的打开和关闭api,这是rtthread线程同步的基础,利用全局中断的打开和关闭可以实现对临界区的保护。

//装载中断
/*
vector:中断号
handle:中断服务程序
param:中断服务程序的参数
name:中断的名称
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector,

                                            rt_isr_handler_t handler,
                                            void *param,
                                            char *name);
     

//屏蔽中断:可避免再次触发的中断对正在处理的中断的影响
/*
vector:中断号
*/
void rt_hw_interrupt_mask(int vector);

//取消屏蔽中断
/*
vector:中断号
*/
void rt_hw_interrupt_umask(int vector);

//关闭全局中断
/*
返回函数执行前的中断状态
*/
rt_base_t rt_hw_interrupt_disable(void);

//打开全局中断,与关闭全局中断配合使用,保护临界区的效率比互斥锁高,对实时性影响较大。
/*
level:中断状态
*/
void rt_hw_interrupt_enable(rt_base_t level);

//中断通知:修改中断深度 rt_interrupt_nest
void rt_interrupt_enter(void);
void rt_interrupt_leave(void);

三、中断与轮询

轮询模式采用顺序执行的方式:查询到相应的事件对其进行处理。这种方式在实时操作系统中存在的问题是低优先级的线程得不到cpu的使用权,所以通常情况下,RTOS使用中断来驱动外设。
对于低速的情况,中断模式非常好,cpu可以在等待数据到来前处理其它任务。但对于高速设备,由于操作系统切换上下文有8us的事件,如果处理一个25us的任务,数据带宽为8/(25+8)=75.8%,采用轮询模式不存在上下文切换的问题,数据带宽为100%。
四、示例

本示例的线程通过全局中断开关来保护全局变量。

/*

  • Copyright (c) 2006-2018, RT-Thread Development Team
    *
  • SPDX-License-Identifier: Apache-2.0
    *
  • Change Logs:
  • Date Author Notes
  • 2018-08-24 yangjie the first version
    */

/ 程序清单:关闭中断进行全局变量的访问 /

include <rthw.h>

include <rtthread.h>

define THREAD_PRIORITY 20

define THREAD_STACK_SIZE 512

define THREAD_TIMESLICE 5

/ 同时访问的全局变量 /
static rt_uint32_t cnt;
void thread_entry(void *parameter)
{

rt_uint32_t no;
rt_uint32_t level;

no = (rt_uint32_t) parameter;
while (1)
{
    /* 关闭中断 */
    level = rt_hw_interrupt_disable();
    cnt += no;
    /* 恢复中断 */
    rt_hw_interrupt_enable(level);

    rt_kprintf("protect thread[%d]'s counter is %d\n", no, cnt);
    rt_thread_mdelay(no * 10);
}

}

int interrupt_sample(void)
{

rt_thread_t thread;

/* 创建thread1线程 */
thread = rt_thread_create("thread1", thread_entry, (void *)10,
                          THREAD_STACK_SIZE,
                          THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
    rt_thread_startup(thread);

/* 创建thread2线程 */
thread = rt_thread_create("thread2", thread_entry, (void *)20,
                          THREAD_STACK_SIZE,
                          THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread != RT_NULL)
    rt_thread_startup(thread);

return 0;

}

/ 导出到 msh 命令列表中 /
MSH_CMD_EXPORT(interrupt_sample, interrupt sample);

原文:https://club.rt-thread.org/as...

推荐阅读
关注数
8074
内容数
181
小而美的物联网操作系统,经过14年的累积发展,RT-Thread 已经拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量超过4亿台,成为国人自主开发、国内最成熟稳定和装机量最大的开源 RTOS。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息