Skip to content

Example: Blink LEDs

Julian Kemmerer edited this page Aug 2, 2020 · 20 revisions

This is an in depth break down of an blinking LED example design to show the PipelineC tool flow.

This example is from a series of examples designed for the Arty Board.

Source

// Use the switches to control LED blink rate

#include "uintN_t.h"

// Each main function is a clock domain
// Only one clock in the design for now 'sys_clk' @ 100MHz
#pragma MAIN_MHZ sys_clk_main 100.0
#pragma PART "xc7a35ticsg324-1l" // xc7a35ticsg324-1l = Arty, xcvu9p-flgb2104-2-i = AWS F1

// Make structs that wrap up the inputs and outputs
typedef struct sys_clk_main_inputs_t
{
	// The switches
	uint4_t sw;
} sys_clk_main_inputs_t;
typedef struct sys_clk_main_outputs_t
{
	// The LEDs
	uint1_t led[4];
} sys_clk_main_outputs_t;

// Blinking means turn on LED for some amount of time, and then turn off
// How much time?
#define BLINK_CLK_CYCLES 10000000
// The switch value, ex. sw[3:0] = 0b1101 = 13
// multiplies the above constant to determine actual blink rate
// Ex. 10000000*13 = 130000000 cycles, 100MHz = 10ns per clock, 130000000 * 10ns = 1.3 sec

// We need to count up to whatever sw*BLINK_CLK_CYCLES equals
uint28_t counter; // Inits to zero
// And we need to remember if the LEDs are on or not - so we know what to do next
uint1_t leds_on;

// The sys_clk_main function
sys_clk_main_outputs_t sys_clk_main(sys_clk_main_inputs_t inputs)
{
    // Do what counters do, increment
    counter = counter + 1;

    // If the counter equals or greater then
    // time to toggle the led and reset counter
    if(counter >= (inputs.sw * BLINK_CLK_CYCLES))
    {
        leds_on = !leds_on;
        counter = 0;
    }

    // Drive output leds (all 4)
    sys_clk_main_outputs_t outputs;
    outputs.led[0] = leds_on;
    outputs.led[1] = leds_on;
    outputs.led[2] = leds_on;
    outputs.led[3] = leds_on;

    return outputs;
}

VHDL wrapper for Vivado

-- Top level file connecting to PipelineC generated code

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;

-- PipelineC packages
use work.c_structs_pkg.all;

entity board is
  port (
    CLK100MHZ : in std_logic;
    sw : in std_logic_vector(3 downto 0);
    led : out std_logic_vector(3 downto 0)
  );
end board;

architecture arch of board is
  
-- Sync inputs to CLK100MHZ
signal sw_r, sw_rr : std_logic_vector(3 downto 0);
  
-- IO type conversion
signal sys_clk_main_inputs : sys_clk_main_inputs_t;
signal sys_clk_main_outputs : sys_clk_main_outputs_t;
  
begin

-- Sync inputs to CLK100MHZ
process(CLK100MHZ) begin
    if rising_edge(CLK100MHZ) then
        sw_r <= sw;
        sw_rr <= sw_r;
    end if;
end process;

-- IO type conversion
process(
    -- Inputs to module
    sw_rr, 
    -- Outputs from PipelineC
    sys_clk_main_outputs
) begin
    -- Input
    sys_clk_main_inputs.sw(0) <= sw_rr(0);
    sys_clk_main_inputs.sw(1) <= sw_rr(1);
    sys_clk_main_inputs.sw(2) <= sw_rr(2);
    sys_clk_main_inputs.sw(3) <= sw_rr(3);
    
    -- Outputs
    led(0) <= sys_clk_main_outputs.led(0)(0);
    led(1) <= sys_clk_main_outputs.led(1)(0);
    led(2) <= sys_clk_main_outputs.led(2)(0);
    led(3) <= sys_clk_main_outputs.led(3)(0);
end process;

-- The PipelineC generated entity
top_inst : entity work.top port map (
    clk_sys_clk_main => CLK100MHZ,
    sys_clk_main_inputs => sys_clk_main_inputs,
    sys_clk_main_return_output => sys_clk_main_outputs
);

end arch;
Clone this wiki locally