Skip to content

Add PIC32MZ EF bare-metal wolfIP port: clocks, UART2, wolfCrypt RNG, LAN8740 PHY#140

Open
dgarske wants to merge 1 commit into
wolfSSL:masterfrom
dgarske:pic32mz
Open

Add PIC32MZ EF bare-metal wolfIP port: clocks, UART2, wolfCrypt RNG, LAN8740 PHY#140
dgarske wants to merge 1 commit into
wolfSSL:masterfrom
dgarske:pic32mz

Conversation

@dgarske

@dgarske dgarske commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

New bare-metal wolfIP port for the Microchip PIC32MZ EF Starter Kit (PIC32MZ2048EFM144, MIPS32 M-class) with a LAN8740 PHY daughter board over RMII. This is a brand-new architecture for wolfIP (first MIPS/PIC32 target) and also verifies wolfCrypt's built-in hardware TRNG (WOLFSSL_PIC32MZ_RNG). Early bring-up code is factored so a future wolfBoot PIC32MZ port can reuse it. All new code lives under src/port/pic32mz/.

Features

  • Command-line build with Microchip XC32 (make, xc32-gcc), matching the other wolfIP ports; no MPLAB X project required. Targets 32MZ2048EFM144 via the PIC32MZ-EF DFP, -O1 (free XC32 tier).
  • Device configuration + 200 MHz clock setup (device_config.c, clock_init.c): DEVCFG0-3 config words (POSC EC 24 MHz -> SPLL 200 MHz SYSCLK, PBCLK2/PBCLK5 = 100 MHz, RMII selected), flash wait-states and prefetch. Isolated for wolfBoot reuse.
  • UART2 console (uart_console.c): 115200 8N1 on RPB14 (U2TX) / RPG6 (U2RX) with PPS mapping, plus XC32 _mon_putc retarget so printf goes to the serial console.
  • Millisecond timebase (timebase.c): 64-bit millis() derived from the CP0 core-timer with software wrap extension; drives the wolfIP poll loop.
  • wolfCrypt hardware TRNG self-test (rng_selftest.c, user_settings.h): exercises WOLFSSL_PIC32MZ_RNG, generating and sanity-checking random blocks; a failing self-test is treated as fatal. Compiles the needed wolfcrypt sources directly from the sibling wolfssl checkout; keeps the crypto engine hash/AES acceleration off so SHA-256 (DRBG) stays software for this milestone.
  • PIC32MZ Ethernet MAC driver (pic32mz_eth.c): EMAC + RMII + MII-management bring-up, clause-22 MDIO read/write primitives, PBCLK5 / PMD6 module enable before EMAC access, and full RX/TX DMA descriptor rings (coherent/uncached buffers) wired to the wolfIP poll/send device ops.
  • LAN8740 PHY driver (phy_lan8740.c): MAC-agnostic (function-pointer MDIO), scans for the PHY, resets, advertises 10/100 full/half, runs auto-negotiation, and reports resolved link speed/duplex. Distinguishes a non-fatal "link down" result from real MDIO/PHY errors.
  • MIPS cache/DMA helpers (cache.h): KSEG0/KSEG1 and virtual/physical macros for coherent EMAC descriptor/buffer access.
  • Demo application (main.c): TRNG self-test, DHCP client, and a TCP echo server on port 7 (or a throughput server on port 9 in the SPEED_TEST build). Fatal bring-up failures (RNG, Ethernet, socket setup) halt the board rather than continue in a partial state.
  • CLI flashing over an MPLAB ICD 5 (make flash): programs the hex via MDB (MPLAB X v6.30), erase-before-program, on the ICSP/debug header; the tool is overridable with MDB= / MDB_TOOL=. (Headless ipecmd cannot resolve device packs; MDB can.)

Hardware verification status

Verified on hardware (PIC32MZ EF Starter Kit, LAN8740 over RMII, flashed via MPLAB ICD 5):

  • Clocks + UART + timebase: accurate 1 Hz heartbeat.
  • wolfCrypt PIC32MZ hardware TRNG: RNG self-test: PASS, distinct entropy each boot.
  • Ethernet MAC/PHY: LAN8740 link up, DHCP bound, ICMP echo, and TCP echo (port 7) round-trip confirmed.

@dgarske dgarske self-assigned this Jul 3, 2026
Copilot AI review requested due to automatic review settings July 3, 2026 00:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new bare-metal PIC32MZ EF architecture port under src/port/pic32mz/, providing early bring-up infrastructure (clocks, UART console, timebase), a wolfCrypt hardware TRNG self-test configuration, and initial Ethernet EMAC MDIO + LAN8740 PHY link bring-up scaffolding.

Changes:

  • Introduces PIC32MZ EF device configuration and 200 MHz clock/flash setup, plus a CP0-based millisecond timebase.
  • Adds UART2 console support with XC32 printf retargeting and a standalone wolfCrypt RNG self-test using WOLFSSL_PIC32MZ_RNG.
  • Adds initial EMAC MII-management (MDIO) routines and a MAC-agnostic LAN8740 PHY bring-up module, with a command-line XC32 Makefile build/flash flow.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/port/pic32mz/.gitignore Ignores XC32/MDB build and flash artifacts for the new port.
src/port/pic32mz/Makefile XC32-based command-line build/flash rules and wolfCrypt source inclusion for self-test.
src/port/pic32mz/board.h Board- and clock-related constants (SYSCLK/PBCLK, UART pins, LEDs).
src/port/pic32mz/cache.h MIPS KSEG address helpers intended for coherent DMA/EMAC access patterns.
src/port/pic32mz/clock_init.c Flash wait-state and prefetch configuration for 200 MHz operation.
src/port/pic32mz/clock_init.h Declares clock/flash init routine for the port.
src/port/pic32mz/device_config.c PIC32MZ DEVCFG0-3 configuration word settings for the target board.
src/port/pic32mz/main.c Bring-up application tying together clock, UART, timebase, RNG self-test, and PHY init.
src/port/pic32mz/phy_lan8740.c LAN8740 PHY scanning/reset/autoneg/link reporting via MDIO function pointers.
src/port/pic32mz/phy_lan8740.h PHY driver API and link-status struct definitions.
src/port/pic32mz/pic32mz_eth.c EMAC module enable/reset and clause-22 MDIO read/write primitives.
src/port/pic32mz/pic32mz_eth.h EMAC/MDIO init and accessor function declarations.
src/port/pic32mz/rng_selftest.c Standalone RNG self-test using wolfCrypt WC_RNG + coarse sanity checks.
src/port/pic32mz/rng_selftest.h Declares the RNG self-test entrypoint.
src/port/pic32mz/timebase.c CP0 Count-derived 64-bit extended counter and millis()/delay_ms().
src/port/pic32mz/timebase.h Declares millis()/delay_ms() timebase API.
src/port/pic32mz/uart_console.c UART2 init, TX/RX helpers, and XC32 _mon_putc retarget.
src/port/pic32mz/uart_console.h UART console API declarations and usage notes.
src/port/pic32mz/user_settings.h wolfCrypt feature selection for PIC32MZ RNG self-test (trimmed algorithms, no FS/sockets).
src/port/pic32mz/wolf_compat.c wolfCrypt min/max shim functions for the bare-metal environment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/port/pic32mz/Makefile
Comment thread src/port/pic32mz/Makefile Outdated
Comment thread src/port/pic32mz/main.c Outdated
Comment thread src/port/pic32mz/pic32mz_eth.c
@dgarske
dgarske force-pushed the pic32mz branch 3 times, most recently from e8db0cf to 4e409fe Compare July 7, 2026 23:44
@dgarske
dgarske requested a review from Copilot July 7, 2026 23:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 8 comments.

Comment thread src/port/pic32mz/user_settings.h
Comment thread src/port/pic32mz/phy_lan8740.c
Comment thread src/port/pic32mz/phy_lan8740.c Outdated
Comment thread src/port/pic32mz/pic32mz_eth.c
Comment thread src/port/pic32mz/main.c
Comment thread src/port/pic32mz/main.c
Comment thread src/port/pic32mz/README.md Outdated
Comment thread src/port/pic32mz/Makefile Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.

Comment thread src/port/pic32mz/wolf_compat.c Outdated
Comment thread src/port/pic32mz/Makefile Outdated
Comment thread src/port/pic32mz/main.c Outdated
Comment thread src/port/pic32mz/main.c
Comment thread src/port/pic32mz/pic32mz_eth.c Outdated
@dgarske
dgarske marked this pull request as ready for review July 10, 2026 23:08
@dgarske dgarske assigned danielinux and wolfSSL-Bot and unassigned dgarske Jul 11, 2026
@dgarske
dgarske requested a review from wolfSSL-Bot July 11, 2026 00:10
Comment on lines +78 to +82
#pragma config FMIIEN = OFF /* RMII (LAN8740 PHY daughter board) */
/* FETHIO selects the default (ON) vs alternate (OFF) Ethernet I/O pins; it
* also moves the RMII reference-clock input (EREFCLK: RB4 default / RJ11
* alternate). Set to the board's routing for the 50 MHz PHY REFCLK. */
#pragma config FETHIO = ON /* default Ethernet I/O pin set */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

device_config.c and pic32mz_eth.c disagree about which pin carries EREFCLK under FETHIO = ON
This comment says the default pin set puts the RMII reference clock on RB4, with RJ11 as the alternate:

 /* FETHIO selects the default (ON) vs alternate (OFF) Ethernet I/O pins; it
  * also moves the RMII reference-clock input (EREFCLK: RB4 default / RJ11
  * alternate). Set to the board's routing for the 50 MHz PHY REFCLK. */
 #pragma config FETHIO =     ON       /* default Ethernet I/O pin set */

But pic32mz_eth.c:362-366 states the opposite for the same FETHIO = ON setting, and the code acts on it:

 /* On the 144-pin default (FETHIO=ON) pinout the 50 MHz
  * reference clock EREFCLK is on RJ11, which is also AN4/C1INB: left
  * analog, the MAC data path gets no clock, so TX stalls mid-frame and RX
  * never clocks in (MDIO/link still work on their own MDC clock). */
 ANSELJCLR = (1u << 11) | (1u << 8) | (1u << 9); /* RJ11 EREFCLK, RJ8/RJ9 ETXD0/1 */

Both cannot be right, and pic32mz_eth.c is the one the hardware validates: the PR reports working DHCP/ICMP/TCP echo, which by that same comment's reasoning is only possible if the ANSELJ11 clear is hitting the actual EREFCLK pin. If device_config.c were right, RB4 would still be analog and nothing would clock in. So the code is correct and this comment is wrong.

Comment on lines +373 to +374
/* LAN8740 link (fills speed/duplex even if the link is currently down). */
ret = phy_lan8740_bringup(pic32mz_mdio_read, pic32mz_mdio_write, 5000u,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment's premise is false. phy_lan8740_bringup() zeroes speed_100 and full_duplex at entry (phy_lan8740.c:114-115) and only fills them from the SCSR read at phy_lan8740.c:158-178, which is reached after the link-up wait. The timeout path returns -2 at phy_lan8740.c:153, before that read — so on link-down both fields are still 0.

pic32mz_eth_init() then commits those zeros to hardware: EMAC1CFG2 without FULLDPLX, EMAC1IPGT = 0x12 (the half-duplex gap), and EMAC1SUPPbits.SPEEDRMII = 0 (10 Mbps RMII). main.c:203 prints "PHY link down at startup (check cable) - continuing", and the main loop at main.c:252-292 never re-reads the PHY or reconfigures the MAC. So a cable inserted after boot negotiates 100BASE-TX full duplex at the PHY while the MAC stays in 10 Mbps half-duplex RMII — link LED on, no traffic, and no path back short of a reset. The -2-is-non-fatal design and the "continuing" message both promise a recovery the code doesn't implement.

This is invisible to the hardware verification in the PR description, since all of it was done with the cable already connected.

Minimal fix — assume the case a later insert will almost certainly negotiate, so the MAC is at least configured correctly when the link does come up:

Suggested change
/* LAN8740 link (fills speed/duplex even if the link is currently down). */
ret = phy_lan8740_bringup(pic32mz_mdio_read, pic32mz_mdio_write, 5000u,
/* LAN8740 link. A -2 (link-down) result leaves speed/duplex unresolved,
* and the MAC is configured once here and never revisited, so assume
* 100BASE-TX full duplex: that is what a later cable insert will
* negotiate in practice. */
ret = phy_lan8740_bringup(pic32mz_mdio_read, pic32mz_mdio_write, 5000u,
&link);
if (ret == -2) {
link.speed_100 = 1;
link.full_duplex = 1;
}

The complete fix is a pic32mz_eth_link_update() that re-reads BMSR/SCSR and re-applies EMAC1CFG2 / EMAC1IPGT / EMAC1SUPP.SPEEDRMII on change, called from the existing 1 Hz heartbeat in main.c:273. That also fixes the symmetric case this port has today: a cable unplugged and moved to a 10 Mbps switch is equally stuck. If you'd rather defer that, the honest interim is the snippet above plus dropping "check cable - continuing" from main.c:204, since recovery is reset-only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants