标签:
教程软件仿真软件 |
分类: DSP |
前面几讲我们分别介绍了有关DSP的特点和发展,还有相关实验步骤。但是只学会那些只是最基础需要了解的,真正想要让DSP按照我们的意愿去工作我们还要努力,最起码我们还要深入DSP内部,了解DSP如何实现各种功能,DSP实现每个功能都有一个相应的模块,每个模块负责自己的功能,这就是我们接下来要学习的。
今天我们首先要讲解的是PIE模块(外部中断扩展模块):本讲看完建议结合【第十五讲】TMS320F28335开发板之外部中断(PIE模块补充篇)
1.中断响应过程
TMS320F28335内部有16根中断线,其中包括2根不可屏蔽中断(NMI)和14根可屏蔽中断。可屏蔽中断通过相应中断使能寄存器可以使能或者禁止中断。
外部中断源:DSP芯片IO引脚上的电平变化触发中断;
内部中断源:DSP内部CPU和各个外设模块产生的中断。
在2833X处理器中,定时器1和定时器2预留给实时操作系统使用,其中断分配给INT13和 INT14(系统规定,不需要也不能后续更改);两个不可屏蔽中断各自占用独立的专用中断;剩下12个可屏蔽中断直接接在PIE模块(外部中断扩展模块),供给外部中断和处理器内部外设单元使用。这些中断源被分成8组,每组中断都分别连接至12个CPU核中断(INT1~INT12)中的一个,所以PIE模块支持96个独立的中断源。96个中断都对应有各自的中断向量表,这些向量表存储在特定的RAM模块并且可以后续根据需要更改。CPU响应中断时可自动获取相应的中断向量。在PIE模块中,每个中断都可以独立使能或者禁止。
采用PIE模块的原因在于:由于众多的外设,每个外设在相应事件发生时都可以产生一个或者多个中断,但CPU无法及时处理这么多的外设中断请求,因此用PIE模块作为控制器来仲裁来自外设和外部引脚的中断请求。
PIE向量表用来存储系统中每个中断服务(ISR)的入口地址,每个中断源都有一个中断向量。在设备初始化时就要设置好中断向量表。
http://s6/middle/0034sXQLzy70HrDLWkZ55&690首先解释几个名词:
IFR:中断标志寄存器
PIEIFR:PIE中断标志寄存器
INTx.y:表示中断,从(INT1.1~INT1.8)——(INT12.1~INT12.8)共96个中断源
(当中断发生时,CPU可以通过这些寄存器的内容进行解码来判断响应哪一个中断。PIE模块根据寄存器PIEIERx和PIEIFRx的当前值来解码、确定CPU所需要的中断向量地址。CPU进入中断后会自动清除PIEIFRx.y位。需要注意的是,PIEIERx寄存器用来决定哪一个中断向量被用来作为跳转地址,所以在清除PIEIERx.y时必须谨慎。)
从图中可以看出:
PIE模块将外设或外部引脚的每8个中断复用一个CPU级(外设级)中断信号。PIE模块将所有中断源分成12组。在同一个PIE分组的将共用一个CPU中断,例如PIE分组1(INT1.y)中的中断共用INT1(CPU中断1),PIE分组12(INT12.y)中的中断共用INT12(CPU中断12)。对于直接连到CPU级的中断源不需要与其他中断源复用。例如,定时器1和定时器2的专用中断INT13和INT14.
对于同一分组的中断在PIE模块中有其相应的PIEIFRx.y和PIEIERx.y(x:1~12 y:1~8),其中x表示第x组,y表示第y个中断。另外,每组中断还对应一个中断应答位PIEACKx(x:1~12)。
一旦外设向PIE请求中断时,PIE相应的中断标志位PIEIFRx.y就会置位,如果该组的中断使能位PIEIERx.y此时也置位,那PIE就会检查相应的PIEACKx位来判断CPU是否准备好响应该组的中断。如果PIEACKx被置位(PIEACKx=1,CPU没有准备好响应该中断),则PIE将等待直到该位被清零(PIEACKx=0,CPU准备好响应该中断),然后发送中断请求至INTx,此时PIEACKx被硬件置位,以等待处理下一次中断。
**也许到现在有些人还不能很好理解上面那个图:中断的工作流程,下面我们用工程流图来直观的表示一下:
http://s6/middle/0034sXQLzy70HrE0brvb5&690
从这个流程图可以很清楚的看出来中断响应过程。
2.PIE寄存器(稍微介绍一下,需要具体的的请查阅手册)
- PIE控制寄存器(PIECTRL):用户可以通过获取PIEVECT位的值来确定哪一个中断请求获取向量。
- PIE中断应答寄存器(PIEACK):每一位代表相应一个PIE分组。当相应位为0,表示该位所在分组可以向CPU发送中断请求。向该位写0无效。
- PIE中断标志寄存器(PIEIFRx,x=1~12)
- PIE中断使能寄存器(PIEIERx,x=1~12)
- CPU中断标志寄存器(IFR)
- CPU中断使能寄存器(IER)
- CPU调试中断使能寄存器(DBGIER) 很少用到
- 外部中断控制寄存器(XINTnCR,n=1~7):2833x系列的期器件支持外部中断XINT1~XINT7,另外XINT13被复用为不可屏蔽中断。每一个外部中断都可以设置成上升沿、下降沿或上升沿及下降沿触发中断,也可以使能或禁止(包括NMI)。Ploarity位是中断极性位。该位用来确定外部引脚的上升沿或下降沿信号产生中断。
-
- 00 下降沿产生中断;
- 01 上升沿产生中断;
- 10 下降沿产生中断;
- 11 上升沿或下降沿产生中断。
- 外部不可屏蔽中断控制寄存器(XNMICR):Ploarity位同上,Select位是INT13中断源选择位:0,定时器1中断源;1,XNMI_XINT13中断源
- 外部中断1、2和不可屏蔽中断寄存器(XINT1CTR、XINT2CTR、XNMICTR):对于XINT1、XINT2和XNMI,分别具有一个16位的计数器,计数器的数值在检测到中断触发边沿时复位至0,可以用来记录中断发生的时间。
********************************************************************************************************************
以上主要讲了硬件部分,下面我们就实验来讲一下软件编程问题:
1.Example_2833xCpuTimer.c 【CPU定时器中断实验】
按照前面所讲的实验的步骤来,加载Example_2833xCpuTimer项目,来观察软件内部中断响应是如何完成的。(以定时器0为例)下面给出相关函数,我也会将中断相关函数解释一下,目前能看懂就行,以后还要系统学习。
// TI File $Revision: /main/14 $
// Checkin $Date: April 21, 2008 15:41:07 $
-
//###########################################################################
//
// FILE: Example_2833xCpuTimer.c
//
// TITLE: DSP2833x Device Getting Started Program.
//
// ASSUMPTIONS:
//
// This program requires the DSP2833x header files.
//
// Other then boot mode configuration, no other hardware configuration
// is required.
//
//
// As supplied, this project is configured for "boot to SARAM"
// operation. The 2833x Boot Mode table is shown below.
// For information on configuring the boot mode of an eZdsp,
// please refer to the documentation included with the eZdsp,
//
// $Boot_Table:
//
// GPIO87 GPIO86 GPIO85 GPIO84
// XA15 XA14 XA13 XA12
// PU PU PU PU
// ==========================================
// 1 1 1 1 Jump to Flash
// 1 1 1 0 SCI-A boot
// 1 1 0 1 SPI-A boot
// 1 1 0 0 I2C-A boot
// 1 0 1 1 eCAN-A boot
// 1 0 1 0 McBSP-A boot
// 1 0 0 1 Jump to XINTF x16
// 1 0 0 0 Jump to XINTF x32
// 0 1 1 1 Jump to OTP
// 0 1 1 0 Parallel GPIO I/O boot
// 0 1 0 1 Parallel XINTF boot
// 0 1 0 0 Jump to SARAM <- "boot to SARAM"
// 0 0 1 1 Branch to check boot mode
// 0 0 1 0 Boot to flash, bypass ADC cal
// 0 0 0 1 Boot to SARAM, bypass ADC cal
// 0 0 0 0 Boot to SCI-A, bypass ADC cal
// Boot_Table_End$
//
// DESCRIPTION:
//
// This example configures CPU Timer0, 1, and 2 and increments
// a counter each time the timers assert an interrupt.
//
// Watch Variables:
// CpuTimer0.InterruptCount
// CpuTimer1.InterruptCount
// CpuTimer2.InterruptCount
//
-
//###########################################################################
// $TI Release: DSP2833x/DSP2823x Header Files V1.20 $
// $Release Date: August 1, 2008 $
-
//###########################################################################
#include "DSP28x_Project.h" // Device Headerfile and Examples Include File
// Prototype statements for functions found within this file.
interrupt void cpu_timer0_isr(void);
//这里是中断服务程序的声明; interrupt void cpu_timer1_isr(void); //注意前面要加上interrupt
interrupt void cpu_timer2_isr(void); //才能将函数声明为中断函数 。
void main(void) //以下是主函数;
{
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP2833x_SysCtrl.c file.
InitSysCtrl(); //系统初始化;
// Step 2. Initalize GPIO:
// This example function is found in the DSP2833x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
// InitGpio(); // Skipped for this example
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT; //关闭CPU中断;
// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP2833x_PieCtrl.c file.
InitPieCtrl(); //PIE初始化;
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000; //中断使能寄存器初始化;
IFR = 0x0000; //中断标志寄存器初始化;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP2833x_DefaultIsr.c.
// This function is found in DSP2833x_PieVect.c.
InitPieVectTable(); //PIE中断向量表初始化;
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers //注意这里的EALLOW和
PieVectTable.TINT0 = &cpu_timer0_isr; //EDIS是必须的,为了
-
PieVectTable.XINT13 = &cpu_timer1_isr; //允许向受保护的寄存器
PieVectTable.TINT2 = &cpu_timer2_isr; //写入中断服务程序的入 //口地址
EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4. Initialize the Device Peripheral. This function can be
// found in DSP2833x_CpuTimers.c
InitCpuTimers(); // For this example, only initialize the Cpu Timers //初始化CPU定时器;
#if (CPU_FRQ_150MHZ)
// Configure CPU-Timer 0, 1, and 2 to interrupt every second:
// 150MHz CPU Freq, 1 second Period (in uSeconds)
-
ConfigCpuTimer(&CpuTimer0, 150, 1000000);
-
ConfigCpuTimer(&CpuTimer1, 150, 1000000);
-
ConfigCpuTimer(&CpuTimer2, 150, 1000000);
#endif
#if (CPU_FRQ_100MHZ)
// Configure CPU-Timer 0, 1, and 2 to interrupt every second:
// 100MHz CPU Freq, 1 second Period (in uSeconds)
-
ConfigCpuTimer(&CpuTimer0, 100, 1000000);
-
ConfigCpuTimer(&CpuTimer1, 100, 1000000);
-
ConfigCpuTimer(&CpuTimer2, 100, 1000000);
#endif
// To ensure precise timing, use write-only instructions to write to the entire register. Therefore, if any
// of the configuration bits are changed in ConfigCpuTimer and InitCpuTimers (in DSP2833x_CpuTimers.h), the
// below settings must also be updated.
-
CpuTimer0Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0 //这部分等讲到定时器再说
-
CpuTimer1Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
-
CpuTimer2Regs.TCR.all = 0x4001; // Use write-only instruction to set TSS bit = 0
// Step 5. User specific code, enable interrupts:
// Enable CPU int1 which is connected to CPU-Timer 0, CPU int13
// which is connected to CPU-Timer 1, and CPU int 14, which is connected
// to CPU-Timer 2:
IER |= M_INT1; //使定时器0、1、2中断使能寄存器使能;
IER |= M_INT13;
IER |= M_INT14;
// Enable TINT0 in the PIE: Group 1 interrupt 7
-
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; //PIE中断使能寄存器使能,即PIEIER1.7=1
- //之所以在这里没有定时器1和2的PIE中断使能寄存器,
- //因为它们的中断直接到CPU级而不经过PIE级
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
// Step 6. IDLE loop. Just sit and loop forever (optional):
for(;;);
}
interrupt void cpu_timer0_isr(void) //定时器0的中断服务程序;
{
-
CpuTimer0.InterruptCount++;
// Acknowledge this interrupt to receive more interrupts from group 1
-
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; //中断应答位,想要了解PIEACK_GROUP1变量可以用
//前面实验中提到的“Open Declaration”来查看定义
//经查看这里的PIEACK_GROUP1用的宏定义
}
interrupt void cpu_timer1_isr(void)
{
-
CpuTimer1.InterruptCount++; //定时器0中断次数;
// The CPU acknowledges the interrupt.
EDIS;
}
interrupt void cpu_timer2_isr(void)
{ EALLOW;
-
CpuTimer2.InterruptCount++;
// The CPU acknowledges the interrupt.
EDIS;
}
-
//===========================================================================
// No more.
-
//===========================================================================
好啦,这一节课讲了有关PIE模块的硬件部分和软件编程部分,这里只是初步讲解,实际用到时可以查阅相关资料。