Chapter 12 ■ Light Sensors: Turning a Laser Pointer into a Hi-Tech Tripwire
Figure 12-34. Light sensor counter LED design
246
Chapter 12 ■ Light Sensors: Turning a Laser Pointer into a Hi-Tech Tripwire
Listing 12-2 is text version for easy copying.
Listing 12-2. light_sensor_counter_led.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity light_sensor_counter_led is
generic(
-- Adjust sensitivity and offset with these two parameters.
-- Find the right Low boundary Higher than ROOM lighting and adjust the trigger point
LOW_BOUNDARY : integer := 1000;
HIGH_BOUNDARY : integer := 3000;
NUM_LEDS : integer := 8
);
port(
clk : in std_logic;
avl_str_sink_valid : in std_logic;
avl_str_sink_channel : in std_logic_vector(4 downto 0);
avl_str_sink_data : in std_logic_vector(11 downto 0);
avl_str_sink_startofpacket : in std_logic;
avl_str_sink_endofpacket : in std_logic;
pb4 : in std_logic; -- when push the button, this go Low
led : out std_logic_vector(NUM_LEDS-1 downto 0)
);
end light_sensor_counter_led;
architecture arch of light_sensor_counter_led is
-- Input registers
signal reg_avl_str_sink_valid : std_logic;
signal reg_avl_str_sink_channel : std_logic_vector(avl_str_sink_channel'range);
signal reg_avl_str_sink_data : std_logic_vector(avl_str_sink_data'range);
signal reg_avl_str_sink_startofpacket : std_logic;
signal reg_avl_str_sink_endofpacket : std_logic;
signal received_sample : std_logic_vector(11 downto 0);
signal count_number_of_trip : unsigned(7 downto 0); -- Counter
signal arm : std_logic := '0'; -- Go High when the received_sample is High value
signal trigger : std_logic := '0'; -- Trigger only when change from High to Low value
signal trigger_dly : std_logic := '0';
begin
process(clk)
variable received_sample_int : integer range 0 to 2**received_sample'length-1;
begin
if rising_edge(clk) then
-- Load the input registers
reg_avl_str_sink_valid <= avl_str_sink_valid;
247
Chapter 12 ■ Light Sensors: Turning a Laser Pointer into a Hi-Tech Tripwire
reg_avl_str_sink_channel <= avl_str_sink_channel;
reg_avl_str_sink_data <= avl_str_sink_data;
reg_avl_str_sink_startofpacket <= avl_str_sink_startofpacket;
reg_avl_str_sink_endofpacket <= avl_str_sink_endofpacket;
-- Get the data from ADC channel 4, which is the photo sensor
if reg_avl_str_sink_channel = "00100" then -- channel 4
if reg_avl_str_sink_valid = '1' then
received_sample <= reg_avl_str_sink_data;
end if;
end if;
received_sample_int := to_integer(unsigned(received_sample));
--Arm when the ADC input is high
if(trigger = '1' or pb4 = '0') then
arm <= '0';
elsif((received_sample_int > HIGH_BOUNDARY) and arm = '0')then
arm <= '1';
end if;
if((received_sample_int < LOW_BOUNDARY) and arm = '1')then
trigger <= '1';
else
trigger <= '0';
end if;
trigger_dly <= trigger;
-- Increnment the LED counter evertime the trip trigger
-- The LED counter will clear by push button 1
if(pb4 = '0') then
count_number_of_trip <= (others => '0');
elsif (trigger_dly = '0' and trigger = '1') then -- rising edge of the trigger
if (count_number_of_trip < 255) then -- Count to the MAX = 255 (2^12 -1)
count_number_of_trip <= count_number_of_trip + 1;
end if;
end if;
end if;
end process;
-- convert unsigned value to std logic vector
led <= not(std_logic_vector(count_number_of_trip));
end;
248
Chapter 12 ■ Light Sensors: Turning a Laser Pointer into a Hi-Tech Tripwire
12.6.3 Light Sensor Top Level
This module is used to connect all of the IPs and the two modules we created in this chapter. It also provides
inputs and outputs to connect to the external world (anything not inside the FPGA). Examine the code in
Listing 12-3. It defines an entity, which are the inputs and outputs as well as some parameters. Tables 12-2
and 12-3 show the generic and port functions in the design.
Table 12-2. Generic Parameters Functions
Generic Name Function
LOW_BOUNDARY Define the ADC expected value in room normal light brightness
HIGH_BOUNDARY Define the ADC expected value of laser beam on the photo sensor
NUM_LEDS Number of LEDs. Set to 8 our system.
All three of the generics (parameters) are directly used by light_sensor_counter_led.vhd.
Table 12-3. Port Names Functions
Port Name Function
SYS_CLK Input:
BeMicro MAX10 on board clock and the frequency is 50MHz
USER_LED Output:
All eight LEDs connection
PB Input:
All four user push button connection. In this design we only use the number 4 push
buttons.
SYS_CLK is connected to the cascade_pll.vhd clock input: inclock0. USER_LED and PB(4) are
connected to light_sensor_counter_led.vhd.
The light_sensor_top.vhd file declares some components and signals which will be used by the top-
level design. After the BEGIN statement, all modules: cascade_pll, adc_pll, adc_interface, light_sensor_adc_
sequencer, and light_sensor_counter_led are stitched together as we saw in Figure 12-28.
In the code in Listing 12-3, we added a NOT gate in the design. Following is the VHDL code of that
NOT gate:
pll_cascade_locked_reset_wire_n <= not pll_cascade_locked_reset_wire;
We would like to keep the second PLL (adc_PLL) in reset when the first PLL (cascade_pll) is NOT
locked. The right-hand side of the code statement (pll_cascade_locked_reset_wire) is connected to the first
PLL lock output and left-hand side is using it as a reset signal for the second PLL. We need to add a NOT
gate between the two signals because the second PLL reset is active HIGH reset. When the first PLL is locked
(High), then the second PLL reset is LOW (NOT reset).
249
Chapter 12 ■ Light Sensors: Turning a Laser Pointer into a Hi-Tech Tripwire
12.6.3.1 Code for Light Sensor Top Level
Listing 12-3. light_sensor_top.vhd
library ieee;
use ieee.std_logic_1164.all;
entity light_sensor_top is
generic(
LOW_BOUNDARY : integer := 1800; -- May vary from board to board...
HIGH_BOUNDARY : integer := 2600; -- May vary from board to board...
NUM_LEDS : integer := 8
);
port(
SYS_CLK : in std_logic; -- inclk0
USER_LED : out std_logic_vector(NUM_LEDS downto 1);
-- pushbutton switch ins
PB : in std_logic_vector(4 downto 1) -- Only use the PB 4
);
end light_sensor_top;
architecture arch of light_sensor_top is
component cascade_pll is
port
(
areset : in std_logic := '0';
inclk0 : in std_logic := '0';
c0 : out std_logic;
locked : out std_logic
);
end component;
component adc_pll
port(inclk0 : in std_logic;
areset : in std_logic;
c0 : out std_logic;
c1 : out std_logic;
locked : out std_logic
);
end component;
component adc_interface is
port (
adc_pll_clock_clk : in std_logic := '0'; -- adc_pll_clock.clk
adc_pll_locked_export : in std_logic := '0'; -- adc_pll_locked.export
clock_clk : in std_logic := '0'; -- clock.clk
reset_sink_reset_n : in std_logic := '0'; -- reset_sink.reset_n
250