查看: 963|回复: 0

万利Kinetis L46开发板之时钟配置

[复制链接]
  • TA的每日心情
    奋斗
    2015-10-5 14:38
  • 签到天数: 175 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2014-12-11 09:39:11 | 显示全部楼层 |阅读模式
    分享到:
    前几天拿到了一套飞思卡尔的开发套件,是万利电子出品的。做工很赞,很高大上。首先我从它的时钟系统入手。去官网下了个数据手册和参考手册下来。
    主要是看数据手册的时钟模块。一看手册,真晕了,时钟系统好复杂。整个时钟系统由 MCG、OSC 和 RTC 几部分组成,此外还与 SIM 有关系,这是因为 SIM 控制了大多数模块的时钟门控。这个跟STM32也是类似的,要用到那个外设,先要把相应的时钟打开。
    下面我自己用例程工程,配置了时钟,并且把总线时钟频率二分频输出到PTC3口上输出,如下图可以看出PTC3有个复用功能是时钟输出。

    然后我从官网下载一些KL46 Demo板的源代码。然后就找到同一型号的芯片的例程。这个例程刚好满足的要求,用PTC3输出时钟,例程还有串口的程序,这部分用不到,我就注释了。我用了Keil v5.1的编译环境。大家注意的是从keil v5版本开始,芯片的支持包要用户选择下载。具体的方法如下:



    把例程打开后:

    我这里是用Jlink V8进行仿真和下载程序的,所以工程的配置还要设置一下才能用,方法如下:



    成功仿真器连上板子的的仿真接口后会出现红框里的信息,仿真接口模式要选择SW模式。
    接着就是配置flash


    要想在PTC3口输出时钟还要做一下工作:
    大家可以看到这里有个条件编译,要把这个参数填进去[url=]预定义方框[/url]才行,或者你可以直接将ENABLE_CLKOUT改为1,这样编译器就会编译这部分代码,在编译器预定义方框打开的步骤如图:

    做完这些工作就可以编译工程和下载程序进行验证了:
    主程序很简单,代码如下:
    int main (void){            char ch;        #ifdef CMSIS  // If we are conforming to CMSIS, we need to call start here    start();#endif                  printf("\n\rRunning the platinum project.\n\r");        while(1)        {                //ch = in_char();                //out_char(ch);        } }首先程序会执行[url=]start();[/url]进行一些系统的初始化。
    我们来看看start();的内部吧:
    void start(void){                 /* Disable the watchdog timer */    SIM_COPC = 0x00;#ifndef CMSIS    // If conforming to CMSIS, we do not need to perform this code        /* Copy any vector or data sections that need to be in RAM */        common_startup();#endif        /* Perform clock initialization, default UART initialization,         * initializes clock out function, and enables the abort button         */                        // common_startup();             sysinit();                printf("\n\r\n\r");                /* Determine the last cause(s) of reset */        outSRS();                        /* Determine specific Kinetis L Family device and revision */        cpu_identify();        #ifndef CMSIS    // If conforming to CMSIS, we do not need to perform this code        /* Jump to main process */        main();        /* No actions to perform after this so wait forever */        while(1);#endif }最重要的是sysinit();函数,因为这个是初始化系统时钟的。源代码如下:/********************************************************************/void sysinit (void){        /* Enable all of the port clocks. These have to be enabled to configure         * pin muxing options, so most code will need all of these on anyway.         */        SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK                      | SIM_SCGC5_PORTB_MASK                      | SIM_SCGC5_PORTC_MASK                      | SIM_SCGC5_PORTD_MASK                      | SIM_SCGC5_PORTE_MASK );                // Release hold with ACKISO:  Only has an effect if recovering from VLLS1, VLLS2, or VLLS3        // if ACKISO is set you must clear ackiso before calling pll_init         //    or pll init hangs waiting for OSC to initialize        // if osc enabled in low power modes - enable it first before ack        // if I/O needs to be maintained without glitches enable outputs and modules first before ack.        if (PMC_REGSC &  PMC_REGSC_ACKISO_MASK)        PMC_REGSC |= PMC_REGSC_ACKISO_MASK;        #ifdef ENABLE_CLKOUT        // Initialize trace clk functionality        clk_out_init();#endif#if defined(NO_PLL_INIT)        mcg_clk_hz = 21000000; //FEI mode                SIM_SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK; // clear PLLFLLSEL to select the FLL for this clock source                uart0_clk_khz = (mcg_clk_hz / 1000); // the uart0 clock frequency will equal the FLL frequency       #else        /* Ramp up the system clock */       /* Set the system dividers */       /* NOTE: The PLL init will not configure the system clock dividers,        * so they must be configured appropriately before calling the PLL        * init function to ensure that clocks remain in valid ranges.        */          SIM_CLKDIV1 = ( 0                        | SIM_CLKDIV1_OUTDIV1(0)                        | SIM_CLKDIV1_OUTDIV4(1) );        /* Initialize PLL */       /* PLL will be the source for MCG CLKOUT so the core, system, and flash clocks are derived from it */        mcg_clk_hz = pll_init(CLK0_FREQ_HZ,  /* CLKIN0 frequency */                             LOW_POWER,     /* Set the oscillator for low power mode */                             CLK0_TYPE,     /* Crystal or canned oscillator clock input */                             PLL0_PRDIV,    /* PLL predivider value */                             PLL0_VDIV,     /* PLL multiplier */                             MCGOUT);       /* Use the output from this PLL as the MCGOUT */       /* Check the value returned from pll_init() to make sure there wasn't an error */       if (mcg_clk_hz < 0x100)         while(1);              SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; // set PLLFLLSEL to select the PLL for this clock source              uart0_clk_khz = ((mcg_clk_hz / 2) / 1000); // UART0 clock frequency will equal half the PLL frequency#endif              /*         * Use the value obtained from the pll_init function to define variables         * for the core clock in kHz and also the peripheral clock. These         * variables can be used by other functions that need awareness of the         * system frequency.         */        mcg_clk_khz = mcg_clk_hz / 1000;          core_clk_khz = mcg_clk_khz / (((SIM_CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> 28)+ 1);        periph_clk_khz = core_clk_khz / (((SIM_CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> 16)+ 1);                /* Enable pin interrupt for the abort button - PTA4 */        /* This pin could also be used as the NMI interrupt, but since the NMI         * is level sensitive each button press will cause multiple interrupts.         * Using the GPIO interrupt instead means we can configure for an edge         * sensitive interrupt instead = one interrupt per button press.         */        enable_abort_button();                        if (TERM_PORT_NUM == 0)        {            /* Enable the pins for the selected UART */#ifdef FREEDOM          /* Enable the UART_TXD function on PTA1 */          PORTA_PCR1 = PORT_PCR_MUX(0x2);                    /* Enable the UART_TXD function on PTA2 */          PORTA_PCR2 = PORT_PCR_MUX(0x2);#endif#ifdef BACES          /* Enable the UART_TXD function on PTA1 */          PORTA_PCR1 = PORT_PCR_MUX(0x2);                    /* Enable the UART_TXD function on PTA2 */          PORTA_PCR2 = PORT_PCR_MUX(0x2);#endif                    #ifdef FIREBIRD                  /* Enable the UART_TXD function on PTA1 */          PORTA_PCR1 = PORT_PCR_MUX(0x2);                    /* Enable the UART_TXD function on PTA2 */          PORTA_PCR2 = PORT_PCR_MUX(0x2);#endif          #ifdef TOWER                              /* Enable the UART_TXD function on PTA14 */            PORTA_PCR14 = PORT_PCR_MUX(0x3); // UART0 is alt3 function for this pin                              /* Enable the UART_RXD function on PTA15 */            PORTA_PCR15 = PORT_PCR_MUX(0x3); // UART0 is alt3 function for this pin#endif                                       SIM_SOPT2 |= SIM_SOPT2_UART0SRC(1); // select the PLLFLLCLK as UART0 clock source        }          if (TERM_PORT_NUM == 1)          {                /* Enable the UART_TXD function on PTC4 */                  PORTC_PCR4 = PORT_PCR_MUX(0x3); // UART1 is alt3 function for this pin                                    /* Enable the UART_RXD function on PTC3 */                  PORTC_PCR3 = PORT_PCR_MUX(0x3); // UART1 is alt3 function for this pin          }                if (TERM_PORT_NUM == 2)          {                 /* Enable the UART_TXD function on PTD3 */                  PORTE_PCR16 = PORT_PCR_MUX(0x3); // UART2 is alt3 function for this pin                                    /* Enable the UART_RXD function on PTD2 */                  PORTE_PCR17 = PORT_PCR_MUX(0x3); // UART2 is alt3 function for this pin          }                  /* UART0 is clocked asynchronously to the core clock, but all other UARTs are         * clocked from the peripheral clock. So we have to determine which clock         * to send to the UART_init function.         */        if (TERM_PORT_NUM == 0)            uart0_init (UART0_BASE_PTR, uart0_clk_khz, TERMINAL_BAUD);        else if (TERM_PORT_NUM == 1)              uart_init (UART1_BASE_PTR, periph_clk_khz, TERMINAL_BAUD);        else if (TERM_PORT_NUM == 2)            uart_init (UART2_BASE_PTR, periph_clk_khz, TERMINAL_BAUD);        else          while(1);}这里是打开所有GPIO的时钟,如下图的手册说明:

    然后程序主要的部分是PLL配置了:
    /* Initialize PLL */
      /* PLL will be the source for MCG CLKOUT so the core, system, and flash clocks are derived from it */
      mcg_clk_hz = [url=]pll_init[/url](CLK0_FREQ_HZ,  /* CLKIN0 frequency */
      LOW_POWER,  /* Set the oscillator for low power mode */
      CLK0_TYPE,  /* Crystal or canned oscillator clock input */
      PLL0_PRDIV,  /* PLL predivider value */
      PLL0_VDIV,  /* PLL multiplier */
      MCGOUT);  /* Use the output from this PLL as the MCGOUT */
      /* Check the value returned from pll_init() to make sure there wasn't an error */
      if (mcg_clk_hz < 0x100)
      while(1);
      SIM_SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; // set PLLFLLSEL to select the PLL for this clock source
    填进去pll_init函数里的几个参数,是可以改的,可以找到相应的头文件修改。
    这里他的一些PLL参数如下图:

    这个参数把时钟设到最大48M,这里用户可以根据自己的需求来修改。
    剩下的就是其他功能模块的初始化了。
    现在就下载程序下去进行验证了,下面附上测试图:

    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    手机版|小黑屋|与非网

    GMT+8, 2024-4-24 07:52 , Processed in 0.116588 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.