乐趣区

关于开源: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…

退出移动版