ULX4M-LS v0.0.2 - NLnet funded FPGA board

At the start of 2021. NLnet decided to sponsor development of modular FPGA board ULX4M (Successor of EMARD ULX3S).


Previews work

The goal of this project is to make a board modular and add more peripherals. We are specially interested into adding fast SerDes peripherals that are now missing on ULX3S. Along with that future plans consist of creating modules with multiple FPGA vendors so we can do more vendor neutral coding.


It all started with selecting the connectors – you can check the story here


We ware also interested in blender so Paula joined the team – her story is here


After we selected the connectors and decided to go with the CM4 IO compatible pin-out we have started to disassemble ULX3S and create new smaller modular board that will fit into CM4 IO carrier boards.


But along with the work HW bugs arrived

On ULX4M v001 we had two “big” issues, and few smaller ones that needed to be fixed…

The first issue was that I did not know that a small board needs to provide 3.3V to a big board, so I did not connect 3.3V to the CM4 IO connector. On v.0.0.1 this was fixed with a bit of wiring, but that was first fixed on v.0.0.2.

The second big issue was that the connectors did not fit perfectly into their slots.
On v.0.0.2 I have moved the connectors apart just a bit to get distance as described in the datasheet.

Next big thing but not an issue was to get better routing to SDRAM.
Matching SDRAM lines is not very important and it was working, but as we want a version with DDR3 this board is great first try to check how to do better routing.
But before routing we needed to switch to a 6 layer board.
On the 4 layer board it was already visible that we cannot get a perfect ground plane below all lines.
So on v.0.0.2 it was time to switch to a 6 layer board.

4 layers to 6 layers

Switching to 6 layers was not as problematic.
I first deleted all ground polygons, then I selected the power polygons and moved them off board.
After that in settings I selected the stackup I wanted.
I think about it and 3 signal layers should be sufficient for routing all pins.

For stackup I decided to go with Signal/GND/Signal/Power/GND/Signal

After I changed the layer count to 6 and named layers I checked if all signals are on the right layer.
Since that was ok, I selected the power polygons, switched them to a power layer and moved them back on the board.
After that I created a new ground polygon on two ground layers.
Some more cleanup was still needed so I checked all of the layers again and moved all of the power lines to the power layer.

ULX4M is now a 6 layer board

Next was to add buttons that were missing on v.0.0.1.
I ordered a few different types and selected ones that looked and felt good.

SDRAM track length

Now that we had everything set I could route the SDRAM, and for that I first need to move it just a bit to the right – so I will have more room for length matching.

For checking all lines length I have used action plugins


In kicad you first select Route-Tune Track Length, click on the longest track and remember or write down the length.
After that use right click for options select – Length Tuning Settings – you can also press CTRL+L to set settings screen. On the Single Track Length Tuning screen set some length – it needs to be more or equal to the longest wire you want to tune, and that is why you need to write down or remember the longest line length.
After setting the parameters. Now you just click on any shorter line and just pull the cursor over it. You will get those fancy curved lines. You can use the keyboard: 1 2 3 4 for spacing and amplitude of line curves.

For SDRAM that should be enough, but for DDR3 we will probably need to take more things into account.
For example every chip package has some line from input pin to logic – those lengths when important are mostly in the datasheet. You also need to take into consideration every layer switching you are doing especially if you are going from top to bottom layer (or opposite) as that can add significant length.

And this is how routing looks like now

Connecting GPIOs

Connecting all of the GPIOs was also not as problematic on 6 layer boards, it is still not too crowded by signals.
I also needed to take HAT routing into consideration and that is bit tricky, as on ULX3S FPGA and ESP32 are sharing significant number of lines, and HAT needs to access some of the lines that are not available on the GPIO port, that goes for SDCARD and JTAG pins, as we want to use HAT for ULX4M programming, and we want to make sure that on HAT ESP32 is able to use the SD CARD.

On v.0.0.2 I also connected all MIPI DSI pins – on full port I have decided to put some SerDes pins for experimenting with the v.0.0.2. I also added 2.54mm pin holes on board that might be used as dipole antennas – so we can experiment if we can send/receive some data…

One big thing that is still an issue is ethernet – it is hard to decide what chip to put there as none of Gb chips are currently available :(
But in this version I have added a QFN48 footprint so maybe in the next version I will not need to order an additional stencil.

Community work

In the time I was busy with HW – emard and lawrie forked smunaut had2019-playground and added some changes needed to get it working on ULX3S and on ULX4M.

Also before ordering v.0.0.2 I needed to check if the SerDes part needed some changes, the easiest way to check that was to use LiteX. I had some issues when I tried to build it https://github.com/enjoy-digital/liteiclink/issues/4 but I somehow managed to fix it directly inside of the generated files. And after loading the loopback sample in the v.0.0.1 board sample, the counter that counts received packets started to blink!

Ordering ULX4M-LS v002

After SerDes confirmation it was time to order the v002 board!
Prices of 6 layer boards on a small scale are more then double of a 4 layer – but that will not be a problem once we get a bigger order…


5pcs. 4 Layer price €63.30 – ENIG – BLACK – 0.2/0.4mm
5pcs. 6 layer price €129.91 – ENIG – BLACK – 0.2/0.4mm

The Stencil is €10.54 + it adds up €20 on shipping

Total JLCPCB costs are:

10 pcs. ULX4M-LS v002 €140.16
Stencil with frame €10.29
5 pcs. ULX4M HAT €6.96

Total including Tax and import fees: €257.47

It was kind of a miracle that 90pcs of LFE5UM-85F-8BG381C parts where available on Mouser so I ordered them instantly.

Price of one UM-85F if 90 is ordered is $35.330

While waiting for the parts I was cleaning the schematics, and sorted everything that we needed for production.


Even for ULX3S we have noted that kitspace is a really cool project sharing page and it helps a lot in part ordering and checking. It also has lots of other things integrated, like pcb ordering, gerber inspection, interactive BOM that is a really valuable tool for hand placement of components…


Hopefully I will get some time to record one video with a complete ULX4M assembly.

Everything has arrived!

Hurry hurry, assembly time is here!

Applying paste to ULX4M-LS board

I got on board at 14h, and ULX4M was assembled a few hours later!

So i first checked if the connector will slip in the socket, and it did!
That was the biggest issue on v001, and only one was made, as it was really hard to fit the board into the socket.

At some point I also ordered a Waveshare board and it also fits nicely!

I rewrote all the lpf files and checked a few samples to see if all that worked on v002 still works…

I also assembled one HAT as if that works it will be much easier to load samples.

On the first HAT I have placed ESP32 WROOM, but after a day of trying to get an SD card sharing to work I decided to try with another HAT with ESP32 WROVER.
And instantly the SD CARD was available to ESP32!

So WROOM will probably need to be worked on.

FTDI worked on the first try, so it is now possible to power the board only from an HAT USB and program it with fujprog, just like ULX3S.
On WROVER it is also possible to program board over WIFI, and WEBREPL and FTP are also working!

Bootloader was not so hard to adjust for ULX4M as smunaut, lawrie and emard already solved hard parts.
I have just adjusted the pinout, and needed to remove some LEDS and BUTTONS as they are not available on the ULX4M.
I also changed the product, and manufacturer text in bootloader fw…

After all that I tried a fixed Litex SerDes sample, it needed some pin adjustments, but as Greg suggested, I updated the fpga toolchain and no more direct fixes are needed. It is producing a working SerDes PCIe loopback sample.

Currently tested

Programming over HAT FTDI – OK
Programming over HAT ESP32 – OK – only WROVER
USB DFU bootloader – OK
PCIe serdes loopback – OK
Ethernet – Not routed – chip is not selected – SERDES still connected directly to the coil
USB HUB – Connected but not tested – will need lawrie help as it is probably easiest to get it from SaxonSoc
SERDES RX TX antennas – EXPERIMENTAL! – not tested
CAM0 – EXPERIMENTAL! – All pins connected – not tested – be careful needs a voltage level check
DISP0 – EXPERIMENTAL! – All pins connected – not tested – be careful needs a voltage level check
CAM1 – EXPERIMENTAL! – All pins connected – not tested – voltage levels – has SERDES pins
DISP1 – EXPERIMENTAL! – All pins connected – not tested – voltage levels – has SERDES pins

I also checked with NLnet and they helped me with the license and license for ULX4M series will be
CERN-OHL-S v2 or later


MIPI-DSI display ready for testing

ULX4M powering only from a USB connector

Paula is still busy, but she thinks she can have a complete December just for blender!

And my next task will be to make a ULX4M-LD board – D stands for DDR in our case this will be DDR3.
In that time I hope other issues could be found if any and clear them for ULX4M-LS v003…

And last news for now – at some point CrowdSupply accepted ULX4M Submission, and we have signed a Statement of Work! So expect the CrowdSupply ULX4M preview page soon!

By: Goran Mahovlić

This project is funded by NLnet https://nlnet.nl/project/ULX3M/

© Intergalaktik