PLL作为DSP的时钟重要组成部分,它除了提高系统内部SYSCLKOUT的频率之外,还有一个重要的用途就是监视外部时钟是不是很好的为DSP内部提供系统时钟。与PLL配置相关的寄存器有两个:PLL状态寄存器PLLSTS和PLL控制寄存器PLLCR,两个寄存器具体的讲解参见第3节。
如果PLL处于使能状态,需要监视PPLSTS寄存器中的MCLKSTS位的状态。如果MCLKSTS被置位,则软件要采集恰当的措施保证系统不出现事故,该措施包括使系统停机、复位等。
两个寄存器中最关键的位域分别为 2位的PLLSTS[DIVSEL]和4位的PLLCR[DIV]。比如TMS320F23885最大工作时钟为150MHz,通常外部晶振频率为30MHz,先将30MHz进行10倍频变成300MHz,再对300MHz进行2分频得到150MHz的时钟。(官方例程里产生150MHz的方式) PLL的设置如表1所示。
PLLSTS[DIVSEL]选择CPU时钟的分频系数(/4,/2,/1),PLLCR[DIV] 选择CPU时钟的倍频系数(*1,*2,……,*10)。
/*
* 函数名称:InitPll
* 函数输入:倍频参数val,分频参数divsel
* val取值为0到10,表示倍频数;divsel取值0到4,0和1表示4分频,2表示2分频,3表示不分频
* 函数输出:无
* 函数调用:InitPll(10,2);
* 先将外部时钟倍频10倍,在分频1/2,最后产生的时钟CLKIN输入CPU28x
*/
void InitPll(unsigned short div, unsigned short divsel)
{
// 确保PLL不是工作在limp mode下,即有外部时钟进入PLL
if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
{
//检测到无外部时钟,软件要采集恰当的措施保证系统不出现事故,该措施包括
//使系统停机、复位等
//用适合的函数替换下面一行
// SystemShutdown(); function.
asm(" ESTOP0");
}
// PLLCR从0x0000改变前,PLLSTS[DIVSEL]必须为0
// 外部RST复位信号会使PLLSTS[DIVSEL]复位
// 此时分频为1/4
if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;
EDIS;
}
// 前面条件都满足后,可以改变PLLCR[DIV]
if (SysCtrlRegs.PLLCR.bit.DIV != val)
{
EALLOW;
// 在设置PLLCR[DIV]前,要禁用主振荡器检测逻辑
//Missing clock detect logic
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
SysCtrlRegs.PLLCR.bit.DIV = div;
EDIS;
//等待PLL稳定且处于锁定状态,即PLLSTS[LOCKS]置位
//等待稳定的时间可能略长,需要禁用看门狗或者循环喂狗
//屏蔽注释,禁用看门够
DisableDog();
while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
{
//屏蔽注释,喂狗
// ServiceDog();
}
EALLOW;
SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0;
EDIS;
}
// 如果需要分频1/2
if((divsel == 1)||(divsel == 2))
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;
EDIS;
}
//注意:下面代码只有在PLL是旁路或者关闭模式时,才可被执行,其他模式禁止。
//倍频时一定要分频,不倍频时才允许不分频
//如果需要切换分频到1/1
// * 首先从默认1/4分频切换到1/2分频,让电源稳定
// 稳定所需要的时间依赖于系统运行速度,此处延时50us只是作为一个特例
// * 稳定后,再切换到1/1
if(divsel == 3)
{
EALLOW;
SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;
DELAY_US(50L);
SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;
EDIS;
}
}