Bringing it all together

Up until this point you have made different hardware designs to achieve a number of features. These features will be used in the board as it functions as Christmas light.

Before going to a processor or communication, things needs to be fixed. The most important thing, from a hardware point of view, is the interface. The following features will need to be present:

Targets

  • LED 0
  • LED 1
  • LED 2
  • LED 3
  • RGB LED 0
  • RGB LED 1

Functions

  • fixed value on LED (0/1)
  • blinking LED on certain frequencies
  • the color on the RGB LEDs
  • the brightness on the RGB LEDs

The configuration which will be applied to your PYNQ Z2, eventually, will come through communication. For now, you will prepare it for communication with a processor. As we all have to agree on the interface and the commands the following is proposed:

LEDs

The 8 rightmost bits (bits 7 downto 0) have an effect on the LEDs. The most-significant nibble (7 downto 4) selects the affected LED(s), while the least-significant nibble selectes the affected pattern. The LED selection is one-hot coded, the pattern is binary coded.

bit description argument
3-0 blank the selected LED(s) “0000”
drive the selected LED(s) “0001”
blink the selected LED(s) Frequency = 2(nibble % 4) Hz
4 LED 0 see 3-0
5 LED 1 see 3-0
6 LED 2 see 3-0
7 LED 3 see 3-0

RGB LEDs

The next-to-last 10 bits (bits 17 downto 8) have an effect on the RGB LEDs. The 6 most significant bits select the affected RGB LED(s), while the least-significant nibble selectes the affected pattern. The selection is one-hot coded, the pattern is binary coded.

bit description argument
11-8 duty cycle “0000” = 0%, “1111” = 100%
12 red on RGB LED 0 see 11-8
13 green on RGB LED 0 see 11-8
14 blue on RGB LED 0 see 11-8
15 red on RGB LED 1 see 11-8
16 green on RGB LED 1 see 11-8
17 blue on RGB LED 1 see 11-8

Operation

The commands are explained above. A few example are given here.

  • When the PYNQ Z2 receives the command 0x000000F1, this selects ALL the LEDs (because of the F) and their operation is: LED on (because of the 1).
  • When the PYNQ Z2 receives the command 0x00008F00, this selects the Red led from RGB LED 1 and it turns it on.
  • When the PYNQ Z2 receives the command 0x0000471C, this selects the Blue led from RGB LED 0 and it turns it on with a (roughly) 50% duty cycle. Additionally is has the left most LED oscillate at 1 Hz.

As you can see from the examples above, the commands can have one single effect, or can have multiple effects. This allows us configure the lights more finely grained. If you would want to recreate exercise 4, you would have to send four commands: 0x1C, 0x2D, 0x4E, 0x8F.

It is useful to keep a copy of the configuration for each target. Otherwise every command would overwrite the previous command. Off course it is not required to keep the complete configuration for each target. Only the relevant information needs to be memorised.

To indicate that a command is ready-for-interpretation, a single input is used: command_valid. As long as this input is high, the command should stay constant. There are no other limitations. The image below gives an example how the commands can be received to recreate exercise 4.

Image created with WaveDrom

Final layout

The entity/module on the hierarchical top-level should look as shown below. Keep the port names as they are shown in the VHDL/Verilog code below.

VHDL

entity xmas_light is
  port (
    reset : in STD_LOGIC;
    clock : in STD_LOGIC;
    command : in STD_LOGIC_VECTOR(31 downto 0);
    command_valid : in STD_LOGIC;
    RGB0 : out STD_LOGIC_VECTOR(2 downto 0);
    RGB1 : out STD_LOGIC_VECTOR(2 downto 0);
    LEDs : out STD_LOGIC_VECTOR(3 downto 0)
  );
end xmas_light;

Verilog

module xmas_light (
  input         reset,
  input         clock,
  input  [31:0] command,
  input         command_valid,
  output [2:0]  rgb0,
  output [2:0]  rgb1,
  output [3:0]  leds
);

Testing (, testing, and some more testing)

With the toplevel-design ready, it needs to be tested. Remember the rule-of-thumb which states that for each hour of designing you should spend two hours on testing !!

The VHDL-code below shows an example of the testbench. Verilog users can also use a VHDL testbench (and the other way around) !! An example waveform as shown below, should be obtained.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity xmas_light_tb is
end xmas_light_tb;

architecture Behavioural of xmas_light_tb is

  component xmas_light is
    port (
      reset : in STD_LOGIC;
      clock : in STD_LOGIC;
      command : in STD_LOGIC_VECTOR(31 downto 0);
      command_valid : in STD_LOGIC;
      RGB0 : out STD_LOGIC_VECTOR(2 downto 0);
      RGB1 : out STD_LOGIC_VECTOR(2 downto 0);
      LEDs : out STD_LOGIC_VECTOR(3 downto 0)
    );
  end component;

  signal reset, clock : STD_LOGIC;
  signal command : STD_LOGIC_VECTOR(31 downto 0);
  signal command_valid : STD_LOGIC;
  signal RGB0 : STD_LOGIC_VECTOR(2 downto 0);
  signal RGB1 : STD_LOGIC_VECTOR(2 downto 0);
  signal LEDs : STD_LOGIC_VECTOR(3 downto 0);

  constant clock_period : time := 10 ns;

begin

  -------------------------------------------------------------------------------
  -- STIMULI
  -------------------------------------------------------------------------------
  PSTIM: process
  begin
    reset <= '1';
    command <= x"00000000";
    command_valid <= '0';
    wait for clock_period*10;

    reset <= '0';
    wait for clock_period*1000;
    
    --*************************************************************************

    -- turn on all LEDs
    command <= x"000000_F1";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate all LEDs at 1 Hz
    command <= x"000000_FC";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate all LEDs at 2 Hz
    command <= x"000000_FD";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate all LEDs at 4 Hz
    command <= x"000000_FE";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate all LEDs at 8 Hz
    command <= x"000000_FF";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    --*************************************************************************

    -- turn on LED(0)
    command <= x"000000_11";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off LED(0)
    command <= x"000000_10";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(0) at 1 Hz
    command <= x"000000_1C";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(0) at 2 Hz
    command <= x"000000_1D";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(0) at 4 Hz
    command <= x"000000_1E";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(0) at 8 Hz
    command <= x"000000_1F";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    --*************************************************************************

    -- turn on LED(1)
    command <= x"000000_21";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off LED(1)
    command <= x"000000_20";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(1) at 1 Hz
    command <= x"000000_2C";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(1) at 2 Hz
    command <= x"000000_2D";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(1) at 4 Hz
    command <= x"000000_2E";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(1) at 8 Hz
    command <= x"000000_2F";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

      -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;


    --*************************************************************************

    -- turn on LED(2)
    command <= x"000000_41";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off LED(2)
    command <= x"000000_40";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(2) at 1 Hz
    command <= x"000000_4C";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(2) at 2 Hz
    command <= x"000000_4D";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(2) at 4 Hz
    command <= x"000000_4E";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(0) at 8 Hz
    command <= x"000000_4F";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    --*************************************************************************
    
    -- turn on LED(3)
    command <= x"000000_81";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- turn off LED(3)
    command <= x"000000_80";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(3) at 1 Hz
    command <= x"000000_8C";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(3) at 2 Hz
    command <= x"000000_8D";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(3) at 4 Hz
    command <= x"000000_8E";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;

    -- oscillate LED(1) at 8 Hz
    command <= x"000000_8F";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;


    -- turn off all LEDs
    command <= x"000000_F0";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*1000;


    -- turn off all RGB LEDs
    command <= x"000_3F0_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_0 - PWM1
    command <= x"000_011_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_0 - PWM2
    command <= x"000_022_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_0 - PWM3
    command <= x"000_043_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_1 - PWM4
    command <= x"000_084_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_1 - PWM5
    command <= x"000_105_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_1 - PWM6
    command <= x"000_206_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_0 - PWM7
    command <= x"000_017_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_0 - PWM8
    command <= x"000_028_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_0 - PWM9
    command <= x"000_049_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_1 - PWMA
    command <= x"000_08A_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_1 - PWMB
    command <= x"000_10B_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_1 - PWMC
    command <= x"000_20C_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_0 - PWMD
    command <= x"000_01D_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_0 - PWME
    command <= x"000_02E_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_0 - PWMF
    command <= x"000_04F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_1 - PWMF
    command <= x"000_08F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_1 - PWMF
    command <= x"000_10F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on BLUE_1 - PWMF
    command <= x"000_20F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on RED_0 - PWMF
    command <= x"000_01F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    -- turn on GREEN_0 - PWME
    command <= x"000_02F_00";  command_valid <= '1';  wait for clock_period*4;
    command <= x"000_000_00";  command_valid <= '0';  wait for clock_period*4;
    wait for clock_period*10000;

    wait;
  end process;


  -------------------------------------------------------------------------------
  -- DEVICE UNDER TEST
  -------------------------------------------------------------------------------
  DUT: component xmas_light port map(
    reset => reset,
    clock => clock,
    command => command,
    command_valid => command_valid,
    RGB0 => RGB0,
    RGB1 => RGB1,
    LEDs => LEDs
  );

  
  -------------------------------------------------------------------------------
  -- CLOCK
  -------------------------------------------------------------------------------
  PCLK: process
  begin
    clock <= '1';
    wait for clock_period/2;
    clock <= '0';
    wait for clock_period/2;
  end process PCLK;

end Behavioural;