S32K144之时钟配置

一般来说,时钟精度、稳定性取决于所采用的时钟源,就MCU S32K来说如内部振荡器SIRC,FIRC,128KLPO,外部晶振等,跟所使用的外设(FTM, LPIT,LPT,RTC等)和哪一路输出时钟(SYS_CLK,BUS_CLK,SPLLDVI1_CLK等)没有直接关系。

由于S32K144提供的时钟源和配置方法比较多,那么如何有效配置得到自己想要的时钟呢?
下面以S32K144为例,从时钟定义图开始,逐步介绍如何寻找S32K144时钟(CORE_CLK, BUS_CLK,)合适的配置方法,并根据测试方法验证配置是否有效。

0. 目标
输出目标
clock clock= 80MHz(以下MHz简称M)
bus clock=40MHz, Normal Mode(默认)
 注意:只有支持105℃的部分S32K144型号,core clock才能支持到最高112M(HSRUN),其他型号不论HSRUN模式,还是RUN模式,最高支持80M。
 
测试工具
PCB: S32K144EVB-Q100
IDE: S32DS for ARM 2018.R1 
 

1.时钟定义

配置时钟先从学会看时钟分配图开始,会看图了,配置就成功了一半。

 
因为能实现目标的路径可能有多种,这里先选中一条配置路径,再判断是否可行(蓝色箭头+框)。
时钟源选择外部晶振8M,即SOSC=8M => SPLL时钟源 SPLL_CLK_SOURCE = SOSC = 8M,

  2.确认内部时钟要求

CORE_CLK/ SYS_CLK 最高支持112M(HSRUN) , 80M(RUN),目标@80M符合要求。

不过,BUS_CLK最高支持56M(HSRUN), 48M(RUN),目标@40M符合要求。

扫描二维码关注公众号,回复: 6553676 查看本文章

3.确认外部晶振 8M

查看S32KEVB-Q100评估板原理图,知外部晶振8M => System PLL输入 SPLL_SOURCE=8M 

 
 
4.确认System PLL分频及倍频
这里选择PREDIV=0, MULT=0b11000 (10进制: 24) 
VCO_CLK=8M/(0+1) X (24+16) = 320MHz
SPLL_CLK=(VCO_CLK)/2 = 160MHz
 

 

考虑:这里MULTI还可以>24 => 倍频因子>40,那么能不能配置VCO_CLK >320M,而最终CORE_CLK=80M呢?

答案是不行,因为VCO_CLK最高支持到320M,可以参考S32K-RM。

 5.具体寄存器配置

可参考RM配置方法

6.设置检测方法

1)初步确定为通过IO口直接输出与总线时钟相关的时钟或者分频后的时钟
2)寻找SCH上是否有可直接利用的MCU引脚
MCU完整型号:FS32K144HRT0VLLT, 封装:LQFP100
查RM附件IO描述表,发现能作为CLKOUT pin的有PTD14, PTE10, PTB5。
 
如有可用CLKOUT pin,配置相应的pin为CLKOUT功能
1)配置PORT的MUX为CLKOUT对应ALT功能,并使能端口时钟;
 
2)配置SIM_CHIPCTL选择输出的时钟,以及输出的分频系数;
输出时钟结构
 
 
CLKOUTSEL - 选择输出时钟,如选择设置CLKOUTSEL=0b1001,则CLKOUT pin输出Bus_Clock
 
7.时钟配置代码
main.c
int main(void)
{
        volatile uint32_t cnt = 0;

    Clock_Init();

    Port_Init();

    Clock_Out_Bus();

    while(1)
    {
        cnt ++;
    }

    return 0;
}
View Code

clock.c - 时钟配置

/**
 * 配置MCU时钟, 使SYS_CLK=80MHz, BUS_CLK=40MHz, FLASH_CLK=20MHz, 用外部晶振f_osc=8MHz
 * SPLL_CLK=160MHz, VCO_CLK=320MHz
 * @note
 * 计算公式:
 * BUS_CLK=SYS_CLK / DIVBUS
 * SYS_CLK=SPLL_CLK / DIVCORE
 * SPLL_CLK=(VCO_CLK) / 2
 * VCO_CLK=SPLL_SOURCE / (PREDIV + 1) x (MULT + 16)
 * 选择外部晶振作为SPLL_SOURCE, SPLL_SOURCE=8MHz
 */
void Clock_Init(void)
{
    // 以下初始化顺序不可改变

    Clock_SOSC_Init_8M(); // SOSC&SPLL_SOURCE初始化为输出8M

    Clock_SPLL_Init_160M(); // SPLL&SCG初始化为输出160M

    Clock_RUNMode_SYS_Init_80M(); // sys clock = 80M, bus clock = 40M, flash = 20M

}


void Clock_ConfigureOut(SIM_CLKOUTSEL_Type clkoutsel)
{
    if(clkoutsel <= RTC_CLK)
    {
        SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTEN_MASK; // disable CLKOUT
        SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTSEL_MASK; // clear CLKOUT

        SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTSEL(clkoutsel); // select CLKOUT source = clkoutsel

        SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTEN_MASK; // enable CLKOUT
    }
}


/**
 * CLKOUT pin输出Bus CLK
 */
void Clock_Out_Bus(void)
{
    Clock_ConfigureOut(BUS_CLK);
}

/**
 * 配置SOSC_CLK=8M
 * @output SOSCDIV1_CLK
 * @output SOSCDIV2_CLK
 * @note
 * 外部晶振8M
 * 计算公式
 * SOSCDIV1_CLK=SOSC_CLK / SOSCDIV1
 * SOSCDIV2_CLK=SOSC_CLK / SOSCDIV2
 */
void Clock_SOSC_Init_8M(void)
{
    // Frequency division for SOSCDIV1_CLK, SOSCDIV2_CLK
    SCG->SOSCDIV=SCG_SOSCDIV_SOSCDIV1(1) // SOSCDIV1=1 : Divide by 1
            | SCG_SOSCDIV_SOSCDIV2(1);   // SOSCDIV2=1 : Divide by 1

    SCG->SOSCCFG=SCG_SOSCCFG_RANGE(0b11) // RANGE=3: 8-40 MHz SOSC
            // RANGE=3: 8-40 MHz SOSC
            | SCG_SOSCCFG_HGO(1)    // HGO=0: Configure crystal oscillator for high-gain operation
            | SCG_SOSCCFG_EREFS(1); // EREFS=1: Internal crystal oscillator of OSC selected

    while(SCG->SOSCCSR & SCG_SOSCCSR_LK_MASK); /* Ensure SOSCCSR unlocked */
    SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN(1);      // SOSC Enable
}

/**
 * 配置MCU时钟SPLL_CLK=160M
 * @require SOSC_CLK = 8M
 * @output SPLL_CLK
 */
void Clock_SPLL_Init_160M(void)
{
    while(SCG->SPLLCSR & SCG_SPLLCSR_LK_MASK); /* Ensure SPLLCSR unlocked */

    // 关闭SPLL
    SCG->SPLLCSR = 0; /* SPLLEN=0: SPLL is disabled (default) */

    // 配置SCG_SPLLCFG, 使VCO_CLK=320MHz, SPLL_CLK=160MHz
    SCG->SPLLCFG = SCG_SPLLCFG_PREDIV(0) | SCG_SPLLCFG_MULT(0b11000);

    SCG->RCCR = SCG_RCCR_SCS(0b0110)  // System Clock Source: System PLL (SPLL_CLK)
            | SCG_RCCR_DIVCORE(0)   // DIVCORE=0
            | SCG_RCCR_DIVBUS(1)    // DIVBUS=1
            | SCG_RCCR_DIVSLOW(1);  // DVISLOW=1

    // 使能SPLL
    SCG->SPLLCSR |= SCG_SPLLCSR_SPLLEN_MASK;
    // Lock SPLL
    SCG->SPLLCSR |= SCG_SPLLCSR_LK_MASK;
}


/**
 * SYS_CLK = 80M, BUS_CLK = 40M, FLASH_CLK=20M
 * @require SPLL_CLK=160M
 * @note SYS_CLK=80MHz,BUS_CLK=40MHz, 使用外部晶振f_osc=8MHz
 * 前提条件使用SPLL_SOURCE=160M作为system clock
 * 计算公式:
 * SYS_CLK=SPLL_CLK / DIVCORE
 * BUS_CLK=SYS_CLK / DIVBUS
 * FLASH_CLK=SYS_CLK / DIVSLOW
 * SPLL_CLK=(VCO_CLK) / 2
 * VCO_CLK=SPLL_SOURCE / (PREDIV + 1) x (MULT + 16)
 *
 * =>DIVCORE=1, DIVBUS=1,DIVSLOW=3
 */
void Clock_RUNMode_SYS_Init_80M(void)
{
    // 配置system clock源, DIVCORE, DIVBUS, DIVFLASH
    SCG->RCCR = SCG_RCCR_SCS(0b0110)// Select System Clock Source: System PLL (SPLL_CLK)
            | SCG_RCCR_DIVCORE(1)
            | SCG_RCCR_DIVBUS(1)
            | SCG_RCCR_DIVSLOW(3);

    // 检查Clock Status(SCG_CSR) 是否为RCCR配置
    while(0b0110 != (SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) { }
}
View Code
Port.c
#define PORTD14_IDX              14
#define PORTD16_IDX              16

#define PORT_CLKOUT_IDX          PORTD14_IDX
#define PORT_LED_GREEN_IDX       PORTD16_IDX


/*
 * PTD14 - CLKOUT
 * PTD16 - GPO for LED
 */
void Port_Init(void)
{
    // Enable clock to PORTD
    if(PCC->PCCn[PCC_PORTD_INDEX] & PCC_PCCn_PR_MASK)
    {
        PCC->PCCn[PCC_PORTD_INDEX] |= PCC_PCCn_CGC(1); // Clock enabled to PORTD
    }

    // Set Port Data Direction
    PTD->PDDR |= 1 << PORT_LED_GREEN_IDX; // Port Data Direction: output

    // set/clear PortD's value
//    PTD->PTSO |= 1 << PORT_LED_GREEN_IDX; // Port Set Output
    PTD->PCOR |= 1 << PORT_LED_GREEN_IDX; // Port Clear Output


    // PTD16 - GPO
    PORTD->PCR[PORT_LED_GREEN_IDX] = PORT_PCR_MUX(0b0000001); // Port D16: MUX=ALT1, GPIO(to green LED on EVB/PCB)
    // PTD14 - CLKOUT
    PORTD->PCR[PORT_CLKOUT_IDX] = PORT_PCR_MUX(0b00000111);  // Port D14: MUX=ALT4, CLKOUT

}
View Code

clock.c - CLKOUT 输出选择

/**
 * CLKOUT pin输出Bus CLK
 */
void Clock_Out_Bus(void)
{
    Clock_ConfigureOut(0b1001);
}


void Clock_ConfigureOut(SIM_CLKOUTSEL_Type clkoutsel)
{
    if(clkoutsel <= 0b1110)
    {
        SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTEN_MASK; // disable CLKOUT
        SIM->CHIPCTL &= ~SIM_CHIPCTL_CLKOUTSEL_MASK; // clear CLKOUT

        SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTSEL(clkoutsel); // select CLKOUT source = clkoutsel

        SIM->CHIPCTL |= SIM_CHIPCTL_CLKOUTEN_MASK; // enable CLKOUT
    }
}
View Code

8. 观察CLKPUT pin 输出

需要用示波器观测PTD14,截图略。

 

猜你喜欢

转载自www.cnblogs.com/fortunely/p/11057040.html