【转】使用软中断

原文地址: http://blog.youkuaiyun.com/qinzhonghello/archive/2008/11/29/3408420.aspx

 

软中断保留给系统中对时间要求最严格以及最重要的下半部使用。目前,只有两个子系统---网络和SCSI直接使用软中断。此外,内核定时器和taskelet都是建立在软中断上的。对于时间要求严格并能自己高效完成加锁工作的应用,软中断会是正确的选择。

     怎样使用软中断呢?

 

1.分配索引

 

在编译期间,可以通过<linux/interrupt.h>中定义的一个枚举类型来静态声明软中断。索引号小的软中断在索引号大的软中断之前执行。要添加新项的话根据赋予它的优先级来决定加入的位置而不是直接添加到列表末尾。

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
   frequency threaded job scheduling. For almost all the purposes
   tasklets are more than enough. F.e. all serial device BHs et
   al. should be converted to tasklets, not to softirqs.
 */

enum
{
    HI_SOFTIRQ=0,
    TIMER_SOFTIRQ,
    NET_TX_SOFTIRQ,
    NET_RX_SOFTIRQ,
    BLOCK_SOFTIRQ,
    TASKLET_SOFTIRQ,
    SCHED_SOFTIRQ,
#ifdef CONFIG_HIGH_RES_TIMERS
    HRTIMER_SOFTIRQ,
#endif
};
2. 注册你的处理程序

 

    在运行时 通过调用open_softirq()注册软件处理程序,该函数有三个参数:软中断的索引号、处理函数和data域存放的数值:

 

void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
    softirq_vec[nr].data = data;
    softirq_vec[nr].action = action;
}
3.触发你的软中断

  通过在枚举类型的列表中添加新项,调用open_softirq()进行注册之后,新的软中断处理程序就能够运行。raise_softirq()函数可以将一个软中断设置为挂起状态,让它在下次调用do_softirq()函数时投入运行:

void fastcall raise_softirq(unsigned int nr)
{
    unsigned long flags;

    local_irq_save(flags);
    raise_softirq_irqoff(nr);
    local_irq_restore(flags);
}
该函数在触发一个软中断之前先要禁止中断,触发后再恢复原来的状态,如果中断本来就已经被禁止了,那么可以调用另一个函数raise_softirq_irqoff():

/*
 * This function must run with irqs disabled!
 */
inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
    __raise_softirq_irqoff(nr);

    /*
     * If we're in an interrupt or softirq, we're done
     * (this also catches softirq-disabled code). We will
     * actually run the softirq once we return from
     * the irq or softirq.
     *
     * Otherwise we wake up ksoftirqd to make sure we
     * schedule the softirq soon.
     */
    if (!in_interrupt())
        wakeup_softirqd();
}
#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
#define or_softirq_pending(x)  or_pda(__softirq_pending, (x))
在中断处理程序中触发软中断是最常见的形式。在这种情况下,中断处理程序执行硬件设备的相关操作,然后触发相应的软中断,最后退出。内核在执行完 中断处理程序之后,马上调用do_softirq()函数,于是软中断开始执行中断处理程序留给它要完成的剩余任务。

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/qinzhonghello/archive/2008/11/29/3408420.aspx

<think>嗯,用户想了解如何使用SysTick实现软中断,我需要先理清楚SysTick的基本工作原理和软中断的概念。SysTick是Cortex-M内核中的一个系统定时器,通常用于生成周期性的中断,比如操作系统的时钟节拍。软中断一般指通过软件触发的中断,但SysTick本身是硬件定时器中断,所以用户的问题可能是指如何配置SysTick来触发中断,并在中断服务函数中执行特定任务。首先,我需要确认SysTick的中断配置步骤。根据引用3,HAL库中通过HAL_SYSTICK_Config函数设置重装载值,SysTick递减到0时会产生中断。用户需要初始化SysTick,设置合适的重装载值和中断优先级,然后编写中断服务函数。引用4提到中断服务函数的名称必须与启动文件中的一致,通常是SysTick_Handler。接下来,代码示例部分需要展示如何初始化SysTick,比如设置时钟源、重装载值,启用中断。然后,在中断服务函数中添加用户的自定义处理逻辑,比如翻GPIO引脚或者执行其他任务。需要注意的是,中断服务函数中应尽量保持代码简洁,避免长时间操作。 用户可能还关心如何触发软中断,但SysTick本身是硬件触发的,所以可能需要解释清楚软中断和硬件中断的区别。不过,根据用户的问题,可能他们只是想通过SysTick的中断来执行特定代码,也就是利用SysTick的周期性中断实现类似软中断的效果。另外,引用1和引用3提到了使用SysTick进行延时管理,这可能与用户的问题相关,但用户更关注的是中断的实现。需要区分延时函数和中断服务函数的不同应用场景。在代码示例中,可以结合两者,展示如何在中断中处理任务,同时不影响主程序的运行。 还要注意引用2中提到的中断优先级问题,特别是在使用RTOS时,SysTick和PendSV的优先级设置会影响任务调度。但用户的问题可能不涉及RTOS,所以可以简要提到优先级配置,但重点放在基本配置上。 最后,确保代码示例正确,比如使用HAL库的函数,正确的中断服务函数名称,以及必要的头文件包含。同时,提醒用户中断处理函数中的注意事项,比如避免阻塞代码,及时清除中断标志等。</think>### 使用SysTick实现软中断的方法及代码示例 SysTick是Cortex-M内核中的系统定时器,可通过配置其重装载值和中断优先级实现周期性软中断。以下是具体实现步骤及代码示例: --- #### **1. SysTick中断配置原理** - **时钟源选择**:SysTick的时钟源可以是内核时钟(如64MHz)或外部时钟(需参考芯片手册)[^3]。 - **重装载值(LOAD)**:通过`HAL_SYSTICK_Config()`设置,决定中断周期。例如,若系统时钟为64MHz,配置为`64MHz/1000`可实现1ms中断周期[^3]。 - **中断优先级**:需通过NVIC设置,通常SysTick优先级为最低(如15),避免影响其他高优先级中断[^2]。 --- #### **2. 代码实现步骤** ##### **步骤1:初始化SysTick** ```c #include "stm32f1xx_hal.h" void SysTick_Init(void) { // 设置SysTick时钟源为HCLK(系统时钟) HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); // 配置SysTick为1ms中断周期(假设系统时钟64MHz) HAL_SYSTICK_Config(SystemCoreClock / 1000); // 启用SysTick中断 HAL_NVIC_EnableIRQ(SysTick_IRQn); // 设置中断优先级(可选) HAL_NVIC_SetPriority(SysTick_IRQn, 15, 0); } ``` ##### **步骤2:编写中断服务函数** ```c volatile uint32_t tick_count = 0; // 全局变量记录中断次数 void SysTick_Handler(void) { HAL_IncTick(); // HAL库的Tick计数器(必须保留) tick_count++; // 用户自定义任务 // 示例:每1000次中断执行一次任务 if (tick_count % 1000 == 0) { // 执行自定义任务(如翻LED) HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); } } ``` ##### **步骤3:主函数调用** ```c int main(void) { HAL_Init(); // 初始化HAL库 SystemClock_Config(); // 配置系统时钟 SysTick_Init(); // 初始化SysTick while (1) { // 主循环可执行其他任务 } } ``` --- #### **3. 关键注意事项** 1. **中断服务函数命名**:必须为`SysTick_Handler`,与启动文件中的定义一致[^4]。 2. **HAL库依赖**:需保留`HAL_IncTick()`,否则HAL的延时函数(如`HAL_Delay()`)将失效[^3]。 3. **中断执行时间**:避免在中断服务函数中执行复杂操作,防止中断嵌套或响应延迟。 4. **优先级冲突**:若使用RTOS(如FreeRTOS),需调整SysTick优先级以避免与任务调度冲突[^2]。 --- #### **4. 应用场景** - **周期性任务**:如数据采集、状态检测。 - **时间片调度**:在无RTOS时实现简单任务切换。 - **精准延时**:结合`tick_count`实现微秒级延时[^1]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值