프로젝트 목적
- VHDL을 이용하여 생활에서 많이 사용하는 디지털 시계를 구현해 봄으로써 Clock의 활용과 7 Segment의 제어를 익히고 디지털 시계의 구현을 통해 VHDL의 응용 능력을 기른다.
- 입력 장치인 Push Button Switch, 출력 장치인 FND(7 Segment)의 특성을 이해한다.

프로젝트 개요
- 본 프로젝트에서는 7 Segment LED를 이용한 디지털 시계를 VHDL을 이용하여 구현하고자 한다.
- 프로젝트에서 사용하는 7 Segment LED는 6개의 Segment LED가 Dynamic 구동방식으로 동작한다.
- 디지털 시계는 6개의 7 Segment LED에 시, 분, 초 각각 2자리씩 표현한다. 그리고 시계를 리셋 시키는 기능과 시간을 맞추는 작업은 FPGA 보드에 있는 스위치를 이용한다.
- 본 프로젝트에서 사용하는 FPGA 보드의 기본 주파수는 33Mhz를 사용한다. 디지털 시계의 1초를 구하기 위해서는 33Mhz의 Main Clock 주파수를 변환 작업을 통하여 1초로 만들고 1초를 60분주하여 1분을 만든다.

PXA255-FPGA 보드

FPGA

Altera Cyclon EP1C6

Logic Elements

5980

Logic Gate

120000 Logic Gate

RAM Bit

92160 Bit

외부 CPU

PXA255

외부 인터페이스

32 Bit Address/Data Bus

입력 I/O

Push SW, Dip SW, ADC, Image Sensor

출력 I/O

Text LCD, LED, 7 Segment, Buzzer, DotMatrix, VGA

기타 I/O

EEPROM


- 디지털 시계에서는 7 Segment LED 제어를 위하여 EP1C6 칩 11~18의 데이터 라인 8핀과 19~25까지의 COM 라인 6핀을 출력 PORT로 사용한다.
- PXA255-FPGA 보드에서 사용하는 FND는 공통으로 사용하는 데이터 라인 8개와 7 Segment의 출력을 결정하는 COM라인 6개로 구성된다.
- FND 동작은 6개라인(FCOM[5..0])의 6비트 중 비트 값이 0인 Segment에 데이터(FDATA[7..0])를 출력한다.
- 각각 다른 데이터를 7 Segment LED에 출력 하려면 6개의 FCOM의 비트들을 쉬프트 시켜가면서 FCOM의 값이 바뀌는 시점에 데이터 라인을 세팅하면 선택된 7 Segment LED에 데이터를 출력한다. 이와 같은 방법을 Dynamic Display 방식이라고 한다.
- Dynamic Display 방식은 빠른 속도로 쉬프트 시킴으로서 사람의 눈의 잔상효과를 이용하여 마치 6개의 7 Segment가 동시에 출력되는 것처럼 보여준다.

디지털 시계 프로그램의 블록도


- 위의 블럭도에서는 입력으로 Main Clock과 리셋 버튼, 그리고 시, 분, 초를 제어할 수 있는 스위치 3개를 가진다.
- 디지털 시계의 출력으로는 6개의 7 Segment를 제어하기 위한 8개의 데이터 라인 FDATA_SM[7..0]과 출력 7 Segment 선택 라인인 FCOM[5..0]의 6개 출력을 가진다.

구현
- clk_div.vhd -
library ieee;
use ieee.std_logic_1164.all;

entity clk_div is
           generic(count : integer range 0 to 30000 := 2);
           port(CLK_IN : in std_logic;
                      SM_CLK : out std_logic );
end clk_div;

architecture sample of clk_div is
begin
           process(CLK_IN)
                     variable tmp : integer range 0 to 30000 := 0;
           begin
                     if(CLK_IN'event and CLK_IN = '1') then
                                if(tmp = count-1) then
                                          tmp := 0;
                                          SM_CLK <= '1';
                                else
                                          tmp := tmp + 1;
                                          SM_CLK <= '0';
                                end if;
                     end if;
           end process;
end sample;

- DigitalTimer.vhd -
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity DigitalTimer is
           port( CLK                    : in std_logic;
                       rset              : in std_logic;
                       ih_key          : in std_logic;
                       im_key         : in std_logic;
                       is_key          : in std_logic;
                       FDATA_SM    : out std_logic_vector(7 downto 0) := "00111111";
                       FCOM                     : out std_logic_vector(5 downto 0) := "001111" );
end DigitalTimer;

architecture rt1 of DigitalTimer is
           function fnd_disnum(cnt : integer range 0 to 9) return std_logic_vector is
                     variable seg_decode : std_logic_vector(7 downto 0);
           begin
                     case cnt is
                                when 0 => seg_decode := "00111111";
                                when 1 => seg_decode := "00000110";
                                when 2 => seg_decode := "01011011";
                                when 3 => seg_decode := "01001111";
                                when 4 => seg_decode := "01100110";
                                when 5 => seg_decode := "01101101";
                                when 6 => seg_decode := "01111101";
                                when 7 => seg_decode := "00100111";
                                when 8 => seg_decode := "01111111";
                                when 9 => seg_decode := "01100111";
                                when others => seg_decode := "00000000";
                     end case;
                     return (seg_decode);
           end fnd_disnum;                    

           -- clock division
           component clk_div
                     generic(count : integer range 0 to 30000);
                     port( CLK_IN : in std_logic;
                                  SM_CLK : out std_logic );
           end component;

           -- used signal
           signal temp : integer range 0 to 5;
           signal cnt_sec1 : integer range 0 to 10 := 0;
           signal cnt_min : integer range 0 to 10 := 0;
           signal cnt_min1 : integer range 0 to 10 := 0;

           signal seg0 : std_logic_vector(7 downto 0) := "00111111";
           signal seg1 : std_logic_vector(7 downto 0) := "00111111";
           signal seg2 : std_logic_vector(7 downto 0) := "00111111";
           signal seg3 : std_logic_vector(7 downto 0) := "00111111";
           signal seg4 : std_logic_vector(7 downto 0) := "00111111";
           signal seg5 : std_logic_vector(7 downto 0) := "00111111";
           signal sclk0, sclk1, sclk2, sclk3 : std_logic := '0';

           signal temp_clk : std_logic;
           signal fnd_clk : std_logic;
           signal sec_clk : std_logic;

begin
           LED_CLK_DIV : clk_div generic map(330) port map(CLK, fnd_clk);                    -- fnd_clk : 100Khz
           TEMP_CLK_DIV : clk_div generic map(3300) port map(CLK, temp_clk);              -- temp_clk : 10Khz
           SEC_CLK_DIV : clk_div generic map(10000) port map(temp_clk, sec_clk);         -- sec_clk : 1hz

           -- FND Output Process
           process(fnd_clk)
           begin
                     if(fnd_clk'event and fnd_clk = '1') then
                                case temp is
                                          when 0 => temp <=1; FCOM <= "111110"; FDATA_SM <= seg5;
                                          when 1 => temp <=2; FCOM <= "111101"; FDATA_SM <= seg4;
                                          when 2 => temp <=3; FCOM <= "111011"; FDATA_SM <= seg3;
                                          when 3 => temp <=4; FCOM <= "110111"; FDATA_SM <= seg2;
                                          when 4 => temp <=5; FCOM <= "101111"; FDATA_SM <= seg1;
                                          when 5 => temp <=0; FCOM <= "011111"; FDATA_SM <= seg0;
                                          when others => FCOM <= "111111"; FDATA_SM <= "00111111";
                                end case;
                     end if;
           end process;

           -- 1 second Process
           process(sec_clk, rset, is_key)
                     variable cnt : integer range 0 to 10 := 0;
           begin
                     if(rset = '1' or is_key = '1') then
                                cnt := 0;
                                sclk0 <= '0';
                                seg0 <= fnd_disnum(0);
                     elsif(sec_clk'event and sec_clk = '1') then
                                if(cnt = 9) then
                                          cnt := 0;
                                          sclk0 <= '0';
                                elsif(cnt = 8) then
                                          sclk0 <= '1';
                                          cnt := cnt + 1;
                                else
                                          cnt := cnt + 1;
                                          sclk0 <= '0';
                                end if;
                                seg0 <= fnd_disnum(cnt);
                     end if;
           end process;

           -- 10 second process
           process(sec_clk, rset, is_key)
           begin
                     if(rset = '1' or is_key = '1') then
                                cnt_sec1 <= 0;
                     elsif(sec_clk'event and sec_clk = '1') then
                                if(sclk0 = '1') then
                                          if(cnt_sec1 = 5) then
                                                     cnt_sec1 <= 0;
                                          else
                                                     cnt_sec1 <= cnt_sec1 + 1;
                                          end if;
                                end if;
                     end if;
                     seg1 <= fnd_disnum(cnt_sec1);
           end process;
           sclk1 <= '1' when(cnt_sec1 = 5 and sclk0 = '1') else '0';

           -- 1 miniute process
           process(sec_clk, rset, im_key)
           begin
                     if(rset = '1') then
                                cnt_min <= 0;
                     elsif(sec_clk'event and sec_clk = '1') then
                                if(im_key = '1') then
                                          if(cnt_min = 9) then
                                                     cnt_min <= 0;
                                           else
                                                     cnt_min <= cnt_min + 1;
                                          end if;
                                elsif(sclk1 = '1') then
                                          if(cnt_min = 9) then
                                                     cnt_min <= 0;
                                          else
                                                     cnt_min <= cnt_min + 1;
                                          end if;
                                end if;
                     end if;
                     seg2 <= fnd_disnum(cnt_min);
           end process;
           sclk2 <= '1' when(cnt_min = 9 and sclk1 = '1') else
                                 '1' when(cnt_min = 9 and im_key = '1') else '0';
          
           -- 10 miniute process
           process(sec_clk, rset)
           begin
                     if(rset = '1') then
                                          cnt_min1 <= 0;
                     elsif(sec_clk'event and sec_clk = '1') then
                                if(sclk2 = '1') then
                                          if(cnt_min1 = 5) then
                                                     cnt_min1 <= 0;
                                          else
                                                     cnt_min1 <= cnt_min1 + 1;
                                          end if;
                                end if;
                     end if;
                     seg3 <= fnd_disnum(cnt_min1);
           end process;
           sclk3 <= '1' when(cnt_min1 = 5 and sclk2 = '1') else '0';

           -- hour process
           process(sec_clk, rset, ih_key)
                     variable cnt : integer range 0 to 24 := 0;
                     variable a, b : integer range 0 to 50 := 0;
           begin
                     if(rset = '1') then
                                cnt := 0;
                     elsif(sec_clk'event and sec_clk = '1') then
                                if(ih_key = '1') then
                                          if(cnt = 23) then
                                                     cnt := 0;
                                          else
                                                     cnt := cnt + 1;
                                          end if;
                                elsif(sclk3 = '1') then
                                          if(cnt = 23) then
                                                     cnt := 0;
                                          else
                                                     cnt := cnt + 1;
                                          end if;
                                end if;
                     end if;
                     a := cnt / 10;
                     b := cnt mod 10;
                     seg4 <= fnd_disnum(b);
                     seg5 <= fnd_disnum(a);
           end process;
end rt1;


결론

 이번 프로젝트에서는 디지털시계를 HDL언어인 VHDL를 사용하여 설계하여 실습 보드인 PXA255 FPGA에 직접 올려보았다.

디지털시계를 구현하기 위해서 33Mhz의 메인 클럭에서 1hz의 클럭을 얻기 위한 묘듈이 필요했다. 이 묘듈은 카운터를 이용하여 원하는 수만큼 카운트 한 후 신호를 내보내는 원리로 동작한다.

디지털시계는 1초, 10초, 1분, 10분, 시간을 각각 처리하는 프로세스 문으로 작성되며, 모든 동작은 1hz인 second clock에 동기 되어 동작하게 된다. 그 외 sclk0, sclk1, sclk2, sclk3 의 클럭들이 내부에서 발생 된다. sclk0은 9초에서 10초로 넘어 갈 때, sclk1은 59초에서 1분으로 넘어 갈 때, sclk2는 9분에서 10분으로 넘어 갈 때, sclk3는 59분에서 1시간으로 넘어 갈 때 사용 되는 신호이다.

이번 프로젝트를 통해서 타이밍에 대한 이해와 VHDL의 활용능력 및 쿼터스 같은 툴 사용에 대해 익숙해 진 것 같다. 또한 자신이 작성한 디지털시계를 직접 FPGA에 올려 보고 제대로 동작을 하는지 확인해봄으로써, 평소 시뮬레이션만 해보는 것과 다르게 회로설계에 대한 자신감을 가질 수 있었다.





+ Recent posts