DSP28035时钟设置讲解

来源:互联网 发布:电路分析软件 编辑:程序博客网 时间:2024/05/22 11:46


TMS320x2803x系列(28035为例)系统时钟与TMS320x280x, 2801x, 2804x 系列时钟是不太一样的。
下面是TMS320x280x, 2801x, 2804x系列的时钟图如下:


这里写图片描述
这里写图片描述
TMS320x2803x系列(28035为例)的时钟与系统框图如下:
这里写图片描述
从上图可以看出SPI-A,SPI-B,SCI-A的时钟来自低速外设时钟LSPCLK; eCAN-A,LIN-A的时钟由SYSCLKOUT的二分频获得; 其它外设的时钟都是SYSCLKOUT。其中LSPCLK的大小由LOSPCP寄存器所设置,如下图:
这里写图片描述
TMS320x2803x系列(28035为例)的时钟源选择,如下图:
这里写图片描述
时钟源选择
2803x系列DSP有两个内部时钟源(INTOSC1和INTOSC2),可以不需要外部时钟。同时,也具有PLL时钟模块。一共有4种时钟源可供选择:
1) INTOSC1(10MHz)
内部时钟源1(INTOSC1),此时钟提供给看门狗块模块,内核和CPU定时器2 。
时钟频率默认为10MHz,可以通过INTOSCnTRIM寄存器修改频率。
2) INTOSC2(10MHz)
功能与INTOSC1是一样的。
3) 外部晶体振荡器
使用外部晶体振荡器给芯片提供时钟,晶振连接于X1/X2 脚。
4) 外部时钟源
如果不使用外部晶振作为时钟源,可以选择这种模式。时钟从外部时钟源的XCLKIN引脚输入生成。
注意:XCLKIN复用于GPIO19或GPIO38脚。可以通过XCLK寄存器的XCLKINSEL位选择是GPIO19还是GPIO38作为XCLKIN输入。
CLKCTL(XCLKINOFF)为0时,不使能此时钟。如果时钟源不使用或作为GPIO引脚时,用户应该在启动引导时禁用。

上面时钟图粗看起来很复杂,如果仔细分析,其实也很简单。从图的中间画一条分隔线,左边部分为4个输入时钟源,其中INTOSC1和INTOSC2是一模一样的,XTAL和XCLKIN是另外的两个时钟源; 右边部分三个时钟模块,从上到下分别是看门狗时钟WDCLK,系统时钟OSCCLK(此时钟到PLL),以及CPU定时器2时钟CPUTMR2CLK。
看完时钟框图后,下面是软件系统时钟的设置
在main函数的最初位置初始化DSP,即调用void InitialDSP(void)函数。

void InitialDSP(void){    DINT;    IER = 0x0000;    IFR = 0x0000;    InitSysCtrl();    InitPieCtrl();    InitPieVectTable();    #ifdef RunInFlash    memcpy( &secureRamFuncs_runstart,            &secureRamFuncs_loadstart,            &secureRamFuncs_loadend - &secureRamFuncs_loadstart);    InitFlash();    #endif    InitAdc();    InitGpio();    InitSci();    InitSpi();    InitCpuTimers();    EALLOW;    PieVectTable.TINT2 = &OSTickISR;    PieVectTable.USER12 = &OSCtxSw;    PieVectTable.SCIRXINTA = &InterComRxInterrupt;    PieVectTable.SCITXINTA = &InterComTxInterrupt;    EDIS;    …}

函数很多,这里主要讲解InitSysCtrl()。

void InitSysCtrl(void){    EALLOW;    SysCtrlRegs.WDCR= 0x0068;         //关看门狗    EDIS;    EALLOW;    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1; // 关ADC时钟    (*Device_cal)();                        // 用于校准内部振荡器和ADC,这个函数在boot ROM的时候,芯片会自动调用。    SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 0; // 启动ADC时钟    EDIS;    XtalOscSel ();                  //选择外部晶振时钟XTALOSC作为系统时钟源, 且关闭所有未使用的时钟以节省电源。     InitPll(12,1);                  //12*20M/4=60M    InitPeripheralClocks();        //初始化外设时钟}

下面是XtalOscSel ()函数的分析。

void XtalOscSel (void){    EALLOW;    SysCtrlRegs.CLKCTL.bit.XTALOSCOFF = 0;     // 开启外部晶振时钟XTALOSC    SysCtrlRegs.CLKCTL.bit.XCLKINOFF = 1;      // 关闭外部时钟源XCLKIN    SysCtrlRegs.CLKCTL.bit.OSCCLKSRC2SEL = 0;  // OSCCLKSRC2来自外部晶振时钟源    SysCtrlRegs.CLKCTL.bit.OSCCLKSRCSEL = 1;   // OSCCLK来自INTOSC2/ext clk    SysCtrlRegs.CLKCTL.bit.WDCLKSRCSEL = 1;    // 看门狗时钟来自外部晶振时钟源    SysCtrlRegs.CLKCTL.bit.INTOSC2OFF = 1;     // 关闭INTOSC2    SysCtrlRegs.CLKCTL.bit.INTOSC1OFF = 1;     // 关闭INTOSC1    EDIS;}

这个函数主要是对CLKCTL寄存器的配置,要对照上面的时钟框图来看才好理解,主要是对图中几个开关状态的设置。CLKCTL寄存器各个位的功能如下:
这里写图片描述
这里写图片描述
这里写图片描述
接下来初始化PLL,函数是InitPll(12,1);

void InitPll(Uint16 val, Uint16 divsel){    volatile Uint16 iVol;    if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)       // 判断时钟是否丢失    {        EALLOW;        SysCtrlRegs.PLLSTS.bit.MCLKCLR = 1;        EDIS;    }    if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)       // PLLCR 被修改之前DIVSEL必须设置为 0     {        EALLOW;        SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;        EDIS;    }    if (SysCtrlRegs.PLLCR.bit.DIV != val)        //修改PLLCR    {        EALLOW;        SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;      // 设置PLLCR 之前关闭主时钟丢失检测        SysCtrlRegs.PLLCR.bit.DIV = val;            // PLLCR[DIV] = 12        EDIS;        EALLOW;        SysCtrlRegs.WDCR= 0x0068;        EDIS;        while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1) //当PLLCR被改写的时候,PLL会上锁。等待解锁完成。        {        }        EALLOW;        SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0;        // 打开主时钟丢失检测功能        EDIS;    }    if((divsel == 1)||(divsel == 2))    {        EALLOW;        SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;    // divsel = 1,SYSCLKOUT = (OSCCLK*12)/4        EDIS;    }    if(divsel == 3)    {        EALLOW;        SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;        DELAY_US(50L);        SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;        EDIS;    }}

上面的代码都是按照手册里提供的程序流程图来写的,下面把PLLCR更改的程序流程图贴出来。
这里写图片描述
看看PLL是如何配置的,如下图,可以看到有三种配置模式,分别是不使能PLL,使能PLL,PLL旁路(当OSCCLK失效时,自动转到PLL模式)。
本例代码选择使能PLL工作模式(PLLSTS.PLLOFF = 0)。
这里写图片描述
下面是PLL的状态寄存器PLLSTS和控制寄存器PLLCR; 状态寄存器PLLSTS反映了PLL的工作状态,控制寄存器PLLCR用于设置PLL的倍频系数。
这里写图片描述
这里写图片描述
这里写图片描述
最后一步初始化外设时钟,函数是InitPeripheralClocks()
这个函数还是比较简单的,主要是启动各个外设模块的时钟,当然为了节省功耗,也可以关掉没用到的外设模块时钟,将对应的模块时钟使能位设置为0即可。

void InitPeripheralClocks(void){   EALLOW;   SysCtrlRegs.LOSPCP.all = 0x0002;         SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;      // ADC   SysCtrlRegs.PCLKCR3.bit.COMP1ENCLK = 1;    // COMP1   SysCtrlRegs.PCLKCR3.bit.COMP2ENCLK = 1;    // COMP2   SysCtrlRegs.PCLKCR3.bit.COMP3ENCLK = 1;    // COMP3   SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1;    // eCAP1   SysCtrlRegs.PCLKCR0.bit.ECANAENCLK=1;      // eCAN-A   SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 1;    // eQEP1   SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 1;    // ePWM1   SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 1;    // ePWM2   SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 1;    // ePWM3   SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 1;    // ePWM4   SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 1;    // ePWM5   SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 1;    // ePWM6   SysCtrlRegs.PCLKCR1.bit.EPWM7ENCLK = 1;    // ePWM7   SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK = 1;    // HRPWM   SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 1;     // I2C   SysCtrlRegs.PCLKCR0.bit.LINAENCLK = 1;     // LIN-A   SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 1;     // CLA1   SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1;     // SCI-A   SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1;     // SPI-A   SysCtrlRegs.PCLKCR0.bit.SPIBENCLK = 1;     // SPI-B   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;     // Enable TBCLK within the ePWM    EDIS;}