DSP28335定时器
文章目录
一、定时器介绍
TMS320F28335的CPU Time有三个,分别为Timer0,Timer1当未移植操作其中Timer2是为操作系统DSP/BIOS架留的,Timer2,系统时可用来做普通的定时器。这三个定时器的中断信号分别为TINTO,TINT1,TINT2,分别对应于中断向量INT1,INT13,INT14。
从上图可知, 定时器有一个预分频模块和一个定时/计数模块, 其中预分频模块包括一个 16 位的定时器分频寄存器(TDDRH: TDDR) 和一个 16 位的预定标计数器(PSCH: PSC) ; 定时/计数模块包括一个 32 位的周期寄存器(PRDH: PRD)和一个 32 位的计数寄存器(TIMH:TIM) 。
当系统时钟(SYSCLKOUT) 来一个脉冲, PSCH: PSC 预定标计数器减 1, 当 PSCH:PSC 预定标计数器减到 0 的时候, 预定标计数器产生下溢后向定时器的 32 位计数器 TIMH:TIM 借位, 即 TIMH:TIM 计数器减 1, 同时 PSCH: PSC 可以重载定时器分频寄存器(TDDRH: TDDR) 的值; 当计数寄存器 TIMH: TIM 减到 0 产生下溢的时候, 计数寄存器会重载周期寄存器(PRDH: PRD) 的值, 同时定时器会产生一个中断信号给 CPU。
以我的理解来说,16 位的定时器分频寄存器(TDDRH: TDDR)和 32 位的周期寄存器(PRDH: PRD)用来装载计数的初始值, 16 位的预定标计数器(PSCH: PSC)和32 位的计数寄存器(TIMH:TIM)相乘就是一次定时时间。
二、定时器配置步骤
以定时器0为例,相关库函数在DSP2833x CpuTimers.c文件中
1.使能定时器时钟
我们知道 F28335 的 CPU 定时器的时钟是由外设时钟控制寄存器 3 所控制,并且在对系统时钟控制寄存器写操作时必须关闭写保护。
代码如下(示例):
//使能定时器时钟
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; //CPU Timer 0
EDIS;
2.初始化定时器参数
包括制定定时器寄存器地址、 周期寄存器值、 预定标计数器值等。要使用 F28335 的 CPU 定时器, 还需要对其内部相关寄存器的设置。
代码如下(示例):
//指向定时器 0 的寄存器地址
CpuTimer0.RegsAddr = &CpuTimer0Regs;
//设置定时器 0 的周期寄存器值
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
//设置定时器预定标计数器值为 0
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
//确保定时器 0 为停止状态
CpuTimer0Regs.TCR.bit.TSS = 1;
//重载使能
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
3.定时器计时参数设置
要使用定时器还需要设置它的定时周期以及设置定时器的控制寄存器等。 这些在 TI 提供的库函数“DSP2833x_CpuTimers.c” 内已经有函数实现。
void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
该函数有3个参数, 第1个表示哪个定时器, 第2个表示定时器频率, 第3个表示定时器周期值。
4.开启定时器中断功能,并使能定时器
//设置定时器 0 的中断入口地址为中断向量表的 INT0
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
//开始定时器功能
CpuTimer0Regs.TCR.bit.TSS=0;
//开启 CPU 第一组中断并使能第一组中断的第 7 个小中断, 即定时器 0
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
//使能总中断
EINT;
ERTM;
5.编写定时器中断服务函数
最后我们还需要编写一个定时器中断服务函数, 通过中断函数处理定时器产生的相关中断。 定时器中断服务函数名在上一步就已经指定, 即中断服务函数入口地址, 只不过在编写中断服务函数时需要在函数名前面加上一个关键字“interrupt” 。
interrupt void TIM0_IRQn(void)
{
功能程序
}
三、硬件设计
本实验硬件平台为普中dsp28335开发板,用到了led灯以及定时器。
四、软件设计
本章所要实现的功能是: 通过 Timer0 中断控制 D2 指示灯闪烁。 程序框架如下:
(1) 初始化定时器 0, 并使能相应中断
//定时器0初始化函数
//Freq:CPU时钟频率(150MHz)
//Period:定时周期值,单位us
void TIM0_Init(float Freq, float Period)
{
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer 0
EDIS;
//设置定时器0的中断入口地址为中断向量表的INT0
EALLOW;
PieVectTable.TINT0 = &TIM0_IRQn;
EDIS;
//指向定时器0的寄存器地址
CpuTimer0.RegsAddr = &CpuTimer0Regs;
//设置定时器0的周期寄存器值
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
//设置定时器预定标计数器值为0
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
//确保定时器0为停止状态
CpuTimer0Regs.TCR.bit.TSS = 1;
//重载使能
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period);
//开始定时器功能
CpuTimer0Regs.TCR.bit.TSS=0;
//开启CPU第一组中断并使能第一组中断的第7个小中断,即定时器0
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
//使能总中断
EINT;
//使能仿真调试中断
ERTM;
}
(2) 编写定时器 0 中断函数
interrupt void TIM0_IRQn(void)
{
EALLOW;
LED2_TOGGLE;
//清除中断标志位
PieCtrlRegs.PIEACK.bit.ACK1=1;
EDIS;
}
(3) 编写主函数
void main()
{
InitSysCtrl();//系统时钟初始化,默认已开启F28335所有外设时钟
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
LED_Init();
TIM0_Init(120,500000);
while(1);
}
总结
DSP28335中的三个定时器Timer0、Timer1、Timer2的中断配置的区别主要体现在:
(1)开启定时器中欧那个端功能并使能定时器中开启CPU第一组中断并使能定时器对应的PIE中断配置中,对于Timer0,需要两者都需要使能,而对于Timer1、Timer2,由于直接到CPU,故只需使能CPU中断。
(2)中断服务函数的配置,Timer0,需要对PIE中断标志位清零。而对于Timer1、Timer2,由于直接到CPU,不需要做任何标志位清零。
(3)关于要使用定时器还需要设置它的定时周期库函数ConfigCpuTimer();
void ConfigCpuTimer(struct CPUTIMER_VARS *Timer, float Freq, float Period)
该函数有3个参数, 第1个表示哪个定时器, 第2个表示定时器频率, 第3个表示定时器周期值。 当主频Freq变化时,他的定时时间也会相应变化。