本帖最后由 强仔00001 于 2014-12-8 13:07 编辑
前几天拿到了一套飞思卡尔的开发套件,是万利电子出品的。做工很赞,很高大上。首先我从它的时钟系统入手。去官网下了个数据手册和参考手册下来。 主要是看数据手册的时钟模块。一看手册,真晕了,时钟系统好复杂。整个时钟系统由 MCG、OSC 和 RTC 几部分组成,此外还与 SIM 有关系,这是因为 SIM 控制了大多数模块的时钟门控。这个跟STM32也是类似的,要用到那个外设,先要把相应的时钟打开。 下面我自己用例程工程,配置了时钟,并且把总线时钟频率二分频输出到PTC3口上输出,如下图可以看出PTC3有个复用功能是时钟输出。
然后我从官网下载一些KL46 Demo板的源代码。然后就找到同一型号的芯片的例程。这个例程刚好满足的要求,用PTC3输出时钟,例程还有串口的程序,这部分用不到,我就注释了。我用了Keil v5.1的编译环境。大家注意的是从keil v5版本开始,芯片的支持包要用户选择下载。具体的方法如下:
把例程打开后:
我这里是用Jlink V8进行仿真和下载程序的,所以工程的配置还要设置一下才能用,方法如下:
成功仿真器连上板子的的仿真接口后会出现红框里的信息,仿真接口模式要选择SW模式。 接着就是配置flash
要想在PTC3口输出时钟还要做一下工作: 大家可以看到这里有个条件编译,要把这个参数填进去预定义方框才行,或者你可以直接将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);
}
}
首先程序会执行start();进行一些系统的初始化。 我们来看看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);
}
好长的代码;P。
不过它的流程都跟其他的MCU大同小异。
首先关闭看门狗。
然后打开这里是打开所有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 = 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
填进去pll_init函数里的几个参数,是可以改的,可以找到相应的头文件修改。 这里他的一些PLL参数如下图:
这个参数把时钟设到最大48M,这里用户可以根据自己的需求来修改。 剩下的就是其他功能模块的初始化了。 现在就下载程序下去进行验证了,下面附上测试图:
补上高大上的板板靓照
|