Posts
Search
Contact
Cookies
About
RSS

A newbies guide to FPGA's (Papilio Pro)

Added 14 Dec 2013, 7:58 a.m. edited 19 Jun 2023, 3:36 a.m.

Well I'm leaving Java development for a little while and for the time being future blog posts will be a little of the blind leading the blind! This short series will be on FPGA's for people new to FPGA's written by someone also new to FPGA's ! I started this first project just as a bit of code to flash a LED on and off every few seconds or so, after developing it further I used PWM (Pulsed Width Modulation) to make the LED glow on and off. Obviously you need a minimum current for current to even flow through a diode so you can't just vary an analogue voltage to make a LED dimmer, this is where PWM comes in. Simply put all you do is change the duty cycle of a square wave, if a square wave is ON 10% and OFF 90% of the time the LED will look dim, if its ON 90% of the time and OFF 10% of the time it will look much brighter. In order to avoid any flickering we make the square wave frequency very, very! fast :) (we likes fast!) after all its the simplest silicon junction you can make, with typical switching times in the nanoseconds! So much for the general theory, but now how do we program this FPGA thingie, first of all you need to select a prototyping board, I chose the Papilio Pro from the Gadget Factory - I have to say I'm over the moon with this as a starter kit, it really is a nice bit of kit. I have to strongly recommend before you go any further and even insist you read Hamsters intro to FPGA's Its a great read, read it all as you would a novel and do the simulation too, this will hold you while you wait for your Papilio Pro to arrive... Now I'm going to assume you've come back here after doing the requisite reading and have some nice shiny new FPGA hardware on your workbench ;) The Papilio Pro has a user LED (led1) some flash memory for power on programming (when the FPGA gets power it programs itself from this flash memory) as well as a dual channel USB<>Serial chip there is also some SDRAM this isn't as straight forward to access as SRAM but it does have cost and performance benefits... oh and I haven't mentioned what are in effect GPIO pins you have 48 of them arranged in 3 "wings" Before starting any coding you need to decide what pins you are using, to do this you use a User Constraint File (ucf) lets take a really simple one from my first project

NET led1 LOC = "P112" | IOSTANDARD=LVTTL;
NET clock LOC = "P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns;

CONFIG PROHIBIT=P144;
CONFIG PROHIBIT=P69;
CONFIG PROHIBIT=P60;
both led1 and clock are fixed these pins are hardwired and the PROHIBIT config keeps you (and the IDE) clear of pins that are either hardwired to GND or VCC for config or other reasons. A clock period of 31.25ns corresponds to a clock frequency of 32Mhz this is a paradigm shift if you're used to micro controllers where you're usually working with millisecond timers... and not only that 32Mhz isn't the limit, its really just a useful frequency, 32 is one of those numbers with a high level of utility in common with all the other base 2 numbers (2,4,8,16,32,64......4096 etc!) You can even make a micro controller circuit which on the Papilio Pro typically run at 100mhz (not too shabby) as I understand it its also possible to get simple circuits running up to 300mhz but you really need to know how to work the IDE timing constraints and write really really tight expert code for uber hacking like that! As I usually do I'm going to break up the code into significant sections and leave you a download link for the code below...
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.numeric_std.all;
like nearly all languages you'll start off with a clause of code specifying which libraries to include VHDL is case insensitive so you can be as sloppy as you like but it is very verbose and very strict about its grammar. In case you haven't twigged you really ain't programming in the traditional sense - really its a descriptive language, there is almost NO program flow :-o the nearest to flow you will get is IF / THEN / ELSE aside from the IF / ELSE everything is happening at the same time and the same "step" of code happens over and over again every clock cycle... This coding paradigm is something that often just stumps traditional programmers, you need to get some practive with Logisim and also learn about Finite State Machines (FSM)
entity main is
Port (
 clock : in STD_LOGIC;
 led1 : out STD_LOGIC
 );
end main;
My main (and only!) entity is defined and its input and output ports specified we only have a clock input (all your circuits should have this at least!) and a single output (I have a VGA "wing") but I'm leaving that fun for later (can't wait to make my own VGA test pattern circuit! but that's for later!)
architecture Behavioral of main is

    signal counter : STD_LOGIC_VECTOR(19 downto 0) := (others => '0');
 signal onDuty : signed(7 downto 0) := (others => '0');
 signal dutyCount : signed(7 downto 0) := (others => '0');
  signal subCounter : std_logic_vector(10 downto 0) := "00000000001";
   signal direction : boolean := true;
Now we can begin to define how the circuit is described first of all our "variables" or what are really bundles of flip flops... a "signed(7 downto 0)" is a signed 8 bit collection of bits I'm only using signed values here so I can easily see if a value drops below zero...
begin
  clock_proc: process(clock)
      begin
           if rising_edge(clock) then
              counter(19 downto 0) <= counter(19 downto 0) + 1;
our clock process is sensitive to changes on the clock input pin... whenever we see a rising edge of the clock square wave the we increment a 20 bit counter. As I'm not bothering with any of the FPGA's clock tiles (there's PLL's and assorts of goodies to use!) I'm using a 20 bit counter to bring the 32 million pules a second into some more usable ball park, so we wait 32*10^6 / 2^20 or roughly a 30th of a second.
if counter = 0 then 
   -- change the duty cycle
    if direction then
       onDuty(7 downto 0) <= onDuty(7 downto 0) + 2; -- +2%
 else 
       onDuty(7 downto 0) <= onDuty(7 downto 0) - 2; -- -2%
 end if;

 if onDuty < 0 then
       onDuty <= (others => '0');
      direction <= not direction;
  end if;
 if onDuty > 99 then
      onDuty <= "01100011";
      direction <= not direction;
  end if;
end if; -- counter = 0
So roughly 30 times a second we are changing the duty cycle percentage and if needed changing the direction of travel (as it were) that the fade is traveling in...
-- down counter
subCounter(10 downto 0) <= subCounter(10 downto 0) - 1;
    if subCounter = 0 then
      subCounter <= "10000000000";
       dutyCount(7 downto 0) <= dutyCount(7 downto 0) + 1;      if dutyCount > 99 then
           dutyCount <= (others => '0');
       end if;

     if dutyCount < onDuty then
           led1 <= '1';
       else
            led1 <= '0';
       end if;
 end if; -- subCounter = 0
It's been pointed out to me that instead of using a separate subcounter and duty counter I could have used the lower part of the main counter, but hay its a tiny tiny circuit underutilized less that half a percent of the FPGA's resources, anyhoo... this way the actual PWM bit is basically a little easier to see whats happening with the separate counters... I'll leave it to you to see how you could re-implement the whole thing just using the main counter.... and finally (phew) heres the whole main VHDL