Sunday, 8 September 2019

Counters in Verilog with the ULX3S

It's time for another learning experience with the ULX3S.  When using FPGAS or Microcontrollers in general it's very useful to generate and use counters.  Counters as their name suggest are ways time can be added to logic circuits.  If you wanted an LED to flash once a second use a counter.  If you want several LEDS to flash at different rates independently use several counters...If you want to ensure an event occurs at a specific point in time...use a counter.

Counters in FPGA are particularly cool as you can have as many of them as you like or need, unlike microcontrollers.  The other thing is that the counters are all independent of each other in an FPGA.  So multiple counters can be used to control things without affecting the operating of anything else...that's very hard to achieve with a microcontroller...the program flow is always linear.

Lets make a counter flash an LED once a second. In order to do that we need to know a couple of things:

What is the clock speed of the oscillator used on the ULX3S development board?
What is the control logic for the LEDS (active high or active low)?

We can find these answers either from the schematic of the ULX3S or from the constraints file.  Both of which are helpfully available here:

https://github.com/emard/ulx3s

https://github.com/emard/ulx3s-examples/blob/master/README.md

The schematic is broken down into several pages and was created in KiCad.  There is also a PDF version here:

https://github.com/emard/ulx3s/blob/master/doc/schematics.pdf

We are interested in page 4 called 'Blinkey' and page 6 called 'USB'.  Blinkey shows the eight LEDS referenced from zero to seven in the centre of the page four in cell B,3.  The LEDS are common ground connected which means they are 'active high' - A control signal from 'Bank 7' the FPGA needs to be high in order to get an LED to turn on.  The current limiting resistors used are 549 ohms so with 3.3 Vdc logic the current flowing through each LED when on will be 6 mA - bright enough! I've used FPGA development boards in the past where the IO was active low so its useful information to know.


The oscillator is in cell A, 3 on the top middle of the page and it is referenced as being 25 MHz - also useful to know.  It is of course possible to use phase lock loops to generate faster clock signals if that is what is required.


The User Constraints File or UCF as it is sometimes referred to is a list of information which tells the software which pins on the FPGA are connected to what and more usefully how they are referred to.  We could write our own UCF file if we wanted to and for complicated designs or if we had created our own circuit with an FPGA we would have to write our own. Helpfully the board designer of the ulx3s (EMARD) has written one for us. When we come to write the verilog code we can use the same naming convention and that way we don't have to write our own UCF file.

The sections we are interested in are:

# The clock "usb" and "gpdi" sheet
LOCATE COMP "clk_25mhz" SITE "G2";
IOBUF  PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
FREQUENCY PORT "clk_25mhz" 25 MHZ;

and

## LED indicators "blinkey" and "gpio" sheet
LOCATE COMP "led[7]" SITE "H3";
LOCATE COMP "led[6]" SITE "E1";
LOCATE COMP "led[5]" SITE "E2";
LOCATE COMP "led[4]" SITE "D1";
LOCATE COMP "led[3]" SITE "D2";
LOCATE COMP "led[2]" SITE "C1";
LOCATE COMP "led[1]" SITE "C2";
LOCATE COMP "led[0]" SITE "B2";
IOBUF  PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF  PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;

Just for reference a hash ( '#' ) symbol before a line means that the text after that is a comment

LOCATE COMP means to locate the drive logic to a particular section within the FPGA fabric.
IOBUF  PORT means the line is to be configured as a buffered input or output..
PULLMODE=NONE means the line will not have an internal pull up or pull down resistor enabled.
IO_TYPE=LVCMOS33 means the line will be configured to be low voltage CMOS at 3.3 Vdc.
DRIVE=4 means the line will be able to source 16 mA of current.  Drive 1 = 4 mA, Drive 2 = 8 mA, Drive 3 = 12 mA and finally drive 4 - 16 mA

When we write the verilog code we need to refer to the clock as clk_25mhz and the individual leds as led[0]

I was really hoping to use a program called IceStudio to program the ulx3s as it is essentially a graphical front end for apio which collates the usage of Yosys, Ptrellis and NextPNR.  Unfortunately the developers of IceStudio do not wish to add the ulx3s to the list of supported development boards.  They have their reasons for doing that.  I suspect it would be possible to fork IceStudio to work with ULX3S but I'm not going to do that as:
  1. I don't have the skill!
  2. I don't have the time to learn the skill!
  3. I don't want to annoy the IceStudio developers because they are nice guys and have worked hard.
I can use the program to demonstrate what we are going to do though...very useful. I find graphical information easier to pick up over seeing lines of HDL Syntax.



The diagram is meant to show that we have one input called clk_25mhz, we have two outputs called LED and wifi_gpio.

The blue box labelled PrescalerN is some pre-written code which basically is a verilog counter module.  It will take the clock input, count how many clock pulses there are and when it has reached 25 000 000 counts it will send a signal to the LED output.  The wifi_gpio output will be set high.

In verilog code this looks like this:

module top (
    input clk_25mhz,            // 25 MHz clock input 
    output reg led [7:0] = 1'b0,   // 8 Bit LED Output register, set LED[0] to be in a predefined state
    output wifi_gpio0     // Output for Wifi enable 
);
    reg [24:0] count = 0;          // Register for the counter
 
    always @(posedge clk_25mhz)    // Interrupt at the positive 25 MHz clock edge
    begin
       if (count == 25000000)    // If the count register has reached 25 million
                begin
                    led0 <= ~led0; // toggle the LED[0] On and OFF with a one second interval.
                    count <= 1'b0; // and reset the count to 1 (binary) 
                end
            else                   // else
                begin    
                    count <= count + 1'd1; // increment the count by 1
                end
    end

    assign wifi_gpio0 = 1'b1; //set the wifi_gpio High

endmodule

The code should be fairly easy to follow. The wifi_gpio input is only needed if your board has an ESP32. The command enables the ESP32 so code can be pushed over wifi. I haven't been doing that at the moment although I should! I'm fairly certain the code will work, I would like to have tested it and in later posts I will be looking into open source verification software like verilator and GTKwave. These programs allow one to simulate verilog code and show how the inputs and outputs will respond.

Lets save the text file (call it top.v) somewhere sensible I chose: C:\msys64\src\Alex\ulx3s\One Second Counter

 Next copy in the constraints file and apio.ini and fire up ConEmu.exe (Windows) and navigate to the folder we just made. It's also at this point that I should state that the board I'm working with has an ECP5 Lattice Semiconductor FPGA so the commands are tailored to it. If you are working with a ECP 12F board or an ECP 85F board you will need to change to commands appropriately.

 

Type the following command to turn the verilog code in top.v into the bit file ready for uploading to
the ulx3s development board: 

apio build --board ulx3s-45f 

The output should look like this:
 
Ignore the warnings... Plug in the ulx3s into your computer using a microUSB cable - exciting times! 

Next lets upload to the ulx3s development board: 

apio upload --board ulx3s-45f 

The output should look like this:
 

Finally its good practice to remove unnecessary files from the build process: 

 apio clean 

 As everything worked you should be able to see an LED flash like in the video below: 


Again not the most exciting thing in the world but it is the hello world of FPGAS and from a tiny acorn an mighty oak tree grows ;) 

That is all for now - Langster!

Thursday, 5 September 2019

ULX3S Open Source FPGA Development Board

I have made no secret of the fact that I am interested in FPGA technology and have been trying to relearn VHDL for some time.  I am also very keen on using open source programs and development tools.

Recently (sometime in the last couple of years) I heard about project IceStorm by Clifford Wolfe.  Mr Wolfe has reverse engineered Lattice Semiconductor's bit-stream files and written a software tool called Yosys which is used to convert verilog files into mapping files which can then be loaded onto a lattice semi-conductor FPGA.  At the moment proprietary FPGA development tools are very large pieces of software which take a lot of space on a hard disk, are feature heavy and not free to use (require licence files), often unsupported (Xilinx WEBise anyone) and I found difficult to use.  I'm not saying they aren't good but if I can use open source software tools I will...I like the idea behind the licensing models.  I'll donate what I can afford and assist wherever I can.

The Yosys Website is here: http://www.clifford.at/yosys/

Project ICE Storm: http://www.clifford.at/icestorm/

Until recently I didn't have a Lattice Semiconductor FPGA development board but that changed when I was offered a ULX3S open source board from the very clever guys at the Radiona Hackspace.  I had come into contact with these gentlemen when I was trying to learn to use the Elbert V2 and Mimas V2 Xilinx based FPGA development boards.  They developed a very cool piece of kit to make use of the open source tools for teaching a Digital Logic course at their local university.

The ULX3S with 3D printed case and buttons!
The board arrived in very good order with a 3D printed case, buttons and some pre-built examples.  I had a quick play with it and intended to write up my experiences and get started on using it.  That was probably this time last year...I am attempting to get back into blogging my experiences, trials and tribulations outside of work as I find it quite useful and I find it forces me to improve on my electronics and development skills.  Anyway...back to the board:

The board is in my opinion, very well designed and implemented.  I particularly like the addition of the ESP32 so files can be uploaded over wifi.

Here are some photos of the board:

The top side of the PCB with buttons, microSD card and display
The underside of the PCB with the ESP32 module
Here is the website for the project: https://radiona.org/ulx3s/

Here is a Hackaday write up: https://hackaday.com/2019/01/14/ulx3s-an-open-source-lattice-ecp5-fpga-pcb/#more-340565

I'll be honest, I bought the board to support the project, I haven't got a project or use in mind.  To be even more honest I still want to re-learn a hardware description language so that when I do have a project in mind I'll be able to make use of the technology.  I do have ideas for a piece of instrumentation but that is a way off and requires a lot more than just the FPGA!

The first thing I did with the board was use it to emulate an Amiga 500 computer using the pre-loaded Minimig project which came ready to play on the board.  All I had to do was grab some amiga disk images and I could play all the games from my misspent youth.  Retro gaming with FPGA devices is a very popular hobby as the hardware is not being emulated but actually realised within the fabric of the device which leads to a more realistic experience.

Playing Lotus Turbo Challenge 2 and Utopia are fun diversions but not quite what I had in mind for the device.

The open source tools all appear to be for linux operating systems only at the moment so I installed Linux Mint on my main PC and got to work installing all of the pieces of software needed from project Ice storm.  

My LinuxFu is not that strong so I may have messed this up somewhere along the way.  I know I have downloaded, and compiled the following pieces of software:

IceStudio
prjtrellis
Yosys
nextPNR

I was then pointed towards the apio project by a colleague and downloaded the windows version of that software along with all the other bits and pieces needed by following the instructions here:

https://github.com/ulx3s/fpga-odysseus

It installed fine although I would ensure that if following the instructions that you don't upgrade the apio software.

Once presented with the command prompt by loading the ConEmu.exe program it is pretty easy to get started:


This screen brought my back to my days of the DOS prompt.  I know the linux command prompt is fairly similar but I just don't use linux enough to be comfortable with it...I am slowly improving though...

I made a folder called Alex and then a sub folder called ulx3s, you could use any folder names you like.  I then copied two files into the folder:

apio.ini - found from the folder C:\msys64\src\fpga-odysseus\tutorials\01-Basics\01-LED
ulx3s_v20.lpf - found from the folder C:\msys64\src\fpga-odysseus\tutorials\01-Basics\01-LED

The apio.ini file is a text file that tells the apio software everything needed to prepare files for upload to the ulx3s board and ulx3s_v20.lpf is the constraints file for the board, it tells apio and all of the other software which pins are connected to what and where between the FPGA and the external peripherals.

I next created a simple text file in notepad++ - you could use any text editor to be honest.  I called it top.v and typed out the following simple program:

//Hello world LED program

//create a module called top
module top (
    output [7:0] led, //create an output vector called 'led' with 8 bits
    output wifi_gpio0 //create an output for the wifi gpio
);
    assign led = 8'b10101010; //set the state of the bits in the vector to the number 170
 // this sets the bits on and off alternately

    assign wifi_gpio0 = 1'b1; // set the wifi gpio wifi high 
endmodule //end the module

Save the file in the directory made previously:

C:\msys64\src\Alex\ulx3s

Next jump to the ConEmu command prompt and make sure all of the files we need are there by typing ls and hit enter :


next type the following: apio build --board ulx3s-45f'

You should see the following displayed, ignore the warning messages:


  The following files will have been created in the directory:

Exciting times....now it is time to upload the program to the FPGA.  Make sure the ULX3S board is plugged into a suitable USB port and powered up.

Type the following command:

apio upload --board ulx3s-45f

If all goes according to plan you should see the following:


Next type the following:

apio clean

This removes all of the unnecessary files created during the processes.  Finally its time to admire your work.  If everything went according to plan you should see the following LED pattern on your ULX3S!


Ok so its nothing special but it's a start. I'm hoping soon to do a bit more with it.  I hear good things about something called ICE Studio:

https://icestudio.io/

It doesn't have support for the ulx3s yet but I'm hopeful it can be added soon!

That's all for now - Langster!