This library allows to stream out data with around 11 Mbyte/s from a RP2040 or RP2350 MCU using the PIO to bit-bang a 100 Mbit Fast Ethernet connection. It is somewhat similar to Pico-10BASE-T, which implemented TX-only 10 MBit Ethernet.
Warning: Do not connect to any POE capable equipment!
Ideally use a pulse transformer with proper matching circuitry. In my experiments I directly connected the two GPIOs to an old ethernet cable and it worked with all devices I've tested - only do that at your own risk. You also could use some old Ethernet switch and connect it in between the Pico and your machine to be safe.
Demo digitizing some WBFM IF signal with the internal ADC and streaming it out via Fast Ethernet:
Pico-100BASE-TX.mp410BASE-T is rather trivial to implement using an SPI peripheral, as it only uses two voltage levels and Manchester encoding. 100BASE-TX transmission however is harder to implement, it uses MLT-3 encoding, is scrambled, uses a 4B5B line code, and is transmitted at 125 MHz symbol rate.
There are three levels this code sequentially cycles through, -1, 0 and +1. If there is a zero to be transmitted, the state remains identical to the last symbol. For a one, it moves to the next state. For a row of ones, the output would be -1, 0, +1, 0, -1, 0 and so on.
Using the side-set feature of the PIO, MLT-3 encoding is implemented on two GPIOs that output either 0b01, 0b00 or 0b10 for each MLT-3 symbol, respectively. As the twisted pair is connected between those two GPIOs, the three voltage levels are obtained.
The scrambler is implemented using an LFSR that is 11 bits wide and has taps at the 11th and 9th bit (x^11 + x^9 + 1). This results in a pseudorandom sequence that repeats after 2047 bits. We pre-compute a lookup-table that contains 30 bits of the sequence per entry, and uses 2047 entries (plus the maximum size of a frame for convenience). This takes around 10 KB of RAM in the MCU.
Each 4-bit nibble is encoded using the 4B5B line code resulting in 5 bits. Special 5-bit symbols J, K as well as T and R are reserved to signal the start and end of an Ethernet frame, furthermore there is an idle symbol consisting of all ones. For efficiency purposes, we use a LUT with 256 entries, containing two 4B5B symbols per entry. This allows to encode each byte of the Ethernet frame with only one access into the table.
With pre-inversion of the scrambling code (already containg the idle symbol), we can directly send the stream of idle symbols to the PIO by DMA. So we only have to use CPU cycles if we really want to transmit a frame.
This page also contains some useful information in addition to IEEE 802.3.
Make sure you have the latest version of the pico-sdk installed together with an appropriate compiler. You should be able to build the pico-examples.
To build Pico-100BASE-TX for a Pico2:
After the build succeeds you can copy the resulting *.uf2 file of the application you want to run to the board.
The repository contains a library - libpico100basetx - which implements the main functionality. It reads the data from a ringbuffer, and streams it out via the 100BASE-TX UDP frames. In addition to that, the apps folder contains a couple of example applications:
This application uses the PIO to generate a 16-bit counter value which is written to a DMA ringbuffer, which is then streamed out via UDP datagrams.
The data from the internal ADC is streamed out.
This app streams the audio data from a PCM1802 audio ADC board. The used pinout is the same as on this adapter PCB, and the audio samplerate is 75 kHz.
Pico-100BASE-TX is developed by Steve Markgraf, and is loosely based on hsdaoh-rp2350.
.png)


