2. S32K时钟系统配置与性能测量

任务目标

基于 S32K144 的时钟树,将外部晶振(8MHz)经 PLL 倍频后配置为 120MHz 内核时钟,并用 LPIT 定时器测量实际主频,通过 LPUART 串口输出测量结果。

时钟链路

SOSC 8 MHz SPLL ×30 → 240 MHz DIVCORE ÷2 → 120 MHz CORE_CLK 120 MHz LPIT / LPUART

关键配置

  • SOSC 8MHz 晶振,SPLL 倍频 ×30 得 240MHz VCO 输出。
  • DIVCORE = ÷2,CORE_CLK / BUS_CLK = 120MHz。
  • LPIT 使用 SPLL 分频后的 1MHz 时钟作为计数源,测量 1 秒内 CORE_CLK 计数值。
  • LPUART1 波特率 115200,用于输出测量结果。

完整代码

#include "S32K144.h"

#define SOSC_FREQ      8000000UL
#define SPLL_MULT      30UL
#define DIVCORE        2UL
#define TARGET_HZ      120000000UL

volatile uint32_t g_tick_ms = 0;

/* ---- 时钟初始化:SOSC 8M -> SPLL 240M -> CORE 120M ---- */
void Clock_Init(void)
{
    /* 1. 使能 SOSC */
    SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV1(1) | SCG_SOSCDIV_SOSCDIV2(1);
    SCG->SOSCCFG = SCG_SOSCCFG_RANGE(2) | SCG_SOSCCFG_EREFS(1);
    SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK;
    while (!(SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK)) {}

    /* 2. 配置 SPLL:8M * 30 / 1 = 240M */
    SCG->SPLLCFG = SCG_SPLLCFG_MULT(SPLL_MULT - 16) | SCG_SPLLCFG_PREDIV(0);
    SCG->SPLLCSR = SCG_SPLLCSR_SPLLEN_MASK;
    while (!(SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK)) {}

    /* 3. 切换 CORE 到 SPLL,DIVCORE=2 -> 120MHz */
    SCG->RCCR = SCG_RCCR_SCS(6) | SCG_RCCR_DIVCORE(DIVCORE - 1)
              | SCG_RCCR_DIVBUS(1) | SCG_RCCR_DIVSLOW(3);
    while (((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) != 6) {}
}

/* ---- LPIT 初始化:1MHz 计数源,1ms 中断 ---- */
void LPIT_Init(void)
{
    PCC->PCCn[PCC_LPIT_INDEX] = PCC_PCCn_CGC_MASK;
    LPIT0->MCR = LPIT_MCR_M_CEN_MASK;
    LPIT0->TMR[0].TVAL = 1000;          /* 1MHz / 1000 = 1kHz -> 1ms */
    LPIT0->TMR[0].TCTRL = LPIT_TMR_TCTRL_T_EN_MASK
                        | LPIT_TMR_TCTRL_MODE(0);
    LPIT0->MIER = LPIT_MIER_TIE0_MASK;
    NVIC_EnableIRQ(LPIT0_Ch0_IRQn);
}

void LPIT0_Ch0_IRQHandler(void)
{
    LPIT0->MSR = LPIT_MSR_TIF0_MASK;
    g_tick_ms++;
}

/* ---- LPUART1 初始化:115200 @ 120MHz ---- */
void LPUART1_Init(void)
{
    PCC->PCCn[PCC_LPUART1_INDEX] = PCC_PCCn_CGC_MASK;
    LPUART1->BAUD = LPUART_BAUD_OSR(15) | LPUART_BAUD_SBR(65);
    LPUART1->CTRL = LPUART_CTRL_TE_MASK | LPUART_CTRL_RE_MASK;
}

void UART_SendChar(char c)
{
    while (!(LPUART1->STAT & LPUART_STAT_TDRE_MASK)) {}
    LPUART1->DATA = c;
}

void UART_SendStr(const char *s)
{
    while (*s) UART_SendChar(*s++);
}

void UART_SendNum(uint32_t n)
{
    char buf[12]; int i = 0;
    if (n == 0) { UART_SendChar('0'); return; }
    while (n) { buf[i++] = '0' + n % 10; n /= 10; }
    while (i--) UART_SendChar(buf[i]);
}

/* ---- 主频测量:用 1ms 定时器测 1 秒内 CORE 循环次数 ---- */
uint32_t Measure_CoreFreq(void)
{
    uint32_t start, end, elapsed_ms;
    g_tick_ms = 0;
    start = DWT->CYCCNT;
    while (g_tick_ms < 1000) {}
    end = DWT->CYCCNT;
    elapsed_ms = g_tick_ms;
    return (end - start) / elapsed_ms * 1000;
}

int main(void)
{
    Clock_Init();
    LPUART1_Init();
    LPIT_Init();

    /* 使能 DWT 周期计数器 */
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_MASK;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_MASK;
    DWT->CYCCNT = 0;

    UART_SendStr("S32K144 Clock Measure\r\n");

    for (;;) {
        uint32_t freq = Measure_CoreFreq();
        UART_SendStr("CORE_CLK = ");
        UART_SendNum(freq / 1000000);
        UART_SendStr(".");
        UART_SendNum((freq % 1000000) / 100000);
        UART_SendStr(" MHz\r\n");
    }
}

运行与验证

  1. 用 S32 Design Studio 新建 S32K144 工程,将上述代码替换 main.c,链接 S32K144 启动文件与链接脚本。
  2. 编译烧录后,用串口工具(115200-8-N-1)连接 LPUART1(PTB0/PTB1)。
  3. 预期输出格式:CORE_CLK = 120.0 MHz,每秒刷新一次。
  4. 若读数偏差超过 ±1MHz,检查 SOSC 起振、SPLL 锁定标志及 DIVCORE 分频值。