28335学习笔记2——F28335 时钟及控制系统

1.F28335系统时钟来源

在这里插入图片描述
F28335的时钟来源有两种:
(1)采用外部振荡器作为时钟源(外部时钟)——即在XCLKIN引脚上、或复用X1引脚引入其他数字系统或外部振荡器的时钟信号;
(2)采用F28335内部振荡器作为时钟源(内部时钟)——即在X1和X2引脚间连接一个晶体从而产生时钟源。
一般选择采用内部时钟,在X1和X2之间接入一个30MHz的晶振。内部信号时钟源和外部信号时钟源通过异或门后选择接入成为OSCCLK即振荡器时钟信号。OSCCLK受到寄存器PLLSTS(OSCOFF)位控制是否通断。信号经过开关后分两路传输,一路直接通过;另一路经过PLL锁相环模块。之所以不能直接使用OSCCLK信号的原因是它的频率太低。需要进入锁相环倍频和分频后才能使用。通过对寄存器PLLSTS(PLLOFF)位控制,可以使能锁相环。使能后通过寄存器PLLCTR设置倍频数(最大可为10)。倍频数为10时,通过PLL后的时钟信号VCOCLK为300MHz。所以还有对寄存器PLLSTS(DIVSEL)设置分频系数为2.得到最终的150MHz的时钟信号CLKIN来供给CPU。

2.F28335系统控制及外设时钟

CLKIN系统信号提供给C28x内核的时钟,它作为SYSCLKOUT从CPU传出(也就是说,CLKIN与SYSCLKOUT频率相同)。28335DSP中外设的时钟信号则是对系统时钟信号SYSCLKOUT处理后得到的。如下图所示
在这里插入图片描述
可以通过外设时钟控制寄存器使能外部时钟。在实际应用中,为了降低系统功耗,不使用的外设最好将其外设时钟禁止。外设时钟包括快速外设和慢速外设两种,分别通过HISPCP和LOSPCP寄存器进行设置。SPI、I2C、MCBSP这些串口通信协议都使用低速外设时钟信号。AD采用高速时钟信号。除此之外,系统时钟经过1/2分频后提供给eCAN模块。系统时钟直接输出给系统控制寄存器模块、DMA模块、EPWM模块、ECAP模块、EQEP模块。

3.F28335时钟单元常用寄存器

①外设时钟控制寄存器PCLCR0/1/3
控制片上各种外设时钟的状态,使能或禁止。
②高/低速外设时钟预分频寄存器HISPCP/LOSPCP
分别控制高/低速的外设时钟。
③锁相环状态寄存器PLLSTS
④锁相环控制寄存器PLLCR
用于控制芯片PLL的倍数,在向PLL控制寄存器进行写操作之前,需要:
(1)在PLL完全锁住后,即PLLSTS【PLLLOCKS】=1
(2)芯片不能工作在LIMP模式,即PLLSTS[MCLKSTS】=0

4.自定义系统时钟

这里我主要想说一下TI提供的和系统时钟相关的文件和函数。

4.1 InitSysCtrl()函数

该函数位于TI提供的库文件DSP2833x_SysCtrl.c 内, 功能是按照需求配置系统控制寄存器值:默认将看门狗关闭,系统时钟配置为150MHz,并分出高速时钟和低速时钟以及使能DSP各外设时钟。
需要提前声明一点的是系统控制寄存器SysCtrlRegs的定义在TI提供的DSP2833x_GlobalVariableDefs.c库文件中
在这里插入图片描述
结构体类型SYS_CTRL_REGS的声明与外部变量SysCtrlRegs的定义在DSP2833x_SysCtrl.h头文件中。从下面代码可以看出系统控制寄存器中包含的寄存器即是F28335时钟单元常用寄存器。

// System Control Register File:
//
struct SYS_CTRL_REGS {
    
    
   Uint16              rsvd7;     // 0
   union   PLLSTS_REG  PLLSTS;    // 1
   Uint16              rsvd1[8];  // 2-9
   union   HISPCP_REG  HISPCP;    // 10: High-speed peripheral clock pre-scaler
   union   LOSPCP_REG  LOSPCP;    // 11: Low-speed peripheral clock pre-scaler
   union   PCLKCR0_REG PCLKCR0;   // 12: Peripheral clock control register
   union   PCLKCR1_REG PCLKCR1;   // 13: Peripheral clock control register
   union   LPMCR0_REG  LPMCR0;    // 14: Low-power mode control register 0
   Uint16              rsvd2;     // 15: reserved
   union   PCLKCR3_REG PCLKCR3;   // 16: Peripheral clock control register
   union   PLLCR_REG   PLLCR;     // 17: PLL control register
   // No bit definitions are defined for SCSR because
   // a read-modify-write instruction can clear the WDOVERRIDE bit
   Uint16              SCSR;      // 18: System control and status register
   Uint16              WDCNTR;    // 19: WD counter register
   Uint16              rsvd4;     // 20
   Uint16              WDKEY;     // 21: WD reset key register
   Uint16              rsvd5[3];  // 22-24
   // No bit definitions are defined for WDCR because
   // the proper value must be written to the WDCHK field
   // whenever writing to this register.
   Uint16              WDCR;      // 25: WD timer control register
   Uint16              rsvd6[6];  // 26-31
};

在这里插入图片描述

InitSysCtrl函数程序代码如下:

// InitSysCtrl:
//---------------------------------------------------------------------------
// 这段函数的功能就是将系统控制寄存器初始化到想要的状态;
//具体步骤可以分成四部分:
// - 禁止看门狗电路
// - 给PLLCR寄存器赋值以获得想要的系统时钟频率
// - 给高、低速外设时钟预定标寄存器赋值以获得想要的高、低速外设时钟频率
// - 对需要使用的外设时钟进行使能

void InitSysCtrl(void)
{
    
    

   // Disable the watchdog
   DisableDog();

   // Initialize the PLL control: PLLCR and DIVSEL
   // DSP28_PLLCR and DSP28_DIVSEL are defined in DSP2833x_Examples.h
   InitPll(DSP28_PLLCR,DSP28_DIVSEL);

   // Initialize the peripheral clocks
   InitPeripheralClocks();
}

在DsiableDog()函数中禁用了看门狗电路

void DisableDog(void)
{
    
    
    EALLOW;
    SysCtrlRegs.WDCR= 0x0068;
    EDIS;
}

在InitPeripheralClocks()函数中

// 函数名:初始化外设时钟
//---------------------------------------------------------------------------
//这个是用来初始化外设模块的时钟,具体分2个步骤:
//首先设置高、低速外设预定标寄存器;
//第二是对各个外设时钟进行有选择的使能;
//为了降低功耗,尽量不使能不用的外设模块时钟;
//
//注:如果某一外设时钟没使能,则不能对其相关的寄存器进行读写;

void InitPeripheralClocks(void)
{
    
    
   EALLOW;

// HISPCP/LOSPCP prescale register settings, normally it will be set to default values
   SysCtrlRegs.HISPCP.all = 0x0001;
   SysCtrlRegs.LOSPCP.all = 0x0002;//Lowspeedclock=SYSCLKOUT/4=150/4=37.5MHZ;

// XCLKOUT to SYSCLKOUT ratio.  By default XCLKOUT = 1/4 SYSCLKOUT
   // XTIMCLK = SYSCLKOUT/2
   XintfRegs.XINTCNF2.bit.XTIMCLK = 1;
   // XCLKOUT = XTIMCLK/2
   XintfRegs.XINTCNF2.bit.CLKMODE = 1;
   // Enable XCLKOUT
   XintfRegs.XINTCNF2.bit.CLKOFF = 0;

// 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 2833x 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 = 0;    // ADC

   // *IMPORTANT*
   // The ADC_cal function, which  copies the ADC calibration values from TI reserved
   // OTP into the ADCREFSEL and ADCOFFTRIM registers, occurs automatically in the
   // Boot ROM. If the boot ROM code is bypassed during the debug process, the
   // following function MUST be called for the ADC to function according
   // to specification. The clocks to the ADC MUST be enabled before calling this
   // function.
   // See the device data manual and/or the ADC Reference
   // Manual for more information.

   ADC_cal();


   SysCtrlRegs.PCLKCR0.bit.I2CAENCLK = 0;   // I2C
   SysCtrlRegs.PCLKCR0.bit.SCIAENCLK = 0;   // SCI-A
   SysCtrlRegs.PCLKCR0.bit.SCIBENCLK = 0;   // SCI-B
   SysCtrlRegs.PCLKCR0.bit.SCICENCLK = 0;   // SCI-C
   SysCtrlRegs.PCLKCR0.bit.SPIAENCLK = 0;   // SPI-A
   SysCtrlRegs.PCLKCR0.bit.MCBSPAENCLK = 0; // McBSP-A
   SysCtrlRegs.PCLKCR0.bit.MCBSPBENCLK = 0; // McBSP-B
   SysCtrlRegs.PCLKCR0.bit.ECANAENCLK=0;    // eCAN-A
   SysCtrlRegs.PCLKCR0.bit.ECANBENCLK=0;    // eCAN-B

   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;   // Disable TBCLK within the ePWM
   SysCtrlRegs.PCLKCR1.bit.EPWM1ENCLK = 0;  // ePWM1
   SysCtrlRegs.PCLKCR1.bit.EPWM2ENCLK = 0;  // ePWM2
   SysCtrlRegs.PCLKCR1.bit.EPWM3ENCLK = 0;  // ePWM3
   SysCtrlRegs.PCLKCR1.bit.EPWM4ENCLK = 0;  // ePWM4
   SysCtrlRegs.PCLKCR1.bit.EPWM5ENCLK = 0;  // ePWM5
   SysCtrlRegs.PCLKCR1.bit.EPWM6ENCLK = 0;  // ePWM6
   SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;   // Enable TBCLK within the ePWM

   SysCtrlRegs.PCLKCR1.bit.ECAP3ENCLK = 0;  // eCAP3
   SysCtrlRegs.PCLKCR1.bit.ECAP4ENCLK = 0;  // eCAP4
   SysCtrlRegs.PCLKCR1.bit.ECAP5ENCLK = 0;  // eCAP5
   SysCtrlRegs.PCLKCR1.bit.ECAP6ENCLK = 0;  // eCAP6
   SysCtrlRegs.PCLKCR1.bit.ECAP1ENCLK = 0;  // eCAP1
   SysCtrlRegs.PCLKCR1.bit.ECAP2ENCLK = 0;  // eCAP2
   SysCtrlRegs.PCLKCR1.bit.EQEP1ENCLK = 0;  // eQEP1
   SysCtrlRegs.PCLKCR1.bit.EQEP2ENCLK = 0;  // eQEP2

   SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK = 0; // CPU Timer 0
   SysCtrlRegs.PCLKCR3.bit.CPUTIMER1ENCLK = 0; // CPU Timer 1
   SysCtrlRegs.PCLKCR3.bit.CPUTIMER2ENCLK = 0; // CPU Timer 2

   SysCtrlRegs.PCLKCR3.bit.DMAENCLK = 0;       // DMA Clock
   SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 0;     // XTIMCLK
   SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1;    // GPIO input clock

   EDIS;
}

在InitPll(DSP28_PLLCR,DSP28_DIVSEL)函数中初始化PLLSTS[CLKINDIV]和PLLCR控制寄存器

void InitPll(Uint16 val, Uint16 divsel)
{
    
    

   // Make sure the PLL is not running in limp mode
   if (SysCtrlRegs.PLLSTS.bit.MCLKSTS != 0)
   {
    
    
      // Missing external clock has been detected
      // Replace this line with a call to an appropriate
      // SystemShutdown(); function.
      asm("        ESTOP0");
   }

   // 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;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39529052/article/details/106037825