Skip to content

Commit 1d5a069

Browse files
committed
Add PIC32MZ EF bare-metal wolfIP port: clocks, UART2, wolfCrypt RNG, LAN8740 PHY
1 parent 2515829 commit 1d5a069

22 files changed

Lines changed: 1874 additions & 0 deletions

src/port/pic32mz/.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Build artifacts
2+
*.o
3+
app.elf
4+
app.hex
5+
app.map
6+
# MDB / IPE transient files
7+
mdb_flash.cmd
8+
MPLABXLog.*
9+
log.*

src/port/pic32mz/Makefile

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# wolfIP PIC32MZ EF port - build with Microchip XC32
2+
#
3+
# Copyright (C) 2026 wolfSSL Inc. Part of the wolfIP TCP/IP stack (GPLv3).
4+
#
5+
# Phase 0: clocks + UART2 console + heartbeat.
6+
# Phase 1: wolfCrypt PIC32MZ hardware TRNG self-test.
7+
# Phase 2: MDIO + LAN8740 PHY link bring-up.
8+
# (Full Ethernet RX/TX driver + wolfIP core are added in later phases.)
9+
#
10+
# Usage:
11+
# make # build app.hex
12+
# make flash # program over the on-board debugger (v6.20 IPE)
13+
# make clean
14+
# Overridable:
15+
# XC32_BIN= XC32 bin dir (default /opt/microchip/xc32/v5.10/bin)
16+
# DFP= device family pack version dir
17+
# DEVICE= 32MZ2048EFM144
18+
# WOLFSSL_ROOT= path to wolfssl checkout (used from Phase 1 on)
19+
# MDB= MPLAB X MDB CLI (default v6.20; v6.30 dropped the EF SK debugger)
20+
21+
XC32_BIN ?= /opt/microchip/xc32/v5.10/bin
22+
DFP ?= /opt/microchip/mplabx/v6.30/packs/Microchip/PIC32MZ-EF_DFP/1.5.173
23+
DEVICE ?= 32MZ2048EFM144
24+
25+
CC := $(XC32_BIN)/xc32-gcc
26+
BIN2HEX := $(XC32_BIN)/xc32-bin2hex
27+
SIZE := $(XC32_BIN)/xc32-size
28+
29+
# Flashing via MDB (Microchip DeBugger CLI). The headless ipecmd cannot resolve
30+
# device packs ("Unable to locate DFP"), but MDB launches the full platform and
31+
# resolves them like the IDE/IPE GUI does. Default tool is an MPLAB ICD 5 on the
32+
# ICSP header; the EF Starter Kit's flaky on-board debugger (MDB tool type "sk",
33+
# only in v6.20) proved unreliable over USB, so an external debugger is preferred.
34+
MDB ?= /opt/microchip/mplabx/v6.30/mplab_platform/bin/mdb.sh
35+
MDB_DEVICE ?= PIC32MZ2048EFM144
36+
MDB_TOOL ?= icd5
37+
38+
ROOT := ../../..
39+
# Default to a wolfssl checkout sitting beside the wolfip repo.
40+
WOLFSSL_ROOT ?= $(ROOT)/../wolfssl
41+
42+
# -O1 is available in the free XC32 edition (-O2/-Os/-O3 need a PRO license).
43+
CFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)"
44+
CFLAGS += -O1 -g -Wall -Wextra -ffunction-sections -fdata-sections
45+
CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src
46+
CFLAGS += -DWOLFSSL_USER_SETTINGS -I$(WOLFSSL_ROOT)
47+
CFLAGS += $(EXTRA_CFLAGS)
48+
49+
# Heap for the Hash-DRBG (wc_InitRng allocates the DRBG state).
50+
LDFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)"
51+
LDFLAGS += -Wl,--defsym,_min_heap_size=0x8000
52+
LDFLAGS += -Wl,--gc-sections -Wl,-Map=app.map,--cref
53+
54+
# Port + application sources (strict warnings)
55+
APP_SRCS := device_config.c clock_init.c uart_console.c timebase.c \
56+
wolf_compat.c rng_selftest.c pic32mz_eth.c phy_lan8740.c main.c
57+
APP_OBJS := $(patsubst %.c,%.o,$(APP_SRCS))
58+
59+
# wolfcrypt sources for the RNG self-test (compiled with relaxed warnings).
60+
# Pulled directly from the sibling wolfssl checkout, no copy.
61+
WC_SRC := $(WOLFSSL_ROOT)/wolfcrypt/src
62+
WC_NAMES := random sha256 hash wc_port logging memory error
63+
WC_OBJS := $(addsuffix .o,$(addprefix wc_,$(WC_NAMES)))
64+
CFLAGS_WC := -mprocessor=$(DEVICE) -mdfp="$(DFP)" -O1 -g \
65+
-ffunction-sections -fdata-sections \
66+
-DWOLFSSL_USER_SETTINGS -I. -I$(WOLFSSL_ROOT)
67+
68+
# wolfIP core stack (relaxed warnings; does not need wolfssl).
69+
CFLAGS_CORE := -mprocessor=$(DEVICE) -mdfp="$(DFP)" -O1 -g \
70+
-ffunction-sections -fdata-sections -I. -I$(ROOT) -I$(ROOT)/src
71+
72+
ALL_OBJS := $(APP_OBJS) wolfip.o $(WC_OBJS)
73+
74+
all: app.hex
75+
@echo "Built PIC32MZ wolfIP port"
76+
@$(SIZE) app.elf
77+
78+
app.elf: $(ALL_OBJS)
79+
$(CC) $(CFLAGS) $(ALL_OBJS) $(LDFLAGS) -o $@
80+
81+
app.hex: app.elf
82+
$(BIN2HEX) $<
83+
84+
%.o: %.c
85+
$(CC) $(CFLAGS) -c $< -o $@
86+
87+
wc_%.o: $(WC_SRC)/%.c
88+
$(CC) $(CFLAGS_WC) -c $< -o $@
89+
90+
wolfip.o: $(ROOT)/src/wolfip.c
91+
$(CC) $(CFLAGS_CORE) -c $< -o $@
92+
93+
# Program the hex over an MPLAB ICD 5 (on the ICSP/debug header) via MDB. Close
94+
# the MPLAB X IPE/IDE GUI first so it isn't holding the tool. Command script:
95+
# set programoptions.eraseb4program true -> full chip erase before program
96+
# hwtool icd5 -p -> connect the ICD 5 for programming
97+
# program <app.hex> / Reset -> program, then release from reset
98+
# The trailing "Reset" is required: -p alone leaves the target held in reset.
99+
# See the mplab-icd5 skill for connection/wiring troubleshooting.
100+
flash: app.hex
101+
@printf 'device %s\nset programoptions.eraseb4program true\nhwtool %s -p\nprogram %s\nReset\nquit\n' \
102+
"$(MDB_DEVICE)" "$(MDB_TOOL)" "$(CURDIR)/app.hex" > mdb_flash.cmd
103+
cd $(dir $(MDB)) && sh ./mdb.sh $(CURDIR)/mdb_flash.cmd
104+
105+
clean:
106+
rm -f *.o app.elf app.hex app.map mdb_flash.cmd MPLABXLog.* log.*
107+
108+
.PHONY: all clean flash

src/port/pic32mz/README.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# wolfIP PIC32MZ EF Port
2+
3+
Bare-metal [wolfIP](../../../README.md) port for the **Microchip PIC32MZ EF**
4+
(PIC32MZ2048EFM144, MIPS32 M-class) with a **LAN8740** PHY over RMII. Built
5+
with the Microchip XC32 toolchain; no MPLAB X project or Harmony framework
6+
required. Also exercises wolfCrypt's built-in hardware TRNG
7+
(`WOLFSSL_PIC32MZ_RNG`).
8+
9+
## Hardware
10+
11+
- **MCU:** PIC32MZ2048EFM144 (200 MHz, 2 MB flash, 512 KB RAM), EF Starter Kit.
12+
- **PHY:** LAN8740 daughter board over RMII (PHY drives the 50 MHz reference clock).
13+
- **Console:** UART2, `U2TX` on RPB14 / `U2RX` on RPG6, 115200 8N1.
14+
- **Programmer:** MPLAB ICD 5 on the ICSP/debug header (see the mplab-icd5 skill).
15+
16+
## Layout
17+
18+
| File | Purpose |
19+
|------|---------|
20+
| `device_config.c` | DEVCFG config words: 200 MHz PLL (POSC EC 24 MHz), RMII, watchdog off. |
21+
| `clock_init.c/.h` | Flash wait-states + prefetch. Reusable early bring-up (wolfBoot). |
22+
| `cache.h` | MIPS KSEG0/KSEG1 + virtual/physical helpers for DMA memory. |
23+
| `uart_console.c/.h` | UART2 console + XC32 `_mon_putc` `printf` retarget. |
24+
| `timebase.c/.h` | 64-bit `millis()` from the CP0 core timer. |
25+
| `pic32mz_eth.c/.h` | EMAC + RMII + MDIO bring-up, DMA descriptor rings, `poll`/`send`. |
26+
| `phy_lan8740.c/.h` | MAC-agnostic clause-22 LAN8740 driver (scan, autoneg, link). |
27+
| `rng_selftest.c/.h` | wolfCrypt hardware-TRNG self-test. |
28+
| `user_settings.h` | wolfCrypt configuration (`WOLFSSL_MICROCHIP_PIC32MZ`). |
29+
| `config.h` | wolfIP profile (MTU, socket counts, DHCP). |
30+
| `main.c` | TRNG self-test, DHCP, and a TCP echo / throughput server. |
31+
32+
## Build
33+
34+
Requires XC32 (>= v5.10) and the PIC32MZ-EF DFP, plus a wolfssl checkout beside
35+
the wolfip repo (override with `WOLFSSL_ROOT=`).
36+
37+
```sh
38+
make # -> app.hex
39+
make SPEED_TEST=1 EXTRA_CFLAGS=-DSPEED_TEST # throughput server on port 9
40+
make flash # program over MPLAB ICD 5 (MDB)
41+
make clean
42+
```
43+
44+
Overridable: `XC32_BIN`, `DFP`, `DEVICE`, `WOLFSSL_ROOT`, `MDB`, `MDB_TOOL`.
45+
46+
## Test
47+
48+
Console at 115200 8N1. On boot the firmware prints the banner, the RNG
49+
self-test result, the resolved PHY link, and (once bound) the DHCP address:
50+
51+
```
52+
=== wolfIP PIC32MZ EF port ===
53+
[RNG] self-test: PASS
54+
Ethernet init (LAN8740 over RMII)...
55+
DHCP bound: 10.0.4.x
56+
TCP service listening on port 7
57+
```
58+
59+
Then, from a host on the same network:
60+
61+
```sh
62+
ping <ip>
63+
echo hello | nc <ip> 7 # echo (default build)
64+
dd if=/dev/zero bs=1460 count=700 | nc <ip> 9 # RX throughput (SPEED_TEST build)
65+
nc <ip> 9 </dev/null | pv >/dev/null # TX throughput (SPEED_TEST build)
66+
```
67+
68+
## Notes
69+
70+
- DMA descriptors/buffers use XC32 `__attribute__((coherent))` (uncached), so
71+
no cache maintenance is needed; the EMAC is given physical addresses.
72+
- The Ethernet module needs PBCLK5 enabled and `PMD6.ETHMD` cleared before any
73+
EMAC register access — `pic32mz_emac_mii_init()` does this first.
74+
- Build with `EXTRA_CFLAGS=-DPIC32_ETH_TRACE` to trace the EMAC bring-up.

src/port/pic32mz/board.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* board.h
2+
*
3+
* Board constants for the PIC32MZ EF Starter Kit (DM320007) + LAN8740 PHY DB.
4+
*
5+
* Copyright (C) 2026 wolfSSL Inc.
6+
*
7+
* This file is part of wolfIP TCP/IP stack.
8+
*
9+
* wolfIP is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation; either version 3 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* wolfIP is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
22+
*/
23+
#ifndef PIC32MZ_BOARD_H
24+
#define PIC32MZ_BOARD_H
25+
26+
/* Clock tree (set by DEVCFG config words at reset; see device_config.c) */
27+
#define SYS_CLK_FREQ 200000000ul /* SYSCLK from SPLL */
28+
#define PBCLK2_FREQ 100000000ul /* peripheral bus 2 (UART) = SYSCLK/2 */
29+
#define PBCLK5_FREQ 100000000ul /* peripheral bus 5 (EMAC) = SYSCLK/2 */
30+
31+
/* Console UART: U2TX on RPB14, U2RX on RPG6 (external MCP2221 USB-UART) */
32+
#define CONSOLE_BAUD 115200u
33+
34+
/* On-board LEDs LED1/LED2/LED3 on RH0/RH1/RH2 (active high) */
35+
#define LED_MASK 0x0007u
36+
#define LED_HEARTBEAT 0x0001u /* LED1 = RH0 */
37+
38+
#endif /* PIC32MZ_BOARD_H */

src/port/pic32mz/cache.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* cache.h
2+
*
3+
* MIPS KSEG segment helpers for DMA-coherent access on PIC32MZ.
4+
*
5+
* Copyright (C) 2026 wolfSSL Inc.
6+
*
7+
* This file is part of wolfIP TCP/IP stack.
8+
*
9+
* wolfIP is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation; either version 3 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* wolfIP is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program; if not, write to the Free Software
21+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
22+
*/
23+
#ifndef PIC32MZ_CACHE_H
24+
#define PIC32MZ_CACHE_H
25+
26+
#include <stdint.h>
27+
28+
/* The PIC32MZ Ethernet controller (EMAC) is not cache-coherent and programs
29+
* its descriptor base/buffer pointers with PHYSICAL addresses. The simplest
30+
* coherent scheme on MIPS is to access all descriptor rings and DMA buffers
31+
* through KSEG1 (uncached) virtual aliases and hand the EMAC the physical
32+
* address. This avoids per-operation cache clean/invalidate entirely.
33+
*
34+
* Equivalent to XC32 <sys/kmem.h> KVA0_TO_KVA1 / KVA_TO_PA / PA_TO_KVA1, but
35+
* kept self-contained so the early bare-metal layer can be lifted into
36+
* wolfBoot without pulling in the XC32 system headers.
37+
*/
38+
39+
/* Cached KSEG0 virtual address -> uncached KSEG1 virtual address */
40+
#define PIC32_KVA0_TO_KVA1(v) (((uint32_t)(v)) | 0x20000000u)
41+
42+
/* Any KSEG0/KSEG1 virtual address -> physical address (for the EMAC) */
43+
#define PIC32_KVA_TO_PA(v) (((uint32_t)(v)) & 0x1FFFFFFFu)
44+
45+
/* Physical address -> uncached KSEG1 virtual address */
46+
#define PIC32_PA_TO_KVA1(pa) (((uint32_t)(pa)) | 0xA0000000u)
47+
48+
/* Pointer helper: uncached view of a normally-allocated object */
49+
#define PIC32_UNCACHED(p) ((void *)PIC32_KVA0_TO_KVA1(p))
50+
51+
#endif /* PIC32MZ_CACHE_H */

src/port/pic32mz/clock_init.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* clock_init.c
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfIP TCP/IP stack.
6+
*
7+
* wolfIP is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfIP is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
#include <xc.h>
22+
#include "clock_init.h"
23+
24+
void clock_init(void)
25+
{
26+
/* Flash wait-states + prefetch for 200 MHz SYSCLK.
27+
* PFMWS = 2 wait-states is required above ~134 MHz on PIC32MZ EF.
28+
* PREFEN = 3 enables predictive prefetch for cacheable and
29+
* non-cacheable regions. PRECON is not lock-protected. */
30+
PRECONbits.PFMWS = 2;
31+
PRECONbits.PREFEN = 3;
32+
33+
/* Peripheral buses PBCLK2 (UART) and PBCLK5 (EMAC) remain at their
34+
* reset default of SYSCLK/2 = 100 MHz, which is what this port targets.
35+
* The L1 cache and KSEG0 coherency are enabled by the XC32 reset
36+
* startup code, so nothing is done here for v1. */
37+
}

src/port/pic32mz/clock_init.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* clock_init.h
2+
*
3+
* Copyright (C) 2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfIP TCP/IP stack.
6+
*
7+
* wolfIP is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfIP is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
#ifndef PIC32MZ_CLOCK_INIT_H
22+
#define PIC32MZ_CLOCK_INIT_H
23+
24+
/* Configure flash wait-states / prefetch for 200 MHz operation.
25+
* The PLL itself is brought up at reset from the DEVCFG config words
26+
* (FNOSC=SPLL), so by the time main() runs SYSCLK is already 200 MHz.
27+
* Bare-metal reusable (intended to be lifted into a future wolfBoot port). */
28+
void clock_init(void);
29+
30+
#endif /* PIC32MZ_CLOCK_INIT_H */

0 commit comments

Comments
 (0)