You are on page 1of 20

Nicholas Alcazar

Samuel Magana
CPE 133 - 01
Final Project

FPGA Alarm Clock


Step 1: Introduction

This guide will show how to implement an Alarm Clock using only a FPGA board. This project
was designed by Samuel Magana and Nicholas Alcazar for the CPE 133 course at Cal Poly San
Luis Obispo headed by Hummel. This alarm clock has functionality for: setting the current time,
setting the alarm time, arming or disarming the alarm, and snoozing the alarm. When the alarm
is activated, a game activates in order to stop the alarm. The goal of the game is the flip the
switches which correspond to the pattern of LEDs that light up. Pressing snooze will add 10
minutes to the alarm time and cancel the game.

Materials:

Basys 3 Xilinx Artix-7 FPGA (XC7A35T-ICPG236C)


Computer: Vivado HLx 2016.2

Step 2: Structural Diagram

All the logic for the Alarm Clock takes place on the FPGA board. The Top level box diagram for
the alarm clock has 8 inputs and 6 outputs. The board uses 2 switches to set either the time or
the alarm and another switch to arm the alarm. The board also used 8 switches for the alarm
game. The board uses three of the buttons. Two of these buttons are used when setting the
time and the other button is used as the snooze. 11 of the LEDs on the board were used. 3 of
the LEDs were used to show what mode the alarm clock was in and the other 8 LEDs were
used for the alarm game. Lastly, there are a 4 bit bus and a 7 bit bus used to power the 4 digit 7
segment display on the board.

Step 3: Submodules

Figure 1 : Top Module for Clock


Clock: This project uses a single module to hold, increment, and set the current time. As seen
in Figure 1 the module has 4 inputs: BHR (button for increasing the value for hours), BMIN
(button for increasing the value for minutes, CLK (clock which gets speed down to 60hz inside),
and switch (input for putting the clock into set mode). The two outputs for this module are
LEDSET (indicator light for the set function) and O[15:0] (a 16 bit bus to hold the value of time in
binary coded decimal). Its important to notice that the leftmost digit in the bus isnt in BCD to
allow for the display to show an AM/PM indicator on that digit.

Figure 2: Top Module for Display Selector


toDisplay: This project uses a multiplexer to choose what time is being pushed to the LED
display. As seen in Figure 2 the module has 3 inputs: ALARM[15:0] (the bus holding the alarm
time from the AlarmFunc module), TIMEO[15:0] (the bus holding the time from the clock
module), and selector (selector for the multiplexer based on the SETA switch Alarm Set).

Figure 3:Top Module for Driver


Driver: This project uses a module to push the value of time onto the 4 digit 7 segment display.
As seen in Figure 3 the module translates a binary number to the corresponding digit on a 7
segment display. Also, this module breaks up the input to show only one digit at a time to allow
the display to appear to show all digits simultaneously (running at 120hz). This module has 2
inputs: CLK (clock), and I[15:0] (16 bit bus holding the value for time). The module has two

outputs: D[3:0] (4 bit bus to determine which digit on the LED display is active), and O[6:0] (7 bit
but to light up the corresponding LEDs on one digit). Its important to note that the driver module
takes into account the special coding used in the first digit, bits 15 to 12.

Figure 4: Top Module for ALARM


AlarmFunc: This project uses a module to deal with everything related to the alarm, the alarm
time and the alarm game. As seen in Figure 4 the module has 8 inputs: ARM (switch to turn the
alarm on/off), BHR (used to increment the value for hours in the alarm time, BMIN (used to
increment the value for minutes in the alarm time), CLK (clock), LEDGAME[7:0] (the bus of 8
switches used in the alarm game), SETA (switch to allow for setting the time for the alarm),
SETTIME (the switch to set to current time to avoid cases when both SETTIME and SETA are
high), SNOOZEBUTTON (button to allow for the alarm to snooze), and CURRTIME[15:0]
(output from the clock module to be compared with the value of alarm time). The module has 4
outputs: LEDALARMON (LED to indicate the status of the alarm), LEDALARMSET (LED to
indicate if youre setting the alarm time), LEDBUS[7:0] (the bus of 8 LEDs used in the alarm
game), and O[15:0] (the value of alarm time pushed to the display).

Source Code:
-------------------------------------------------- DISPLAY_CLOCK MAIN MODULE
------------------------------------------------entity Digital_CLock is
Port ( CLK : in STD_LOGIC;
BHR :in STD_LOGIC;
BMIN :in STD_LOGIC;
SWITCH : in STD_LOGIC;
LEDSET : out STD_LOGIC;
LEDBUS :out STD_LOGIC_VECTOR (7 downto 0);

LEDGAME : in STD_LOGIC_VECTOR(7 downto 0);


LEDALARMSET : out STD_LOGIC;
LEDALARMON : out STD_LOGIC;
SNOOZEBUTTON : in STD_LOGIC;
ARM : in STD_LOGIC;
SETA : in STD_LOGIC;
D : out STD_LOGIC_VECTOR (3 downto 0);
O : out STD_LOGIC_VECTOR (6 downto 0));
end Digital_CLock;
architecture Behavioral of Digital_CLock is
-------------------------------------------------- SUBMODULES COMPONENTS
-------------------------------------------------- CLOCK
component Time_mod Port (
BHR : in STD_LOGIC;
BMIN : in STD_LOGIC;
CLK : in STD_LOGIC;
LEDSET : out STD_LOGIC;
O : out STD_LOGIC_VECTOR ( 15 downto 0);
-- SETIN : in STD_LOGIC_VECTOR (15 downto 0);
switch : in STD_LOGIC);
end component;
-- ALARM FUNCTIONALITY
component alarm port(
CLK : in STD_LOGIC;
SETA : in STD_LOGIC;
BMIN : in STD_LOGIC;
BHR : in STD_LOGIC;
SNOOZEBUTTON : in STD_LOGIC;
SETTIME : in STD_LOGIC;
ARM : in STD_LOGIC;
currtime :in STD_LOGIC_VECTOR (15 downto 0);
O : out STD_LOGIC_VECTOR (15 downto 0);
LEDBUS :out STD_LOGIC_VECTOR (7 downto 0);
LEDGAME : in STD_LOGIC_VECTOR(7 downto 0);
LEDALARMSET : out STD_LOGIC;
-- LEDALARMR : out STD_LOGIC; -- rining alarm
LEDALARMON : out STD_LOGIC);
end component;
-- Display Selector
component MUXO Port ( ALARM : in STD_LOGIC_VECTOR (15 downto 0);
TIMEO : in STD_LOGIC_VECTOR (15 downto 0);

selector : in STD_LOGIC;
toDisp : out STD_LOGIC_VECTOR (15 downto 0));
end component;
-- Display Driver
component Display port(
CLK : in STD_LOGIC;
I : in STD_LOGIC_VECTOR (15 downto 0);
O : out STD_LOGIC_VECTOR (6 downto 0);
D : out STD_LOGIC_VECTOR (3 downto 0));
end component;
-------------------------------------------------- SIGNALS BETWEEM MODULES
------------------------------------------------signal DCLK : STD_LOGIC_VECTOR( 15 downto 0);
signal SETS: STD_LOGIC_VECTOR( 15 downto 0);
signal ALARMO : STD_LOGIC_VECTOR( 15 downto 0);
signal DisplayIN : STD_LOGIC_VECTOR( 15 downto 0);
begin
-------------------------------------------------- PORTMAPS
------------------------------------------------clock: time_mod port map( LEDSET=> LEDSET, O=>DCLK, CLK => CLK, SWITCH =>
SWITCH,BHR=>BHR,BMIN=>BMIN);
Driver: Display port map( CLK => CLK,I => DISPLAYIN , O => O, D=>D);
ALARMFUNC: ALARM port map(LEDBUS =>LEDBUS, SETTIME => SWITCH, LEDGAME =>
LEDGAME, BHR=>BHR,BMIN=>BMIN, SETA => SETA ,SNOOZEBUTTON => snoozebutton,
ARM => ARM, CURRTIME => DCLK,O=>ALARMO,
LEDALARMSET => LEDALARMSET, LEDALARMON => LEDALARMON,
CLK =>CLK);
todisplay: MUXO port map( TIMEO => DCLK, ALARM => ALARMO, selector => SETA, toDisp
=> DisplayIN);
end Behavioral;
-------------------------------------------------- SUNMODULE: CLOCK (hold, increment, and set the current time)
------------------------------------------------entity Time_mod is
Port ( CLK : in STD_LOGIC;
BHR: in STD_LOGIC;
BMIN : in STD_LOGIC;
LEDSET : out STD_LOGIC;
O : out STD_LOGIC_VECTOR (15 downto 0);
switch : in STD_LOGIC);
end Time_mod;

architecture Behavioral of Time_mod is


signal clock_one_hz : STD_LOGIC := '0';
signal m_1, m_10, h_1 : STD_LOGIC_VECTOR (3 downto 0);
signal h_10 : STD_LOGIC_VECTOR (2 downto 0);
signal am_pm : STD_LOGIC;
signal tmp : STD_LOGIC_VECTOR (15 downto 0);
--signal button :std_logic;
begin
-- convert 100Mhz to 1 hz
clock_conv: process (CLK) is
variable count: unsigned (24 downto 0) :="0000000000000000000000000";
-- variable countB: unsigned (25 downto 0) :="00000000000000000000000000";
begin
if (rising_edge(CLK)) THEN
count := count + 1;
--countB := countB +1;
if (count > 12500000) THEN
--50000000 (5 is used for simulation purposes)
clock_one_hz <= not clock_one_hz;
count := "0000000000000000000000000";
end if;
end if;
end process clock_conv;
-- process responsible to updating and holding time
time_proc: process (clock_one_hz,switch,bhr,bmin) is
variable sec
: unsigned (7 downto 0) := "00000000";
variable mins_1 : unsigned (3 downto 0) := "0000";
variable mins_10 : unsigned (3 downto 0) := "0000";
variable hours_1 : unsigned (3 downto 0) := "0010";
variable hours_10 : unsigned (2 downto 0) := "001";
variable am
: STD_LOGIC := '0';
begin
-- signal assignment ------------------tmp (3 downto 0)
<= STD_LOGIC_VECTOR(mins_1);
tmp (7 downto 4)
<= STD_LOGIC_VECTOR(mins_10);
tmp (11 downto 8) <= STD_LOGIC_VECTOR(hours_1);
tmp (14 downto 12) <= STD_LOGIC_VECTOR(hours_10);
tmp (15)
<= am;
----------------------------------------------if (rising_edge(clock_one_hz)) THEN

if(switch = '1') THEN


sec := "00000000";
LEDSET <= '1';
if (BMIN = '1') THEN
--bmin <= not bmin;
mins_1 := mins_1 +1;
if ( mins_1 > 9 ) THEN
mins_1 := "0000";
mins_10 := mins_10 + 1;
if ( mins_10 > 5 ) THEN
mins_10 := "0000";
end if;
end if;
end if;
if(BHR = '1') THEN
--bmin <= not bmin;
hours_1 := hours_1 + 1;
if ( (hours_1 = 2) AND (hours_10 = 1) ) THEN
am := not am;
end if;
if ( hours_10 > 0 ) THEN
if (hours_1 > 2) THEN
hours_1 := "0001";
hours_10 := "000";
end if;
else
if ( hours_1 > 9 ) THEN
hours_10 := "001";
hours_1 := "0000";
end if;
end if;
end if;
else
LEDSET <= '0';
sec := sec + 1;
if ( sec > 240 ) THEN
sec := "00000000";
mins_1 := mins_1 + 1;
if ( mins_1 > 9 ) THEN
mins_1 := "0000";
mins_10 := mins_10 + 1;
if ( mins_10 > 5 ) THEN

mins_10 := "0000";
hours_1 := hours_1 + 1;
--AM/PM toggle?
if ( (hours_1 = 2) AND (hours_10 = 1) ) THEN
am := not am;
end if;
if ( hours_10 > 0 ) THEN
if ( hours_1 > 2) THEN
hours_1 := "0001";
hours_10 := "000";
end if;
else
if ( hours_1 > 9 ) THEN
hours_10 := "001";
hours_1 := "0000";
end if;
end if;
end if;
end if;
end if;
end if;
end if;
end process time_proc;
output_sel: process (tmp) is
variable d4 : STD_LOGIC_VECTOR(3 downto 0);
begin
d4 := tmp (15 downto 12);
-- Output for right 3 digits
O(3 downto 0) <= tmp(3 downto 0);
O(7 downto 4) <= tmp(7 downto 4);
O(11 downto 8) <= tmp(11 downto 8);
-- Output for first digit (AM/PM included)
if (d4 = "0000") THEN
O(15 downto 12) <= "1100";
elsif ( d4 = "0001" ) THEN
O(15 downto 12) <= "1101";
elsif (d4 = "1000") THEN
O(15 downto 12) <= "1110";
elsif (d4 = "1001") THEN

O(15 downto 12) <= "1111";


else
O(15 downto 12) <= "0000";
end if;
end process output_sel;
end Behavioral;
-------------------------------------------------- SUNMODULE: DISPLAY DRIVER( translates a binary number to the corresponding digit on a
7 segment display)
------------------------------------------------entity display is
Port ( CLK : in STD_LOGIC;
I : in STD_LOGIC_VECTOR (15 downto 0);
O : out STD_LOGIC_VECTOR (6 downto 0);
D : out STD_LOGIC_VECTOR (3 downto 0));
end display;
architecture Behavioral of display is
signal d0, d1, d2,d3, tmp : STD_LOGIC_VECTOR (3 downto 0);
begin
d0 <= I(3 downto 0); -- mm 1's
d1 <= I(7 downto 4); -- mm 10's
d2 <= I(11 downto 8); -- hr 1's
d3 <= I( 15 downto 12);-- hr 10's

process (CLK) is
-- counter variable
variable count : unsigned (19 downto 0) := "00000000000000000000";
begin
if (rising_edge(CLK)) THEN
if (count = 833333) THEN
count := "00000000000000000000";
else
count := count + 1;
end if;
end if;
-- Select which digit to power
if (count < 208333) THEN
D <= "0111";
tmp <= d3;

elsif ( count > 208333 AND count < 416666) THEN


D <= "1011";
tmp <= d2;
elsif ( count > 416666 AND count < 624999) THEN
D <= "1101";
tmp <= d1;
elsif ( count > 624999 AND count < 833334) THEN
D <= "1110";
tmp <= d0;
else
D <= "1111";
end if;
end process;

-- BINARY TO HEX CONVERTER


with tmp select
-abcdefg
O <= "0000001" when "0000",
-- 0
"1001111" when "0001",
-- 1
"0010010" when "0010",
-- 2
"0000110" when "0011",
-- 3
"1001100" when "0100",
-- 4
"0100100" when "0101",
-- 5
"0100000" when "0110",
-- 6
"0001111" when "0111",
-- 7
"0000000" when "1000",
-- 8
"0000100" when "1001",
-- 9
"1111101" when "1100",
-- 0 - AM --c
"1001101" when "1101",
-- 1 -AM --d
"1111011" when "1110", -- 0 -PM -- e
"1001011" when "1111", --1 -PM -- f
"1111111" when others;

end Behavioral;
-------------------------------------------------- SUNMODULE: ALARM( SET ALARM TIME, SNOOZE, LED GAME,DISARM AND ARM
ALARM)
------------------------------------------------entity ALARM is
Port ( SETA : in STD_LOGIC;
BMIN : in STD_LOGIC;
BHR : in STD_LOGIC;

LEDBUS : out STD_LOGIC_VECTOR (7 downto 0);


LEDGAME : in STD_LOGIC_VECTOR(7 downto 0);
SNOOZEBUTTON : in STD_LOGIC;
SETTIME : in STD_LOGIC;
ARM : in STD_LOGIC := '0';
CLK : in STD_LOGIC;
currtime :in STD_LOGIC_VECTOR (15 downto 0);
O : out STD_LOGIC_VECTOR (15 downto 0);
LEDALARMSET : out STD_LOGIC;
LEDALARMON : out STD_LOGIC);
end ALARM;
architecture Behavioral of ALARM is
signal ALARMTIME :STD_LOGIC_VECTOR (15 downto 0);
signal clock_one_hz : std_logic := '0';
signal d4 :STD_LOGIC_VECTOR (3 downto 0);
signal clockw : std_logic := '0';
begin
alarm : process(ARM,SETA,BMIN,BHR,clock_one_hz,currtime) is
variable sec
: unsigned (7 downto 0) := "00000000";
variable mins_1 : unsigned (3 downto 0) := "0000";
variable mins_10 : unsigned (3 downto 0) := "0000";
variable hours_1 : unsigned (3 downto 0) := "0010";
variable hours_10 : unsigned (2 downto 0) := "001";
variable am
: STD_LOGIC := '0';
begin
ALARMTIME (3 downto 0)
<= STD_LOGIC_VECTOR(mins_1);
ALARMTIME (7 downto 4)
<= STD_LOGIC_VECTOR(mins_10);
ALARMTIME (11 downto 8) <= STD_LOGIC_VECTOR(hours_1);
d4(2 downto 0) <= STD_LOGIC_VECTOR(hours_10);
d4 (3)
<= am;
if (d4 = "0000") THEN
ALARMTIME(15 downto 12) <= "1100";
elsif ( d4 = "0001" ) THEN
ALARMTIME(15 downto 12) <= "1101";
elsif (d4 = "1000") THEN
ALARMTIME(15 downto 12) <= "1110";
elsif (d4 = "1001") THEN
ALARMTIME(15 downto 12) <= "1111";
else
ALARMTIME(15 downto 12) <= "0000";
end if;

O <= ALARMTIME;
-------------------------------------------------- BUTTONS USE CLOCK RISING EDGE TO SLOW DOWN CLOCK INCREMENT BASED ON
BUTTON PRESS
------------------------------------------------IF(rising_edge(clock_one_hz)) THEN
if ((SETA = '1') AND SETTIME = '1') THEN
LEDALARMSET <= '1';
-------------------------------------------------- SET BUTTON BASED ON BUTTONS PRESS
------------------------------------------------if (bmin = '1') THEN
mins_1 := mins_1 +1;
if ( mins_1 > 9 ) THEN
mins_1 := "0000";
mins_10 := mins_10 + 1;
if ( mins_10 > 5 ) THEN
mins_10 := "0000";
end if;
end if;
end if;
if(bhr = '1') THEN
hours_1 := hours_1 + 1;
if ( (hours_1 = 2) AND (hours_10 = 1) ) THEN
am := not am;
end if;
if ( hours_10 > 0 ) THEN
if (hours_1 > 2) THEN
hours_1 := "0001";
hours_10 := "000";
end if;
else
if ( hours_1 > 9 ) THEN
hours_10 := "001";
hours_1 := "0000";
end if;
end if;
end if;
else
LEDALARMSET <= '0';
end if;

-------------------------------------------------- SNOOZEBUTTON FUNCTIONALITY INCREMENTS SET ALARM TIME BY 10 MINS


------------------------------------------------If(SNOOZEBUTTON = '1') THEN
if(arm = '1') THEN
mins_10 := mins_10 +1;
if ( mins_10 > 5 ) THEN
mins_10 := "0000";
hours_1 := hours_1 + 1;
if ( (hours_1 = 2) AND (hours_10 = 1) ) THEN
am := not am;
end if;
if ( hours_10 > 0 ) THEN
if (hours_1 > 2) THEN
hours_1 := "0001";
hours_10 := "000";
end if;
else
if ( hours_1 > 9 ) THEN
hours_10 := "001";
hours_1 := "0000";
end if;
end if;
end if;
end if;
end if;
end if;
--end if;
--end if;
end process alarm;
alarmOFF: process (clock_one_hz,currtime,ARM, snoozebutton,LEDGAME) is
variable count : unsigned (1 downto 0) := "00";
begin
-------------------------------------------------- LED "GAME" USES SECOND CLOCK 'CLOCKW' TO 'RANDOMLY' CHOOSE FROM THE 4
CASES
-- COUNTER STOPS INCREMENTING WHEN ARM = '1'
------------------------------------------------if(rising_edge(clockw)) THEN
If(arm = '1') THEN
count := count;
else
count := count + 1;
end if;

if(rising_edge(clock_one_hz)) THEN
if(arm = '1') THEN
LEDALARMON <='1';
if(count = 0 and (alarmtime = currtime)) THEN
LEDBUS(0) <= '1';
LEDBUS(2) <= '1';
LEDBUS(6) <= '1';
LEDBUS(7) <= '1';
if((LEDGAME(0) = '1' and LEDGAME(2) = '1' and LEDGAME(6) = '1' and LEDGAME(7)=
'1' ) or SNOOZEBUTTON = '1' ) THEN
LEDBUS(0) <= '0';
LEDBUS(2) <= '0';
LEDBUS(6) <= '0';
LEDBUS(7) <= '0';
end if;
elsif(count = 1 and (alarmtime = currtime) ) THEN
LEDBUS(1) <= '1';
LEDBUS(3) <= '1';
LEDBUS(4) <= '1';
LEDBUS(6) <= '1';
if((LEDGAME(1) = '1' and LEDGAME(3) = '1' and LEDGAME(4) = '1' and LEDGAME(6)=
'1') or SNOOZEBUTTON = '1') THEN
LEDBUS(1) <= '0';
LEDBUS(3) <= '0';
LEDBUS(4) <= '0';
LEDBUS(6) <= '0';
end if;
elsif(count = 2 and (alarmtime = currtime)) THEN
LEDBUS(0) <= '1';
LEDBUS(1) <= '1';
LEDBUS(3) <= '1';
LEDBUS(4) <= '1';
if((LEDGAME(0) = '1' and LEDGAME(1) = '1' and LEDGAME(3) = '1' and
LEDGAME(4)= '1') or SNOOZEBUTTON = '1') THEN
LEDBUS(0) <= '0';
LEDBUS(1) <= '0';
LEDBUS(3) <= '0';
LEDBUS(4) <= '0';
end if;
elsif(count = 3 and (alarmtime = currtime)) THEN
LEDBUS(2) <= '1';
LEDBUS(5) <= '1';
LEDBUS(6) <= '1';

LEDBUS(7) <= '1';


if((LEDGAME(2) = '1' and LEDGAME(5) = '1' and LEDGAME(6) = '1' and LEDGAME(7)=
'1') or SNOOZEBUTTON = '1' ) THEN
LEDBUS(2) <= '0';
LEDBUS(5) <= '0';
LEDBUS(6) <= '0';
LEDBUS(7) <= '0';
end if;
end if;
elsif(arm = '0') THEN
LEDALARMON <='0';
LEDBUS(0) <= '0';
LEDBUS(1) <= '0';
LEDBUS(2) <= '0';
LEDBUS(3) <= '0';
LEDBUS(4) <= '0';
LEDBUS(5) <= '0';
LEDBUS(6) <= '0';
LEDBUS(7) <= '0';
end if;
end if;
--end if;
end process alarmoff;
clock_conv: process (CLK) is
variable count: unsigned (24 downto 0) :="0000000000000000000000000";
-------------------------------------------------- CLOCK FOR BUTTON PRESS
------------------------------------------------begin
if (rising_edge(CLK)) THEN
count := count + 1;
--countB := countB +1;
if (count > 12500000) THEN
--50000000 (5 is used for simulation purposes)
clock_one_hz <= not clock_one_hz;
count := "0000000000000000000000000";
end if;
end if;
end if;
end process clock_conv;
-------------------------------------------------- CLOCK TO RANDOMLY INCREMENT COUNT BETWEEN 0 AND 3

------------------------------------------------clockd: process (CLK) is


variable count: unsigned (24 downto 0) :="0000000000000000000000000";

begin
if (rising_edge(CLK)) THEN
count := count + 1;
--countB := countB +1;
if (count > 50000000) THEN
--50000000 (5 is used for simulation
purposes)
clockw <= not clockw;
count := "0000000000000000000000000";
end if;
end if;
end process clockd;

end Behavioral;
----------------------------------------------- DISPLAY SELECTOR(BETWEEN ,SET TIME, SET ALARM TIME AND CURRENT TIME)
--------------------------------------------entity MUXO is
Port ( ALARM : in STD_LOGIC_VECTOR (15 downto 0);
TIMEO : in STD_LOGIC_VECTOR (15 downto 0);
selector : in STD_LOGIC;
toDisp : out STD_LOGIC_VECTOR (15 downto 0));
end MUXO;
architecture Behavioral of MUXO is
-- selects output of cuRrent time and clock set and SET ALARM TIME
begin
display: process(selector) is
begin
if(selector = '1') THEN
toDisp <= alarm;
else
todisp <= timeO;
end if;
end process display;
end Behavioral;

You might also like