How to initialize PLL block on ECP5 FPGA using 'ecppll'.
A phase-locked loop or phase lock loop (PLL) is a control system that generates an output signal whose phase is fixed relative to the phase of an input signal. Keeping the input and output phase in lockstep also implies keeping the input and output frequencies the same, thus a phase-locked loop can also track an input frequency. And by incorporating a frequency divider, a PLL can generate a stable frequency that is a multiple of the input frequency.
In context of Computer Architecture, PLLs are used to generate a stable, high-frequency clock signal from a lower-frequency reference clock and is crucial for microprocessors and other digital circuits that require high-speed operation. Xilinx FPGAs have their own Clocking Wizard IP to get the output signal with required frequency and phase difference. However this is not the case with Lattice FPGAs
In this blog post, I will document what I did to intialize the PLL block on ECP5 FPGA and verified the output on the DSO (Digital Signal Oscilloscope) with instructions for Debian-based linux distros ( I am an Arch user but I feel most of them use Ubuntu/Debian so I have documented the blog for those users. Arch users can install directly the below packages through AUR ) . I am using the onboard PLL block on ECP5 FPGA to generate a 100Mhz clock signal from 12Mhz clock signal on iCEBreaker++ FPGA, initialised by ‘ecppll’ tool.
Step 1: Software Setup
As we are working with the ECP5 FPGA fabric, we need to install Yosys suite and nextpnr-ecp5 tools to program the fabric.
-
To install Yosys, follow the steps provided here (I prefer building from source, there are other ways to install yosys and you are free to try it). You can verify the installation by executing
yosys --help
oryosys -p "help"
. -
nextpnr-ecp5 relies on Project Trellis. Install it with following commands :-
git clone --recursive https://github.com/YosysHQ/prjtrellis
cd prjtrellis/libtrellis
cmake -DCMAKE_INSTALL_PREFIX=/usr/local .
make
sudo make install
After this, we have to clone the nextpnr repository and follow the given steps:-
cd nextpnr/
cmake . -DARCH=ecp5 -DTRELLIS_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
Step 2: Generate PLL module in Verilog
Now we are done with installations, Let’s start with generating PLL module using ecppll
tool. This tool is included in Project Trellis and you can verify the installation by executing ecppll --help
.
Now the board I am using, iCEBreaker++ has internal 12Mhz crystal oscillator to generate the clock and I want 100Mhz clock as output. So, my ecppll command will be to generate 100Mhz clock from 12Mhz clock will be :-
ecppll -f test.v -n test -i 12 -o 100
- ‘-f’ argument is used to generate a verilog file containing the instantation named as “test.v”.
- ‘-n’ argument is used to name the module i.e “test”.
- ‘-i’ argument is used to specify the input frequency in Mhz.
- ‘-o’ argument is used to specify the output frequency in Mhz.
You can find more arguments and understand their uses by executing ecppll --help
or by following this documentation.
Although the tool won’t echo a message of verilog file generation, you can verify yourself using ls
command and see that the file (named as test.v in my case) has been generated in your directory.
Note:- If you already have a file with the same name, the contents of the file will get overwritten by the tool. So make sure you give a unique file name for your instantation if you do not want your previous contents to get overwritten.
Step 3: Programming the FPGA
The only way to observe whether the PLL output is correct or not, is by programming the FPGA and use a DSO (Digital Signal Oscilloscope) to verify it. Use a text editor to create a .pcf
file which maps your device pins with input and output of your Verilog file (I mapped it to PMOD pins on my board, as they can work as GPIO pins to observe the output). Here’s an example that I followed. You might have to refer the schematic of your board to find the pin number which you want to map.
Here’s the Makefile that I used to synthesize, generate bitstream and flash it on the board -
PROJ=test
all: ${PROJ}.bit
%.json: %.v
yosys -p "synth_ecp5 -json $@" $<
%_out.config: %.json
nextpnr-ecp5 --json $< --textcfg $@ --12k --package CABGA256 --lpf ${PROJ}.pcf
%.bit: %_out.config
ecppack --compress $< $@
prog: ${PROJ}.bit
ecpprog -S ${PROJ}.bit
flash: ${PROJ}.bit
ecpprog ${PROJ}.bit
clean:
$(RM) -f ${PROJ}.bit ${PROJ}_out.config ${PROJ}.json
.PHONY: prog clean
Use a text editor and copy above Makefile in the same directory. execute it and connect your output pin with DSO’s probes to see the output.
Acknowledgements
- I like to thank Greg Davill for his advent-calendar-of-circuits-2020 Github repository, especially the icebreaker++-ram project which has been immensely helpful for me to refer the schematic of the board to map correct pins with my verilog code.
- I like to thank Piotr Esden-Tempski and Omkar Bhilare to provide me with the iCEBreaker++ board and the icebreaker-ecp5-examples repository that I have refered while working on this blog.