====== LAB 9: A BCD-Counter ====== ===== Synopsis ===== The desired exposure time and the number of pictures are stored in BCD (Binary Coded Decimal) format. This means that every decimal digit is coded by its binary value. Therefore, two times 4 bits are needed to represent the decimal number ’15’. If a binary representation was used, 4 bits would be enough. While this representation is convenient for the display driver modules, it makes it a lot harder to do the actual counting. A procedure shall be designed that implements a single digit BCD adder with carry. A complete BCD counter is then generated by calling this procedure for each digit of the counter range. The start of a new exposure is signaled via TIMER_GO. It is not necessary to detect a rising edge as this signal is active for the duration of one clock period, only. When the start signal arrives, the lens shutter has to be opened. The lens shutter remains open as long as the EXPOSE signal is set to ’1’. The picture count (NO_PICS) shall be incremented whenever a new picture is taken, i.e. whenever a rising edge of the EXPOSE signal is detected. Additional TIMER_GO signals during the actual exposure of the new picture have to be ignored. The exposure timer is a bit tricky as only the display values (EXP_TIME) are available as input. It is therefore necessary to map the BCD-values to counter limits. Of course, it would be possible to use a single counter. Yet it is probably more comprehensible to split the task between two counters as all exposure times are a multiple of 1/512 second. At a clock frequency of 8192 Hz this equals 16 clock cycles. These timesteps will be counted by a second counter and will be compared with the counter limits from the mapper. Please have a look at the module interface before you start to design: {{:vhdl_workshop:workshop_exposurecontroller.svg?nolink&550|The exposure controller}} ==== Behaviour ==== A procedure to increment a BCD digit is needed. The digit itself and a carry flag are needed as parameters for this purpose. Based on this procedure a counter for the number of pictures is to be implemented. The value shall be incremented whenever a rising edge of the EXPOSE signal occurs. A combinational process maps the exposure time to the equivalent number of 1/512 s timesteps. The exposure timer shall be realized with another process and consists of two counters. The first counter shall generate the 1/512 s timebase, i.e. a pulse is to be generated every 16th clock cycle. This pulse is used to count the number of timesteps and the counter value will be compared with the limit that results from the selected exposure time. It is good design practice in synchronous designs to keep the number of clock domains, i.e. the number of different clock signals for the Flip Flops as small as possible. This avoids problems during synthesis of the design. Therefore, the CLK signal shall be used for all registers! ==== Data types ==== The control signals CLK, RESET, TIMER_GO and EXPOSE shall be of type **std_ulogic**, as usual. The data signals EXP_TIME and NO_PICS are of the **T_DIGITS** type that is defined in the P_DISPLAY package. An **integer** variable may be used for the binary counter of the exposure timer. ==== To do ==== * Create the new VHDL file. * Write a testbench to verify the design. Use assertions to check the exposure times during the simulation run. * Compile and simulate the design. * Compare the number of Flip Flops that you would expect with the synthesis result again. ===== Implementation ===== library ieee; use ieee.std_logic_1164.all; use work.P_DISPLAY.all; entity EXP_CTRL is -- system signals: CLK, RESET -- control signals: TIMER_GO, EXPOSE -- data signals: EXP_TIME, NO_PICS end EXP_CTRL; architecture RTL of EXP_CTRL is -- The EXP_TIME signal must be mapped to a limit for the -- exposure timer, i.e. an internal signal is needed procedure INC_DIGIT ( DIGIT : inout integer; CARRY : inout std_ulogic) is begin if CARRY = '1' then if DIGIT /= 9 then DIGIT := DIGIT + 1; CARRY := '0'; else DIGIT := 0; end if; -- OVERFLOW end if; -- CARRY = '1' end INC_DIGIT; begin -- architecture MAPPER: process (EXP_TIME) begin -- default assignment for all outputs to avoid latches if EXP_TIME = (5,1,2) then LIMIT <= 0; elsif EXP_TIME = (2,5,6) then LIMIT <= 1; -- Map all other exposure times to the corresponding limit end if; end process MAPPER; EXP_TIMER: process (CLK, RESET) variable COUNT_16 : integer range ; -- Counter to generate 1/512s timesteps variable TIMER : integer range ; -- Counter for the final exposure time begin if RESET = '1' then -- Reset all registers elsif (CLK'event and CLK = '1') then if EXPOSE = '1' then -- Exposure timer -- 2 cascaded counters: 1st -> 1/512s timesteps -- 2nd -> exposure time elsif TIMER_GO = '1' then -- Start exposure timer end if; end if; end process EXP_TIMER; PIC_COUNT: process(CLK, RESET) variable LAST_EXPOSE : std_ulogic; variable CARRY : std_ulogic; variable DIGIT : integer; begin if RESET = '1' then LAST_EXPOSE := '0'; NO_PICS <= (0, 0, 0); elsif CLK'event and CLK = '1' then -- Check for rising edge of EXPOSE signal CARRY := '1'; for I in T_DIGITS'low to T_DIGITS'high loop -- Increment the picture counter end loop; end if; -- Rising EXPOSE edge end if; -- Rising clock edge end process PIC_COUNT; end RTL; ===== Testbench ===== library ieee; use ieee.std_logic_1164.all; use work.P_DISPLAY.all; entity TB_EXP_CTRL is end TB_EXP_CTRL; architecture TEST of TB_EXP_CTRL is constant PERIOD : time := 1 sec/8192; --constant PERIOD : time := 5 ns; component EXP_CTRL port(CLK : in std_ulogic; RESET : in std_ulogic; TIMER_GO : in std_ulogic; EXP_TIME : in T_DIGITS; EXPOSE : buffer std_ulogic; NO_PICS : buffer T_DIGITS); end component; signal W_CLK : std_ulogic := '0'; signal W_RESET : std_ulogic; signal W_TIMER_GO : std_ulogic; signal W_EXP_TIME : T_DIGITS; signal W_EXPOSE : std_ulogic; signal W_NO_PICS : T_DIGITS; begin DUT : EXP_CTRL port map( CLK => W_CLK, RESET => W_RESET, TIMER_GO => W_TIMER_GO, EXP_TIME => W_EXP_TIME, EXPOSE => W_EXPOSE, NO_PICS => W_NO_PICS); W_CLK <= not W_CLK after PERIOD/2; STIMULI : process begin W_RESET <= '1'; W_TIMER_GO <= '1'; W_EXP_TIME <= (0,6,4); -- EXPOSE: '0', NO_PICS: (0,0,0) wait for 3*PERIOD; W_RESET <= '0'; W_TIMER_GO <= '0'; -- no changes wait for 3*PERIOD; W_TIMER_GO <= '1'; wait for 1*PERIOD; W_TIMER_GO <= '0'; wait for 1*PERIOD; W_TIMER_GO <= '1'; wait for 1*PERIOD; W_TIMER_GO <= '0'; wait for 1*PERIOD; W_TIMER_GO <= '1'; wait for 1*PERIOD; W_TIMER_GO <= '0'; wait for 1 sec/64; -- EXPOSE: '1', NO_PICS: (0,0,1) wait for 10 * PERIOD; W_EXP_TIME <= (5,1,2); for I in 1 to 100 loop W_TIMER_GO <= '1'; wait for 1*PERIOD; W_TIMER_GO <= '0'; wait for 1 sec/512; end loop; -- NO_PICS: (1,0,1) wait; end process STIMULI; end TEST; configuration CFG_TB_EXP_CTRL of TB_EXP_CTRL is for TEST end for; end CFG_TB_EXP_CTRL; ===== Package ===== {{page>.:package}}