Skip to content

03 · Clocks, Power & Boot

Every S32K project starts the same way: configure the clocks. Until you do, the chip runs on a fallback internal oscillator, peripherals are gated off to save power, and nothing timing-related (UART baud rates, CAN bit timing, PWM frequencies) can be trusted. This module explains the S32K1xx clock architecture conceptually, what happens between power-on and your main(), the run modes, and the watchdog surprise that catches every newcomer on their first day with this chip.

The clock sources (S32K1xx)

The SCG (System Clock Generator) module manages four clock sources:

Source What it is Frequency Typical use
SOSC System OSCillator — external crystal 8 MHz on the EVB Accurate reference for the PLL; CAN needs crystal-grade accuracy
SIRC Slow Internal RC oscillator 8 MHz Cheap default; low-power modes
FIRC Fast Internal RC oscillator 48 MHz What the chip boots on; usable directly for many peripherals
SPLL System PLL — multiplies SOSC (or FIRC) up to 80 MHz core (112 MHz HSRUN) Full-speed operation

Each source can also feed peripheral clocks through dividers (SOSCDIV1/2, SIRCDIV1/2, FIRCDIV1/2, SPLLDIV1/2) — peripherals pick one of these via their PCC entry (below). Three system clocks derive from the selected source via dividers: core clock (CPU, max 80 MHz in RUN), bus clock (most peripherals, max 48 MHz), and flash clock (max ~26.67 MHz in RUN). Keeping these dividers legal is your job when you switch sources.

Typical full-speed recipe on the S32K144EVB (conceptual):

8 MHz crystal (SOSC)
   → SPLL: divide by 1, multiply by 40  → VCO = 320 MHz
   → VCO/2 = 160 MHz SPLL output
   → DIVCORE = /2 → 80 MHz core clock
   → DIVBUS  = /2 → 40 MHz bus clock
   → DIVSLOW = /3 → ~26.67 MHz flash clock

The sequence in code (register-level, exactly the shape the SDK's generated code takes):

/* 1. Enable SOSC: configure range for an 8 MHz crystal, enable it,
      wait for SCG->SOSCCSR valid flag. */
/* 2. Configure SPLL: source = SOSC, PREDIV, MULT as above; enable;
      wait for SCG->SPLLCSR valid flag. */
/* 3. Switch the system clock: write SCG->RCCR with
      SCS = SPLL, DIVCORE/DIVBUS/DIVSLOW as above. */
/* 4. Read back SCG->CSR until SCS shows SPLL is really the source. */

The pattern to internalize: enable → wait for valid → switch → verify. Clock hardware takes real microseconds to stabilize, and every step has a status flag you must poll. Skipping the wait "usually works" — the worst kind of bug.

SDK-style equivalent

In the S32K1 SDK you describe all of the above in a clock_manager configuration structure (generated by the S32DS clock tool) and call CLOCK_SYS_Init(...) / CLOCK_DRV_Init(...) once at startup. The structure fields map one-to-one onto the SCG registers — the tool just spares you the bit-packing.

Peripheral clock gating: the PCC

On the S32K, every peripheral's clock is off until you turn it on via the PCC (Peripheral Clock Controller). Touching a peripheral's registers with its clock gated doesn't just fail silently — it hard-faults the CPU.

/* Register-level: enable clocks before ANY access to the peripheral. */
PCC->PCCn[PCC_PORTD_INDEX]   |= PCC_PCCn_CGC_MASK;   /* PORT D pin-config */
PCC->PCCn[PCC_LPUART1_INDEX]  = PCC_PCCn_PCS(3)      /* clock source: FIRCDIV2 */
                              | PCC_PCCn_CGC_MASK;   /* ...then gate on */

Two ideas in that snippet: CGC (Clock Gate Control) switches the clock on, and PCS (Peripheral Clock Select) picks which divided source (SOSCDIV2, SIRCDIV2, FIRCDIV2, SPLLDIV2) feeds a functional clock to peripherals that need one, like LPUART and ADC. Rule: configure PCS before setting CGC, and never change PCS while the gate is open.

If your firmware hard-faults on the very first register write to a peripheral — check the PCC first. This is the #1 S32K beginner crash.

Boot: from power-on to main()

  1. Power-on reset. Hardware waits for stable voltage, then the core boots on FIRC at 48 MHz — no crystal required, guaranteed to work.
  2. Flash option/security check. The chip reads the flash configuration field at 0x400 (module 2's warning) to decide if debug access is allowed.
  3. Vector fetch. Core loads the initial stack pointer from address 0x0 and jumps to the reset handler from 0x4.
  4. Startup code copies .data, zeroes .bss — and must deal with the watchdog:

The watchdog is ALREADY RUNNING when main() starts

The S32K1 WDOG comes out of reset enabled, with a timeout of about 1 ms (128 cycles of the 128 kHz LPO clock). If startup code doesn't disable or reconfigure it quickly, the chip resets before reaching main() — an infinite silent reboot loop that looks exactly like "my board is dead." SDK startup does this for you:

/* Register-level: unlock, then disable (allowed only briefly after unlock) */
WDOG->CNT   = 0xD928C520u;               /* unlock key */
WDOG->TOVAL = 0x0000FFFFu;               /* max timeout while reconfiguring */
WDOG->CS    = WDOG_CS_UPDATE_MASK;       /* ...and EN bit left 0 = disabled */

Development firmware disables it; production firmware re-enables it properly (module 9). If you ever port startup code yourself, this is step zero.

  1. main() runs — and its first real act is the clock setup above.

Run modes

Mode Core clock What it's for
RUN up to 80 MHz Normal operation — all of Level 1 lives here
HSRUN up to 112 MHz (parts that support it) Short bursts of extra performance; some flash-programming restrictions
VLPR ~4 MHz class Very-low-power run for battery-parked scenarios
STOP/VLPS stopped Sleep states — a body ECU must draw ~100 µA class while the car is parked; wake on CAN traffic or pin change (Level 2 topic)

The automotive angle: a car may sit at the airport for three weeks. Dozens of ECUs stay connected to the battery the whole time. Their combined sleep current budget is milliamps — which is why low-power modes are a first-class design concern in body electronics rather than an afterthought.

Why clock config comes first, always

  • Baud rates (UART, module 5) and CAN bit timing (module 7) are computed from the peripheral clock. Change the clock, silently break every baud rate — CAN in particular needs crystal accuracy, not RC-oscillator accuracy.
  • PWM frequencies and timer periods (module 8) scale with the bus clock.
  • Flash wait states must match the core speed, or the chip crashes at high frequency.

So the discipline is: one clock-init function, called first in main(), and the resulting frequencies written down in one header everyone uses:

#define CORE_CLK_HZ   80000000u
#define BUS_CLK_HZ    40000000u
#define LPUART_FUNC_CLK_HZ  48000000u   /* FIRCDIV2, chosen in PCC */

Cheat sheet

Item Notes
Boot clock FIRC, 48 MHz — what you're running on until you configure SCG
SOSC External crystal (8 MHz on EVB); required reference for accurate CAN
SPLL PLL from SOSC: 8 MHz → 160 MHz out → 80 MHz core via DIVCORE
Clock-switch pattern enable → wait valid flag → switch RCCR → verify CSR
PCC Per-peripheral clock gate (CGC) + functional clock select (PCS)
Access before CGC set Hard fault — the #1 beginner crash on S32K
WDOG at reset Enabled, ~1 ms timeout — startup must handle it or the chip reboot-loops
WDOG unlock / refresh keys 0xD928C520 / 0xB480A602
Run modes RUN (80 MHz) · HSRUN (112) · VLPR (low power) · STOP/VLPS (sleep)

How It Actually Works

Clock generation on S32K is a tree of dividers and muxes feeding out of SCG (System Clock Generator), and the numbers you write into SCG->SPLLCFG or SCG->SIRCCFG map onto physical PLL feedback-divider and reference-divider hardware, not abstract "speed settings".

On reset, the chip boots from SIRC (Slow Internal RC oscillator, ~8 MHz, not the fast FIRC) in a deliberately conservative default state — this exists because an external crystal takes time to start oscillating reliably (tens to hundreds of microseconds of ringing before it's stable) and a fault-tolerant automotive part cannot assume the crystal exists or works. The System PLL (SPLL) then locks onto a chosen reference — internal FIRC or the external SOSC crystal — via a phase-frequency detector and charge pump that literally compares the phase of the reference and feedback-divided output clocks and nudges a voltage-controlled oscillator until they align; the LOCK status bit is a real analog lock-detector circuit, not a fixed delay.

Power modes (RUN → VLPR → STOP/VLPS) work by gating clock trees and, in the deeper states, powering down entire logic domains through the SMC (System Mode Controller) and PMC (Power Management Controller) — VLPR literally clamps the core clock below a threshold (typically 4 MHz) because the internal voltage regulator in low-power mode cannot supply enough current for the core to run its normal pipeline speed without violating the chip's timing margins. Waking from STOP requires a configured wake-up source (LPTMR, RTC, external pin via LLWU) because the peripheral clock trees needed to even recognize an interrupt are physically off until the SMC sequences them back on — this sequencing, not software, is why STOP-mode wake latency is measured in microseconds rather than being instantaneous.

(Described from the S32K reference manual's SCG/SMC/PMC chapters; not measured on physical silicon in this course.)

Exercise

Without hardware: compute a full clock recipe for a hypothetical S32K144 board with a 16 MHz crystal instead of 8 MHz. Choose SPLL PREDIV and MULT so the core still lands exactly on 80 MHz (respect the documented VCO input range of 8–16 MHz after PREDIV and the ×16–×47 MULT range), then pick DIVBUS and DIVSLOW so bus ≤ 48 MHz and flash ≤ 26.67 MHz. Write the result as a commented C header (CORE_CLK_HZ, BUS_CLK_HZ, dividers). Then answer: which of UART, CAN, and a blinking LED would keep working unchanged if you forgot clock init entirely and stayed on FIRC 48 MHz — and why?