中断服务提供者
一个中断请求可以被CPU服务,也可以被DMA模块服务。在这个文档里中断请求也可以被称作服务请求,因为DMA内的服务并不称得上中断(不用管这句话)。
下面是TC1.6内核数据手册对Interrupt System开头的描述:
这里讲的比TC264手册清楚:在一个中断系统里,外设或外部中断可以向中断服务者CPU或DMA通道产生中断请求。
因此,中断服务请求对应的服务提供者可以是CPU,也可以是DMA
这也就解释了TC264标准库IfxSrc_cfg.h中为什么要有一个枚举类型:
typedef enum
{
IfxSrc_Tos_cpu0 = 0, /**< \brief CPU0 interrupt service provider, which handles the interrupt service request. */
IfxSrc_Tos_cpu1 = 1, /**< \brief CPU1 interrupt service provider, which handles the interrupt service request. */
IfxSrc_Tos_dma = 3 /**< \brief DMA interrupt service provider, which handles the interrupt service request. */
} IfxSrc_Tos;
当我们每写一个中断函数时,都要选择中断的服务提供者。
中断处理结构
这里就不翻译了,直接上结构图容易理解。
从左往右看,每一路中断诱发信号可能有三种来源:
1.Peripherals外设 2.External外部中断 3.SW(software)软件触发
这三种信号进入SRN(Service Request Node 中断处理节点)中,SRN通过配置寄存器选择中断提供者(DMA还是CPU)与中断优先级(Service Request Priority Number(SRPN))。Interrupt Control Unit(ICU)将会比较各个SRN中的SRPN然后将最高优先级的Interrupt Priority Number(PIPN)传入中断提供者中。若CPU中有其他中断程序,将会比较PIPN与Current CPU Priority Number(CCPN)来决定是否执行新的中断。如果CPU执行新的中断,那么它将提供中断允许信号且返回中断优先级。
中断向量表Interrupt Vector Table
中断向量表的内容不需要知道,因为在代码中中断向量表的值总是0,我们只需要一直置零即可。
中断向量表可以理解为比较两个中断的优先级然后将需要执行的中断指针指向胜出的那个中断。
下面贴两张图:
External Interrupt
这里把External Interrupt包含成GPIO中断与外设中断(如摄像头等),也就是上面中断诱发信号的 Peripherals与External。逐飞贴心的把External(GPIO)中断写在了EXTI中断库里,把Peripherals(外设)中断写在了ERU中断库里。当我们在比赛中想要脱机调阈值时或者配置摄像头处理中断时,可以分别使用逐飞的库函数。下面以ERU中断为例:
void eru_init(ERU_PIN_enum eru_pin, TRIGGER_enum trigger);
void eru_enable_interrupt(ERU_PIN_enum eru_pin);
void eru_disable_interrupt(ERU_PIN_enum eru_pin);
上面第一个函数为初始化函数,第一个参数为External Interrupt的枚举:
typedef enum // 枚举ERU通道
{
//一个通道只能选择其中一个引脚作为 外部中断的输入
//例如通道0 可选引脚为P10_7 和 P15_4,
//在LQFP144封装中没有P10_7
ERU_CH0_REQ4_P10_7 = 0*3, ERU_CH0_REQ0_P15_4, //通道0可选引脚 LQFP没有P10_7引脚
//在LQFP144封装中没有P10_8
ERU_CH1_REQ5_P10_8 = 1*3, ERU_CH1_REQ10_P14_3, //通道1可选引脚 LQFP没有P10_8引脚
ERU_CH2_REQ7_P00_4 = 2*3, ERU_CH2_REQ14_P02_1, ERU_CH2_REQ2_P10_2, //通道2可选引脚
ERU_CH3_REQ6_P02_0 = 3*3, ERU_CH3_REQ3_P10_3, ERU_CH3_REQ15_P14_1, //通道3可选引脚
//通道4与通道0 共用中断函数 在中断内通过判断标志位来识别是哪个通道触发的中断
ERU_CH4_REQ13_P15_5 = 4*3, ERU_CH4_REQ8_P33_7, //通道4可选引脚
//通道5与通道1 共用中断函数
ERU_CH5_REQ1_P15_8 = 5*3, //通道5可选引脚
//通道6与通道2 共用中断函数
ERU_CH6_REQ12_P11_10 = 6*3, ERU_CH6_REQ9_P20_0, //通道6可选引脚
//通道7与通道3 共用中断函数
ERU_CH7_REQ16_P15_1 = 7*3, ERU_CH7_REQ11_P20_9, //通道7可选引脚
}ERU_PIN_enum;
第二个参数为触发方式:上升沿,下降沿,或是两者都行
typedef enum // 枚举触发方式
{
RISING,
FALLING,
BOTH,
}TRIGGER_enum;
当我们想要配置摄像头中断时,即可调用函数:
eru_init(MT9V03X_VSYNC_PIN, FALLING); //初始化场中断,并设置为下降沿触发中断
只不过与GPIO的枚举不同,第一个参数在摄像头文件夹里单独宏定义了。这种除GPIO中断以外的中断逐飞它称为场中断。
当然,如果我们想用按键控制中断时,即GPIO中断,也可以用上面的方法配置,只不过要调用逐飞EXTI头文件里的函数而不是ERU。
如下是外设中断函数:
IFX_INTERRUPT(eru_ch3_ch7_isr, 0, ERU_CH3_CH7_INT_PRIO)
{
enableInterrupts();//开启中断嵌套
if(GET_GPIO_FLAG(ERU_CH3_REQ6_P02_0))//通道3中断
{
CLEAR_GPIO_FLAG(ERU_CH3_REQ6_P02_0);
if (CAMERA_GRAYSCALE == camera_type) mt9v03x_vsync();
else if (CAMERA_BIN_UART == camera_type) ov7725_uart_vsync();
else if (CAMERA_BIN == camera_type) ov7725_vsync();
}
if(GET_GPIO_FLAG(ERU_CH7_REQ16_P15_1))//通道7中断
{
CLEAR_GPIO_FLAG(ERU_CH7_REQ16_P15_1);
}
}
注意在完成中断任务时要清除中断标志位。
IFX_INTERRUPT是宏函数,三个参数分别为外部中断的名字(可以随便设)、向量表(上文说过全置0即可)、中断优先级。
Software Interrupt
typedef enum //枚举模块号
{
CCU6_0,
CCU6_1,
}CCU6N_enum;
typedef enum //枚举通道号
{
PIT_CH0,
PIT_CH1,
}CCU6_CHN_enum;
逐飞的头文件里只列举了四个关于Software Interrupt的通道号(两个模块号,每个模块号有两个通道号),在其他人的比赛代码里也中用到了这四个。预测TC264只有四个软件触发通道可以用,即只能写四个软件触发的中断。
以下是逐飞库里有关Software Interrupt的函数声明:
void pit_init(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch, uint32 time);
void pit_close(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch);
void pit_start(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch);
void pit_disable_interrupt(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch);
void pit_enable_interrupt(CCU6N_enum ccu6n, CCU6_CHN_enum pit_ch);
逐飞亦贴心的为我们补充了定时中断函数的声明:
#define pit_interrupt_ms(ccu6n, pit_ch, time) pit_init(ccu6n, pit_ch, time*1000) //(单位为 毫秒)
#define pit_interrupt_us(ccu6n, pit_ch, time) pit_init(ccu6n, pit_ch, time) //(单位为 微秒)
如下是软件中断函数:
IFX_INTERRUPT(cc60_pit_ch0_isr, 0, CCU6_0_CH0_ISR_PRIORITY)
{
enableInterrupts();//开启中断嵌套
PIT_CLEAR_FLAG(CCU6_0, PIT_CH0);
int Err;
Err=ImageDeal[45].Center-40;
SteerPID_Realize(Err);
ICM_OneOrderFilter(); //陀螺仪采集
}
同上, 注意在完成中断任务时要清除中断标志位。