一般來說,時鍾精度、穩定性取決於所采用的時鍾源,就MCU S32K來說如內部振盪器SIRC,FIRC,128KLPO,外部晶振等,跟所使用的外設(FTM, LPIT,LPT,RTC等)和哪一路輸出時鍾(SYS_CLK,BUS_CLK,SPLLDVI1_CLK等)沒有直接關系。
由於S32K144提供的時鍾源和配置方法比較多,那么如何有效配置得到自己想要的時鍾呢?
下面以S32K144為例,從時鍾定義圖開始,逐步介紹如何尋找S32K144時鍾(CORE_CLK, BUS_CLK,)合適的配置方法,並根據測試方法驗證配置是否有效。
1.時鍾定義
配置時鍾先從學會看時鍾分配圖開始,會看圖了,配置就成功了一半。

2.確認內部時鍾要求
CORE_CLK/ SYS_CLK 最高支持112M(HSRUN) , 80M(RUN),目標@80M符合要求。
不過,BUS_CLK最高支持56M(HSRUN), 48M(RUN),目標@40M符合要求。
3.確認外部晶振 8M
查看S32KEVB-Q100評估板原理圖,知外部晶振8M => System PLL輸入 SPLL_SOURCE=8M


考慮:這里MULTI還可以>24 => 倍頻因子>40,那么能不能配置VCO_CLK >320M,而最終CORE_CLK=80M呢?
答案是不行,因為VCO_CLK最高支持到320M,可以參考S32K-RM。
5.具體寄存器配置
可參考RM配置方法
6.設置檢測方法




int main(void) { volatile uint32_t cnt = 0; Clock_Init(); Port_Init(); Clock_Out_Bus(); while(1) { cnt ++; } return 0; }
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) { } }

#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 }
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 } }
8. 觀察CLKPUT pin 輸出
需要用示波器觀測PTD14,截圖略。