ESP32 XU

This page describes how to make an ESP32 work as a WIFI gateway for the PDP2011 XU. We’ll go over the requirements for the ESP32 software, the required hardware and connections, and how to configure the XU on the PDP2011 side.

The current limitations are:

  • In theory the ESP32 code should run on all ESP32 variants – however, there are too many to test them all. I have so far mainly used the ESP32-C3-DevKitM-1 and ESP32-C3-DevKitM-1U for development. The ESP32-DevKitC and ESP32-PICO-KIT have also been tested and found to work.
  • Throughput and latency depend very much on the quality of the WIFI signal. The usual ESP32 devkit boards have very small PCB trace antennas that may need some pointing or tilting to get the best connection. There are variants with external antenna connectors (eg ESP32-C3-DevKitM-1U) that work a lot better with weaker WIFI signal and may give better response times. My current semi-permanent test setup uses a ESP32-C3-DevKitM-1U, an Adafruit #5444 cable, and a Linx ANT-2.4-CW-HWR-RPS antenna.
  • The SPI component in ESP32-C3 is newer – faster and more robust than the earlier generations; and it seems much happier with the new XU SPI master – although I’ve not been able yet to investigate fully, and some of the issues I’ve had with ESP32 are probably my fault. Still, if you’re going to buy a board specifically for the purpose of a wireless PDP2011, I’d recommend the ESP32-C3-DevKitM-1 or -1U.
  • So far only the 2.11BSD IP stack has been tested. Also, the current code does not (yet) allow setting (changing) the MAC address. By implication that means that running DECNET is not currently possible, and there are no guarantees yet that this will be possible in the future.
  • The current code only allows STA mode. This means that you will need to connect the ESP32 as a station to an existing AP (Wifi Access Point), but you cannot make the ESP32 work as an AP itself. It shouldn’t be difficult at all to make this work, but it is not on the top of my list to add – I don’t think AP mode is very useful other than for demonstrations.

Building the ESP32 code

The ESP32 code is built against the stable release of esp-idf: IDF v5.0; since changes were made recently to the esp-idf APIs that the code uses, you cannot easily use an older version, and to use the C3 chips you’d need recent versions anyway. Check the instructions at

https://github.com/espressif/esp-idf/releases/tag/v5.0

to install the stable version. It is, all of it, pretty much on the bleeding edge; v5.0 was released December 2, 2022, and it comes with lots of requirements for versions of supporting software like python, cmake, ninja-build that in practice sort-of mean that you’ll have to have a recent OS too. I’m now using AlmaLinux version 9; recent versions of other major Linux distros will probably work fine too. You can run everything you need for the ESP inside a VirtualBox image if you don’t feel like upgrading your system – except that downloading the code onto the ESP boards might sometimes need a couple retries.

Once installed (don’t forget to run the install.sh in the esp-idf directory – that’ll pull in the compilers etc), setup the environment (. export.sh in the esp-idf directory) and go to the pdp11/xuesp directory. There, run the appropriate idf.py set-target, build, flash, and monitor commands. Something like this :

# idf.py set-target esp32c3
# idf.py build
# idf.py flash monitor

where the first line is probably not necessary since the same setting will likely be in the sdkconfig file from the distribution; but if you don’t use a C3-based board you’ll have to set the target CPU type.

It is usually a good idea to use the -p flag to tell idf.py which serial port the esp32 board is connected to – on Linux, this is probably something like /dev/ttyUSB0, but there’ll be serial ports in use for your PDP2011 console port as well, and maybe also a debug port for the XU microcode. If you don’t set the -p flag, idf.py will try all ports until it finds an esp32, and potentially send strings out on the wrong port; most likely nothing will break, but it’s better not to let it try.

If you get to this point and the build runs as it should, the ESP32 will be flashed with the freshly compiled code and then the idf.py monitor will turn into a console interface on the esp32. It’ll show lots of messages telling you it is starting up and is trying to connect to a default AP, which will fail. This takes half a minute or so.

The PDP2011-ESP console

At the end of the startup – after the ESP has connected to an AP, or exhausted its retries, you’ll see a prompt. There could still be AP messages after the prompt has been written, so if you don’t see it press enter a couple times.

PDP2011-ESP> 

The console has several commands built in; the most important is the wifi command that you’ll need to enter the SSID of your AP and the password for it. Like so:

PDP2011-ESP> wifi my-ssid my-password

What the wifi command does is copy the ssid name and the password to the NVS in the esp32, to use in connecting to the AP when it starts up. So you’ll have to restart the esp32 to activate, for example by the restart command, but a power cycle will also work. After that, the ESP should connect to the AP, and request a DHCP address.

If the ESP32 you’re using was running other code before, it may still have other variables and settings in its NVS, and those could interfere with what we want it to do now. To get rid of those, you can use the erasenvs command – but do that before setting up the wifi details, because those will be gone too.

The other commands that the console knows about are:

  • wifi (without arguments); to show the wifi status
  • restart; to cause a soft reset
  • info; to show some information on the hardware
  • stats; to show counters
  • erasenvs; to clear the NVS
  • dumpnvs; to list the contents of the NVS
  • recvprint; to print incoming frames for debugging
  • xmitprint; to print outgoing frames for debugging

Normally you should only need the wifi and restart commands at the first start; after that everything should just run without any intervention. The other commands are there for debugging – or if you’re changing your network setup. If you’ve used your ESP32 for other code, you can use the erasenvs command to clear any data that has been left – and you should also do that when you decommission the ESP32, since your wifi details will be stored there. Or better yet, do an idf.py erase_flash.

Wiring up the ESP and the FPGA board

Wiring is of course very much dependent on which FPGA and ESP board you have. I’ve not defined a fixed standard yet; so far I’ve been using the 2×13 connector on the bottom of the de0nano for most testing, and I’m probably going to design a small PCB for that. On all other boards, it’d make sense to reuse the pin assignments of the regular xu pins, but you’d have to find one extra for the xu_srdy signal. Don’t put anything in concrete, I’ll probably define a pin assignment in a future release – and don’t worry about the xu_debug_tx either, there’s hardly any useful output at this time anyway.

On the ESP side of things, the pins are defined in the app_spitask.c; they are dependent on the model. Note that the pin numbers become pin names on the devkit boards – the mapping is not one to one. The pins I’m using in my current setups with DE0-Nano, ESP32-C3-DevKitM-1, ESP-PICO-KIT and ESP-DevKitC are:

signal nameDE0-Nano pinFPGA pinC3-DevKitM-1ESP-PICO-KITDevkitC
xu_srdyGPIO_2[1]PIN_B1632121
xu_mosiGPIO_2[0]PIN_A1472323
xu_misoGPIO_2[3]PIN_C1621919
xu_sclkGPIO_2[5]PIN_D1661818
xu_csGPIO_2[4]PIN_C151055
xu_debug_txGPIO_2[2]PIN_C14n/an/an/a

Setting up the FPGA build

There are two changes to the XU signals in the unibus instantiation: firstly, you’ll have to tell the XU that it has the ESP frontend, and secondly, the ESP needs an extra signal called ‘xu_srdy’ that signals that the ESP is ready to receive a command. Like so:

      have_xu => 1,
      have_xu_esp => 1,
      xu_cs => xu_cs,
      xu_mosi => xu_mosi,
      xu_sclk => xu_sclk,
      xu_miso => xu_miso,
      xu_srdy => xu_srdy,
      xu_debug_tx => xu_debug_tx,             -- optional

and of course xu_srdy needs to be connected to an I/O pin.

Setting up 2.11BSD

The networking setup in 2.11BSD is exactly the same as you would do with a ‘real’ DEUNA or DELUA – what goes by a DE-type network adapter in the kernel. If you haven’t done so already, build a kernel with NDE set to 1 (only 1 DE is supported).

Then look into /etc/netstart, and set up the shell variables and the appropriate ifconfig command. One thing to note is that you MUST use the ip address that the ESP32 has gotten from DHCP – another address may appear to work, but will give you lots of subtle problems. I haven’t really investigated yet, but it appears as if certain frame types (arp?) are not forwarded by some deeper layer of the ESP32 (micro-)code if the destination IP doesn’t match what the ESP32 thinks it is – even though it shouldn’t deal with IP addresses.