From 79622d3884bbd3fdd40c4d00f0b33894bd347542 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Mon, 9 Nov 2026 12:44:58 -0500 Subject: [PATCH 1/5] Initial support for mcxe247 --- .github/workflows/test-configs.yml | 6 +++ config/examples/mcxe247.config | 57 ++++++++++++++++++++++++++ docs/Targets.md | 47 ++++++++++++++++++++++ hal/s32k1xx.c | 15 +++---- hal/s32k1xx.h | 60 ++++++++++++++++++++++++---- hal/s32k1xx.ld | 4 ++ test-app/app_s32k1xx.c | 64 +++++++++++++++++------------- test-app/startup_arm.c | 20 ++++++++-- 8 files changed, 229 insertions(+), 44 deletions(-) create mode 100644 config/examples/mcxe247.config diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index 452ebc6a5f..37df45f6b5 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -561,6 +561,12 @@ jobs: arch: arm config-file: ./config/examples/nxp-s32k148.config + nxp_mcxe247_test: + uses: ./.github/workflows/test-build.yml + with: + arch: arm + config-file: ./config/examples/mcxe247.config + max32666_test: uses: ./.github/workflows/test-build.yml with: diff --git a/config/examples/mcxe247.config b/config/examples/mcxe247.config new file mode 100644 index 0000000000..e8a23f4e35 --- /dev/null +++ b/config/examples/mcxe247.config @@ -0,0 +1,57 @@ +# wolfBoot configuration for NXP MCX E247 (FRDM-MCXE247) +# +# MCXE247: Cortex-M4F, 2MB flash (1.5MB Program Flash + 512KB FlexNVM), 256KB +# SRAM. It is register compatible with the S32K148 and uses the s32k1xx HAL. +# Default: RUN mode at 48 MHz (FIRC - internal RC oscillator) +# +# Build: cp config/examples/mcxe247.config .config && make + +ARCH?=ARM +CORTEX_M4?=1 +NO_MPU=1 +TARGET?=s32k1xx +SIGN?=ECC256 +HASH?=SHA256 +VTOR?=1 +NO_ASM?=0 +EXT_FLASH?=0 +SPI_FLASH?=0 +ALLOW_DOWNGRADE?=0 + +# Flash can be programmed only once between erases +NVM_FLASH_WRITEONCE?=1 + +WOLFBOOT_VERSION?=0 +V?=0 +SPMATH?=1 +RAM_CODE?=1 +DUALBANK_SWAP?=0 + +# Select the MCXE247 variant. SRAM is ECC protected and is not initialized at +# reset, so clear it before the stack is used. +CFLAGS_EXTRA+=-DMCXE247 -DWOLFBOOT_RAM_ECC_INIT + +# 4KB sectors +WOLFBOOT_SECTOR_SIZE?=0x1000 + +# Memory layout (Program Flash 0x00000000 - 0x0017FFFF): +# Bootloader: 0x00000000 - 0x0000BFFF (48 KB) +# Boot Partition: 0x0000C000 - 0x000C3FFF (736 KB) +# Update Partition: 0x000C4000 - 0x0017BFFF (736 KB) +# Swap Sector: 0x0017C000 - 0x0017CFFF (4 KB) +WOLFBOOT_PARTITION_SIZE?=0xB8000 +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xC000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0xC4000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x17C000 + +# Console on the MCU-Link VCOM port: LPUART2, PTE12 (TX) and PTD17 (RX), ALT3 +CFLAGS_EXTRA+=-DDEBUG_UART_NUM=2 +CFLAGS_EXTRA+=-DDEBUG_UART_TX_PORT=S32K_PORT_E -DDEBUG_UART_TX_PIN=12 +CFLAGS_EXTRA+=-DDEBUG_UART_TX_MUX=PORT_PCR_MUX_ALT3 +CFLAGS_EXTRA+=-DDEBUG_UART_RX_PORT=S32K_PORT_D -DDEBUG_UART_RX_PIN=17 +CFLAGS_EXTRA+=-DDEBUG_UART_RX_MUX=PORT_PCR_MUX_ALT3 + +# Debugging options +DEBUG?=0 +DEBUG_SYMBOLS?=0 +DEBUG_UART?=1 diff --git a/docs/Targets.md b/docs/Targets.md index ac736baf21..55fa257e19 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -43,6 +43,7 @@ This README describes configuration of supported targets. * [NXP MCXN947](#nxp-mcxn947) * [NXP RW612](#nxp-rw612) * [NXP S32K1XX](#nxp-s32k1xx) +* [NXP MCXE247](#nxp-mcxe247) * [NXP P1021 PPC](#nxp-qoriq-p1021-ppc) * [NXP T10xx PPC (T1024 / T1040)](#nxp-qoriq-t10xx-ppc-t1024--t1040) * [NXP T2080 PPC](#nxp-qoriq-t2080-ppc) @@ -7314,6 +7315,52 @@ cmd> - [ ] **CAN/LIN bootloader**: Add firmware update over CAN or LIN bus for automotive applications +## NXP MCXE247 + +The NXP MCX E247 is a Cortex-M4F microcontroller that is register compatible +with the S32K148 (NXP AN14731), so it uses the bare-metal `s32k1xx` HAL with the +`MCXE247` variant. No SDK is needed. The port targets the FRDM-MCXE247 board. + +The 2 MB of flash is not contiguous: 1.5 MB of Program Flash is at `0x00000000` +and the remaining 512 KB is FlexNVM at `0x10000000`. Only the Program Flash is +used. The system runs at 48 MHz (FIRC). Flash cannot be programmed in HSRUN. + +### NXP MCXE247: Memory Layout + +| Region | Address Range | Size | +|--------|---------------|------| +| Bootloader | 0x00000000 - 0x0000BFFF | 48 KB | +| Boot Partition | 0x0000C000 - 0x000C3FFF | 736 KB | +| Update Partition | 0x000C4000 - 0x0017BFFF | 736 KB | +| Swap Sector | 0x0017C000 - 0x0017CFFF | 4 KB | + +### NXP MCXE247: Building + +```sh +cp config/examples/mcxe247.config .config +make +``` + +The console is on the MCU-Link VCOM port (LPUART2, PTE12 TX, PTD17 RX, 115200 +8N1). The test application shows green on the RGB LED for version 1 and blue +for later versions, and has the same console as the +[S32K1xx test application](#nxp-s32k1xx-test-application). + +### NXP MCXE247: Programming with Lauterbach TRACE32 + +Connect the 10-pin debug cable to J14 and short JP4 to disable the onboard +MCU-Link SWD. TRACE32 R2024.09 has no MCXE247 entry: use `SYStem.CPU S32K148` +and program `factory.bin` at `0x00000000`. + +`factory.bin` includes the Flash Configuration Field at `0x400`. Its security +byte at `0x40C` must be programmed to `0xFE`: an erased byte secures the chip +at the next reset, and only a mass erase recovers it. + +While TRACE32 is attached it halts the CPU at the reset vector on every reset. +Detach with `SYStem.Down` before testing an update, which relies on a software +reset. + + ## TI Hercules TMS570LC435 See [/config/examples/ti-tms570lc435.config](/config/examples/ti-tms570lc435.config) for example configuration. diff --git a/hal/s32k1xx.c b/hal/s32k1xx.c index 0e7f732ca9..97879845bb 100644 --- a/hal/s32k1xx.c +++ b/hal/s32k1xx.c @@ -18,7 +18,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * - * HAL for NXP S32K1xx (S32K142, S32K144, S32K146, S32K148) + * HAL for NXP S32K1xx (S32K142, S32K144, S32K146, S32K148) and the register + * compatible NXP MCX E247. * Tested on S32K142: Cortex-M4F, 256KB Flash, 32KB SRAM */ @@ -304,9 +305,9 @@ void uart_init(void) /* Transmit a single byte (raw, no conversion) - RAMFUNCTION for use during flash ops */ void RAMFUNCTION uart_tx(uint8_t byte) { - while (!(LPUART1_STAT & LPUART_STAT_TDRE)) {} - LPUART1_DATA = byte; - while (!(LPUART1_STAT & LPUART_STAT_TC)) {} + while (!(LPUART_STAT & LPUART_STAT_TDRE)) {} + LPUART_DATA = byte; + while (!(LPUART_STAT & LPUART_STAT_TC)) {} } /* Used for sending ASCII and CRLF conversions */ @@ -330,16 +331,16 @@ void uart_write(const char* buf, unsigned int sz) */ int RAMFUNCTION uart_read(char* c) { - uint32_t stat = LPUART1_STAT; + uint32_t stat = LPUART_STAT; /* Clear any error flags first */ if (stat & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE | LPUART_STAT_PF)) { - LPUART1_STAT = stat; /* Write 1 to clear flags */ + LPUART_STAT = stat; /* Write 1 to clear flags */ } /* Check if data available - read even if there was an error */ if (stat & LPUART_STAT_RDRF) { - *c = (char)(LPUART1_DATA & 0xFF); + *c = (char)(LPUART_DATA & 0xFF); return 1; } diff --git a/hal/s32k1xx.h b/hal/s32k1xx.h index 8f5ef04e2b..29ee928392 100644 --- a/hal/s32k1xx.h +++ b/hal/s32k1xx.h @@ -174,7 +174,7 @@ #define PCC_LPUART0 (*(volatile uint32_t *)(PCC_BASE + 0x1A8UL)) #define PCC_LPUART1 (*(volatile uint32_t *)(PCC_BASE + 0x1ACUL)) #define PCC_LPUART2 (*(volatile uint32_t *)(PCC_BASE + 0x1B0UL)) -#define PCC_FTFC (*(volatile uint32_t *)(PCC_BASE + 0x0B0UL)) +#define PCC_FTFC (*(volatile uint32_t *)(PCC_BASE + 0x080UL)) #define PCC_CGC (1UL << 30) /* Clock Gate Control */ #define PCC_PCS_SHIFT 24 @@ -242,10 +242,46 @@ #define PORT_PCR_MUX_ALT6 (6UL << PORT_PCR_MUX_SHIFT) /* Alternate function 6 */ #define PORT_PCR_MUX_ALT7 (7UL << PORT_PCR_MUX_SHIFT) /* Alternate function 7 */ -/* S32K142EVB LED pins (accent RGB LED accent accent accent accent LED accent accent accent-low accent LED) */ -#define LED_PIN_BLUE 0 /* PTD0 - Blue LED (active low) */ -#define LED_PIN_RED 15 /* PTD15 - Red LED (active low) */ -#define LED_PIN_GREEN 16 /* PTD16 - Green LED (active low) */ +/* GPIO port base addresses */ +#define GPIOB_BASE (0x400FF040UL) +#define GPIOC_BASE (0x400FF080UL) + +/* GPIO registers by port base address */ +#define GPIO_PSOR(base) (*(volatile uint32_t *)((base) + 0x04UL)) +#define GPIO_PCOR(base) (*(volatile uint32_t *)((base) + 0x08UL)) +#define GPIO_PTOR(base) (*(volatile uint32_t *)((base) + 0x0CUL)) +#define GPIO_PDDR(base) (*(volatile uint32_t *)((base) + 0x14UL)) + +/* RGB LED pins (all active low) */ +#ifdef MCXE247 +/* FRDM-MCXE247 D1: PTC12 blue, PTC13 red, PTB11 green */ +#define LED_PIN_BLUE 12 +#define LED_PIN_RED 13 +#define LED_PIN_GREEN 11 +#define LED_BLUE_GPIO GPIOC_BASE +#define LED_RED_GPIO GPIOC_BASE +#define LED_GREEN_GPIO GPIOB_BASE +#define LED_BLUE_PCC PCC_PORTC +#define LED_RED_PCC PCC_PORTC +#define LED_GREEN_PCC PCC_PORTB +#define LED_BLUE_PCR PORTC_PCR(LED_PIN_BLUE) +#define LED_RED_PCR PORTC_PCR(LED_PIN_RED) +#define LED_GREEN_PCR PORTB_PCR(LED_PIN_GREEN) +#else +/* S32K142EVB: PTD0 blue, PTD15 red, PTD16 green */ +#define LED_PIN_BLUE 0 +#define LED_PIN_RED 15 +#define LED_PIN_GREEN 16 +#define LED_BLUE_GPIO GPIOD_BASE +#define LED_RED_GPIO GPIOD_BASE +#define LED_GREEN_GPIO GPIOD_BASE +#define LED_BLUE_PCC PCC_PORTD +#define LED_RED_PCC PCC_PORTD +#define LED_GREEN_PCC PCC_PORTD +#define LED_BLUE_PCR PORTD_PCR(LED_PIN_BLUE) +#define LED_RED_PCR PORTD_PCR(LED_PIN_RED) +#define LED_GREEN_PCR PORTD_PCR(LED_PIN_GREEN) +#endif /* ============== LPUART Registers ============== */ @@ -350,18 +386,21 @@ #define LPUART_CTRL LPUART0_CTRL #define LPUART_DATA LPUART0_DATA #define PCC_LPUART PCC_LPUART0 + #define LPUART_IRQn LPUART0_IRQn #elif DEBUG_UART_NUM == 2 #define LPUART_BAUD LPUART2_BAUD #define LPUART_STAT LPUART2_STAT #define LPUART_CTRL LPUART2_CTRL #define LPUART_DATA LPUART2_DATA #define PCC_LPUART PCC_LPUART2 + #define LPUART_IRQn LPUART2_IRQn #else /* DEBUG_UART_NUM == 1 (default) */ #define LPUART_BAUD LPUART1_BAUD #define LPUART_STAT LPUART1_STAT #define LPUART_CTRL LPUART1_CTRL #define LPUART_DATA LPUART1_DATA #define PCC_LPUART PCC_LPUART1 + #define LPUART_IRQn LPUART1_IRQn #endif /* Port identifier values for preprocessor comparisons */ @@ -509,14 +548,21 @@ * S32K144: 512KB Flash (0x00000 - 0x7FFFF), 64KB SRAM, 4KB sectors * S32K146: 1MB Flash (0x00000 - 0xFFFFF), 128KB SRAM, 4KB sectors * S32K148: 2MB Flash (0x00000 - 0x1FFFFF), 256KB SRAM, 4KB sectors + * MCXE247: 1.5MB Program Flash (0x00000 - 0x17FFFF), 256KB SRAM, 4KB sectors. + * Register compatible with the S32K148 (NXP AN14731). The other + * 512KB of its 2MB is FlexNVM at 0x10000000 and is not used here. * * IMPORTANT: Flash sector size depends on total flash size: * - 256KB Flash (S32K142): 2KB sectors - * - 512KB+ Flash (S32K144/146/148): 4KB sectors + * - 512KB+ Flash (S32K144/146/148, MCXE247): 4KB sectors * * All variants use 8-byte phrase programming. */ -#if defined(S32K148) +#if defined(MCXE247) + #define FLASH_SIZE (1536 * 1024) /* 1.5MB Program Flash */ + #define SRAM_SIZE (256 * 1024) /* 256KB */ + #define FLASH_SECTOR_SIZE 4096 /* 4KB sectors */ +#elif defined(S32K148) #define FLASH_SIZE (2048 * 1024) /* 2MB */ #define SRAM_SIZE (256 * 1024) /* 256KB */ #define FLASH_SECTOR_SIZE 4096 /* 4KB sectors */ diff --git a/hal/s32k1xx.ld b/hal/s32k1xx.ld index e28275919b..2a9f763174 100644 --- a/hal/s32k1xx.ld +++ b/hal/s32k1xx.ld @@ -84,3 +84,7 @@ _wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@; /* Stack at end of SRAM_U (grows down from 0x20003000) */ END_STACK = ORIGIN(SRAM_U) + LENGTH(SRAM_U); + +/* RAM cleared with word stores when WOLFBOOT_RAM_ECC_INIT is set */ +_start_ecc_ram = ORIGIN(SRAM_L); +_end_ecc_ram = ORIGIN(SRAM_U) + LENGTH(SRAM_U); diff --git a/test-app/app_s32k1xx.c b/test-app/app_s32k1xx.c index 1971e647df..27be4f3bfd 100644 --- a/test-app/app_s32k1xx.c +++ b/test-app/app_s32k1xx.c @@ -82,57 +82,63 @@ static void systick_init(void) static void led_init(void) { - /* Enable clock to PORTD */ - PCC_PORTD |= PCC_CGC; + /* Enable clock to the LED ports */ + LED_BLUE_PCC |= PCC_CGC; + LED_RED_PCC |= PCC_CGC; + LED_GREEN_PCC |= PCC_CGC; /* Configure LED pins as GPIO */ - PORTD_PCR0 = PORT_PCR_MUX_GPIO; /* Blue LED */ - PORTD_PCR15 = PORT_PCR_MUX_GPIO; /* Red LED */ - PORTD_PCR16 = PORT_PCR_MUX_GPIO; /* Green LED */ + LED_BLUE_PCR = PORT_PCR_MUX_GPIO; + LED_RED_PCR = PORT_PCR_MUX_GPIO; + LED_GREEN_PCR = PORT_PCR_MUX_GPIO; /* Set as outputs */ - GPIOD_PDDR |= (1UL << LED_PIN_BLUE) | (1UL << LED_PIN_RED) | (1UL << LED_PIN_GREEN); + GPIO_PDDR(LED_BLUE_GPIO) |= (1UL << LED_PIN_BLUE); + GPIO_PDDR(LED_RED_GPIO) |= (1UL << LED_PIN_RED); + GPIO_PDDR(LED_GREEN_GPIO) |= (1UL << LED_PIN_GREEN); /* All LEDs off initially (active low) */ - GPIOD_PSOR = (1UL << LED_PIN_BLUE) | (1UL << LED_PIN_RED) | (1UL << LED_PIN_GREEN); + GPIO_PSOR(LED_BLUE_GPIO) = (1UL << LED_PIN_BLUE); + GPIO_PSOR(LED_RED_GPIO) = (1UL << LED_PIN_RED); + GPIO_PSOR(LED_GREEN_GPIO) = (1UL << LED_PIN_GREEN); } static void led_green_on(void) { - GPIOD_PCOR = (1UL << LED_PIN_GREEN); /* Active low */ + GPIO_PCOR(LED_GREEN_GPIO) = (1UL << LED_PIN_GREEN); /* Active low */ } static void led_green_off(void) { - GPIOD_PSOR = (1UL << LED_PIN_GREEN); + GPIO_PSOR(LED_GREEN_GPIO) = (1UL << LED_PIN_GREEN); } static void led_blue_on(void) { - GPIOD_PCOR = (1UL << LED_PIN_BLUE); /* Active low */ + GPIO_PCOR(LED_BLUE_GPIO) = (1UL << LED_PIN_BLUE); /* Active low */ } static void led_blue_off(void) { - GPIOD_PSOR = (1UL << LED_PIN_BLUE); + GPIO_PSOR(LED_BLUE_GPIO) = (1UL << LED_PIN_BLUE); } static void APP_RAMFUNCTION led_red_on(void) { - GPIOD_PCOR = (1UL << LED_PIN_RED); /* Active low */ + GPIO_PCOR(LED_RED_GPIO) = (1UL << LED_PIN_RED); /* Active low */ } static void APP_RAMFUNCTION led_red_off(void) { - GPIOD_PSOR = (1UL << LED_PIN_RED); + GPIO_PSOR(LED_RED_GPIO) = (1UL << LED_PIN_RED); } static void led_toggle_version(uint32_t version) { if (version == 1) { - GPIOD_PTOR = (1UL << LED_PIN_GREEN); + GPIO_PTOR(LED_GREEN_GPIO) = (1UL << LED_PIN_GREEN); } else { - GPIOD_PTOR = (1UL << LED_PIN_BLUE); + GPIO_PTOR(LED_BLUE_GPIO) = (1UL << LED_PIN_BLUE); } } @@ -174,20 +180,20 @@ static volatile uint8_t uart_rx_buf[UART_RX_BUF_SIZE]; static volatile uint32_t uart_rx_head = 0; /* Write index (ISR writes here) */ static volatile uint32_t uart_rx_tail = 0; /* Read index (app reads from here) */ -/* LPUART1 RX Interrupt Handler */ -void isr_lpuart1(void) +/* Console LPUART RX Interrupt Handler */ +void isr_debug_uart(void) { - uint32_t stat = LPUART1_STAT; + uint32_t stat = LPUART_STAT; /* Clear only the error flags (write 1 to clear) - do NOT write other bits */ uint32_t errors = stat & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE | LPUART_STAT_PF); if (errors) { - LPUART1_STAT = errors; /* Write 1 to clear only error flags */ + LPUART_STAT = errors; /* Write 1 to clear only error flags */ } /* Read all available bytes from FIFO */ - while (LPUART1_STAT & LPUART_STAT_RDRF) { - uint8_t c = (uint8_t)(LPUART1_DATA & 0xFF); + while (LPUART_STAT & LPUART_STAT_RDRF) { + uint8_t c = (uint8_t)(LPUART_DATA & 0xFF); uint32_t next_head = (uart_rx_head + 1) % UART_RX_BUF_SIZE; /* Store byte if buffer not full */ @@ -236,13 +242,13 @@ static void uart_rx_irq_enable(void) /* Set interrupt priority lower than SysTick (higher number = lower priority) * SysTick defaults to priority 0, so set LPUART to 2 to ensure * jiffies keeps incrementing even during heavy UART traffic. */ - NVIC_SetPriority(LPUART1_IRQn, 2); + NVIC_SetPriority(LPUART_IRQn, 2); - /* Enable LPUART1 interrupt in NVIC */ - NVIC_EnableIRQ(LPUART1_IRQn); + /* Enable LPUART interrupt in NVIC */ + NVIC_EnableIRQ(LPUART_IRQn); /* Enable Receiver Interrupt in LPUART */ - LPUART1_CTRL |= LPUART_CTRL_RIE; + LPUART_CTRL |= LPUART_CTRL_RIE; } /* Print hex buffer (similar to stm32h5 style) */ @@ -643,7 +649,7 @@ static int cmd_update_xmodem(void) /* Flush all printf output before starting XMODEM */ fflush(stdout); /* Wait for UART TX to complete */ - while (!(LPUART1_STAT & LPUART_STAT_TC)) {} + while (!(LPUART_STAT & LPUART_STAT_TC)) {} /* Drain any pending RX data before starting XMODEM */ { @@ -962,8 +968,12 @@ void main(void) #ifdef DEBUG_UART printf("\r\n"); printf("========================================\r\n"); +#ifdef MCXE247 + printf("MCXE247 wolfBoot Test Application\r\n"); +#else printf("S32K1xx wolfBoot Test Application\r\n"); - printf("Copyright 2025 wolfSSL Inc.\r\n"); +#endif + printf("Copyright 2025-2026 wolfSSL Inc.\r\n"); printf("========================================\r\n"); printf("Firmware Version: %lu\r\n", (unsigned long)version); diff --git a/test-app/startup_arm.c b/test-app/startup_arm.c index 5f5a5e12b7..0c3dff50da 100644 --- a/test-app/startup_arm.c +++ b/test-app/startup_arm.c @@ -40,7 +40,21 @@ extern void isr_usart3(void); #endif #ifdef TARGET_s32k1xx -extern void isr_lpuart1(void); +extern void isr_debug_uart(void); +/* Only the console LPUART selected with DEBUG_UART_NUM has a handler */ +#if defined(DEBUG_UART_NUM) && (DEBUG_UART_NUM == 0) +#define isr_lpuart0 isr_debug_uart +#define isr_lpuart1 isr_empty +#define isr_lpuart2 isr_empty +#elif defined(DEBUG_UART_NUM) && (DEBUG_UART_NUM == 2) +#define isr_lpuart0 isr_empty +#define isr_lpuart1 isr_empty +#define isr_lpuart2 isr_debug_uart +#else +#define isr_lpuart0 isr_empty +#define isr_lpuart1 isr_debug_uart +#define isr_lpuart2 isr_empty +#endif #endif #if defined(TARGET_va416x0) || defined(TARGET_lpc55s69) @@ -473,11 +487,11 @@ void (* const IV[])(void) = isr_empty, // LPSPI2 28 isr_empty, // Reserved29 29 isr_empty, // Reserved30 30 - isr_empty, // LPUART0_RxTx 31 + isr_lpuart0, // LPUART0_RxTx 31 isr_empty, // Reserved32 32 isr_lpuart1, // LPUART1_RxTx 33 isr_empty, // Reserved34 34 - isr_empty, // LPUART2_RxTx 35 + isr_lpuart2, // LPUART2_RxTx 35 isr_empty, // Reserved36 36 isr_empty, // Reserved37 37 isr_empty, // ADC0 38 From 2a7a81289ae64d4a080c1aaea299dbfaf5084f5c Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Mon, 9 Nov 2026 12:48:31 -0500 Subject: [PATCH 2/5] Fix s32k148 flash layout --- config/examples/nxp-s32k148.config | 16 ++++++++-------- docs/Targets.md | 2 +- hal/s32k1xx.h | 14 +++++--------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/config/examples/nxp-s32k148.config b/config/examples/nxp-s32k148.config index b60d221332..574be8da52 100644 --- a/config/examples/nxp-s32k148.config +++ b/config/examples/nxp-s32k148.config @@ -1,6 +1,6 @@ # wolfBoot configuration for NXP S32K148 # -# S32K148: Cortex-M4F, 2MB Flash, 256KB SRAM +# S32K148: Cortex-M4F, 2MB flash (1.5MB Program Flash + 512KB FlexNVM), 256KB SRAM # Flash sector size: 4KB (larger flash variants use 4KB sectors) # Default: RUN mode at 48 MHz (FIRC - internal RC oscillator) # @@ -34,15 +34,15 @@ CFLAGS_EXTRA+=-DS32K148 # 4KB sectors (S32K144/146/148 with 512KB+ flash) WOLFBOOT_SECTOR_SIZE?=0x1000 -# Memory layout for S32K148 (2MB Flash): +# Memory layout for S32K148 (Program Flash 0x00000000 - 0x0017FFFF): # Bootloader: 0x00000000 - 0x0000BFFF (48 KB) -# Boot Partition: 0x0000C000 - 0x000FBFFF (960 KB) -# Update Partition: 0x000FC000 - 0x001EBFFF (960 KB) -# Swap Sector: 0x001EC000 - 0x001ECFFF (4 KB) -WOLFBOOT_PARTITION_SIZE?=0xF0000 +# Boot Partition: 0x0000C000 - 0x000C3FFF (736 KB) +# Update Partition: 0x000C4000 - 0x0017BFFF (736 KB) +# Swap Sector: 0x0017C000 - 0x0017CFFF (4 KB) +WOLFBOOT_PARTITION_SIZE?=0xB8000 WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xC000 -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0xFC000 -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x1EC000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0xC4000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x17C000 # Clock mode: Default is RUN mode with FIRC (48 MHz internal RC) # To enable HSRUN mode (112 MHz), uncomment below (requires SOSC + SPLL, not fully implemented): diff --git a/docs/Targets.md b/docs/Targets.md index 55fa257e19..08c229ef2b 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -7131,7 +7131,7 @@ Example configuration files: - [/config/examples/nxp-s32k142.config](/config/examples/nxp-s32k142.config) - S32K142 (256KB Flash, 32KB SRAM) - [/config/examples/nxp-s32k144.config](/config/examples/nxp-s32k144.config) - S32K144 (512KB Flash, 64KB SRAM) - [/config/examples/nxp-s32k146.config](/config/examples/nxp-s32k146.config) - S32K146 (1MB Flash, 128KB SRAM) -- [/config/examples/nxp-s32k148.config](/config/examples/nxp-s32k148.config) - S32K148 (2MB Flash, 256KB SRAM) +- [/config/examples/nxp-s32k148.config](/config/examples/nxp-s32k148.config) - S32K148 (1.5MB Program Flash + 512KB FlexNVM, 256KB SRAM) ```sh # Copy configuration (example for S32K142) diff --git a/hal/s32k1xx.h b/hal/s32k1xx.h index 29ee928392..16c080eeaa 100644 --- a/hal/s32k1xx.h +++ b/hal/s32k1xx.h @@ -547,10 +547,10 @@ * S32K142: 256KB Flash (0x00000 - 0x3FFFF), 32KB SRAM, 2KB sectors * S32K144: 512KB Flash (0x00000 - 0x7FFFF), 64KB SRAM, 4KB sectors * S32K146: 1MB Flash (0x00000 - 0xFFFFF), 128KB SRAM, 4KB sectors - * S32K148: 2MB Flash (0x00000 - 0x1FFFFF), 256KB SRAM, 4KB sectors - * MCXE247: 1.5MB Program Flash (0x00000 - 0x17FFFF), 256KB SRAM, 4KB sectors. - * Register compatible with the S32K148 (NXP AN14731). The other - * 512KB of its 2MB is FlexNVM at 0x10000000 and is not used here. + * S32K148: 1.5MB Program Flash (0x00000 - 0x17FFFF), 256KB SRAM, 4KB sectors + * MCXE247: Same memory as the S32K148 and register compatible (NXP AN14731). + * The other 512KB of the 2MB on both parts is FlexNVM at 0x10000000 + * and is not used here. * * IMPORTANT: Flash sector size depends on total flash size: * - 256KB Flash (S32K142): 2KB sectors @@ -558,14 +558,10 @@ * * All variants use 8-byte phrase programming. */ -#if defined(MCXE247) +#if defined(S32K148) || defined(MCXE247) #define FLASH_SIZE (1536 * 1024) /* 1.5MB Program Flash */ #define SRAM_SIZE (256 * 1024) /* 256KB */ #define FLASH_SECTOR_SIZE 4096 /* 4KB sectors */ -#elif defined(S32K148) - #define FLASH_SIZE (2048 * 1024) /* 2MB */ - #define SRAM_SIZE (256 * 1024) /* 256KB */ - #define FLASH_SECTOR_SIZE 4096 /* 4KB sectors */ #elif defined(S32K146) #define FLASH_SIZE (1024 * 1024) /* 1MB */ #define SRAM_SIZE (128 * 1024) /* 128KB */ From bf2eb49e8fe06e9c61fed766bbcb1e6877e7d386 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Tue, 10 Nov 2026 14:33:05 -0500 Subject: [PATCH 3/5] turn on ethernet, wolfip, and network test via new network command --- config/examples/mcxe247.config | 21 +++++++++- docs/Targets.md | 56 +++++++++++++++++++++++-- src/boot_arm.c | 7 ++-- test-app/ARM-s32k1xx-wolfip.ld | 75 ++++++++++++++++++++++++++++++++++ test-app/Makefile | 30 +++++++++++++- test-app/app_s32k1xx.c | 26 ++++++++++++ test-app/wolfip_tftp_test.c | 45 ++++++++++++++++---- 7 files changed, 241 insertions(+), 19 deletions(-) create mode 100644 test-app/ARM-s32k1xx-wolfip.ld diff --git a/config/examples/mcxe247.config b/config/examples/mcxe247.config index e8a23f4e35..e0cb097008 100644 --- a/config/examples/mcxe247.config +++ b/config/examples/mcxe247.config @@ -27,8 +27,9 @@ SPMATH?=1 RAM_CODE?=1 DUALBANK_SWAP?=0 -# Select the MCXE247 variant. SRAM is ECC protected and is not initialized at -# reset, so clear it before the stack is used. +# Select the MCXE247 variant. SRAM is ECC protected and holds no valid ECC after +# power-on. Clearing it at reset keeps the ECC valid, so the ERM records no +# errors and its interrupts can be enabled safely. CFLAGS_EXTRA+=-DMCXE247 -DWOLFBOOT_RAM_ECC_INIT # 4KB sectors @@ -51,6 +52,22 @@ CFLAGS_EXTRA+=-DDEBUG_UART_TX_MUX=PORT_PCR_MUX_ALT3 CFLAGS_EXTRA+=-DDEBUG_UART_RX_PORT=S32K_PORT_D -DDEBUG_UART_RX_PIN=17 CFLAGS_EXTRA+=-DDEBUG_UART_RX_MUX=PORT_PCR_MUX_ALT3 +# wolfIP network test in the test-app (optional) +# Adds the "network" console command. Needs a wolfIP checkout and an MCUXpresso +# SDK (for the fsl_enet driver). +ENABLE_WOLFIP?=0 +WOLFBOOT_LIB_WOLFIP?=../lib/wolfip +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk +# Without WOLFBOOT_TEST_TFTP the command only acquires a DHCP lease. The file +# must fit the 40 KB receive buffer. +WOLFBOOT_TEST_TFTP?=1 +CFLAGS_EXTRA+=-DHOST_IP_STR='"192.168.50.1"' -DTFTP_FILENAME='"wolfip_test.bin"' +# WOLFIP_SPEED_TEST=1 makes the command run a TCP throughput server on port 9 +# instead (it never returns; reset the board to stop it). WOLFBOOT_TEST_TFTP +# overrides it: with both set to 1 the command runs the TFTP fetch and the speed +# server is never started. +WOLFIP_SPEED_TEST?=0 + # Debugging options DEBUG?=0 DEBUG_SYMBOLS?=0 diff --git a/docs/Targets.md b/docs/Targets.md index 08c229ef2b..640be08e5a 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -7346,17 +7346,67 @@ The console is on the MCU-Link VCOM port (LPUART2, PTE12 TX, PTD17 RX, 115200 for later versions, and has the same console as the [S32K1xx test application](#nxp-s32k1xx-test-application). +### NXP MCXE247: Configuration Options + +The [S32K1xx configuration options](#nxp-s32k1xx-configuration-options) also +apply to the MCXE247, with these differences: + +- Select the variant with `MCXE247` instead of `S32K144`, `S32K146` or `S32K148`. +- The console is on LPUART2, not LPUART1. `mcxe247.config` selects it with + `DEBUG_UART_NUM=2` and the `DEBUG_UART_TX_*` and `DEBUG_UART_RX_*` pin + settings. +- `mcxe247.config` also sets `WOLFBOOT_RAM_ECC_INIT`, which clears SRAM at reset + so its ECC is valid. + +### NXP MCXE247: Network test + +The test application can run a wolfIP DHCP and TFTP test over the board's +Ethernet port. This is optional and is the only part of the port that needs the +MCUXpresso SDK, which provides the `fsl_enet` driver. Set `ENABLE_WOLFIP=1` in +`mcxe247.config`, check the wolfIP and SDK paths, then set the TFTP server and +file: + +```sh +ENABLE_WOLFIP?=1 +WOLFBOOT_LIB_WOLFIP?=../lib/wolfip +MCUXPRESSO?=$(PWD)/../NXP/mcuxpresso-sdk/mcuxsdk +WOLFBOOT_TEST_TFTP?=1 +CFLAGS_EXTRA+=-DHOST_IP_STR='"192.168.50.1"' -DTFTP_FILENAME='"wolfip_test.bin"' +``` + +Type `network` on the console to run the test. It acquires a DHCP lease, fetches +the file into RAM (40 KB at most), and prints its size and checksum followed by +`WOLFIP_TEST: PASS` or `WOLFIP_TEST: FAIL`. + +To measure throughput instead, set `WOLFBOOT_TEST_TFTP=0` and +`WOLFIP_SPEED_TEST=1`. After the DHCP lease, the `network` command runs a TCP +server on port 9 that discards what it receives and sends data whenever the +connection can take it. It prints the receive and transmit rates when the +connection closes. Drive it from the PC with `` set to the address the board +printed: + +```sh +# board receives +dd if=/dev/zero bs=1460 count=10000 | nc 9 +# board sends +nc 9 /dev/null +``` + +The server never returns to the console; reset the board to stop it. +`WOLFBOOT_TEST_TFTP` takes priority: with both options set to 1, the command +runs the TFTP fetch and the speed server is never started. + ### NXP MCXE247: Programming with Lauterbach TRACE32 Connect the 10-pin debug cable to J14 and short JP4 to disable the onboard -MCU-Link SWD. TRACE32 R2024.09 has no MCXE247 entry: use `SYStem.CPU S32K148` -and program `factory.bin` at `0x00000000`. +MCU-Link SWD. If TRACE32 has no MCXE247 entry, use `SYStem.CPU S32K148`. +Program `factory.bin` at `0x00000000`. `factory.bin` includes the Flash Configuration Field at `0x400`. Its security byte at `0x40C` must be programmed to `0xFE`: an erased byte secures the chip at the next reset, and only a mass erase recovers it. -While TRACE32 is attached it halts the CPU at the reset vector on every reset. +While TRACE32 is attached, it halts the CPU at the reset vector on every reset. Detach with `SYStem.Down` before testing an update, which relies on a software reset. diff --git a/src/boot_arm.c b/src/boot_arm.c index e22d2ddafd..f36bdf4249 100644 --- a/src/boot_arm.c +++ b/src/boot_arm.c @@ -238,9 +238,10 @@ void isr_reset(void) } void isr_reset_c(void) #elif defined(WOLFBOOT_RAM_ECC_INIT) -/* ECC SRAM faults on a sub-word write to a word not written since power-on, - * so clear [_start_ecc_ram, _end_ecc_ram) with word stores before the stack - * is used. Must be naked: nothing may touch RAM before the loop. */ +/* ECC SRAM words not written since power-on hold no valid ECC. Depending on + * the part, accessing them faults or records an ECC error event. Clear + * [_start_ecc_ram, _end_ecc_ram) with word stores before the stack is used so + * the ECC is valid. Must be naked: nothing may touch RAM before the loop. */ extern void isr_reset_c(void); __attribute__((naked, used, noreturn)) void isr_reset(void) diff --git a/test-app/ARM-s32k1xx-wolfip.ld b/test-app/ARM-s32k1xx-wolfip.ld new file mode 100644 index 0000000000..27fd53f269 --- /dev/null +++ b/test-app/ARM-s32k1xx-wolfip.ld @@ -0,0 +1,75 @@ +/* + * Linker script for the wolfBoot test application on NXP S32K148/MCXE247 with wolfIP + * + * The application runs from the boot partition after the wolfBoot header. + * RAM is all of SRAM_U, which the ENET DMA uses and is outside the code cache. + * + * SRAM is ECC protected and holds no valid ECC after power-on. .bss runs to the + * end of RAM so that startup also clears the heap and stack with word stores, + * which keeps the ECC valid and the ERM free of error events. + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = @WOLFBOOT_TEST_APP_ADDRESS@, LENGTH = @WOLFBOOT_TEST_APP_SIZE@ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x1F000 /* 124KB SRAM_U */ +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + *(.text*) + *(.rodata*) + *(.init*) + *(.fini*) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + KEEP(*(.ramcode)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end = .; + . = ORIGIN(RAM) + LENGTH(RAM); + _end_bss = .; + __bss_end__ = .; + } > RAM +} + +/* Partition info for libwolfboot */ +_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@; +_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@; +_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@; +_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@; + +/* Stack and heap indicators */ +_start_heap = _end; +_end_stack = ORIGIN(RAM) + LENGTH(RAM); + +/* Keep room above .bss for the stack and the heap used by printf */ +ASSERT(_end_stack - _end >= 0x2000, "not enough RAM left for the stack") diff --git a/test-app/Makefile b/test-app/Makefile index 9b96d45d87..c2d9948f8f 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -1716,8 +1716,8 @@ WOLFTPM_CFLAGS:=$(CFLAGS) WOLFHSM_CFLAGS:=$(CFLAGS) # Optional wolfIP network stack in the test-app. -# ENABLE_WOLFIP=1 wolfIP ethernet port (nxp_fman, or nxp_enetc on -# LS1028A) + a link/PHY smoke test. +# ENABLE_WOLFIP=1 wolfIP ethernet port (nxp_fman, nxp_enetc on LS1028A, +# or nxp_mcxe_enet on MCXE247) + a link/PHY smoke test. # WOLFBOOT_TEST_TFTP=1 additionally pull in wolfIP core + TFTP client for # the full network TFTP-fetch test. # Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout, e.g. @@ -1732,6 +1732,32 @@ ifeq ($(ENABLE_WOLFIP),1) WOLFIP_PORT:=nxp_enetc WOLFIP_PORT_OBJ:=nxp_enetc.o CFLAGS+=-DWOLFIP_PORT_ENETC + else ifeq ($(TARGET),s32k1xx) + ifeq ($(filter -DMCXE247,$(CFLAGS_EXTRA)),) + $(error ENABLE_WOLFIP=1 on s32k1xx is only supported on MCXE247) + endif + ifeq ($(wildcard $(MCUXPRESSO)/drivers/enet/fsl_enet.c),) + $(error ENABLE_WOLFIP=1 on MCXE247 needs MCUXPRESSO set to an MCUXpresso SDK checkout) + endif + WOLFIP_PORT:=nxp_mcxe_enet + WOLFIP_PORT_OBJ:=nxp_mcxe_enet.o + LSCRIPT_TEMPLATE=ARM-s32k1xx-wolfip.ld + # The generic MCUXPRESSO_* defaults describe a different part + MCXE247_DEVICE:=$(MCUXPRESSO)/devices/MCX/MCXE/MCXE247 + CFLAGS+=-DWOLFIP_PORT_MCXE_ENET -DCPU_MCXE247VLL + # The TFTP receive buffer shares the 124KB of SRAM_U + CFLAGS+=-DTFTP_RAM_MAX=0xA000U + CFLAGS+=-I$(MCXE247_DEVICE) -I$(MCXE247_DEVICE)/drivers + CFLAGS+=-I$(MCXE247_DEVICE)/../periph0 + CFLAGS+=-I$(MCUXPRESSO)/drivers/common -I$(MCUXPRESSO)/drivers/enet + CFLAGS+=-I$(MCUXPRESSO)/components/phy + CFLAGS+=-I$(MCUXPRESSO)/components/phy/device/phylan8741 + CFLAGS+=-I$(MCUXPRESSO)/arch/arm/CMSIS/Core/Include + APP_OBJS+=$(MCUXPRESSO)/drivers/enet/fsl_enet.o + APP_OBJS+=$(MCUXPRESSO)/drivers/common/fsl_common.o + APP_OBJS+=$(MCUXPRESSO)/drivers/common/fsl_common_arm.o + APP_OBJS+=$(MCXE247_DEVICE)/drivers/fsl_clock.o + APP_OBJS+=$(MCUXPRESSO)/components/phy/device/phylan8741/fsl_phylan8741.o else WOLFIP_PORT:=nxp_fman WOLFIP_PORT_OBJ:=nxp_fman.o diff --git a/test-app/app_s32k1xx.c b/test-app/app_s32k1xx.c index 27be4f3bfd..f6e07541d4 100644 --- a/test-app/app_s32k1xx.c +++ b/test-app/app_s32k1xx.c @@ -37,6 +37,9 @@ #include "keystore.h" #include "target.h" #include "image.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif #ifdef TARGET_s32k1xx @@ -62,6 +65,14 @@ static uint32_t get_time_ms(void) return jiffies; } +#ifdef ENABLE_WOLFIP +/* Millisecond timebase for wolfip_tftp_test.c */ +uint32_t wolfip_test_get_ms(void) +{ + return jiffies; +} +#endif + static void delay_ms(uint32_t ms) { uint32_t start = jiffies; @@ -711,6 +722,9 @@ static int cmd_update(const char *args); static int cmd_timestamp(const char *args); static int cmd_trigger(const char *args); static int cmd_status(const char *args); +#ifdef ENABLE_WOLFIP +static int cmd_network(const char *args); +#endif typedef struct { int (*fn)(const char *args); @@ -726,6 +740,9 @@ static const console_cmd_t commands[] = { {cmd_trigger, "trigger", "Trigger update (if update image in flash)"}, {cmd_update, "update", "Update firmware via XMODEM"}, {cmd_timestamp, "timestamp", "Show current system time"}, +#ifdef ENABLE_WOLFIP + {cmd_network, "network", "Run the wolfIP network test"}, +#endif {cmd_reboot, "reboot", "Reboot the system"}, {NULL, NULL, NULL} }; @@ -844,6 +861,15 @@ static int cmd_update(const char *args) return cmd_update_xmodem(); } +#ifdef ENABLE_WOLFIP +static int cmd_network(const char *args) +{ + (void)args; + wolfip_tftp_test_report(); + return 0; +} +#endif + static int parse_command(const char* cmd) { int i; diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c index 96b1e8b4f7..d00a74a96e 100644 --- a/test-app/wolfip_tftp_test.c +++ b/test-app/wolfip_tftp_test.c @@ -2,7 +2,8 @@ * * Optional wolfIP network test for the wolfBoot test-app. Ethernet port and ms * timebase are compile-time selected: NXP QorIQ FMan (T2080/T1024/T1040, - * big-endian PowerPC) or NXP Layerscape ENETC (LS1028A, AArch64). Modes: + * big-endian PowerPC), NXP Layerscape ENETC (LS1028A, AArch64) or the + * MCUXpresso fsl_enet driver (MCXE247, Cortex-M4). Modes: * default DHCP lease only * WOLFBOOT_TEST_TFTP + TFTP RRQ fetch into RAM, report size+checksum * (optionally verify them via TFTP_EXPECT_SIZE/SUM) @@ -46,6 +47,13 @@ #define WOLFIP_NETDEV_LINK_UP nxp_enetc_link_up #define WOLFIP_NETDEV_SET_LOG nxp_enetc_set_log #define WOLFIP_NETDEV_NAME "ENETC" +#elif defined(WOLFIP_PORT_MCXE_ENET) +#include "nxp_mcxe_enet.h" +#define WOLFIP_NETDEV_INIT nxp_mcxe_enet_init +#define WOLFIP_NETDEV_PHY_ADDR nxp_mcxe_enet_phy_addr +#define WOLFIP_NETDEV_PHY_READ nxp_mcxe_enet_phy_read +#define WOLFIP_NETDEV_LINK_UP nxp_mcxe_enet_link_up +#define WOLFIP_NETDEV_NAME "MCXE247 ENET" #else #include "nxp_fman.h" #define WOLFIP_NETDEV_INIT nxp_fman_init @@ -100,6 +108,21 @@ static uint64_t now_ms(void) { return read_tb() / (tb_hz() / 1000ULL); } +#elif defined(WOLFIP_PORT_MCXE_ENET) +/* 1 ms SysTick count, kept by the target app. */ +extern uint32_t wolfip_test_get_ms(void); +#define SYST_CVR_REG (*(volatile uint32_t *)0xE000E018UL) + +/* Combine the tick count and the SysTick down-counter to seed the RNG. */ +static uint64_t read_tb(void) +{ + return ((uint64_t)wolfip_test_get_ms() << 24) | (SYST_CVR_REG & 0xFFFFFFU); +} + +static uint64_t now_ms(void) +{ + return (uint64_t)wolfip_test_get_ms(); +} #else /* PowerPC e5500/e6500 Time Base via SPRs (TBL=268, TBU=269) = platform clock * / 16; default is the VPX3-152 value (600 MHz -> 37.5 MHz). Other platform @@ -224,9 +247,21 @@ static struct wolfIP *wolfip_bringup(void) } } +#if defined(WOLFBOOT_TEST_TFTP) || defined(WOLFIP_SPEED_TEST) +/* Zero a local struct without pulling in a libc memset (freestanding app). */ +static void zmem(void *p, unsigned int n) +{ + unsigned int i; + for (i = 0; i < n; i++) + ((uint8_t *)p)[i] = 0; +} +#endif + #ifdef WOLFBOOT_TEST_TFTP /* ---- TFTP RRQ fetch into a RAM buffer + integrity check ------------- */ +#ifndef TFTP_RAM_MAX #define TFTP_RAM_MAX (128U * 1024U) +#endif #define TFTP_LOCAL_PORT 6900U struct tftp_ram_ctx { @@ -239,14 +274,6 @@ static struct tftp_ram_ctx g_tftp; struct tftp_glue { struct wolfIP *s; int sock; }; -/* Zero a local struct without pulling in a libc memset (freestanding app). */ -static void zmem(void *p, unsigned int n) -{ - unsigned int i; - for (i = 0; i < n; i++) - ((uint8_t *)p)[i] = 0; -} - static int tftp_io_open(void *arg, const char *name, int is_write, uint32_t *size_hint, void **handle) { From 64628f4b237293177d165d53046c8ca469d08079 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 11 Nov 2026 12:09:46 -0500 Subject: [PATCH 4/5] Add trace32 scripts --- docs/Targets.md | 12 ++ tools/scripts/mcxe247/e247_debug.cmm | 86 ++++++++++++++ .../mcxe247/e247_flash_factory_bin.cmm | 111 ++++++++++++++++++ tools/scripts/mcxe247/e247_flash_update.cmm | 82 +++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 tools/scripts/mcxe247/e247_debug.cmm create mode 100644 tools/scripts/mcxe247/e247_flash_factory_bin.cmm create mode 100644 tools/scripts/mcxe247/e247_flash_update.cmm diff --git a/docs/Targets.md b/docs/Targets.md index 640be08e5a..1e63ef5c5d 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -7402,6 +7402,18 @@ Connect the 10-pin debug cable to J14 and short JP4 to disable the onboard MCU-Link SWD. If TRACE32 has no MCXE247 entry, use `SYStem.CPU S32K148`. Program `factory.bin` at `0x00000000`. +Scripts for this are in `tools/scripts/mcxe247`. They find the build output +relative to their own location, so run them from the wolfBoot checkout, for +example `DO /tools/scripts/mcxe247/e247_flash_factory_bin.cmm`: + +| Script | Purpose | +|--------|---------| +| `e247_debug.cmm` | Reset and halt the CPU, then load the `wolfboot.elf` and `test-app/image.elf` symbols | +| `e247_flash_factory_bin.cmm` | Program `factory.bin`, erase the update partition and swap sector, then reset and detach | +| `e247_flash_update.cmm` | Program `test-app/image_v2_signed.bin` into the update partition, then reset and detach | + +Each script writes a log to the TRACE32 system directory (`~~`). + `factory.bin` includes the Flash Configuration Field at `0x400`. Its security byte at `0x40C` must be programmed to `0xFE`: an erased byte secures the chip at the next reset, and only a mass erase recovers it. diff --git a/tools/scripts/mcxe247/e247_debug.cmm b/tools/scripts/mcxe247/e247_debug.cmm new file mode 100644 index 0000000000..f07c30d4d0 --- /dev/null +++ b/tools/scripts/mcxe247/e247_debug.cmm @@ -0,0 +1,86 @@ +;; e247_debug.cmm +;; +;; Connect TRACE32 to the NXP MCXE247 (FRDM-MCXE247) and halt the CPU at the +;; reset vector, then load the wolfBoot and test-app symbols. +;; No arguments: DO e247_debug.cmm +;; +;; Board setup (UM12286): +;; - Lauterbach 10-pin cable on J14 (SWD/JTAG 2x5 header) +;; - JP4 SHORTED: disables the onboard MCU-Link SWD so it does not fight +;; the external probe on SWDIO/SWCLK +;; - JP3 open: keeps the MCU-Link VCOM console (LPUART2, 115200 8N1) +;; +;; Notes: +;; - TRACE32 R2024.09 has no MCXE247 entry. The S32K148 is the same part for +;; debug purposes (NXP AN14731: same core, pinout and flash controller). +;; - All output, including errors, is logged to ~~/e247_debug.log +;; - The ELF files are loaded from the wolfBoot checkout this script is in. + +; wolfBoot root: three levels above this script +&basedir=OS.PPD()+"\..\..\.." + +AREA.OPEN A000 "~~/e247_debug.log" /Create /NoFileCache +PRINT "e247_debug.cmm " DATE.DATE() " " DATE.TIME() + +RESet +SYStem.RESet +SYStem.CPU S32K148 +SYStem.CONFIG.DEBUGPORTTYPE SWD +SYStem.Option DUALPORT ON +SYStem.MemAccess DAP +Trace.DISable + +; reset and halt at the reset vector, retrying with a slow debug clock +SYStem.JtagClock 10MHz +PRINT "[1] SYStem.Up @ 10MHz" +ON ERROR CONTinue +SYStem.Up +ON ERROR inherit + +IF !SYStem.Up() +( + PRINT "[2] SYStem.Up @ 1MHz" + SYStem.Down + SYStem.JtagClock 1MHz + ON ERROR CONTinue + SYStem.Up + ON ERROR inherit +) + +IF !SYStem.Up() +( + PRINT %ERROR "MCXE247: connection failed (check JP4 shorted, cable on J14, board powered)" + AREA.CLOSE A000 + ENDDO +) + +IF STATE.RUN() +( + ON ERROR CONTinue + Break + ON ERROR inherit +) + +IF STATE.RUN() +( + PRINT %ERROR "MCXE247: connected but CPU did not halt" + AREA.CLOSE A000 + ENDDO +) + +PRINT "MCXE247 halted, PC=0x"+FORMAT.HEX(8.,Register(PC))+" SP=0x"+FORMAT.HEX(8.,Register(SP)) +AREA.CLOSE A000 + +mode.hll + +IF OS.FILE("&basedir\wolfboot.elf") + data.load.elf "&basedir\wolfboot.elf" /nocode +IF OS.FILE("&basedir\test-app\image.elf") + data.load.elf "&basedir\test-app\image.elf" /nocode /noclear +; The ELF files hold the paths of the build machine. Look the sources up in +; this checkout instead, so it also works when TRACE32 runs on another host +; (e.g. Windows with the checkout in WSL). +sYmbol.SourcePATH.SetBaseDir "&basedir" +sYmbol.SourcePATH.Set "&basedir" "&basedir\src" "&basedir\hal" "&basedir\test-app" "&basedir\lib\wolfssl\wolfcrypt\src" + +ENDDO diff --git a/tools/scripts/mcxe247/e247_flash_factory_bin.cmm b/tools/scripts/mcxe247/e247_flash_factory_bin.cmm new file mode 100644 index 0000000000..c1d7b1da04 --- /dev/null +++ b/tools/scripts/mcxe247/e247_flash_factory_bin.cmm @@ -0,0 +1,111 @@ +;; e247_flash_factory_bin.cmm +;; +;; Program factory.bin (wolfBoot + signed test app) into the NXP MCXE247 +;; (FRDM-MCXE247) and erase the update partition and swap sector. +;; No arguments: DO e247_flash_factory_bin.cmm +;; +;; Connects with e247_debug.cmm (reset and halt), programs the image with the +;; TRACE32 S32K flash algorithm, verifies it, resets the board to boot and +;; detaches the debugger. +;; Range erased and programmed: 0x00000000--0x0017CFFF (bootloader, boot +;; partition, update partition, swap sector). factory.bin must fit in the +;; bootloader + boot partition (0x00000000--0x000C3FFF). The FlexNVM at +;; 0x10000000 is left as is. +;; +;; factory.bin contains the Flash Configuration Field at 0x400. An erased or +;; wrong security byte (0x40C) secures the chip at the next reset, so the byte +;; is checked in the file before anything is erased and in flash before reset. +;; Output is logged to ~~/e247_flash_factory_bin.log +;; factory.bin is taken from the wolfBoot checkout this script is in. + +; This script's directory, and the wolfBoot root three levels above it +&scriptdir=OS.PPD() +&basedir="&scriptdir\..\..\.." +&file="&basedir\factory.bin" +&start=0x00000000 +&end=0x0017CFFF +; factory.bin (bootloader + boot partition) must end before the update partition +&maxsize=0xC4000 +&fsec_addr=0x40C +&fsec_unsecure=0xFE + +DO "&scriptdir\e247_debug.cmm" + +AREA.OPEN A000 "~~/e247_flash_factory_bin.log" /Create /NoFileCache +PRINT "e247_flash_factory_bin.cmm " DATE.DATE() " " DATE.TIME() + +IF !SYStem.Up() +( + PRINT %ERROR "not connected, see ~~/e247_debug.log" + AREA.CLOSE A000 + ENDDO +) +IF !OS.FILE("&file") +( + PRINT %ERROR "&file not found" + AREA.CLOSE A000 + ENDDO +) +&size=OS.FILE.SIZE("&file") +IF &size>&maxsize +( + PRINT %ERROR "&file is larger than the bootloader + boot partition" + AREA.CLOSE A000 + ENDDO +) + +; Refuse an image that would secure the chip +Data.LOAD.Binary "&file" VM:&start +IF Data.Byte(VM:&fsec_addr)!=&fsec_unsecure +( + PRINT %ERROR "&file: security byte at 0x40C is not 0xFE, not programming" + AREA.CLOSE A000 + ENDDO +) + +; The flash algorithm runs from SRAM, which is ECC protected and must be +; written before it is read +Data.Set AD:0x20000000++0x215F %Long 0 + +; Vendor flash declaration: checks security, disables the watchdog +DO ~~/demo/arm/flash/s32k PREPAREONLY CPU=S32K148 DUALPORT=1 + +; Sectors in range not covered by the file are erased +PRINT "programming &file (" FORMAT.Decimal(0.,&size) " bytes) at "+FORMAT.HEX(8.,&start) +FLASH.ReProgram &start--&end /Erase +Data.LOAD.Binary "&file" &start +FLASH.ReProgram OFF + +; The Flash Configuration Field is guarded against normal programming +FLASH.AUTO 0x400--0x40F /CENSORSHIP +Data.LOAD.Binary "&file" 0x400--0x40F /SKIP 0x400 +FLASH.AUTO OFF + +Data.LOAD.Binary "&file" &start /DIFF +IF FOUND() +( + PRINT %ERROR "verify FAILED, not resetting" + AREA.CLOSE A000 + ENDDO +) +IF Data.Byte(C:&fsec_addr)!=&fsec_unsecure +( + PRINT %ERROR "security byte in flash is not 0xFE, not resetting" + AREA.CLOSE A000 + ENDDO +) +PRINT "verify OK" +FLASH.RESet + +; Reset and boot +AREA.CLOSE A000 +DO "&scriptdir\e247_debug.cmm" +AREA.OPEN A000 "~~/e247_flash_factory_bin.log" /Append /NoFileCache +Go +; Detach: while attached, TRACE32 catches every reset at the reset vector, so +; a software reset (e.g. to start a firmware update) would leave the CPU halted +SYStem.Down +PRINT "done, board running, debugger detached" +AREA.CLOSE A000 + +ENDDO diff --git a/tools/scripts/mcxe247/e247_flash_update.cmm b/tools/scripts/mcxe247/e247_flash_update.cmm new file mode 100644 index 0000000000..a05f235380 --- /dev/null +++ b/tools/scripts/mcxe247/e247_flash_update.cmm @@ -0,0 +1,82 @@ +;; e247_flash_update.cmm +;; +;; Program the signed update image into the update partition of the NXP +;; MCXE247 (FRDM-MCXE247). +;; No arguments: DO e247_flash_update.cmm +;; +;; Connects with e247_debug.cmm (reset and halt), programs the image with the +;; TRACE32 S32K flash algorithm, verifies it, resets the board to boot and +;; detaches the debugger. +;; Range erased and programmed: 0x000C4000--0x0017BFFF. Every other flash area +;; is left as is. The update is not triggered: use the test-app console +;; command "trigger" followed by "reboot". +;; Output is logged to ~~/e247_flash_update.log +;; The image is taken from the wolfBoot checkout this script is in. + +; This script's directory, and the wolfBoot root three levels above it +&scriptdir=OS.PPD() +&basedir="&scriptdir\..\..\.." +&file="&basedir\test-app\image_v2_signed.bin" +&start=0x000C4000 +&end=0x0017BFFF + +DO "&scriptdir\e247_debug.cmm" + +AREA.OPEN A000 "~~/e247_flash_update.log" /Create /NoFileCache +PRINT "e247_flash_update.cmm " DATE.DATE() " " DATE.TIME() + +IF !SYStem.Up() +( + PRINT %ERROR "not connected, see ~~/e247_debug.log" + AREA.CLOSE A000 + ENDDO +) +IF !OS.FILE("&file") +( + PRINT %ERROR "&file not found" + AREA.CLOSE A000 + ENDDO +) +&size=OS.FILE.SIZE("&file") +IF &size>(&end-&start+1) +( + PRINT %ERROR "&file is larger than its partition" + AREA.CLOSE A000 + ENDDO +) + +; The flash algorithm runs from SRAM, which is ECC protected and must be +; written before it is read +Data.Set AD:0x20000000++0x215F %Long 0 + +; Vendor flash declaration: checks security, disables the watchdog +DO ~~/demo/arm/flash/s32k PREPAREONLY CPU=S32K148 DUALPORT=1 + +; Sectors in range not covered by the file are erased +PRINT "programming &file (" FORMAT.Decimal(0.,&size) " bytes) at "+FORMAT.HEX(8.,&start) +FLASH.ReProgram &start--&end /Erase +Data.LOAD.Binary "&file" &start +FLASH.ReProgram OFF + +Data.LOAD.Binary "&file" &start /DIFF +IF FOUND() +( + PRINT %ERROR "verify FAILED" + AREA.CLOSE A000 + ENDDO +) +PRINT "verify OK" +FLASH.RESet + +; Reset and boot +AREA.CLOSE A000 +DO "&scriptdir\e247_debug.cmm" +AREA.OPEN A000 "~~/e247_flash_update.log" /Append /NoFileCache +Go +; Detach: while attached, TRACE32 catches every reset at the reset vector, so +; the software reset that starts the update would leave the CPU halted +SYStem.Down +PRINT "done, board running, debugger detached" +AREA.CLOSE A000 + +ENDDO From 8d9863307fecac11e704453894d1181999f1c7b4 Mon Sep 17 00:00:00 2001 From: Thomas Cook Date: Wed, 11 Nov 2026 13:08:54 -0500 Subject: [PATCH 5/5] fix source path resolution for wolfip objects --- docs/Targets.md | 2 +- tools/scripts/mcxe247/e247_debug.cmm | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/Targets.md b/docs/Targets.md index 1e63ef5c5d..e889bdf78a 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -7408,7 +7408,7 @@ example `DO /tools/scripts/mcxe247/e247_flash_factory_bin.cmm`: | Script | Purpose | |--------|---------| -| `e247_debug.cmm` | Reset and halt the CPU, then load the `wolfboot.elf` and `test-app/image.elf` symbols | +| `e247_debug.cmm` | Reset and halt the CPU, then load the `wolfboot.elf` and `test-app/image.elf` symbols. Takes the MCUXpresso SDK path as an optional argument, used to find the ENET driver sources (default: `../NXP/mcuxpresso-sdk/mcuxsdk` next to the checkout) | | `e247_flash_factory_bin.cmm` | Program `factory.bin`, erase the update partition and swap sector, then reset and detach | | `e247_flash_update.cmm` | Program `test-app/image_v2_signed.bin` into the update partition, then reset and detach | diff --git a/tools/scripts/mcxe247/e247_debug.cmm b/tools/scripts/mcxe247/e247_debug.cmm index f07c30d4d0..6367cddbca 100644 --- a/tools/scripts/mcxe247/e247_debug.cmm +++ b/tools/scripts/mcxe247/e247_debug.cmm @@ -2,7 +2,10 @@ ;; ;; Connect TRACE32 to the NXP MCXE247 (FRDM-MCXE247) and halt the CPU at the ;; reset vector, then load the wolfBoot and test-app symbols. -;; No arguments: DO e247_debug.cmm +;; Usage: DO e247_debug.cmm [""] +;; The SDK dir is only used to find the fsl_enet and PHY driver sources of a +;; test-app built with ENABLE_WOLFIP=1. It defaults to the MCUXPRESSO path in +;; mcxe247.config (../NXP/mcuxpresso-sdk/mcuxsdk, next to the checkout). ;; ;; Board setup (UM12286): ;; - Lauterbach 10-pin cable on J14 (SWD/JTAG 2x5 header) @@ -16,8 +19,12 @@ ;; - All output, including errors, is logged to ~~/e247_debug.log ;; - The ELF files are loaded from the wolfBoot checkout this script is in. +PARAMETERS &sdkdir + ; wolfBoot root: three levels above this script &basedir=OS.PPD()+"\..\..\.." +IF "&sdkdir"=="" + &sdkdir="&basedir\..\NXP\mcuxpresso-sdk\mcuxsdk" AREA.OPEN A000 "~~/e247_debug.log" /Create /NoFileCache PRINT "e247_debug.cmm " DATE.DATE() " " DATE.TIME() @@ -80,7 +87,20 @@ IF OS.FILE("&basedir\test-app\image.elf") ; The ELF files hold the paths of the build machine. Look the sources up in ; this checkout instead, so it also works when TRACE32 runs on another host ; (e.g. Windows with the checkout in WSL). +; Sources are found by file name in these directories. sYmbol.SourcePATH.SetBaseDir "&basedir" -sYmbol.SourcePATH.Set "&basedir" "&basedir\src" "&basedir\hal" "&basedir\test-app" "&basedir\lib\wolfssl\wolfcrypt\src" +&srcdirs="""&basedir"" ""&basedir\src"" ""&basedir\hal"" ""&basedir\test-app""" +&srcdirs="&srcdirs ""&basedir\lib\wolfssl\wolfcrypt\src""" +; wolfIP and its MCXE247 port (test-app built with ENABLE_WOLFIP=1) +&srcdirs="&srcdirs ""&basedir\lib\wolfip\src"" ""&basedir\lib\wolfip\src\tftp""" +&srcdirs="&srcdirs ""&basedir\lib\wolfip\src\port\nxp_mcxe_enet""" +; MCUXpresso SDK drivers used by the wolfIP port, if the SDK is there +IF OS.DIR("&sdkdir") +( + &srcdirs="&srcdirs ""&sdkdir\drivers\enet"" ""&sdkdir\drivers\common""" + &srcdirs="&srcdirs ""&sdkdir\devices\MCX\MCXE\MCXE247\drivers""" + &srcdirs="&srcdirs ""&sdkdir\components\phy\device\phylan8741""" +) +sYmbol.SourcePATH.Set &srcdirs ENDDO