【原创】从零入手Kinetis系统开发(九)之中断使用方法
0赞
发表于 2012/4/13 11:24:32
阅读(12327)
N久没更新从零系列了,呵呵,今天终于抽出空来写写了。其实写这个系列真是个头疼的事,作为主要面对入门级大众的博客既要少些非常专业性的语言(咳咳,当然太专业的俺也说不出,嘿嘿),通俗化而又不失专业,同时作为工程技术类博客,又马虎不得,笔风要严谨。所以好久能憋出一篇算是得意的系列来就不错了,嘿嘿,这不,终于憋出第九篇了,哈哈...(想起本山大叔小品,写月子2的段子了,挺像来)
对于掌握一款单片机(Coretex-M系列定位就是高端单片机,呵呵,和Cortex-A系列的应用处理器定位是两个档次)来说,其中断机制是必须要掌握的,所以作为一个单片机开发者,编写相应的中断服务程序是最基本的要求之一了。前面提到过,本来在第八篇系列就该写写中断的使用方法了(其实这都算晚了,呵呵),不过那会儿玩TSI玩的正在热头上就趁热打铁的写了TSI模块,以致于拖到现在才开始写中断,哈哈,所以不多说废话了,直接进入正题。
Kinetis的中断机制其实也即是Cortex-M4核的机制,ARM从Cortex-M3核系列(ARMv7-M架构)开始就引入了嵌套向量中断控制器(NVIC)来管理其中断功能,其主要的特点包括:
(1)可嵌套中断支持,这点不用细说了,几乎大多数内核都支持中断嵌套,不过可能嵌套的级数有些不同;
(2)向量中断支持,Cortex-M系列通过查询中断向量表找到相应的ISR(中断服务程序)入口,并跳转执行;
(3)动态优先级调整,即支持软件运行时改变中断优先级,其实飞思卡尔的HCS12也支持这个,嘿嘿;
(4)中断延迟大大缩短,引入了一些新特性,例如咬尾中断,晚到中断;
(5)中断可屏蔽,支持条件性屏蔽即只屏蔽优先级低于某个阈值的中断,当然也可以屏蔽全部中断了;
Cortex-M核的NVIC最多支持200多个中断(包括系统异常16个和外部中断240个),只不过各大开云棋牌官网在线客服厂商根据自家芯片的资源做了定制。其中前16个中断为系统中断(即核自己的,咱管不着,不过一些场合用的到),咱们主要关心的是IRQ中断(即外部中断,含外设资源),本系列既然主打Kinetis,就以其为例,重点介绍其特点和使用流程,刚刚是补补常识,下面才进入到本篇主角,哈哈:
1.首先介绍飞思卡尔Kinetis系列中断特点:
(1)低中断延迟,从中断发生到进入中断服务程序最多12时钟周期;
(2)最多120个中断,包含16个核中断和剩余的外部IRQ中断;
(3)最多16个可编程优先级;
(4)动态改变优先级;
(5)可重定位向量表,通过写SCB_VTOR寄存器。
2.按部就班,老套路了,介绍完特点之后,下面细说说要写完整的中断服务程序的流程步骤,擦亮眼睛啦,呵呵,先上个图:
(1)使能外设的中断功能,也就是说打开外设的中断使能位(如果外设支持中断的话),使之与NVIC的中断输入连接;
(2)清除已经挂号发生的中断(避免刚打开即进入,可能造成一些不必要的影响),写NVICICPRx寄存器;
(3)使能相应IRQ中断号在NVIC的中断功能,写NVICISERx寄存器;
(4)配置中断优先级(可选,不设置的话默认,即按照在中断向量表的排序来决定),写NVICIPx;
(5)写相应的中断服务程序(ISR);
(6)使能全局中断EnableInterrupts,其实在启动代码部分已经开启,不过为了稳妥还是再使能一次。
哦了,按照上面6步即可完成相应资源中断功能的实现,so easy吧,呵呵,下面就根据实例来看下具体在程序里是如何实现的吧:
3.该步通过拿出来我以前分享的IAR框架代码来分析下,具体如何实现中断服务机制的,以上篇系列的TSI中断为例,贴代码:
(1)使能相应外设的中断:
ENABLE_EOR_INT; /* 使能TSI越界中断 */
(2)根据TSI的IRQ中断号,清除已经发生的TSI中断事件,并且使能TSI中断功能,首先在K60的datasheet或者直接到其头文件开始处即可找到中断向量表,查到TSI的IRQ中断号(但是要注意IRQ号=中断向量表号-16(即前16个核中断,它们不是IRQ中断)):
注意图中所示为中断向量表号,IRQ中断号为99-16=83。
然后利用ARM核自带的API函数使能TSI的IRQ中断,如下
enable_irq(83); /* 使能TSI的IRQ中断 */
该函数的具体内容如下,注意每个NVICCPRx和NVICISERx都是32字节对齐的,即管理32个IRQ中断,所以要根据TSI实际的中断号算出其具体在哪一个寄存器里设置。
void enable_irq (int irq)
{
int div;
div = irq/32;
switch (div)
{
case 0x0:
NVICICPR0 |= 1 << (irq%32);
NVICISER0 |= 1 << (irq%32);
break;
case 0x1:
NVICICPR1 |= 1 << (irq%32);
NVICISER1 |= 1 << (irq%32);
break;
case 0x2:
NVICICPR2 |= 1 << (irq%32);
NVICISER2 |= 1 << (irq%32);
break;
}
}
(3)配置优先级,这一步如果没特殊需要的话可以默认,不设置即可,如果设置的话也可以通过API函数执行,如下
set_irq_priority (83,5); /* 设置TSI中断优先级为5,注意越小优先级越大 */
(4)编写相应的中断服务函数
/********************************************************************************
**Routine: TSI_isr
**Description: TSI模块,out of Range 中断服务程序,中断服务号为99,IRQ为83
**Notes:
********************************************************************************/
void TSI_isr(void);
然后在写完该中断服务函数之后,我们需要把该中断函数地址映射到中断向量表里面,所以找到isr.h文件打开,设置如下;
#undef VECTOR_099 /* 取消原来默认的宏定义 */
#define VECTOR_099 TSI_isr /* 重定义中断服务函数名为VECTOR_99*/
(5)使能全局中断
EnableInterrupts; /* 其宏定义为CPSIE i,即设置特殊功能寄存器 */
完整的中断编写流程如上,喝口水。其中可能有些寄存器和有关NVIC概念和结构之类的建议看看官方文档或者直接到ARM官网下载Cortex-M核的介绍瞅一瞅,相信会让你受益匪浅。
我所介绍的只是肤浅表面的入门流程,换句话说有点授之以鱼了,这点检讨一下,不过要完整的介绍NVIC原理的确有点心有余力不足,呵呵,建议大家有时间找找相关资料查查,知其所以然。上面的流程应付一些简单应用已经绰绰有余了,着急应用的网友可以直接用在应用上,还是那句话,修行在个人,大家的起跑线都是一样的,至于最后谁跑在最前面就看谁付出的努力,哈哈。
最后还想再说一句,虽然说了N编了,呵呵,转载请注明出处和作者信息,分享是好的,希望大家支持了,呵呵,未完待续~