2. S32G时钟与引脚复用配置实战

任务说明

本案例在 S32G 上完成两件事:一是把系统时钟树配置到目标频率(PLL 倍频 + 分频),二是把 CAN 与以太网的引脚复用(MSCR)配置为对应外设功能。这里用寄存器操作方式实现,便于在没有配置工具的环境下直接落地;若使用 S32 Design Studio 的配置工具,生成的代码逻辑与此一致。

时钟树与引脚复用关系

FXOSC 40 MHz PLL 倍频 ×40 → 1600 MHz 分频器 CORE ÷2 → 800 MHz CAN 时钟 MSCR: ALT=1 以太网时钟 MSCR: ALT=2 GPIO 时钟 MSCR: ALT=0

关键寄存器与配置要点

  • 时钟:FXOSC 40 MHz 经 PLL 倍频到 1600 MHz,再经 CORE 分频器得到 800 MHz 内核时钟。配置顺序为:先使能 FXOSC,再配置 PLL 倍频系数并等待锁定,最后设置分频器。
  • 引脚复用:每个引脚通过 MSCR 寄存器的 MUX_MODE 字段选择功能。CAN 用 ALT=1,以太网用 ALT=2,GPIO 用 ALT=0。配置前需确保对应外设时钟已使能。

完整实现代码

#include <stdint.h>

/* S32G 寄存器基址(示例地址,实际以参考手册为准) */
#define MC_ME_BASE      0x402DC000u
#define MC_CGM_BASE     0x402DC300u
#define FXOSC_BASE      0x402E0000u
#define SIUL2_BASE      0x40290000u

/* MC_ME 寄存器 */
#define MC_ME_CTL       (*(volatile uint32_t *)(MC_ME_BASE + 0x00))
#define MC_ME_PLL0CR    (*(volatile uint32_t *)(MC_ME_BASE + 0x20))

/* MC_CGM 分频寄存器 */
#define MC_CGM_CORE_DC0 (*(volatile uint32_t *)(MC_CGM_BASE + 0x00))

/* FXOSC 控制 */
#define FXOSC_CTL       (*(volatile uint32_t *)(FXOSC_BASE + 0x00))

/* SIUL2 MSCR 寄存器:每个引脚 4 字节 */
#define SIUL2_MSCR(n)   (*(volatile uint32_t *)(SIUL2_BASE + 0x240 + (n) * 4))

/* 引脚编号(示例,实际以封装引脚映射为准) */
#define PIN_CAN0_TX     10u
#define PIN_CAN0_RX     11u
#define PIN_ENET0_TX    20u
#define PIN_ENET0_RX    21u

#define MSCR_MUX_MODE_SHIFT  0u
#define MSCR_MUX_MODE_MASK   0x7u

static void mscr_set_mux(uint32_t pin, uint32_t alt)
{
    uint32_t v = SIUL2_MSCR(pin);
    v &= ~(MSCR_MUX_MODE_MASK << MSCR_MUX_MODE_SHIFT);
    v |= (alt & MSCR_MUX_MODE_MASK) << MSCR_MUX_MODE_SHIFT;
    SIUL2_MSCR(pin) = v;
}

void clock_init(void)
{
    /* 1. 使能 FXOSC */
    FXOSC_CTL |= 0x1u;
    while ((FXOSC_CTL & 0x2u) == 0u) { /* 等待 FXOSC 稳定 */ }

    /* 2. 配置 PLL0:40 MHz × 40 = 1600 MHz */
    MC_ME_PLL0CR = (40u << 16) | 0x1u;
    while ((MC_ME_PLL0CR & 0x80000000u) == 0u) { /* 等待 PLL 锁定 */ }

    /* 3. CORE 分频:1600 / 2 = 800 MHz */
    MC_CGM_CORE_DC0 = (1u << 24) | 0x1u;
    while ((MC_CGM_CORE_DC0 & 0x80000000u) == 0u) { /* 等待分频切换完成 */ }
}

void pinmux_init(void)
{
    /* CAN0:ALT=1 */
    mscr_set_mux(PIN_CAN0_TX, 1u);
    mscr_set_mux(PIN_CAN0_RX, 1u);

    /* ENET0:ALT=2 */
    mscr_set_mux(PIN_ENET0_TX, 2u);
    mscr_set_mux(PIN_ENET0_RX, 2u);
}

int main(void)
{
    clock_init();
    pinmux_init();

    /* 验证:读回 MSCR 确认复用值 */
    if ((SIUL2_MSCR(PIN_CAN0_TX) & MSCR_MUX_MODE_MASK) != 1u) return -1;
    if ((SIUL2_MSCR(PIN_ENET0_TX) & MSCR_MUX_MODE_MASK) != 2u) return -1;

    for (;;) { }
    return 0;
}

运行与验证

  1. 用 S32 Design Studio 或 GCC 交叉工具链编译,烧录到 S32G 目标板。
  2. 运行后通过调试器读取 MC_CGM_CORE_DC0,确认分频比已生效(bit24=1 表示 ÷2)。
  3. 读取 SIUL2_MSCR(10) 和 SIUL2_MSCR(20),低 3 位应分别为 1 和 2,即 CAN 与以太网复用配置正确。
  4. 若 main 返回 -1,说明 MSCR 读回值与预期不符,需检查引脚编号与 ALT 值是否与封装/参考手册一致。

通过条件:时钟分频寄存器读回值符合预期,且 CAN/以太网引脚的 MUX_MODE 分别为 1 和 2。