F28027第三节课---系统时钟(二)

来源:互联网 发布:免费听书的软件 编辑:程序博客网 时间:2024/05/12 10:51

今天还是继续学习时钟

今天看芯片手册的时候,发现自己昨天好敷衍。。今天必须要来做点补充,不然虚的慌

第一、安全装置watchdog

首先看下watchdog整体装置:


看门狗要复位输出脉冲信号,从Generate Output Pulsemo模块来看,有两个控制条件:SCSR.WDENINT(选择输出信号)和输入一个有边沿跳变的脉冲信号(上图所示1),这里我们就不重点讨论WDENINT取值了,因为我们现在要做的是关闭看门狗,无复位信号输出。

上图所示的方框1,是一个二输入或门,也就是方框2或者看门狗计数器模块任何一个有高电平的跳变信号,或门输出就是一个高脉冲信号,也就是有复位信号产生,这显然和我们的本意是不相符的,我们现在要做的是使方框2和看门狗计数器都输出低电平。

对于方框2,是一个异或门,也就是当两端输入的电平是一样时,输出为低电平,否则输出高电平。通过上面的分析,我们需要该异或门输出低电平,也就是两端输入保持一直,就需要WDCR.WDCHK=101B。

对于看门狗计数器,有一个输入信号和一个复位控制信号,也就是有两种办法让计数器输出保持低电平:无输入信号和周期性写复位信号。当看门狗使能位WDCR.WDDIS=1,使能禁止,就会导致无输入信号;周期性写复位信号,也就是看门狗复位密钥寄存器WDKEY先写一个0x55,然后再写一个0xAA,就会产生一个复位信号。在这里我有个疑问,密钥寄存器的输出连到一个单边先取反再或的一个二输入或门,由于或门的另一端是直连一个高电平,然后取反,也就是这端输入始终保持低电平,或门的输出值也就是等于密钥寄存器的输出值,那既然这样的话,这个或门在这里有什么其他的神奇作用呢?欢迎各路大神吐槽指点。

好了,啰嗦到这里,昨天关闭看门狗那一条语句SysCtrlRegs.WDCR= 0x0068也就很清晰明了了,那继续下一个时钟问题。

第二、时钟源

废话不多说,还是先上图,再一步一步的分析:


图中这么多圈圈框框的,有没有晕晕的感觉,昨天我就是看这个图特烦躁(还没有圈圈框框),走向绕来绕去的,今天反省了下,静下心好好的看了下这个结构图,还是so easy的嘛,就是几个开关选择器而已,来,一起来看下怎么简单:

首先,该芯片总共可以有四个时钟源,内部振荡器1、内部振荡器2、晶体振荡器、外部时钟输入,这四个时钟源具体接入方法大家直接看上面这个图就知道了,我就不啰嗦了,其中INTOSCnTRIM是对内部10M时钟信号进行粗调和细调的。

上面所有的圈圈框框,除了XCLK[XCLKINSEL]控制信号以外,其他都是由CLKCTL时钟控制寄存器控制的。

假设我们现在需要以内部振荡器1为时钟源,那就要关闭内部振荡器2、晶体振荡器、外部输入时钟。

先来操作最简单的,关闭晶体振荡器和外部输入时钟,如上图的左下角,也就是XTALOSCOFF=1、XCLKINOFF=1,这两个时钟源模块输出信号为低电平了,也就是左下角那个异或门输出为低电平;

再来关闭内部振荡器2,只要INTOSC2OFF控制信号为低电平,内部振荡器2就关闭了。

最后就是输出内部振荡器1的时钟信号。最重要的是打开内部振荡器的控制信号INTOSC1OFF=0,然后就是把该信号送到CPU时钟模块,时钟模块一般由PLL锁相环电路构成,所以我们只要把时钟基准信号送到PLL模块,也就是方框2,使OSCCLKSRCSEL=0,其他几个输出信号是watchdog和timer2的,若需要,打开相应的开关状态即可。

至此,昨天打酱油的东西全部复习了一遍。

第三、PLL锁相环

刚才第二点最后也说了,时钟源基准信号是送到PLL锁相环电路进行相应的调理之后才能作为系统时钟的,PLL锁相环电路场景分为两种:正常模式和跛行模式。

简单来说(还是习惯性的先上图),PLL工作模式如下:


从图中看,主要由两个寄存器控制PLL锁相环装置:PLLCR、PLLSTS,下面我们来看下这两个寄存器:

先看简单的PLLCR:



从上面很直观明了的知道,PLLCR[DIV]和PLLSTS[DIVSEL]组合起来进行时钟调理,独立看是没有意义的。

那我们现在来看下PLLSTS的寄存器结构:




这又是噼里啪啦一大串英文解说,每当这个时候,恨不得自己身边坐着一个英语过八级的漂亮女朋友,可惜陪我的只有有道词典,关键还翻译的不准确,只能半翻译半猜测了。

吐槽完了,我们再来看最开始那个PLL流转图,我们用到只是PLLSTS[OSCOFF]和PLLSTS[PLLOFF],其中OSCOFF是PLL时钟选择控制位,而PLLOFF是PLL的使能位,PLLSTS[DIVSEL]和PLLCR[DIV]是配合使用的。有点要注意的是,在写入 PLLCR 前,PLLSTS[DIVSEL] 必须为 0,而只有当 PLLSTS[PLLOCKS]=1 时才应被改变。

说了那么多废话,最后来一个PLL锁相环调整电路的整体流程思路(当然来自芯片手册):


简单的复述下流程:

1、检查PLLSTS[MCLKSTS]位是否为1,为1说明CPU工作在跛行模式,要赶紧做出相应的调整了;

2、当PLLSTS[MCLKSTS]位恢复为0后,检查PLLSTS[DIVSEL]是否为2或者3,如果是,直接把PLLSTS[DIVSEL]设置为0

3、当上一步检查到PLLSTS[DIVSEL]不为2或者3时,把PLLSTS[MCLKOFF]设为1,关闭振荡器故障检测,这样就不会在调整PLLCR期间再次进入跛行模式;

4、设置PLLCR[DIV]的值;

5、检查PLLSTS[PLLLOCKS]值是否为1,也就是PLLCR是否完成写入锁定;

6、当完成PLL完成锁定后,开启振荡器故障检测;

7、如果有需要,调整PLLSTS[DIVSEL]的值,但是有点需要注意,PLLSTS[DIVSEL]调整为1或2时,可以直接设置,当调整为3时,先调整到2,再调整到3。

流程也讲完了,现在我们来看下示例程序:

InitPll(12,2);

void InitPll(Uint16 val, Uint16 divsel)
{
   volatile Uint16 iVol;


   // Make sure the PLL is not running in limp mode
   if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
   {
      EALLOW;
      // OSCCLKSRC1 failure detected. PLL running in limp mode.
      // Re-enable missing clock logic.
      SysCtrlRegs.PLLSTS.bit.MCLKCLR = 1;
      EDIS;
      // Replace this line with a call to an appropriate
      // SystemShutdown(); function.
      asm("        ESTOP0");     // Uncomment for debugging purposes
   }

   // DIVSEL MUST be 0 before PLLCR can be changed from
   // 0x0000. It is set to 0 by an external reset XRSn
   // This puts us in 1/4
   if (SysCtrlRegs.PLLSTS.bit.DIVSEL != 0)
   {
       EALLOW;
       SysCtrlRegs.PLLSTS.bit.DIVSEL = 0;
       EDIS;
   }

   // Change the PLLCR
   if (SysCtrlRegs.PLLCR.bit.DIV != val)
   {
      EALLOW;
      // Before setting PLLCR turn off missing clock detect logic
      SysCtrlRegs.PLLSTS.bit.MCLKOFF = 1;
      SysCtrlRegs.PLLCR.bit.DIV = val;
      EDIS;

      // Optional: Wait for PLL to lock.
      // During this time the CPU will switch to OSCCLK/2 until
      // the PLL is stable.  Once the PLL is stable the CPU will
      // switch to the new PLL value.
      //
      // This time-to-lock is monitored by a PLL lock counter.
      //
      // Code is not required to sit and wait for the PLL to lock.
      // However, if the code does anything that is timing critical,
      // and requires the correct clock be locked, then it is best to
      // wait until this switching has completed.

      // Wait for the PLL lock bit to be set.

      // The watchdog should be disabled before this loop, or fed within
      // the loop via ServiceDog().

      // Uncomment to disable the watchdog
      DisableDog();

      while(SysCtrlRegs.PLLSTS.bit.PLLLOCKS != 1)
      {
          // Uncomment to service the watchdog
          // ServiceDog();
      }

      EALLOW;
      SysCtrlRegs.PLLSTS.bit.MCLKOFF = 0;
      EDIS;
    }

    // If switching to 1/2
    if((divsel == 1)||(divsel == 2))
    {
        EALLOW;
        SysCtrlRegs.PLLSTS.bit.DIVSEL = divsel;
        EDIS;
    }

    // If switching to 1/1
    // * First go to 1/2 and let the power settle
    //   The time required will depend on the system, this is only an example
    // * Then switch to 1/1
    if(divsel == 3)
    {
        EALLOW;
        SysCtrlRegs.PLLSTS.bit.DIVSEL = 2;
        DELAY_US(50L);
        SysCtrlRegs.PLLSTS.bit.DIVSEL = 3;
        EDIS;
    }
}

经过之前的流程分析,程序分析起来是不是很简单了,呵呵,我提两个点:当检查到跛行模式后,强制把MCLKCLR置1,就是为了退出时钟检测电路;另外,他的程序没有检测PLLSTS[DIVSEL]是否为2或3,而是直接检测是否为0,然后在处理子函数中关闭检测电路。

第四、外设时钟

对于外设时钟这点还真的没什么好讲的,当寄存器对应的位置1时,就是使能输出,否则就是使能禁止,直接贴图了:





上面那几个贴图是外设时钟控制寄存器的,不同的寄存器不同的位对应不同的外设

还有一个低速外设时钟预分频器寄存器LOSPCP


贴图贴完了,再看示例程序了:

void InitPeripheralClocks(void)
{
   EALLOW;

// LOSPCP prescale register settings, normally it will be set to default values

   GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 3;  // GPIO18 = XCLKOUT
   SysCtrlRegs.LOSPCP.all = 0x0002;

// XCLKOUT to SYSCLKOUT ratio.  By default XCLKOUT = 1/4 SYSCLKOUT
   SysCtrlRegs.XCLK.bit.XCLKOUTDIV=2; // Set XCLKOUT = SYSCLKOUT/1

// Peripheral clock enables set for the selected peripherals.
// If you are not using a peripheral leave the clock off
// to save on power.
//
// Note: not all peripherals are available on all 2802x derivates.
// Refer to the datasheet for your particular device.
//
// This function is not written to be an example of efficient code.

   SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;       // ADC
   SysCtrlRegs.PCLKCR3.bit.COMP1ENCLK = 1;     // COMP1
   SysCtrlRegs.PCLKCR3.bit.COMP2ENCLK = 1;     // COMP2
   SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 1; // CPU Timer-0
   SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 1; // CPU Timer-1
   SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK = 1; // CPU Timer-2
   SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 1;     // eCAP1
   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.PCLKCR3.bit.GPIOINENCLK = 1;    // GPIO
   SysCtrlRegs.PCLKCR0.bit.HRPWMENCLK=1;       // HRPWM
   SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 1;      // I2C
   SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 1;      // SCI-A
   SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 1;      // SPI-A

   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;      // Enable TBCLK within the EPWM

   EDIS;
}

是不是都能看的明白,虽然要翻阅芯片手册,但至少能明白每个语句的含义了,方便直接后续调整了。

到这里,我们就把F2802x_SysCtrl.c文件全部讲完了,有没有收获,我有点,但是好困现在,又是两点,白天太忙,没时间让我做小动作,菊花厂的工作还是很繁忙的,关键是我白天的工作和晚上的学习完全没关联,长久下去会不会人格分裂,好担心,去洗澡压压惊了。

菜鸟交流qq群107691092

1 0
原创粉丝点击