Design and build of a Lattice iCE40UP development board

It’s been another nine months since the last post. I will not dwell on the reasons for the lack of updates, except to say I have been busy with my projects; I just haven’t had the enthusiasm to post here until now. However the next post will go over some smaller projects I’ve completed recently, but this post is dedicated to my own take on a dev board for the Lattice iCE40 UltraPlus FPGA (PDF).

I’ve wanted to have a play with some non Altera (owned by Intel now) FPGAs for quite some time. Every single project I’ve undertaken that incorporated an FPGA starting with MAXI09 has used an Altera FPGA. While Xilinx (now owned by AMD) has always been Altera’s main competitor, there are others, including Lattice Semiconductor, and the iCE40 is one of their product lines.

The FPGA I’ve chosen to base my development board around, the iCE40UP5K, has the following main features:

  • 5200 LUTs
  • 1280Kb of single port static RAM
  • 120Kb of pseudo dual port RAM
  • Two hard I2C interfaces
  • Two hard SPI interfaces
  • Three RGB LED output pins
  • Two on-chip oscillators (10Khz and 48Mhz)
  • DSP functions: multiply and multiply and accumulate (MAC)
  • Up to six external clocks
  • One Phase Lock Loop (PLL)
  • 48 pin Quad Flat No-lead (QFN) and 30 ball Wafer-level chip scale packaging (WLCSP) packaging options
  • 39 IO pins on the QFN package

QFN is a new one for me, but I hoped, and it turned out to be the case, that it would not be outside my soldering talents.

In all, it’s a remarkable little part, and they are cheap: £8.17 for one from mouser.com at the time of writing. In terms of logic and the amount of RAM offered, it’s similar to the EP2C5 Cyclone 2 (PDF) part used on my VGA graphics card. However on that part the single port RAM is not present, nor are the hard peripheral interfaces. And critically that part is now obsolete. Of course they are pin constrained relative to the massive QFPs available for that FPGA. If I needed many pins on a modern part I’d no doubt be compelled to investigate BGA packaging solutions.

In terms of configuration details, these FPGAs are at the same time simpler and more complicated then the Altera parts I am used to.

First of all almost any SPI flash, of sufficient capacity, can be used to hold the design. The designs can also be loaded directly, from a host computer, into the FPGA in the same way as a typical Altera part. Lattice terms this SPI slave mode.

However, JTAG is not used for the host interface; SPI is used instead. This means the program hardware is not mandated by Lattice, though naturally they offer their own programmers. A typical programmer needs to be able to program the flash directly and the FPGA.

But using off the shelf programming hardware would not be as much fun as building my own, so before building a development board, I opted to build my own SPI flash programmer. This will be described in the following post. However it’s worth stating that the development board I’ve designed and built can be used with any iCE40 compatible programmer.

Another interesting aspect of these FPGAs is that it is possible to use open source tooling to create designs for them. Whilst Lattice provides their own tools (IceCube2), even supplying a Linux build, I was particularly drawn to these parts by the availability of open source software for compiling HDL designs into loadable bit streams. However there was a downside, in the sense that I would have some additional work to do: these tools, at least in the standard way they are used, support only Verilog and not VHDL, the language that all my HDL projects have so far been written in.

So my very first job, and something I started doing about a year ago in fact, was to become familiar with Verilog. In summary, I am surprised I would enjoy writing my designs with it. It is a fairly free form language and lacks strict type checking, something VHDL is, for good or bad, famed for. But with the correct “add-on” tools (described below) it is possible to retain a reasonable level of safety without impacting productivity unduly, which I feel is essential.

A secondary reason to being keen to learn Verilog is simply to broaden my knowledge of hardware engineering to make myself more “marketable”.

So the tools I’m currently using are:

  1. Verilator : As an additional sanity check all Verilog code is passed through Verilator in its linting mode. For example, it will fail lines which assign a 4 bit wide field to a 3 bit wide one, instead of silently truncating the 4 bit wide field to 3 bits. Note that Verilator can be used for many other tasks including compiling Verilog code into runnable machine code.
  2. iverilog : This is a Verilog compiler which turns a Verilog source file into an intermediate representation which can be used for running test benches. It performs a similar function to GHDL, which I’ve used to compile VHDL code in the past.
  3. Yosys : This is a compiler that performs the initial steps to synthesise Verilog code into a final deployable design, tailored for the target FPGA.
  4. NextPnR : Performs the place and route step in generating the final bitstream file.
  5. IcePack : Part of the IceStorm suite, this tool produces the final bitstream file suitable for loading into a supported FPGA, either directly or via an SPI Flash memory.

In terms of development board features I have opted for the following:

  • iCE40UP5K in QFN
  • N25Q032A (PDF) flash
  • DB15 VGA port:
  • PS/2 port with two channels for a mouse and keyboard
  • I2C:
  • LEDs and buttons
  • User header
  • Powered by a switching regulator and a barrel jack

It’s worth saying that parts of this feature list is based simply on the available parts I have laying about!

In terms of the VGA port, four bits each for Red, Green and Blue are available, yielding 4096 colours.

An initial idea for a use for the board is to play with softcores. Enough logic, and onboard memory, should be available to implement a simple 16 or possibly 32 bit core along with a text mode display. That’s just one possible use, of course.

When it came to drawing up the schematic, I reused portions from other past projects. For instance, the VGA and DAC section was lifted straight out of the schematic for my 68000-targetted video card but with the width of each component reduced from 8 to 4 bits.

Because the schematic is quite simple it fits on three pages. The first page describes the arrangement of the power regulators, the FPGA and configuration flash:

The power and flash arrangements were mostly borrowed from Lattice’s iCE40 UltraPlus Breakout Board (PDF) schematic. However the decoupling capacitor clusters were reduced from 3 to 2 for board space reasons.

Unlike on a typical Altera setup where the flash is programmed through the FPGA, here the programmer is given access to the flash or FPGA through hardware jumpers. Essentially these jumpers will route the MOSI and MISO pins from the header to either the SPI flash or the FPGA.

It’s worth stating that Lattice’s documentation is superb and well organised. You can even download a ZIP file containing all the PDFs in one bundle. I’ll discuss the mechanism for programming the flash and/or FPGA in detail in the next blog post, which discusses the programmer solution I’ve come up with.

The power connections to the FPGA are, as per any modern FPGA, complicated. There are five voltage levels on the board:

  • 5V : This is the step down voltage from the switching regulator and is otherwise only used for PS/2 port power pins
  • 3.3V : VCCIO* – this is attached to the various IO banks
  • 1.2V : VCC – this is the internal core rail
  • 2.5V : VPP_2V5 – another internal rail
  • 1.2V : VCCPLL – the phased locked loop supply

There are some oddities in the generation of these rails which are worth noting. I have not bothered to dig into the details and have simply replicated the Lattice schematic, but the Lattice development board uses the drop from a diode to generate the 2.5V rail. The FPGA’s  VCCPLL connection is, again for reasons I’ve not looked into, on the far side of a 100 Ohm resistor.

Next, the VGA and PS/2 section. Very little to say here; the DAC setup is copied out of the VGA card I previously designed, with the PS/2 ports copied from MAXI030:

Lastly the “other” page. This contains the I2C portion, user headers, LEDs, a single push button attached to the FPGA, and the mounting holes:

Next up, PCB routing.

As usual this is a 4 layer board with internal power planes.

This was an interesting challenge because of the small size of the QFN FPGA IC. After struggling with placing the decoupling capacitors on the back-side of the PCB behind the FPGA, I opted to cut the count on each pin from 3 to 2 and shrink these, and most other, passive parts from 1206 packaging to 0805. All my previous boards used 1206 for passive parts. I also thought it would be fun to challenge myself with soldering smaller SMT parts.

Another new thing, for me, with this board design is it uses derived trace sizes. That is, the width and other properties of a trace and via are mandated by the netlist name for that trace. Thus the 5V traces (netlist name +5V) all have a width of 0.065 mils, guaranteed. This is nice because it means it is no longer necessary to manually change trace widths when routing the board.

The downside is some loss of flexibility. For instance, when routing power traces to the small QFN pads on the FPGA you need to use narrow traces. But other parts of that netlist can and should be wider as it is a trace used for routing relatively high currents to various places, including the FPGA. There are a couple of workarounds to that problem, but the one I have opted for is to use filled zones, as KiCAD calls them, to create squares of copper to join the high current pads together:

This shows the connections around the 3.3V and 1.2V regulators. Instead of using traces, beside the 5V trace, filled zones are used to join pads. In fact this workaround for not being able to use multiple widths of traces for the same netlist results in a more robust board design, as more of the available board space can be used to carry current.

Another PCB design technique the above shows is the use of stitching; vias that join filled zones, also known as copper pours, on different layers.

Here is the final design, as manufactured. Only the outer two layers are shown:

For a change I decided to use rounded corners on this board.

As it’s not completely trivial, here is the Vcc plane:

The inverted T-shaped cut-out is the 1.2V power rail.

The mandatory 3D views:

And the back:

Quite a cute little board I think!

The boards where duly ordered from jlcpcb.com and arrived about a week later. In the meantime I’d ordered the needed parts from mouser.com.

Soldering up the boards was a tedious process, but not particularly difficult. I possibly should have opted to buy a solder stencil, especially for the back. However the downside with stencils is the placement must be done in one sitting, which can be rather tiring.

After picking, placing and soldering the parts for the power section, I encountered my first problem: in switching to 0805 capacitors I’d naively assumed the same values would be available in my “sample book” of SMT passives. This doesn’t seem to be the case; the higher values, eg a 10uF part used to decouple the external supply was not present. Instead of waiting for more parts to arrive, I simply used the highest value available. With this done, the main rails were looking good with the 5V, 3.3V and 1.2V all present and correct.

After soldering up the decoupling capacitors and diode for the FPGA I thought I’d measure the drop across the 2.5V step down diode, a MBR130 (PDF). Unfortunately I did not see the expected 0.7V, but a much lower 0.2V. None the less, after looking at the relevant datasheet it can be seen the maximum VPP_2V5 on the FPGA is 3.46V, so any drop or no drop at all should be tolerated by the device. Still, I think next time I’ll use a 2.5V regulator for this rail.

Soldering the QFN was fairly easy: I used a very thin bead of paste around the perimeter and a small dot on the ground pad in the center. Naturally there were some bridges to clear, but this was easily done with my favorite flux, SMFL. I cannot link to this flux as it is apparently no longer manufactured, which is just my luck. Luckily what I have left in the can should last a good while.

The last critical parts, for basic functionality, to attach were the configuration flash and associated headers, 50MHz oscillator can, LEDs and button.

It was then time to test a simple design, naturally an LED flasher or rather counter, using the 3 LEDs.

The initial joy of seeing the SPI flash take the design (with the headers in the correct position) was tempered when it was noticed that only one of the LEDs (LED0) was flashing. It was only then that I dug into the datasheet to see what was special about the 3 LED pins, intended for driving an RGB LED that were being used for driving two of the LEDs. I had previously glossed over their significance after reading that these pins could be used for regular IO if desired. This is a common attribute to FPGA IO pins; sometimes they have a special purpose but all the times I’ve seen this in Altera parts they can be used as regular IO instead if desired.

For some reason in my schematic I had LED0 attached to a regular IO (which is why it was working normally) and LED1 and LED2 on two of the special LED pins. The third LED pin was used for the button which, as it happened, was working fine so it was usable for ordinary input.

In short, there is one big obstacle preventing an LED pins from being used as an output pin: it must be a current sink and not a current source, which is how my LEDs were attached. This is naturally all documented in the relevant datasheet (PDF).

To fix this without totally scrapping this board was actually fairly easy: the two impacted LED were reversed and the far end of the current limiting resistor was tied to a nearby Vcc pad instead of ground. This last thing involved some track butchery with a scalpel, but was simple enough. In addition the Verilog code was altered so these LEDs were turned on with a logic 0 output.

With that change, I had 3 counting LEDs!

I felt pretty pleased with myself at this point. I’d succeeded in building a board that incorporated an FPGA I’d never used before, and I’d succeeded in writing the software to program an SPI flash attached to said FPGA. And of course I’d written a little bit of Verilog, that worked!

Here is a picture of the current setup, after finishing the assembly:

If you look closely you can see the bottom two LEDs are reversed compared to the top one, but beside that error the board appears to work well.

So far I have also tested the buzzer and the VGA port, and both appear to work fine. However I should have used a 3.3V buzzer instead of a 5V one, or used a transistor to switch it the buzzer up to 5V. A minor problem.

In terms of the VGA output, the initial test was a simple test pattern, but because of wanting to learn about the iCE40UP’s block RAM I opted to write a simple character generator as well:

This was surprisingly easy to do. No non-standard Verilog code to instantiate the ROM was needed; it is inferred from ordinary Verilog code with the character image (the Amstrad CPC font) being loaded from a text file in an “initial” block.

Total resource usage for the above design is also tiny: 2% of the logic, and 6% of the block RAM is used.

The next tasks are all fairly mundane:

  1. Update the schematic and PCB design for this board to fix the error with the usage of the LED pins and put the resultant files in a new github.com/aslak3 repository, in case anyone is interested in replicating this design, and for prosperity.
  2. Redo and reorder another board I’ve designed that uses an iCE40UP to fix problems with LED pins which, sadly, are not fixable with a scalpel.
  3. Write the next blog post to document the SPI programmer and some other smaller projects.

After that, it’s not completely clear. But working on a new softcore, in Verilog, sounds like it could be a load of fun…

UPDATE: The github repo for this board has been created.

2 thoughts on “Design and build of a Lattice iCE40UP development board

  1. rvense

    Cool board!

    I made a vaguely VT-100-compatible thing with an ICE40HX8k developer board from Lattice and a plug-in board for the VGA output. I think I got it running stably 1280×1024. What resolution are you using?

    This was without no softcore, I just parsed the escapes in Verilog. It worked, mostly, but it was extremey tedious and I wouldn’t recommend that.

    PS: Nice to see an update from you!

    Reply
    1. aslak Post author

      Thanks for the comment!

      It’s just 640×480@60Hz at the minute, but it could go higher I’m sure. Implementing a terminal emulator in pure Verilog sounds like trouble!

      I’m working on a softcore now, a rewrite of my old cpu32 design in Verilog. Hoping I can make some progress in making it pipelined…

      PS. Hoping to write here a lot more often with no more gaps of 9 months. 😀

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.