Chinaunix首页 | 论坛 | 博客
  • 博客访问: 218710
  • 博文数量: 27
  • 博客积分: 358
  • 博客等级: 一等列兵
  • 技术积分: 291
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-25 17:35
文章分类

全部博文(27)

文章存档

2015年(1)

2014年(4)

2013年(6)

2012年(4)

2011年(12)

分类: 嵌入式

2011-06-13 16:20:58

    上次写了飞思卡尔官方给出的demo程序的启动流程的前面部分:
    在存储器最前面放置好向量表-->把通用寄存器清零-->开中断-->跳转到start函数继续执行初始化。在start函数中,顺次执行三个函数:禁用看门狗-->初始化C语言环境(向量表重定向、拷贝数据段到RAM、清零bss段等)-->系统外设初始化。
③系统外设初始化函数 sysinit()
  1. #include "common.h"
  2. #include "sysinit.h"
  3. #include "uart.h"

  4. /********************************************************************/

  5. /* Actual system clock frequency */
  6. int core_clk_khz;
  7. int core_clk_mhz;
  8. int periph_clk_khz;

  9. /********************************************************************/
  10. void sysinit (void)
  11. {
  12.         /*
  13.          * Enable all of the port clocks. These have to be enabled to configure
  14.          * pin muxing options, so most code will need all of these on anyway.
  15.          */
  16.         SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK
  17.                       | SIM_SCGC5_PORTB_MASK
  18.                       | SIM_SCGC5_PORTC_MASK
  19.                       | SIM_SCGC5_PORTD_MASK
  20.                       | SIM_SCGC5_PORTE_MASK );

  21.      /* Ramp up the system clock */
  22.     core_clk_mhz = pll_init(CORE_CLK_MHZ, REF_CLK);

  23.     /*
  24.          * Use the value obtained from the pll_init function to define variables
  25.      * for the core clock in kHz and also the peripheral clock. These
  26.      * variables can be used by other functions that need awareness of the
  27.      * system frequency.
  28.      */
  29.     core_clk_khz = core_clk_mhz * 1000;
  30.       periph_clk_khz = core_clk_khz / (((SIM_CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> 24)+ 1);

  31.       /* For debugging purposes, enable the trace clock and/or FB_CLK so that
  32.        * we'll be able to monitor clocks and know the PLL is at the frequency
  33.        * that we expect.
  34.        */
  35.     trace_clk_init();
  36.       fb_clk_init();

  37.       /* Enable the pins for the selected UART */
  38.          if (TERM_PORT == UART0_BASE_PTR)
  39.          {
  40.             /* Enable the UART0_TXD function on PTD6 */
  41.             PORTD_PCR6 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  42.             /* Enable the UART0_RXD function on PTD7 */
  43.             PORTD_PCR7 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  44.          }

  45.          if (TERM_PORT == UART1_BASE_PTR)
  46.        {
  47.                  /* Enable the UART1_TXD function on PTC4 */
  48.           PORTC_PCR4 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  49.           /* Enable the UART1_RXD function on PTC3 */
  50.           PORTC_PCR3 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  51.       }

  52.       if (TERM_PORT == UART2_BASE_PTR)
  53.       {
  54.                  /* Enable the UART2_TXD function on PTD3 */
  55.           PORTD_PCR3 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  56.           /* Enable the UART2_RXD function on PTD2 */
  57.           PORTD_PCR2 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  58.       }

  59.       if (TERM_PORT == UART3_BASE_PTR)
  60.       {
  61.                  /* Enable the UART3_TXD function on PTC17 */
  62.           PORTC_PCR17 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  63.           /* Enable the UART3_RXD function on PTC16 */
  64.           PORTC_PCR16 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  65.       }
  66.       if (TERM_PORT == UART4_BASE_PTR)
  67.       {
  68.                  /* Enable the UART3_TXD function on PTC17 */
  69.           PORTE_PCR24 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  70.           /* Enable the UART3_RXD function on PTC16 */
  71.           PORTE_PCR25 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  72.       }
  73.       if (TERM_PORT == UART5_BASE_PTR)
  74.       {
  75.                  /* Enable the UART3_TXD function on PTC17 */
  76.           PORTE_PCR8 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin

  77.           /* Enable the UART3_RXD function on PTC16 */
  78.           PORTE_PCR9 = PORT_PCR_MUX(0x3); // UART is alt3 function for this pin
  79.       }
  80.       /* UART0 and UART1 are clocked from the core clock, but all other UARTs are
  81.          * clocked from the peripheral clock. So we have to determine which clock
  82.          * to send to the uart_init function.
  83.          */
  84.         if ((TERM_PORT == UART0_BASE_PTR) | (TERM_PORT == UART1_BASE_PTR))
  85.             uart_init (TERM_PORT, core_clk_khz, TERMINAL_BAUD);
  86.         else
  87.        uart_init (TERM_PORT, periph_clk_khz, TERMINAL_BAUD);
  88. }
  89. /********************************************************************/
  90. void trace_clk_init(void)
  91. {
  92.     /* Set the trace clock to the core clock frequency */
  93.     SIM_SOPT2 |= SIM_SOPT2_TRACECLKSEL_MASK;

  94.     /* Enable the TRACE_CLKOUT pin function on PTA6 (alt7 function) */
  95.     PORTA_PCR6 = ( PORT_PCR_MUX(0x7));
  96. }
  97. /********************************************************************/
  98. void fb_clk_init(void)
  99. {
  100.     /* Enable the clock to the FlexBus module */
  101.         SIM_SCGC7 |= SIM_SCGC7_FLEXBUS_MASK;

  102.      /* Enable the FB_CLKOUT function on PTC3 (alt5 function) */
  103.     PORTC_PCR3 = ( PORT_PCR_MUX(0x5));
  104. }
  105. /********************************************************************/
首先写SIM_SCGC5寄存器。SCGC5表示的是System Clock Gating Control Register 5(系统时钟门控制寄存器5).系统集成模块 --System integration module (SIM)--控制寄存器组中共有8个SCGC寄存器,它们分别控制不同外设所需要的时钟的开关,SCGC5寄存器控制的是PORTA~PORTE、TSI、REGFILE和LPTIMER时钟的开关,向对应的位写入1表示使能时钟。第一段代码分别打开了PORTA~PORTE的时钟开关。
上面pll_init(unsigned char,unsigned char)函数用来增加系统时钟。
  1. unsigned char pll_init(unsigned char clk_option, unsigned char crystal_val)
  2. {
  3.   unsigned char pll_freq;

  4.   if (clk_option > 3) {return 0;} //return 0 if one of the available options is not selected
  5.   if (crystal_val > 15) {return 1;} // return 1 if one of the available crystal options is not available
  6. //This assumes that the MCG is in default FEI mode out of reset.

  7. // First move to FBE mode
  8. #if (defined(K60_CLK) || defined(ASB817))
  9.      MCG_C2 = 0;
  10. #else
  11. // Enable external oscillator, RANGE=2, HGO=1, EREFS=1, LP=0, IRCS=0
  12.     MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK;
  13. #endif

  14. // after initialization of oscillator release latched state of oscillator and GPIO
  15.     SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK;
  16.     LLWU_CS |= LLWU_CS_ACKISO_MASK;
  17.   
  18. // Select external oscilator and Reference Divider and clear IREFS to start ext osc
  19. // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
  20.   MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3);

  21.   /* if we aren't using an osc input we don't need to wait for the osc to init */
  22. #if (!defined(K60_CLK) && !defined(ASB817))
  23.     while (!(MCG_S & MCG_S_OSCINIT_MASK)){}; // wait for oscillator to initialize
  24. #endif

  25.   while (MCG_S & MCG_S_IREFST_MASK){}; // wait for Reference clock Status bit to clear

  26.   while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; // Wait for clock status bits to show clock source is ext ref clk

  27. // Now in FBE

  28. #if (defined(K60_CLK))
  29.    MCG_C5 = MCG_C5_PRDIV(0x18);
  30. #else
  31. // Configure PLL Ref Divider, PLLCLKEN=0, PLLSTEN=0, PRDIV=5
  32. // The crystal frequency is used to select the PRDIV value. Only even frequency crystals are supported
  33. // that will produce a 2MHz reference clock to the PLL.
  34.   MCG_C5 = MCG_C5_PRDIV(crystal_val); // Set PLL ref divider to match the crystal used
  35. #endif

  36.   // Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk monitor disabled, PLL VCO divider is clear
  37.   MCG_C6 = 0x0;
  38. // Select the PLL VCO divider and system clock dividers depending on clocking option
  39.   switch (clk_option) {
  40.     case 0:
  41.       // Set system options dividers
  42.       //MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2
  43.       set_sys_dividers(0,0,0,1);
  44.       // Set the VCO divider and enable the PLL for 50MHz, LOLIE=0, PLLS=1, CME=0, VDIV=1
  45.       MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(1); //VDIV = 1 (x25)
  46.       pll_freq = 50;
  47.       break;
  48.    case 1:
  49.       // Set system options dividers
  50.       //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
  51.      set_sys_dividers(0,1,1,3);
  52.       // Set the VCO divider and enable the PLL for 100MHz, LOLIE=0, PLLS=1, CME=0, VDIV=26
  53.       MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(26); //VDIV = 26 (x50)
  54.       pll_freq = 100;
  55.       break;
  56.     case 2:
  57.       // Set system options dividers
  58.       //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
  59.       set_sys_dividers(0,1,1,3);
  60.       // Set the VCO divider and enable the PLL for 96MHz, LOLIE=0, PLLS=1, CME=0, VDIV=24
  61.       MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(24); //VDIV = 24 (x48)
  62.       pll_freq = 96;
  63.       break;
  64.    case 3:
  65.       // Set system options dividers
  66.       //MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2
  67.       set_sys_dividers(0,0,0,1);
  68.       // Set the VCO divider and enable the PLL for 48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0
  69.       MCG_C6 = MCG_C6_PLLS_MASK; //VDIV = 0 (x24)
  70.       pll_freq = 48;
  71.       break;
  72.   }
  73.   while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set

  74.   while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set

  75. // Now running PBE Mode

  76. // Transition into PEE by setting CLKS to 0
  77. // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
  78.   MCG_C1 &= ~MCG_C1_CLKS_MASK;

  79. // Wait for clock status bits to update
  80.   while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){};

  81. // Now running PEE Mode

  82. return pll_freq;
  83. } //pll_init
    这个函数中两个参数clk_option和crystal_val是两个枚举变量(enum),从它们的定义来看它们的取值范围是0~3和0~15.所以函数开始先进行有效性判断。
        MCG表示的是 Multipurpose Clock Generator(多用途时钟发生器).MCG模块向MCU提供几个时钟源选择。这个模块包含了一个 frequency-locked loop (FLL)和一个 phase-locked loop (PLL).FLL可以通过内部的或外部的参考时钟源来控制,PLL可以通过外部参考时钟来控制。模块可以选择FLL或PLL的输出时钟或者内部或外部时钟源作为MCU的系统时钟。上面MCG_2指的是 MCG Control 2 Register. MCG一共有9种操作模式:FEI, FEE, FBI, FBE, PBE, PEE, BLPI,BLPE,and Stop. 不同运行模式的功耗互不相同,要进入各个模式需要写MCG_1~MCG_6寄存器组中某几个寄存器中的某几个位。  我们可以这样说,采用内部组件的模式所消耗的功率少于采用外部组件的模式。而MCG包括两种专门为低功率应用设计的模式——旁通低功耗内部(BLPI)和旁通低功耗外部(BLPE)。驱动BLPI模式的总线频率要比BLPE 模式低,因此BLPI 模式消耗的功率最小。下图2总结了每一种运行模式的功耗。

    在sysinit()函数中对pll_init(unsigned char,unsigned char)函数的引用包含两个参数:CORE_CLK_MHZ和REF_CLK,从其定义可以看出其值分别为PLL96和XTAL8,分别代表2和3.K60_CLK 被定义为1.因此,在引用pll_init(unsigned char,unsigned char)函数时根据条件编译,执行的语句依次是: 
  1. // First move to FBE mode
  2. MCG_C2 = 0;

  3. // after initialization of oscillator release latched state of oscillator and GPIO
  4.     SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK;
  5.     LLWU_CS |= LLWU_CS_ACKISO_MASK;

  6. // Select external oscilator and Reference Divider and clear IREFS to start ext osc
  7. // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
  8.   MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3);

  9. // wait for Reference clock Status bit to clear
  10. while (MCG_S & MCG_S_IREFST_MASK){};

  11. // Wait for clock status bits to show clock source is ext ref clk
  12. while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){};

  13. MCG_C5 = MCG_C5_PRDIV(0x18);

  14. /* Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk monitor disabled, PLL VCO divider is clear*/
  15.   MCG_C6 = 0x0;

  16. // Set system options dividers
  17. //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
  18.    set_sys_dividers(0,1,1,3);
  19. // Set the VCO divider and enable the PLL for 96MHz, LOLIE=0, PLLS=1, CME=0, VDIV=24
  20.       MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(24); //VDIV = 24 (x48)
  21.       pll_freq = 96;

  22. while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set

  23.   while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set

  24. // Now running PBE Mode

  25. // Transition into PEE by setting CLKS to 0
  26. // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
  27.   MCG_C1 &= ~MCG_C1_CLKS_MASK;

  28. // Wait for clock status bits to update
  29.   while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){};

  30. // Now running PEE Mode

  31. return pll_freq;
    最后,系统运行在PEE模式下。
阅读(4230) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~