S32K1 to S32K3 Migration¶
Everything so far has been S32K1: a Cortex-M4F, the S32 SDK, PCC clock
gates, PORT/GPIO, and driver calls shaped like FLEXCAN_DRV_Init.
NXP's current generation is S32K3, and it is not an incremental part
change — it is a different core, a different peripheral vocabulary, a
different driver stack, and a different boot process. Teams migrating for
the first time consistently underestimate it. This module is the map: what
carries over unchanged, what is renamed, what is genuinely new, and what
will stop your first build cold.
The headline differences¶
| Aspect | S32K1xx | S32K3xx |
|---|---|---|
| Core | Cortex-M0+ (S32K11x) or Cortex-M4F (S32K14x) | Cortex-M7, single / dual / lockstep |
| Max frequency | 80 MHz RUN, up to 112 MHz HSRUN on S32K14x | 160 MHz on most parts; up to 240 MHz on the largest |
| Caches / TCM | None | I-cache, D-cache, ITCM and DTCM |
| Safety target | Systems up to ASIL B | Systems up to ASIL D (lockstep, FCCU, self-test) |
| Driver stack | S32 SDK — PERIPH_DRV_Function() |
RTD (Real-Time Drivers) — AUTOSAR MCAL + low-level IP layer |
| Configuration | Processor Expert / S32 Config Tools | S32 Configuration Tools (MCAL-style, .epc) |
| Security | CSEc (FlexNVM-backed key store) | HSE — a separate security core running NXP firmware |
| Boot | Vector table at 0x0000_0000, straight to your reset handler | BAF validates an IVT, then jumps to your image |
Peripheral vocabulary¶
This table is the one to keep open during a port. Roughly half the peripherals keep their names and most of their behaviour; the other half are replaced by parts with a Power Architecture heritage.
| Function | S32K1 | S32K3 |
|---|---|---|
| Pin mux + GPIO | PORT (PCR[n]) + GPIO (PDDR/PDOR) |
SIUL2 (MSCR[n] output/mux, IMCR[n] input mux) |
| Clock generation | SCG (SOSC/SIRC/FIRC/SPLL) |
MC_CGM + FXOSC/FIRC/PLL_DIG |
| Clock gating / modes | PCC per-peripheral gates, SMC modes |
MC_ME (mode entry) + partition clock control |
| Watchdog | WDOG |
SWT (Software Watchdog Timer) |
| Periodic timer | LPIT |
PIT and STM (system timer module) |
| PWM / motor control | FTM |
eMIOS |
| DMA | eDMA + DMAMUX |
eDMA + DMAMUX (very similar) |
| CAN | FlexCAN (+ CAN FD) |
FlexCAN — more instances, more MBs, CAN FD standard |
| Serial | LPUART, LPSPI, LPI2C |
Same names, same programming model |
| ADC | ADC (SAR) + PDB trigger |
ADC (SAR) + BCTU (body cross triggering unit) |
| Trigger routing | TRGMUX |
TRGMUX |
| Fault handling | Individual error flags | FCCU (Fault Collection and Control Unit) |
| Memory errors | ECC flags per module | MEMU (Memory Error Management Unit) |
| Self-test | — | STCU2 (LBIST / MBIST at startup) |
Notice what survived: LPUART, LPSPI, LPI2C, FlexCAN, eDMA, TRGMUX. If your S32K1 code is well layered, the drivers for those port with modest effort. What does not survive is anything touching pins, clocks, or timers — which, unfortunately, is everything in your board bring-up.
Memory map¶
The addresses move, and this catches people whose linker scripts or bootloaders assume S32K1 layout:
| Region | S32K1xx | S32K3xx |
|---|---|---|
| Code flash | 0x0000_0000 |
0x0040_0000 |
| Data flash | 0x1000_0000 (FlexNVM) |
0x1000_0000 |
| SRAM | 0x1FFF_xxxx (SRAM_L) / 0x2000_0000 (SRAM_U) |
0x2040_0000 |
| ITCM | — | 0x0000_0000 |
| DTCM | — | 0x2000_0000 |
| Factory/OTP region | IFR, reached through flash commands | 0x1B00_0000 (UTEST), directly addressable |
The S32K3's ITCM at 0x0000_0000 is a genuine trap: code that assumed "address 0 is flash" — a bootloader reading a vector table, say — now reads tightly-coupled memory instead.
From the SDK to RTD¶
The same operation, both generations. S32K1, toggling an LED:
/* S32K1 — S32 SDK */
PINS_DRV_Init(NUM_PINS, g_pin_mux_InitConfigArr);
PINS_DRV_ClearPins(PTD, (1u << 15)); /* LED on */
PINS_DRV_SetPins(PTD, (1u << 15)); /* LED off */
S32K3, the same thing through RTD's two layers — the AUTOSAR MCAL API, or the low-level IP driver underneath it:
/* S32K3 — RTD, AUTOSAR MCAL layer */
Port_Init(&Port_Config);
Dio_WriteChannel(DioConf_DioChannel_LED_RED, STD_LOW);
/* S32K3 — RTD, low-level IP layer (leaner, non-AUTOSAR) */
Siul2_Port_Ip_Init(NUM_PORT_CFG, g_pin_mux_InitConfigArr);
Siul2_Dio_Ip_WritePin(LED_RED_PORT, LED_RED_PIN, 0u);
RTD ships both: *_Ip_* functions are the direct hardware layer, and the
AUTOSAR-named modules (Port, Dio, Can, Adc, Mcu, Spi) sit on
top for projects that need MCAL conformance. For a non-AUTOSAR project the
IP layer is closer in spirit to the S32 SDK you already know, and it is
the sensible target for a first port.
The equivalent shift for CAN: FLEXCAN_DRV_Init becomes either
Can_Init() (MCAL) or FlexCAN_Ip_Init() (IP layer). The mailbox,
filtering, and bus-off concepts from module 1 transfer completely — the
hardware is recognisably the same FlexCAN.
Boot: the IVT and the BAF¶
An S32K1 boots by fetching the initial stack pointer and reset vector from address 0. An S32K3 does not. Its BAF (Boot Assist Firmware, in ROM) first reads an IVT (Image Vector Table) from a fixed flash location. The IVT holds the application's start address, configuration words, and — if secure boot is enabled — the parameters the HSE uses to authenticate the image. A device with a blank or invalid IVT does not run your code, no matter how correct your application is. Your build must emit a valid IVT, and your flash tool must program it.
Two more first-day surprises:
- Reading erased flash raises an ECC error. On S32K3, uninitialized
flash has no valid ECC, so reading it faults rather than returning
0xFF. Bootloaders that scan for "is there an application here?" by reading bytes must be rewritten to check a marker they wrote, never to probe blank memory. - Flash writes are wider. The write granularity is larger than the S32K1's 8-byte phrase, and page-aligned. Any NVM code from module 6 needs its alignment constants revisited.
Safety and security hardware¶
- Lockstep. On lockstep parts, two Cortex-M7 cores execute the same instruction stream and hardware compares the results every cycle. A mismatch goes to the FCCU. This is the mechanism behind the ASIL D claim, and it costs you the second core — a dual-core part in lockstep is a single-core part with checking.
- FCCU. A central collector for fault sources (lockstep mismatch, ECC errors, clock monitors, self-test failures) with configurable reactions: interrupt, reset, or driving an external error-out pin that tells the rest of the system this ECU is untrustworthy.
- STCU2. Runs logic and memory built-in self-tests at startup (and, optionally, periodically) — real coverage numbers for the hardware metrics ISO 26262 requires, at the cost of boot time you must budget.
- MEMU. Records and reports ECC events across memories so software can distinguish a corrected single-bit event (log it, watch the rate) from an uncorrectable one (fault reaction).
- HSE. A separate security subsystem running NXP-supplied firmware, handling key storage, secure boot, and cryptographic services. It replaces CSEc and is considerably more capable — and it must be provisioned, which is a production-process question, not just a firmware one.
Migration checklist¶
- Separate your code into hardware-dependent and application layers before migrating. The application logic — filtering, state machines, CAN signal packing, diagnostics — should port unchanged. If it does not, that is the finding, not the port.
- Rebuild the bring-up layer first: clocks (MC_CGM/MC_ME), pins (SIUL2), watchdog (SWT), a timer, and a UART. Get "hello" out of a serial port before touching anything else.
- Produce a valid IVT and confirm the part actually boots your image.
- Port CAN next — it is the most familiar peripheral and gives you a diagnostic channel.
- Revisit every timing assumption. Caches, TCM, and 160 MHz change execution times in both directions; code that "was fast enough" needs re-measuring, not re-assuming.
- Enable the safety hardware deliberately: decide the FCCU reaction for each fault source and write it down. Defaults are not a safety concept.
Cheat sheet¶
| Item | S32K1 | S32K3 |
|---|---|---|
| Core | Cortex-M4F @ ≤112 MHz | Cortex-M7 @ 160 MHz+, lockstep options |
| Drivers | S32 SDK FLEXCAN_DRV_Init |
RTD: Can_Init (MCAL) or FlexCAN_Ip_Init (IP) |
| Pins | PORT->PCR[n] + PTx |
SIUL2 MSCR[n] / IMCR[n] |
| Clocks | SCG + PCC |
MC_CGM + MC_ME |
| Watchdog | WDOG |
SWT |
| PWM | FTM |
eMIOS |
| Periodic timer | LPIT |
PIT / STM |
| ADC trigger | PDB |
BCTU |
| Unchanged | LPUART, LPSPI, LPI2C, FlexCAN, eDMA, TRGMUX | same |
| Code flash base | 0x0000_0000 |
0x0040_0000 (ITCM now at 0) |
| Boot | Vector table at 0 | BAF validates the IVT first |
| Erased flash | Reads 0xFF |
ECC error on read |
| Safety | ECC, WDOG, clock monitor | + FCCU, MEMU, STCU2, lockstep |
| Security | CSEc | HSE firmware-based subsystem |
How It Actually Works¶
The jump from S32K1 to S32K3 isn't a peripheral refresh — it's a different silicon safety architecture. S32K1 achieves its safety island largely through software-visible self-test hardware (like flash ECC and a single lockstep option on select parts); S32K3 bakes in a genuine dual-core lockstep pair by default on many variants, where a checker core physically replicates the main core's logic and runs the identical instruction stream offset by a fixed number of clock cycles, with a hardware comparator continuously checking every bus transaction and register result between the two — a mismatch triggers an immediate safety-fault signal at the hardware level, independent of any software fault handler, because the comparator sits in the silicon's control path, not in an interrupt service routine that could itself be corrupted by the same fault.
S32K3's memory system also adds a hardware MPU (Memory Protection Unit) with finer-grained region control and an ECC scheme that covers more of the internal bus fabric, not just flash/SRAM arrays — this matters for AUTOSAR "freedom from interference" requirements (covered later in this course), because partitioning software into memory regions is only a real safety mechanism if the hardware actually enforces the boundary on every single bus transaction, including ones initiated by DMA, not just CPU loads/stores.
Clock and power architecture on S32K3 also moves to a more segmented tree with independently gateable domains per peripheral cluster, which is why S32K3 parts can hit substantially higher pin counts and peripheral density than S32K1 while still meeting the same automotive power budgets — more of the chip can be clock-gated off simultaneously because domain boundaries were drawn finer in the silicon.
(Described from the S32K1 and S32K3 reference manuals' architecture overview chapters; not measured on physical silicon in this course.)
Exercise¶
You do not need an S32K3 board to do the valuable part of this module.
(1) Take your Level 1 capstone and produce a port assessment: go
file by file and classify every function as portable, needs-rework, or
rewrite, with the S32K3 peripheral named for each rewrite. The ratio you
end up with is a direct measure of how well-layered your code was. (2)
Rewrite one bring-up function — pin initialization — twice: once as it is
today with PINS_DRV_*, once as it would be with Siul2_Port_Ip_* and
Siul2_Dio_Ip_*, and note every assumption that broke. (3) Write the
timing-review list: which of your timing assumptions came from the 80 MHz
M4F, and how would you re-measure each on a cached M7? (4) Draft the FCCU
reaction table for your node: for lockstep mismatch, uncorrectable ECC,
clock loss, and self-test failure, state the reaction (interrupt / reset /
error-out) and justify it against your safe state from module 9. If you do
have an S32K3 evaluation board, add: get a UART "hello" out with RTD, and
document exactly how many steps it took to produce a bootable IVT — that
number is the real answer to "how hard is the migration?"