Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 2 commits
  • 2 files changed
  • 0 comments
  • 1 contributor
117 modules/Buttons/FPGA/ButtonScanner/ButtonScanner.vhd
... ... @@ -1,4 +1,4 @@
1   -----------------------------------------------------------------------------------
  1 +--*********************************************************************
2 2 -- This program is free software; you can redistribute it and/or
3 3 -- modify it under the terms of the GNU General Public License
4 4 -- as published by the Free Software Foundation; either version 2
@@ -15,11 +15,11 @@
15 15 -- 02111-1307, USA.
16 16 --
17 17 -- �2011 - X Engineering Software Systems Corp. (www.xess.com)
18   -----------------------------------------------------------------------------------
  18 +--*********************************************************************
19 19
20   -----------------------------------------------------------------------------------
  20 +--*********************************************************************
21 21 -- Module for scanning a button array.
22   -----------------------------------------------------------------------------------
  22 +--*********************************************************************
23 23
24 24 library IEEE;
25 25 use IEEE.std_logic_1164.all;
@@ -41,6 +41,11 @@ package ButtonScannerPckg is
41 41
42 42 end package;
43 43
  44 +
  45 +--*********************************************************************
  46 +-- Button scanner module.
  47 +--*********************************************************************
  48 +
44 49 library IEEE, UNISIM;
45 50 use IEEE.std_logic_1164.all;
46 51 use IEEE.numeric_std.all;
@@ -50,79 +55,83 @@ use work.CommonPckg.all;
50 55
51 56 entity ButtonScanner is
52 57 generic(
53   - FREQ_G : real := 100.0; -- Operating frequency in MHz.
  58 + FREQ_G : real := 100.0; -- Master clock frequency in MHz.
54 59 SCAN_FREQ_G : real := 1.0 -- Desired frequency for scanning the buttons in KHz.
55 60 );
56 61 port(
57   - clk_i : in std_logic;
58   - b_io : inout std_logic_vector(3 downto 0);
59   - button_o : out std_logic_vector(12 downto 1)
  62 + clk_i : in std_logic; -- Master clock.
  63 + b_io : inout std_logic_vector(3 downto 0); -- Scanning pins to button array.
  64 + -- There is one output for each button in the array. The bit in position i will be high
  65 + -- if button i is pressed.
  66 + button_o : out std_logic_vector(12 downto 1) -- Button states: pressed (1) or not (0).
60 67 );
61 68 end entity;
62 69
63 70 architecture arch of ButtonScanner is
64   - signal driverShf_r : unsigned(b_io'range) := "1000";
65   - signal recvShf_r : unsigned(b_io'range) := "0100";
66   - signal buttonShf_r : unsigned(button_o'range) := "100000000000";
67   - signal bIn_s : std_logic_vector(b_io'range);
  71 + signal driverShf_r : unsigned(b_io'range) := "1000"; -- Indicates which scan pin is the driver.
  72 + signal recvShf_r : unsigned(b_io'range) := "0100"; -- Indicates which scan pin is the receiver.
  73 + signal buttonShf_r : unsigned(button_o'range) := "100000000000"; -- Indicates which button is being scanned.
  74 + signal bIn_s : std_logic_vector(b_io'range); -- The current logic levels on the scan pin inputs.
68 75 begin
69 76
70 77 process(clk_i)
71   - constant ALL_ZERO : std_logic_vector(button_o'range) := (others => ZERO);
  78 + constant ALL_ZERO_C : std_logic_vector(button_o'range) := (others => ZERO);
72 79 -- The delay between scanning individual buttons is the total scan time divided by the number of buttons.
73   - constant MAX_CNTR : natural := integer(ceil(FREQ_G * 1000.0 / (SCAN_FREQ_G * real(button_o'length))));
74   - variable scanCntr_v : natural range 0 to MAX_CNTR; -- Button scan timer.
75   - -- The buttons have to hold their values for a certain number of scans before they are accepted.
76   - constant DEBOUNCE_CNT : natural := 10 * button_o'length;
77   - variable debounceCntr_v : natural range 0 to DEBOUNCE_CNT;
  80 + constant SCAN_PERIOD_C : natural := integer(ceil(FREQ_G * 1000.0 / (SCAN_FREQ_G * real(button_o'length))));
  81 + variable scanTimer_v : natural range 0 to SCAN_PERIOD_C; -- Button scan timer.
  82 + -- The buttons have to hold their values for a certain number of individual scans before they are accepted.
  83 + constant DEBOUNCE_CNT_C : natural := 10 * button_o'length;
  84 + variable debounceCntr_v : natural range 0 to DEBOUNCE_CNT_C;
78 85 -- The previous state of the buttons to which the current state is compared for debouncing.
79   - variable buttonState_v : std_logic_vector(button_o'range) := (others => ZERO);
80   - variable buttonIn_v : std_logic_vector(button_o'range);
  86 + variable buttonNow_v : std_logic_vector(button_o'range); -- Current state.
  87 + variable buttonPrev_v : std_logic_vector(button_o'range) := (others => ZERO); -- Previous state
81 88 begin
82 89 if rising_edge(clk_i) then
83   - if scanCntr_v /= 0 then -- Wait until current button scan time has elapsed.
84   - scanCntr_v := scanCntr_v - 1;
  90 +
  91 + if scanTimer_v /= 0 then -- Wait until current button scan time has elapsed.
  92 + scanTimer_v := scanTimer_v - 1;
  93 +
85 94 else -- OK, now process the state of the currently-driven buttons.
86 95
87   - scanCntr_v := MAX_CNTR; -- Reload the counter for the next scan.
  96 + scanTimer_v := SCAN_PERIOD_C; -- Reload the timer for the next scan.
88 97
89   - if (std_logic_vector(recvShf_r) and bIn_s) = "0000" then
90   - -- The currently driven button is not pressed.
91   - buttonIn_v := (others => ZERO); -- Place a 0 in the current button's position.
92   - else
93   - -- The currently-driven button is pressed.
94   - buttonIn_v := std_logic_vector(buttonShf_r); -- Place a 1 in the current button's position.
  98 + if (std_logic_vector(recvShf_r) and bIn_s) = "0000" then -- The currently driven button is not pressed.
  99 + buttonNow_v := (others => ZERO); -- Place a 0 in the current button's position.
  100 + else -- The currently-driven button is pressed.
  101 + buttonNow_v := std_logic_vector(buttonShf_r); -- Place a 1 in the current button's position.
95 102 end if;
96 103
97   - if ((buttonState_v xor buttonIn_v) and std_logic_vector(buttonShf_r)) /= ALL_ZERO then
  104 + if ((buttonNow_v xor buttonPrev_v) and std_logic_vector(buttonShf_r)) /= ALL_ZERO_C then
98 105 -- If the current button's state has changed from its previous value,
99 106 -- then record its current value and reset the debounce counter.
100   - buttonState_v := (buttonState_v and not std_logic_vector(buttonShf_r)) or buttonIn_v;
101   - debounceCntr_v := DEBOUNCE_CNT;
  107 + buttonPrev_v := (buttonPrev_v and not std_logic_vector(buttonShf_r)) or buttonNow_v;
  108 + debounceCntr_v := DEBOUNCE_CNT_C;
102 109 else
103 110 -- If the current button's state has not changed, then just decrement the debounce counter.
104 111 debounceCntr_v := debounceCntr_v - 1;
105 112 if debounceCntr_v = 0 then
106 113 -- If the debounce counter has reached 0, then output the current state of the buttons.
107   - button_o(1) <= buttonState_v(1);
108   - button_o(2) <= buttonState_v(2);
109   - button_o(3) <= buttonState_v(3);
110   - button_o(7) <= buttonState_v(4);
111   - button_o(8) <= buttonState_v(5);
112   - button_o(4) <= buttonState_v(6);
113   - button_o(11) <= buttonState_v(7);
114   - button_o(5) <= buttonState_v(8);
115   - button_o(9) <= buttonState_v(9);
116   - button_o(6) <= buttonState_v(10);
117   - button_o(10) <= buttonState_v(11);
118   - button_o(12) <= buttonState_v(12);
119   - debounceCntr_v := DEBOUNCE_CNT; -- Reset the debounce counter for the next scan.
  114 + -- The buttons have to be unscrambled according to the table given in the manual.
  115 + button_o(1) <= buttonPrev_v(1); -- Drive B0, read B1.
  116 + button_o(2) <= buttonPrev_v(2); -- Drive B0, read B2.
  117 + button_o(3) <= buttonPrev_v(3); -- Drive B0, read B3.
  118 + button_o(7) <= buttonPrev_v(4); -- Drive B1, read B2.
  119 + button_o(8) <= buttonPrev_v(5); -- Drive B1, read B3.
  120 + button_o(4) <= buttonPrev_v(6); -- Drive B1, read B0.
  121 + button_o(11) <= buttonPrev_v(7); -- Drive B2, read B3.
  122 + button_o(5) <= buttonPrev_v(8); -- Drive B2, read B0.
  123 + button_o(9) <= buttonPrev_v(9); -- Drive B2, read B1.
  124 + button_o(6) <= buttonPrev_v(10); -- Drive B3, read B0.
  125 + button_o(10) <= buttonPrev_v(11); -- Drive B3, read B1.
  126 + button_o(12) <= buttonPrev_v(12); -- Drive B3, read B2.
  127 + debounceCntr_v := DEBOUNCE_CNT_C; -- Reset the debounce counter for the next scan.
120 128 end if;
121 129 end if;
122 130
123 131 if (recvShf_r rol 1) = driverShf_r then
124   - -- If we've finished scanning all the buttons connected to this driver, then shift to the
125   - -- next driver and get ready to scan the buttons its connected to.
  132 + -- If we've finished scanning all the buttons connected to this driver (i.e., next receive
  133 + -- pin is the same as the current driving pin), then shift to the next driver and get ready
  134 + -- to scan the buttons its connected to.
126 135 driverShf_r <= driverShf_r rol 1; -- Go to the next driver.
127 136 recvShf_r <= driverShf_r rol 2; -- Receive from the next input just past the driver.
128 137 buttonShf_r <= buttonShf_r rol 1; -- Holds the bit mask for the next scanned button.
@@ -136,13 +145,25 @@ begin
136 145 end if;
137 146 end process;
138 147
  148 + -- Generate tristatable I/O buffers. One will be driving into the button array,
  149 + -- while the others are inputs that sense the buttons.
139 150 IobufLoop : for i in b_io'low to b_io'high generate
140   --- UIobuf : IOBUF generic map(IOSTANDARD => "LVTTL") port map(T => recvShf_r(i), I => driverShf_r(i), O => bIn_s(i), IO => b_io(i));
  151 + -- T is the tristate control so only the buffer for the driver is not tristated.
  152 + -- I is the input to the buffer, so always set it at logic 1. That won't matter for the receivers, only the driver.
  153 + -- O is the level sensed on the buffer input I/O pin.
  154 + -- I/O is the buffer I/O pin that attaches to the button array.
141 155 UIobuf : IOBUF generic map(IOSTANDARD => "LVTTL") port map(T => not driverShf_r(i), I => driverShf_r(i), O => bIn_s(i), IO => b_io(i));
  156 +-- UIobuf : IOBUF generic map(IOSTANDARD => "LVTTL") port map(T => not driverShf_r(i), I => HI, O => bIn_s(i), IO => b_io(i));
142 157 end generate;
143 158 end architecture;
144 159
145 160
  161 +
  162 +--*********************************************************************
  163 +-- Button scanner test displays the number of the pressed button
  164 +-- (1, 2, 3, ..., A, B, C) on the first digit of the LED display.
  165 +--*********************************************************************
  166 +
146 167 library IEEE;
147 168 use IEEE.std_logic_1164.all;
148 169 use IEEE.std_logic_arith.all;
BIN  modules/Buttons/FPGA/ButtonScanner/buttonscannertest.bit
Binary file not shown

No commit comments for this range

Something went wrong with that request. Please try again.