2. S32K时钟系统配置与性能测量
任务目标
基于 S32K144 的时钟树,将外部晶振(8MHz)经 PLL 倍频后配置为 120MHz 内核时钟,并用 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");
}
}
运行与验证
- 用 S32 Design Studio 新建 S32K144 工程,将上述代码替换
main.c,链接 S32K144 启动文件与链接脚本。 - 编译烧录后,用串口工具(115200-8-N-1)连接 LPUART1(PTB0/PTB1)。
- 预期输出格式:
CORE_CLK = 120.0 MHz,每秒刷新一次。 - 若读数偏差超过 ±1MHz,检查 SOSC 起振、SPLL 锁定标志及 DIVCORE 分频值。