7.39. 不可屏蔽中断

Overview

提供不可屏蔽中断使用方法和常见问题。下面为建议开启不可屏蔽中断。

  • 中断频繁,则可以开启不可屏蔽中断;

  • 中断请求时需要立刻执行中断函数,例如接收数据:系统进临界区时中断响应需要立刻执行;

7.39.1. 应用示例

示例演示:

  • 本例子使用硬件定时器来模拟中断请求

example: 进入 apps/demo/demo_DevKitBoard/include/demo_config.h ,开启宏 USE_TIMER_TEST1_DEMO ;进入 apps/demo/demo_DevKitBoard/include/app_config.h ,开启宏 CONFIG_IPMASK_ENABLE

Note

  • 1.注意:建议中断函数和中断函数调用函数都指定在内部sram,指定方法:在函数定义加上 SEC_USED(.volatile_ram_code),使用到的全局数据有初始化加 SEC_USED(.volatile_ram),没初始化或初始化为0的加 SEC_USED(.sram)。如下程序的TSEC和全局变量宏使用。

不可屏蔽中断方式的中断函数,和中断函数中使用的函数和const要全部放在内部ram,中断函数在调试阶段可以调用打印函数等,但需要注意打印函数可能影响到接收数据。

#include "app_config.h"
#include "system/includes.h"
#include "device/device.h"
#include "asm/clock.h"

//用户只能选择:JL_TIMER2、JL_TIMER3、JL_TIMER4、JL_TIMER5
//PWM使用定时器2或者3映射PWM时候,不能用于定时

static SEC_USED(.volatile_ram) JL_TIMER_TypeDef *TMR = JL_TIMER4;//选择定时器4
static SEC_USED(.volatile_ram) u8 timer_irq = IRQ_TIMER4_IDX;//选择定时器4

static SEC_USED(.volatile_ram) u32 timer_clk = 0;

#define AWINLINE   __attribute__((always_inline))

#define TSEC SEC_USED(.volatile_ram_code) //不可屏蔽中断函数放在内部ram
//#define TSEC

static AWINLINE TSEC void timer_cfg(u32 freq, u32 us)
{
  u8 timer_index[16] =  {0, 4, 1, 5, 2,  6,  3,  7,   8,   12,  9,    13,   10,   14,   11,    15};
  u32 timer_table[16] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768};
  u32 clock = timer_clk;
  u8 psc = 0;
  u8 tmp = 0;
  u32 prd = 0;
  u32 ts = us / (1000 * 1000);//计算秒
  u32 tu = us % (1000 * 1000);//计算秒剩余us
  u8 i;
  float tp = 0;

  if (freq >= clock)
    {
        freq = clock;
      }
    else if (freq <= 1)
    {
        freq = 1;
          if (ts)
          {
              tp = (float)tu / (1000 * 1000);
          }
      }
    /*求prd值*/
    prd = clock / freq;
    if (prd > 65535)
    {
        for (psc = 0; psc < 16; psc++)
          {
              prd = (u32)(clock / (timer_table[psc]) / freq);
              if (prd <= 65535)
              {
                  break;
              }
              else if (psc == 15)
              {
                  prd = 65535;
                  break;
              }
          }
      }
    prd = ts ? (prd * ts + tp * prd) : prd;
    psc = timer_index[psc];
    TMR->CON = 0;
    TMR->CNT = 0;
    TMR->CON |= BIT(14);
    TMR->PRD = prd;
    TMR->CON |= psc << 4; //lsb_clk分频
    TMR->CON |= BIT(0);
}
static void TSEC timer_set(u32 us)//设置时间,该函数可以在中断调用重新设置定时器值
{
  u32 freq = 1000000 / us;
  timer_cfg(freq, us);
}
static void TSEC timer_freq_set(u32 freq)//设置频率,该函数可以在中断调用重新设置定时器值
{
  timer_cfg(freq, 0);
}
static ___interrupt TSEC void timer_isr(void)//中断
{
  if (TMR->CON & BIT(15))
  {
      TMR->CON |= BIT(14);
        putchar('@');
        //todo,中断函数执行程序...
  }
}

//example test
static int c_main(void)
{
  timer_clk = clk_get("timer");//先获取定时器的时钟源
  request_irq(timer_irq, 3, timer_isr, 0);//注册中断函数定和中断优先级
  #if 1
  timer_set(50 * 1000); //初始化50ms进一次中断
  #else
  //timer_freq_set(10000);//设置10K频率进中断
  #endif
  return 0;
}
late_initcall(c_main);

    1. app_main.c 中断列表添加:指定的中断号和优先级和指定核, 中断优先级务必设置为7才能生效 ,如下为IRQ_TIMER4_IDX定时器4的中断号添加:

//中断号           //指定中断优先级为7(最高为7)    //指定注册到核1(0/1)
#ifdef CONFIG_IPMASK_ENABLE
//不可屏蔽中断方法:支持写flash,但中断函数和调用函数和const要全部放在内部ram
{ IRQ_SOFT5_IDX,      6,   0    }, //此中断强制注册到cpu0
{ IRQ_SOFT4_IDX,      6,   1    }, //此中断强制注册到cpu1
#if 1 //如下,TIMER4使用不可屏蔽中断设置,优先级固定7
{IRQ_TIMER4_IDX,    7,    1   },//本次测试用到的是定时器4
#endif
#endif

7.39.2. 常见问题

Note

  • 不可屏蔽中断的中断响应函数里不能使用临界区和spin_lock等操作,否则会出现死锁导致看门狗复位的问题

7.39.3. API Reference