Embedded Ethernet Module (A3053) Design and Development

© 2025 Kevan Hashemi, Open Source Instruments Inc.

Contents

Design
Development
Q3-25Q4-25

Design

[19-SEP-25] All our designs are free and open-source, copyright Open Source Instruments Inc, under the GPL 3.0 license.

Development

Q3-25

[04-AUG-25] Settle upon MCU and Ethernet PHY. In this HTML page we are trying out a Markdown renderer, which we may or may not employ in new entries. Examine the HTML source code for the markdown script and configuration. We use a dedicated "md" tag for the Markdown fields. If the browser fails to load the converter JavaScript, the HTML will instead replace the "md" with a "pre" field so we can still see the Markdown formatting.

[08-AUG-25] We want the PIC32MZ in TQFP-100 to provide an RMII (Reduced Media Independent Interface), JTAG (four-wire programming of PIC32MZ), ISCP (two-wire programming of PIC32MZ), and an eight-bit external data buse (for communicating with the LWDAQ controller). We will have the PIC32MZ as U1 on the circuit, the LAN8720A Ethernet physical layer as U2, and the MPCIE connector as P1. Here are the required connections between U1 and U2 for the RMII.

PIC32MZ Signal U1 Pin LAN8720A Signal U2 Pin Description
ERXD0U1-41RXD0/MODE0U2-8Receive Data 0
ERXD1U1-42RXD1/MODE1U2-7Receive Data 1
ERXERRU1-35RXERU2-10Receive Error Input
ETXD0U1-86TXD0U2-17Transmit Data 0
ETXD1U1-85TXD1U2-18Transmit Data 1
ETXENU1-77TXENU2-16Transmit Enable
EMDCU1-70MDCU2-13Management Data Clock
EMDIOU1-71MDIOU2-12Management Data
EREFCLKU1-16REFCLKOU2-14Reference Clock Out
ECRSDVU1-12CRS_DV/MODE2U2-11Carrier Sense Data Valid
Table: Reduced Media Independent Interface (RMII) Bus Between PIC32MZ and LAN8720A LAN8720A. Copied from PIC32MZ data sheet, Table 1-17, TQFP-100 package pins. The REFCLKO to EREFCLK connection is one way to synchronize the bus.

The LAN8720A requires /RESET on its nRST input, U2-15, which arrives on the board through mPCIe pin P1-16. There are various ways to provide a clock for the synchronous RMII bus. We will load a single 50-MHz oscillator on our board and drive three inputs with the oscillator signal directly: U1-16, U1-49, and U2-5. These are the EREFCLK and OSC1 inputs of the PIC32MZ, and the XTAL1 input of the LAN8720A. We leave U2-4 floating. We route unused, multi-purpose GPIOs from the PIC32MZ to all the connections on the mPCIe connector that have a signal function on the RCM6700. For the six programming connections, we give the programming bus name and the short signal name. These signals are PGC and PGC for the ICSP bus and TCK, TMS, TDI, and TDO for the JTAG bus.

A3053A Signal RCM6700 Signal mPCIe Pin
0VGNDP1-1
+3V3+3.3 VP1-2
U2-21, TXPTx+P1-3
U2-23, RXPRx+P1-4
U2-20, TXNTx−P1-5
U2-22, RXNRx−P1-6
U2-3, LINKLNKP1-7
ECOMECOMP1-8
U1-97, RG13PE0P1-9
U1-2, RA5PE1P1-10
U1-10, RG6PE2P1-11
U1-82, RD5PE3P1-12
U1-11, RG7PE5P1-13
U1-81, RD4PE6P1-14
U1-18, RE8PE7P1-15
U1-15, /MCLR/RESET_INP1-16
U1-20, RB5PD0P1-17
U1-21, RB4PD1/IA6P1-18
U1-22, RB3PD2P1-19
U1-23, RB2PD3/IA7P1-20
U1-26, RB6PC0P1-21
U1-27, RB7PC1P1-22
U1-32, RB8PC2P1-23
U1-33, RB9PC3P1-24
U1-34, RB10PC4P1-25
U1-43, RB14PC5P1-26
U1-44, RB15PB0P1-27
U1-15, /MCLR/RESETP1-28
U1-6, RC1IA0P1-29
U1-7, RC2IA1P1-30
U1-8, RC3IA2P1-31
U1-9, RC4IA3P1-32
U1-91, RE0IA4P1-33
U1-94, RE1IA5P1-34
U1-72, SOSCI/RC13PA0P1-35
U1-73, SOSCO/RC14PA1P1-36
U1-98, RE2PA2P1-37
U1-99, RE3PA3P1-38
U1-100, RE4PA4P1-39
U1-3, RE5PA5P1-40
U1-4, RE6PA6P1-41
U1-5, RE7PA7P1-42
U1-28, RA9/IORDP1-43
U1-24, PGEC1/RB1VBAT_EXTP1-44
U1-19, RE9/IOWRP1-45
U1-38, TCK/RA1SCLKA/IA7P1-46
U1-25, PGED1/RB0STATUSP1-47
U1-17, TMS/RA0TXA/PC6P1-48
U1-39, TDI/RF13SMODEP1-49
U1-40, TDO/RF12RXA/PC7P1-50
0VGNDP1-51
+3V3+3.3 VP1-52
Table: Pin Assignments for the mPCIe Edge Connector. We provide A3053A assignments and RCM6700 assignments. Negative-true signals are prefixed by a forward slash.

The LAN8720A (U2) connections to the mPCIe (P1) contacts provide TX+, TX−, RX+, and RX− for 10/100 Ethernet. We also need ECOM, the Ethernet common-mode voltage. The RCM6700 provides 2.5 V for ECOM. The A3053A will provide 3.3 V. The LAN8720A works fine with a common-mode voltage equal to its supply voltage because its transmit and receive pins are AC-coupled within the chip. We assume that any RCM6700 motherboard will tolerate 3.3 V being driven in place of the 2.5 V that the RCM6700 provides for ECOM.

We consider whether we can program the PIC32MZ from an RCM6700 mother board using the mother board's 2×5 0.05" rectangular plug. We have the ICSP programming lines PGC and PGD routed to the rectangular plug. All we need is an adaptor from a two-row rectangular 0.05" receptacle to a one-row 0.1" plug.

PIC32MZ Signal mPCIe Pin 2×5 Header Pin RCM6700 Signal
MCLR165/RESET_IN
PGC447VBAT_EXT
PGD478STATUS
VDD524+3.3V
GND512GND
Table: ICSP Programming on an RCM6700 Mother Board.

In addition to the ICSP programming connections on the mPCIe connector, we also have all the pins necessary to create a JTAG programming interface on the mother board. These are TCK, TDI, TDO, and TMS. We can route these to a 2×5 0.1" rectangular plug for use with a Microchip JTAG programming cable. The table below gives the pinout of the JTAG plug that we might load on a motherboard designed for the A3053.

Pin Signal Notes
1VddTarget power
2GNDGround
3TCKJTAG Clock
4GNDGround
5TDIData In
6GNDGround
7TDOData Out
8GNDGround
9TMSMode Select
10GNDGround
Table: JTAG Programming on a Mother Board Designed for the A3053. The four JTAG signals are available on the mPCIe socket into which we plut the A3053. We route them to a 2×5 0.1" pitch rectangular plug on the mother board.

When our motherboard is designed for the A3053, we will load on it a 1×6 0.1" rectangular header for ICSP programming, using the standard Microchip programming pinout.

Pin Signal Notes
1/MCLRMicrocontroller Clear, Negative True
2VDDPositive Power Supply, +3.3 V
3GNDNegative Power Supply, 0.0 V
4PGDProgramming Data
5PGCProgramming Clock
6NCNo Connection
Table: ICSP Programming on a Mother Board Designed for the A3053. The three ICSP signals are available on the mPCIe socket into which we plug the A3053. We route them to a 1×6 0.1" pitch rectangular plug on the mother board.

We work our way through the LAN8720A configuration strap documentation. We want to set up our PHY with address zero, so we must pull down RXER with 12 kΩ, because this pin is the configuration strap for the PHY address. The MODE0-2 inputs we pull up to 3V3 so as to enable auto-negotiation and 10/100 Mbps. We pull down LED1 and LED2, which enables the internal 1.2V regulator and configures an interrupt we don't use. These pull-downs also make LET1 and LED2 active-HI. We add to the board a PO805 green LED for LED2, and we send LED1 off as LINK through the mPCIe. We can configure the behavior of these LED signals from the PIC32MZ during run-time. First version of the schematic, S3053A_1 drawn.

[12-AUG-25] We create an mPCIe template for KiCad and adjust its gold finger and corners in places by up to 100 μm in order to bring the dimensions and hole locations into exact agreement with the drawings. The finished template is mPCIe.zip. We begin the A305301A printed circuit board layout starting with the template.

[14-AUG-25] We concern ourselves with the distribution of our 50-MHz clock to three different logic inputs. It looks like we can do this with one trace of 11 mm and another of 24 mm. On the our ALT base board, we see reflections from an unterminated 1-m transmission line that are just enough to cause clock locking failure at 8 MHz. When we terminate with 47 Ω, the reflections vanish. The speed of propagation along the 7-mil track is about 200 m/μs, making the 8-MHz wavelength 25 m. The third harmonic of 8 MHz has wavelength 8 m, and one quarter of that is 2 m. We have problems when the line is one eighth of the wavelength of the third harmonic. In the case of 50-MHz, one eighth of the wavelength of the third harmonic will be 17 cm. Our 2.4-cm tracks are seven times smaller. We will route them and see what happens.


Figure: Drawing of the mCPIe Slot and Contacts. Taken from the mPCIe Specification.

We find that our existing mPCIe template has the contact pads 0.5 mm from the board edge, when the maximum should be 0.25 mm. The contact pads are 2.0 mm long when they should be 2.3 mm long. The beveled edges on the connector end of the board should cut right to the edge of the pads, so that the pads extend to the edge of bevel.


Figure: Drawing of the mPCIe Beveled Edge. Taken from the mPCIe Specification.

[18-AUG-25] First draft of A305301A layout complete and checked once. All components are on the top side. Identification is on the bottom silkscreen.

[21-AUG-25] We clear the solder mask on top and bottom side of the card edge connector. We submit for fabrication. We forget to update the version timestamp on the back side of the board, so it remains 20-AUG-25, despite changes to solder masks today.


Figure: Rendering of A305301A Printed Circuit Board. Left: top side. Right: bottom side.

[10-SEP-25] We have our A305301A boards.

[24-SEP-25] We assemble our first A3035AV1. We load into an mPCIe socket with 3.3-V power. Current consumption with oscillator running, no program in the PIC is 51 mA.

Q4-25

[06-NOV-25] We are programming our A3053 with our PICKit5 and adaptor cable, see PICKit5_RCM6700.jpg for a picture. Programming is reliable and fast. In P3053 we type "make" to build the "hex" file we select in the MPLAB IPE application. Our P3053 repository has undergone dramatic changes to its build structure since we copied it from the Harmony3 repository. The seven makefiles of the original repository are now consolidated into one top-level makefile. The three thousand lines of makefile build instructions are consolidated into one hundred lines. The makefile builds all C and assembler files in our src directory automatically and links them to the PIC32MZ-EF_DFP device package in our adjacent Harmony3 repository. Note that this package does not reside in the P3053 respository, but is available for download as PIC32MZ-EF_DFP.zip:.

Our TCP/IP stack is not yet working. The LAN8720A PHY is providing a link light, but we have no activity light. We have four test point LEDs connected to the RF3, RF2, RF8, and RA2 pins. These are green, blue, white, and red respectively. With our main program, we can flash the RF2, RF8, and RA2 LEDs, but the RF3 green lamp does not flash. The RF3 pin remains high-imdedance despite our efforts to set it as an output. If we short the RF2 pin to the RF3 pin, the blue and green lamps both shine brightly. The blue light does not dim when the green light shares the output.

Our programming interface is the simple, robust, two-wire interface consisting of signals PGD and PGC. It also carries 0V, 3V3, and /MCLR. It turns out that there is no way to obtain debugging information from this two-wire interface, nor will it support a console to receive messages. We direct the MUC's internal UART2 to RF8 and RF2 with the following code in our GPIO setup routine. We are writing to peripheral pin select (PPS) registers to direct RF8 to the UART2 RX input and to direct the UART2 TX output to RF2.

// Select RF8 as the source of UART2 RX. On the A3053A, RF8 is U1-58,
// connected to R11, which in turn feeds D4, the white test point LED.
U2RXR = 0b1011;

// Select UART2 TX as the source of RF2. On the A3053A, RF2 is U1-57,
// connected to, R10, which in turn feeds D3, the blue test point LED.
RPF2R = 0b0010;

// So far, on our A3053A, we have have D3 and D4 dedicated to UART2, but D2
// and D5 are available as test points. Pin U1-56 is RF3, so we want to set
// bit 3 of port F as an output. Pin U1-59 is RA2, so we want to set bit 2
// of port A as an output as well. The constants that hold the numerical
// port codes are defined in plib_gpio.h. To specify the bit, we provide a
// mask.
GPIO_PortOutputEnable(GPIO_PORT_F,0x00000008);
GPIO_PortOutputEnable(GPIO_PORT_A,0x00000004);

We configure the UART2 for 115,200 baud. We write a routine to transmit the four bytes of 32-bit integer one after another through the UART and we look at TX on our oscilloscope. The natural byte ordering on the MCU is little-endian, and the UART byte ordering is least significant bit first, so we see the 32 bits from bit0 to bit31 with a single start 0 and a single stop 1 on either end of each set of eight bits. In this way, we are able to examine the values of the GPIO control registers to see if we have configured the one for RF3 correctly. Here is the byte-transmit function and the integer-transmit function.

static void uart2_putc(char c)
{
    while (UART2_Write((uint8_t*)&c, 1) == 0); 
}

static void uart2_send_int(uint32_t value)
{
	int i;
	for (i = 0; i <= 3; i++) uart2_putc(((uint8_t*)&value)[i]);
}

We test our transmit routine with 0xFFFFFFFF, 0x00000000, 0xAAAAAAAA, 0x55555555, and 0x80800101 and conclude that it is working correctly. In our main loop, we use uart2_send_int to transmit the value of the internal thirty-two bit register TRISF. Consulting table 12-13 in the PIC32MZ datasheet, this register has nine active bits corresponding to nine available pins on the chip, all from Port F.

TRISF13 TRISF12 TRISF8 TRISF5 TRISF4 TRISF3 TRISF2 TRISF1 TRISF0

The register resets to value 0x313F, for which all the above-listed bits are set (1). When one of these bits is set, the pin acts as an input. When it is clearred, the pin acts as an input. The reset value makes all the existing pins inputs. After we configure the chip, in our main loop we examine TRISF and see bits 0-15 are: 1110 1100 1000 1100. So RF0, RF1, RF2, RF4, RF5, RF12, and RF13 are inputs.


Figure: Serial Transmission of TRISF Bits. We have TRISF0-31 in four eight-bit UART bytes. Each byte begins with a LO start bit and ends with a HI stop bit. The 260 μs is three complete byte periods, or 30 bits, for 115.4 kbaud.

We selected RF2 as our UART2 TX output, and it is generating TX and driving the blue lamp, but TRISF2 says RF2 is an input. We configured RF3 as an output so it could drive our green LED, and TRISF2 says it is an output, but we observe RF3 to be high-impedance. We selected RF8 as the input for UART RX, we observe it to be high-impedance, and TRISF8 says it is an input. It turns out that PPS overrides TRISF, so we can now understand why RF2 acts as an output even through TRISF2 says its an input. But we still do not understand why RF3 is not driving its lamp.

[08-NOV-25] We solder three wires to our A3053A and terminate them with pins so we can more easily examine our UART2 TX, and in anticipation of connecting to a UART-USB adaptor. We use TX to look at the LATF and PORTF registers. We see PORTF3 is always LO, unless we short RF3 to RF2, in which case PORTF3 goes HI. We see LATF3 toggling as we try to toggle RF3 with our software. We replace the PIC32MZ, thinking the output transistor might be damaged. After replacement, we see exactly the same symptoms.


Figure: Soldered Wire UART2 Connections.

In the PIC32MZ datasheet, Table 3 give RF3 as pin 56 with function "RPF3/USBID/RF3". In Table 1-14 we see in the description of pin 52 "VUSB3V3" that, "USB internal transceiver supply. If the USB module is not used, this pin must be connected to VSS. When connected to VSS, the shared pin functions on USBID will not be available." We are not using the USB transceiver. We meant to follow the datasheet instructions and connect VUSB3V3 to VSS = 0V, but we actually connected it to VDD = 3V3. As a result, the USB interface is powered up, and RF3 is assigned the USBID function, which is an input. Thus it acts as an input no matter what we do with the configuration registers. We connect U1-56 to U1-50, this new pin is "OSC2/CLKO/RC15". We configure RC15 as an output and toggle it. The green LED flashes.

[10-NOV-25] We start work on the Ethernet PHY interface. Our link signal, LED1 is active-high, which is opposite to the !ETH signal provided by the RCM6700, so our RJ-45 socket's amber link light turns on when there is no link. It is on now. We power a full-size TCB base board with external 5 V and look at the pulses on our TX and RX lines. We see 55-ns pulses in bursts, ever few milliseconds, perhaps forty pulses separated by 30 μs. These pulses should be 100 ns, according to the Ethernet specification. We remove the A3053A, disconnect our 5-V supply and connect PoE. Now we see the pulses from the PoE switch. They are 100 ns a few times a second. We suspect that the PHY thinks that the clock we are supplying is 25 MHz, when it is in fact 50 MHz. We suspect the PIC of interfering with the three MODE straps, and build another A3053A without the PIC, only the PHY. Eventually, we determine that our pull-down strap on the PHY's LED2 (U2-2) output should be a pull-up, or it should be left floating. On the rising edge of nRST = /RST, the state of this line is clocked into the PHY to indicate the clock frequency. We remove R6, the pull-down resistor, allowing the pin to float, and we immediately get a 100 Mbps link. Our LED2 speed indicator is active-low and asserted, meaning 100 Mbps. Our LED1 link and activity indicator is ative-high and asserted, and pulsing LO occasionally to indicate activity. The amber light on the RJ-45 blinks occasionally as LED1 goes LO.

[11-NOV-25] In anticipation of writing assembler code to manage reading to and from the parallel interface and TCP/IP buffers, we obtain the following load and save instruction table from ChatGPT.

| Mnemonic | Meaning                | Bits | Sign Extension | Notes                |
| -------- | ---------------------- | ---- | -------------- | -------------------- |
|  lb      | load byte              | 8    | sign-extend    | signed char          |
|  lbu     | load byte unsigned     | 8    | zero-extend    | unsigned char        |
|  lh      | load halfword          | 16   | sign-extend    | signed short         |
|  lhu     | load halfword unsigned | 16   | zero-extend    | unsigned short       |
|  lw      | load word              | 32   | —              | standard 32-bit load |
|  sb      | store byte             | 8    | —              | writes low 8 bits    |
|  sh      | store halfword         | 16   | —              | writes low 16 bits   |
|  sw      | store word             | 32   | —              | writes all 32 bits   |

We remove R6 from our fully-populated A3053A. We program with our latest LED flashing code. We plug into our Mini-TCB. We immediately get a 100 Mbps link. We try to ping the board at 10.0.0.37, but get no answer. We examine our code, rearranging and consolidating until we see that we failed to call our the application initialization routine that defines our TCP/IP data structure. We add this instruction. We get response from ping 10.0.0.37. We get echo from telnet to 10.0.0.37:90. We tag the firmware as v1.1.