弄了两周终于把28335的启动流程、寄存器及中断向量表的映射方法、内存的划分等有了一个全面的了解,今天看到久违的LED灯的闪烁,顿扫阴霾。特在此总结下28335GPIO及外部中断配置介绍。其实对于一个微控制器,只要能够独立实现这两个功能,也算是入门了。
外界二进制信息(数字量)要被CPU处理,要给存储器存放,就需要外界信息源与两者之间的交换接口,这样的交换接口若用来进行通用目的数字量的输入输出,就被称为通用数字量输入/输出接口,简称GPIO。F28335 DSP有多达88个GPIO口,对应着芯片引出的88个引脚,随着芯片的封装与尺寸的确定,引脚数目是有限的,所以这88个引脚多数都是功能复用的,即可以灵活配置为输入引脚,也可以灵活配置为输出引脚,即可以作为通用I/O引脚,也可以作为特殊功能口(如SCI、SPI、ECAN等),非常灵活,用户根据需要,可以通过GPIO MUX(输入输出多路选择器,复用开关)寄存器来进行相关配置。
F28335DSP将这88个GPIO口分成了A、B、C三大组,A组包括GPIO0至GPIO31,B组包括GPIO32至GPIO63,C组包括GPIO64至GPIO87,每个引脚都复用了多个功能,同一时刻,每个引脚只能用该引脚的一个功能。究竟工作在哪个模式下,可以通过GPIO Mux(复用开关)寄存器配置每个引脚的具体功能(通用数字量I/O或者外设专用功能)。如果将这些引脚选择数字量I/O模式,可以通过方向寄存器GPxDIR配置数字量I/O的方向,即是作为输入引脚还是作为输出引脚;还可以通过量化寄存器GPxQUAL对输入信号进行量化限制,从而可以消除数字量I/O引脚的噪声干扰。
1、可以通过GPxDAT寄存器独立读/写I/O信号;(操作较慢,需要加延时(取反不需),下面的方法不需加延时)
2、利用GPxSET寄存器写1(写0无效)对I/O口进行置位
3、利用GPxCLEAR寄存器写1(写0无效)对I/O口进行清零;
4、利用GPxTOOGLE寄存器置1后(写0无效)来将I/O输出电平翻转,原来高电平变成低电平,原来低电平则变成高电平。
对GPIO模块的设置主要通过三类寄存器来完成(TI的库文件把GPIO的寄存器分成三部分,实际的寄存器在这三类中),分别是:控制寄存器、数据寄存器、中断寄存器。(TI已经定义了三个这样的名字)
extern volatilestruct GPIO_CTRL_REGSGpioCtrlRegs;
externvolatilestruct GPIO_DATA_REGSGpioDataRegs;
extern volatile struct GPIO_INT_REGS GpioIntRegs;
想要操作一个外设,首先可以查看对应外设头文件最后定义的这几个结构体变量,其实就是对这几个结构体的赋值。然后查看对应结构体的元素,后面都有对应的说明,然后可层层查看包含的结构体及元素,后面的注释很容易理解相应的意思,然后根据需要配置即可。
例:GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; // GPIO2 = output
1、控制寄存器
GPxCTRL;//GPIO x Control Register (GPIO0 to 31)另:采样频率:分为同步频率和异步频率
同步频率:当IO口作为普通IO时,对信号采样使用的是同步采样信号,SYSCLKOUT 或者SYSCLKOUT/n
异步频率:当IO口作为SCISPI eCAN I2C这样的外设外口时,不需要同步采样频率,外设本身就有异步的采样频率。
系统复位的时候,所有的管脚都是默认为输入状态,默认都是普通IO口,采样频率默认都为SYSCLKOUT。上拉电阻在复位后默认除了ePWM(GPIO0~GPIO11)外都是默认已经上拉。
采样次数:
采样窗口分3次和6次两种窗口,用来过滤噪声。采样窗口为3的间隔时间为2个采样周期,采样窗口为6的间隔时间为5个采样周期。
只有在这2或者5个采样周期内采集的信号完全一样才说明信号稳定,信号才会传递为DSP,依次来消除噪声。
(采样次数与采样频率根据实际要求配合使用)
GpioCtrlRegs.GPAQSEL1.bit.GPIO15 = 2; // XINT2 Qual using 6 samples
GpioCtrlRegs.GPACTRL.bit.QUALPRD0 = 0x80; // Each sampling window is 128*SYSCLKOUT
GPIO的寄存器(A):
上面表格内容由TI转化为了下面的结构体:
struct GPIO_CTRL_REGS {
union GPACTRL_REG GPACTRL; // GPIO A ControlRegister (GPIO0 to 31)
union GPA1_REG GPAQSEL1; // GPIO A QualifierSelect 1 Register (GPIO0 to 15)
union GPA2_REG GPAQSEL2; // GPIO A QualifierSelect 2 Register (GPIO16 to 31)
union GPA1_REG GPAMUX1; // GPIO A Mux 1 Register(GPIO0 to 15)
union GPA2_REG GPAMUX2; // GPIO A Mux 2 Register(GPIO16 to 31)
union GPADAT_REG GPADIR; // GPIO A DirectionRegister (GPIO0 to 31)
union GPADAT_REG GPAPUD; // GPIO A Pull Up DisableRegister (GPIO0 to 31)
Uint32 rsvd1;
union GPBCTRL_REG GPBCTRL; // GPIO B ControlRegister (GPIO32 to 63)
union GPB1_REG GPBQSEL1; // GPIO B QualifierSelect 1 Register (GPIO32 to 47)
union GPB2_REG GPBQSEL2; // GPIO B QualifierSelect 2 Register (GPIO48 to 63)
union GPB1_REG GPBMUX1; // GPIO B Mux 1 Register(GPIO32 to 47)
union GPB2_REG GPBMUX2; // GPIO B Mux 2 Register(GPIO48 to 63)
union GPBDAT_REG GPBDIR; // GPIO B DirectionRegister (GPIO32 to 63)
union GPBDAT_REG GPBPUD; // GPIO B Pull Up DisableRegister (GPIO32 to 63)
Uint16 rsvd2[8];
union GPC1_REG GPCMUX1; // GPIO C Mux 1 Register(GPIO64 to 79)
union GPC2_REG GPCMUX2; // GPIO C Mux 2 Register(GPIO80 to 95)
union GPCDAT_REG GPCDIR; // GPIO C DirectionRegister (GPIO64 to 95)
union GPCDAT_REG GPCPUD; // GPIO C Pull Up DisableRegister (GPIO64 to 95)
};下面寄存器受EALLOW保护(下面的这个寄存器是外部中断源的选取,用的哪个端口,就把端口号赋给它即可)
一个寄存器是16位的,而一组IO口有32个,所以有的寄存器有2个。
下面是TI库文件中声明的结构体:
struct GPIO_CTRL_REGS {
union GPACTRL_REG GPACTRL; // GPIO A ControlRegister (GPIO0 to 31)
union GPA1_REG GPAQSEL1; // GPIO A QualifierSelect 1 Register (GPIO0 to 15)
union GPA2_REG GPAQSEL2; // GPIO A QualifierSelect 2 Register (GPIO16 to 31)
union GPA1_REG GPAMUX1; // GPIO A Mux 1 Register(GPIO0 to 15)
union GPA2_REG GPAMUX2; // GPIO A Mux 2 Register(GPIO16 to 31)
union GPADAT_REG GPADIR; // GPIO A DirectionRegister (GPIO0 to 31)
union GPADAT_REG GPAPUD; // GPIO A Pull Up DisableRegister (GPIO0 to 31)
Uint32 rsvd1;
union GPBCTRL_REG GPBCTRL; // GPIO B ControlRegister (GPIO32 to 63)
union GPB1_REG GPBQSEL1; // GPIO B QualifierSelect 1 Register (GPIO32 to 47)
union GPB2_REG GPBQSEL2; // GPIO B QualifierSelect 2 Register (GPIO48 to 63)
union GPB1_REG GPBMUX1; // GPIO B Mux 1 Register(GPIO32 to 47)
union GPB2_REG GPBMUX2; // GPIO B Mux 2 Register(GPIO48 to 63)
union GPBDAT_REG GPBDIR; // GPIO B DirectionRegister (GPIO32 to 63)
union GPBDAT_REG GPBPUD; // GPIO B Pull Up DisableRegister (GPIO32 to 63)
Uint16 rsvd2[8];
union GPC1_REG GPCMUX1; // GPIO C Mux 1 Register(GPIO64 to 79)
union GPC2_REG GPCMUX2; // GPIO C Mux 2 Register(GPIO80 to 95)
union GPCDAT_REG GPCDIR; // GPIO C DirectionRegister (GPIO64 to 95)
union GPCDAT_REG GPCPUD; // GPIO C Pull Up DisableRegister (GPIO64 to 95)
};采用上述结构体定义可以直接对GPIO的寄存器进行操作,完成外部引脚的初始化操作。例如,将IOA全部设置GPIO功能,输出状态,0量化:
void Gpio_Select(void)
{ Uint16 var1;
Uint16 var2;
Uint16 var3;
var1=0x0000;
var2=0xffff;
var3=0x0000;
EALLOW;
GpioCtrlRegs.GPAMUX1=var1;//GPIO0-15
GpioCtrlRegs.GPAMUX2=var1;//GPIO16-31
GpioCtrlRegs.GPADIR.all=var2;//GPIO0-31
GpioCtrlRegs.GPAQSEL1.all=var3;
GpioCtrlRegs.GPAQSEL2.all=var3;
EDIS;
}
struct GPIO_DATA_REGS {
union GPADAT_REG GPADAT; // GPIO Data Register (GPIO0 to 31)
union GPADAT_REG GPASET; // GPIO Data Set Register(GPIO0 to 31)
union GPADAT_REG GPACLEAR; // GPIO Data Clear Register (GPIO0 to 31)
union GPADAT_REG GPATOGGLE; // GPIO Data Toggle Register (GPIO0 to 31)
union GPBDAT_REG GPBDAT; // GPIO Data Register(GPIO32 to 63)
union GPBDAT_REG GPBSET; // GPIO Data Set Register(GPIO32 to 63)
union GPBDAT_REG GPBCLEAR; // GPIO Data Clear Register (GPIO32 to 63)
union GPBDAT_REG GPBTOGGLE; // GPIO Data Toggle Register (GPIO32 to 63)
union GPCDAT_REG GPCDAT; // GPIO Data Register(GPIO64 to 95)
union GPCDAT_REG GPCSET; // GPIO Data Set Register(GPIO64 to 95)
union GPCDAT_REG GPCCLEAR; // GPIO Data Clear Register (GPIO64 to 95)
union GPCDAT_REG GPCTOGGLE; // GPIO Data Toggle Register (GPIO64 to 95)
Uint16 rsvd1[8];
};
上面每一组声明的寄存器的类型是一样的,但是在内存中的位置是不一样的。至于名字一样的原因是TI把这类寄存器都作为数据寄存器。
struct GPIO_INT_REGS {
union GPIOXINT_REG GPIOXINT1SEL;// XINT1 GPIO InputSelection
union GPIOXINT_REG GPIOXINT2SEL;// XINT2 GPIO InputSelection
union GPIOXINT_REG GPIOXNMISEL; // XNMI_Xint13 GPIO Input Selection
union GPIOXINT_REG GPIOXINT3SEL;// XINT3 GPIO InputSelection
union GPIOXINT_REG GPIOXINT4SEL;// XINT4 GPIO InputSelection
union GPIOXINT_REG GPIOXINT5SEL;// XINT5 GPIO InputSelection
union GPIOXINT_REG GPIOXINT6SEL;// XINT6 GPIO InputSelection
union GPIOXINT_REG GPIOXINT7SEL;// XINT7 GPIO InputSelection
union GPADAT_REG GPIOLPMSEL; // Low power modes GP I/O input select
}
externvolatilestruct GPIO_CTRL_REGSGpioCtrlRegs;
externvolatilestruct GPIO_DATA_REGS GpioDataRegs;
externvolatilestruct GPIO_INT_REGS GpioIntRegs;
使用上面定义的三个对应的结构体变量即可配置GPIO口。(上面结构体内的元素为联合,查看联合的元素可知,可整体对寄存器赋值,也可对某一位赋值。至于赋予什么值则需查看数据手册或注释,看你想要什么功能。)
想要点亮一个LED灯,首先看硬件原理图,知道LED接到了GPIO2上,需要一个低电平点亮。所以就知道要配置GPIO2为通用IO口、输出,初始化的时候可先关闭LED,所以需向置位寄存器写1置位(也可看上面的结构体有哪些元素,也即是给对应的元素赋值)
#define LED_OFF GpioDataRegs.GPASET.bit.GPIO2= 1;//关闭led,即是向GPIO2的置位寄存器写入1.
GpioDataRegs.GPASET.bit.GPIO2中的GpioDataRegs即是上面说的定义的那个变量,然后配置GpioDataRegs中的元素,需要的是元素union GPADAT_REG GPASET; // GPIO Data Set Register (GPIO0 to 31),再打开这个联合体,
union GPADAT_REG {
Uint32 all;
struct GPADAT_BITS bit;
};
也即是配置这个,继续打开,
需要的是端口2,把其赋值为1即可。(如果是其他端口,则先看是属于第几组,然后GpioDataRegs.GPASET.bit.GPIO2中的A换下,2换成需要的端口即可)
可这样记忆:所有的GPIO端口数据寄存器有一个共同的名字GpioDataRegs,其元素为联合体,之所以定义为联合是可以全体配置,也可以一位一位的配置。GPASET是端口A置位寄存器(为GpioDataRegs的元素。bit是只配置一位,为GPASET的元素。GPIO2是端口2,为bit的元素.)F28335一共有88个GPIO,分为3组,分别是A、B、C。其中A组GPIO可以通过软件配置为外部中断1、2以及NMI功能,B组GPIO可以通过软件配置为外部中断3、4、5、6、7功能。而C组的GPIO不能配置为中断功能。如果将某GPIO配置为外部中断功能,那么下面是设置步骤:
1. 将数字量I/O配置为GPIO功能;
2. 将数字量I/O配置为输入方向;
3. 将数字量I/O量化配置正确;
4. 利用外部中断选择寄存器选择相应的引脚为外部中断源;
5. 为此GPIO触发信号设置极性,上升沿、下降沿或者双边沿;
GpioIntRegs为配置外部中断时候的中断源的选取。例如:
GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 15;//就把GPIO15作为外部中断1的中断源。
F28335内部有16个中断线,其中包括2个不可屏蔽中断(RESET和NMI)与14个可屏蔽中断。可屏蔽中断通过相应的中断使能寄存器使能或者禁止产生的中断,在这14个可屏蔽中断中,其中定时器1与定时器2产生的中断请求通过INT13、INT14中断线到达CPU,这两个中断已经预留给了实时操作系统,因此剩下12个可屏蔽中断可供外部中断和处理器内部的单元使用。F28335的外设中断源远不止12个,有58个,如何将这58个外设中断源分配给这12个中断线,这就需要F28335 PIE外设中断扩展模块来完成。
外设要能够成功产生中断响应,就要首先经外设级中断允许,然后经PIE允许,然后经CPU允许,最终CPU做出响应。F28335的外部中断并没有固定接口,其中GPIO0-GPIO31可配置为外部中断XINT1,XINT2和NMI,注意其中NMI不受PIE管理,而GPIO32-63可配置为XINT3至XINT7。
如果是PIE模块管理的中断,还要进行PIE模块的配置,先简述PIE的原理:
上图的(INTX指的是1-12)只是用一组说明。方框出即时对应的寄存器。在PIE模块内每组中断有相应的中断标志位(PIEIFRx)和使能位(PIEIERx.y)。除此之外,每组PIE中断(INT1~INT12)有一个响应标志位(PIEACK)。
如图所示:PIE管理的整个中断过程分为3级、外设级、PIE级、CPU级(写中断的时候对照每部分写即可)
整个中断处理过程如上所示:
(1)外设级
外设产生中断时,该中断事件相关的中断标志位(IF)置1。此时,如果该中断相应的中断使能寄存器(IE)也置为1,外设就会向PIE控制器发出一个中断请求。如果外设级中断没有被使能(相应的使能位为0),那么外设就不会向PIE发出中断请求,相应的中断标志位会一直保持置位状态,除非用软件清除。当然,在中断标志位保持在1的时候,一旦该中断被使能了,那么外设立马会向PIE发出中断申请。
注:不管在什么情况下,外设寄存器中的中断标志位必须采用软件进行清除。
小结:
外设中断的屏蔽,需要将与该中断相关的外设寄存中的中断使能位置0;(注意配置的时候使能)
外设中断标志位的清除,需要将与该中断相关的外设寄存中的中断标志位置1;
EALLOW;
GpioCtrlRegs.GPAMUX1.bit.GPIO15 = 0; // GPIO15 = GPIO
GpioCtrlRegs.GPADIR.bit.GPIO15 = 0; // GPIO15 = intput
GpioCtrlRegs.GPAQSEL1.bit.GPIO15 = 2; // XINT2 Qual using 6 samples
GpioCtrlRegs.GPACTRL.bit.QUALPRD0 = 0x80; // Each sampling window is 128*SYSCLKOUT
GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL = 15;
EDIS;
// Configure XINT1
XIntruptRegs.XINT1CR.bit.POLARITY = 1; // Falling edge interrupt
// Enable XINT1
XIntruptRegs.XINT1CR.bit.ENABLE = 1; // Enable Xint1
总之,外设中断的配置要有使能外设中断、外设中断标志位的清除、相应外设的配置(例如外部中断要配置相应的IO端口,IO配置为输入、上升沿或下降沿中断等,具体可查看相应寄存器各位配置说明)
(2)PIE级
当外设产生中断事件,相关中断标志位置位,中断使能位使能之后,外设就会把中断请求提交给我们的PIE模块。PIE模块将96个外设和外部引脚的中断进行了分组,分为12组,每组8个中断,分别是PIE1-PIE12。每个组的中断被多路汇集进入1个CPU中断,例如PDPINDA,PDPINDB,XINT1,XINT2,ADCINT,TINT0,WAKEINT这7个中断都在PIE1组内,这些中断都汇集到CPU中断的INT1。
小结:
PIE中断的使能。就得将其相应组的使能寄存器PIEIERx的相应位进行置位;
PIE中断的屏蔽。这是和使能相反的操作;
PIE应答寄存器 PIEACK相关位的清除,以使得CPU能够响应同组的其他中断。
PIE级的中断和外设级的中断比较:外设中断的中断标志位是需要软件清除的,而PIE级的中断标志位都是自动置位或者清除的。但是PIE多了一个PIEACK寄存器,同一时间只能放一个中断过去,只有等到这个中断被响应,给PIEACK置位,才能让同组的下一个中断过去,被CPU响应,而PIEACK当响应一次中断后就会自动置位,因此需要软件写1清0
PIE96个中断对应的外设如下:
对应的中断在PIE中有对应的位置,例如外部中断2在INT1.5上。
PIE级软件编程:
// Initialize the PIEcontrol registers to their default state.
// The default state isall PIE interrupts disabled and flags
// are cleared.
InitPieCtrl();//初始化PIE,都关闭与清零了
之后对PIE寄存器进行操作,首先得使能PIE寄存器
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;// Enable the PIE block
还有应答寄存器清除。可直接用下面这个
// Enable CPU and PIE interrupts
// This example function is found in the DSP2833x_PieCtrl.c file.
EnableInterrupts();
并且使能相应的PIE中断使能寄存器,即下面这段代码
PieCtrlRegs.PIEIER1.bit.INTx4 = 1;// Enable PIE Gropu1 INT4 对应于外设中断向量表中的XINT1
(查上表可知XINT1也即是外部中断1位于第一组第四个,也即PIEIER1及INTx4,使能对应的中断)
然后必须将对应的中断服务程序映射到中断向量表中
EALLOW; // This is needed to write to EALLOW protectedregisters
PieVectTable.XINT1 = &xint1_isr;
EDIS; // This is needed to disable write to EALLOWprotected registers
最后必须在中断服务程序中将对应Group1的PIEACKx=1写1清0
(3)CPU级
CPU也有标志寄存器IFR和使能寄存器IER。当某一个外设中断请求通过PIE发送到CPU时,CPU级中与INTx相关的中断标志位就会被置位。例如,T1的周期中断T1PINT的请求到达CPU这边时,与其相关的INT2的标志位就会被置位。这时候,该标志位就会被所存在IFR中,这时候,CPU不会马上去执行相应的中断,而是等待CPU使能IER寄存器的相关位,并且对CPU寄存器ST1中的全局中断屏蔽位做适当的使能。如果IER中的相关位被置位了,并且INTM的值为0,则中断就会被CPU响应。在T1PINT里,当IER的第2位即INT2被置位,INTM为0,则CPU就会响应定时器T1的周期中断。 CPU接到了终端的请求,就得暂停正在执行的程序,转而去响应中断程序,但是此时,它必须得做一些准备工作,以便于执行完中断程序之后回过头来还能找到原来的地方和原来的状态。CPU会将相应的IER和IFR位进行清除,EALLOW也被清除,INTM被置位,就是不能响应其他中断了,CPU向其他中断发出了通知,正在忙,没空来处理你们的请求了,得等到处理完手上的中断之后才能再来处理你们的请求。然后,CPU会存储返回地址并自动保存相关的信息,例如将正在处理的数据放入堆栈等等,做好这些准备工作之后,CPU会从PIE块中取出对应的中断向量ISR,从而转去执行中断子程序。
中断CPU级总结:
CPU级的操作都是自动的,不管是中断标志位(IFR),还是中断的使能位(IER)。
但是可以通过软件设置开中断、关中断。(而且配置中断前都会先关闭中断、清零标志位)
// Disable CPU interrupts
DINT;
/ Disable CPU interruptsand clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
PIE控制的12组大中断由28335核的CPU中断寄存器IER来控制,即IER确定每个中断到底属于哪一组大中断(如IER |= M_INT12;说明我们要用第12组的中断。但是第12组里面的什么中断CPU并不知道,这个就需要再由PIEIER确定。其中,每一组都有一个自己的PIEIER寄存器。)
CPU的IFR寄存器是中断组(即那12组)的标志寄存器。
IER |= M_INT12;//使能CPU相应的中断使能寄存器,这个是使能CPU INT12中断。
/ Enable globalInterrupts and higher priority real-time debug events:
EINT; //Enable Global interrupt INTM
ERTM; //Enable Global realtime interrupt DBGM
外部中断软件编写:(设置的时候先关闭总中断及标志位,最后再打开)
先配置端口为GPIO口,是为输入口。
然后需要配置GpioIntRegs中的GPIOXINTnSEL寄存器来选择GPIO的端口(也即时中断源),例如GpioIntRegs.GPIOXINT1SEL.bit.GPIOSEL= 0; //Xint1 is GPIO0
然后配置 XIntruptRegs中的XINTnCR来配置中断的一些参数(触发方式、使能中断等):例如:
// Configure XINT1
XIntruptRegs.XINT1CR.bit.POLARITY = 0;// Falling edge interrupt
// Enable XINT1
XIntruptRegs.XINT1CR.bit.ENABLE = 1;// Enable Xint1
其中XINTnCTR寄存器是用于计数的寄存器,可不配置
其他外设总的过程如下:(设置的时候先关闭总中断及标志位)
// Step 1. Initialize SystemControl:
// PLL, WatchDog, enablePeripheral Clocks
// This example functionis found in the DSP2833x_SysCtrl.c file.
InitSysCtrl();//已关闭看门狗,设置时钟150MHZ,注意开启对应外设的时钟。
// Step 2. Initalize GPIO:
// This example functionis found in the DSP2833x_Gpio.c file and
// illustrates how to setthe GPIO to it's default state.
// InitGpio(); // Skipped for this example
Led_Gpio_Init();(这个是根据自己需求写的配置GPIO函数)
// Step 3. Clear all interrupts andinitialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIEcontrol registers to their default state.
// The default state isall PIE interrupts disabled and flags
// are cleared.
// This function is foundin the DSP2833x_PieCtrl.c file.
InitPieCtrl();//初始化PIE,都关闭与清零了
// Disable CPU interruptsand clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIEvector table with pointers to the shell Interrupt
// Service Routines(ISR).
// This will populate theentire table, even if the interrupt
// is not used in thisexample. This is useful for debugpurposes.
// The shell ISR routinesare found in DSP2833x_DefaultIsr.c.
// This function is foundin DSP2833x_PieVect.c.
InitPieVectTable();//初始化中断向量表
// Interrupts that areused in this example are re-mapped to
// ISR functions foundwithin this file.
EALLOW; //This is needed to write to EALLOW protected registers
PieVectTable.TINT0 = &cpu_xint_isr;
(可在DSP2833x_PieVect.h头文件中找到该结构体的声明,查看知道元素PINT TINT0; // Timer 0,把编写的中断函数的地址赋给其即可)
EDIS; //This is needed to disable write to EALLOW protected registers
// Step 4. Initialize the DevicePeripheral. This function can be
// found in DSP2833x_CpuTimers.c
InitCpuTimers(); // For thisexample, only initialize the Cpu Timers
ConfigCpuTimer(&CpuTimer0,150, 50);(只是对定时器0的配置,因为这个写的是定时器0中断)
// To ensure precisetiming, use write-only instructions to write to the entire register. Therefore,if any of the configurationbits are changed in ConfigCpuTimer and InitCpuTimers (in DSP2833x_CpuTimers.h),the below settings mustalso be updated.
// CpuTimer0Regs.TCR.all = 0x4001; // Usewrite-only instruction to set TSS bit = 0
// CpuTimer1Regs.TCR.all = 0x4001; // Usewrite-only instruction to set TSS bit = 0
// CpuTimer2Regs.TCR.all = 0x4001; // Usewrite-only instruction to set TSS bit = 0
// Step 5. User specific code,enable interrupts:
// Enable CPU int1 whichis connected to CPU-Timer 0, CPU int13
// which is connected toCPU-Timer 1, and CPU int 14, which is connected
// to CPU-Timer 2:
IER |= M_INT1;
(#define M_INT1 0x0001在DSP2833x_Device.h中)
(因为只用到定时器0,所以只打开定时器0对应的CPU中断使能寄存器)
PieCtrlRegs.PIECTRL.bit.ENPIE = 1; // Enable the PIE block
似乎也应该加上PIE的应答寄存器的清零。
// Enable TINT0 in thePIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
(打开定时器0对应的PIE中的中断使能寄存器)
// Enable globalInterrupts and higher priority real-time debug events:
EINT; //Enable Global interrupt INTM
ERTM; //Enable Global realtime interrupt DBGM
之后即可。
#include "DSP2833x_XIntrupt.h" // External Interrupts
配置外部中断的时候要用到这个头文件。DSP2833x Device External Interrupt Register Definitions.