Trong phần này em sử dụng tài nguyên trên Kit Spartan 3E để tạo ra một đồng hồ thời gian thực với nội dung:
- Giao tiếp với bộ LCD: Hiển thị thông số về đồng hồ: ngày, tháng, năm, giờ, phút, giây.
- Giao tiếp nút xoay: đọc nút bấm và xoay để điều chỉnh thời gian. Mã thiết kế nh− sau: --- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; entity picoblaze_real_time_clock is
Port ( led : out std_logic_vector(7 downto 0); strataflash_oe : out std_logic;
strataflash_ce : out std_logic; strataflash_we : out std_logic;
switch : in std_logic_vector(3 downto 0); btn_north : in std_logic;
btn_east : in std_logic; btn_south : in std_logic; btn_west : in std_logic;
lcd_d : inout std_logic_vector(7 downto 4); lcd_rs : out std_logic;
lcd_rw : out std_logic; lcd_e : out std_logic; rotary_a : in std_logic; rotary_b : in std_logic; rotary_press : in std_logic; clk : in std_logic); end picoblaze_real_time_clock; --- component kcpsm3
Port ( address : out std_logic_vector(9 downto 0); instruction : in std_logic_vector(17 downto 0);
port_id : out std_logic_vector(7 downto 0); write_strobe : out std_logic;
out_port : out std_logic_vector(7 downto 0); read_strobe : out std_logic;
in_port : in std_logic_vector(7 downto 0); interrupt : in std_logic;
interrupt_ack : out std_logic; reset : in std_logic; clk : in std_logic); end component;
-- declaration of program ROM-- component control
Port ( address : in std_logic_vector(9 downto 0); instruction : out std_logic_vector(17 downto 0); clk : in std_logic);
end component;
--- -- Signals used to connect KCPSM3 to program ROM and I/O logic-- signal address : std_logic_vector(9 downto 0);
signal instruction : std_logic_vector(17 downto 0); signal port_id : std_logic_vector(7 downto 0); signal out_port : std_logic_vector(7 downto 0); signal in_port : std_logic_vector(7 downto 0); signal write_strobe : std_logic;
signal read_strobe : std_logic; signal interrupt : std_logic :='0'; signal interrupt_ack : std_logic; signal kcpsm3_reset : std_logic; - Signals for LCD operation-- signal lcd_rw_control : std_logic;
signal lcd_output_data : std_logic_vector(7 downto 4); signal lcd_drive : std_logic;
-- Signals used to interface to rotary encoder-- signal rotary_a_in : std_logic;
signal rotary_b_in : std_logic; signal rotary_press_in : std_logic;
signal rotary_in : std_logic_vector(1 downto 0); signal rotary_q1 : std_logic;
signal rotary_q2 : std_logic; signal delay_rotary_q1 : std_logic;
signal rotary_event : std_logic; signal rotary_left : std_logic; signal ck1us:std_logic; signal ck50us:std_logic; signal ck2_5ms:std_logic; signal ck62_5ms:std_logic; signal ck1s:std_logic; signal ck_tmp:std_logic; signal ck_flag:std_logic; signal rotary_tmp:std_logic; signal rotary_flag:std_logic;
signal ck25m_cnt:std_logic_vector(1 downto 0); signal ck25m:std_logic;
signal cnt1us:std_logic_vector (5 downto 0); signal cnt50us:std_logic_vector (5 downto 0); signal cnt2_5ms:std_logic_vector (5 downto 0); signal cnt62_5ms:std_logic_vector (4 downto 0); signal cnt1s:std_logic_vector (8 downto 0);
signal port_id1 : std_logic_vector(7 downto 0);
--- -- Start of circuit description--
begin
strataflash_oe <= '1'; strataflash_ce <= '1'; strataflash_we <= '1';
-- KCPSM3 and the program memory -- processor: kcpsm3
port map( address => address, instruction => instruction, port_id => port_id, write_strobe => write_strobe, out_port => out_port, read_strobe => read_strobe, in_port => in_port, interrupt => interrupt, interrupt_ack => interrupt_ack, reset => kcpsm3_reset, clk => clk); program_rom: control
instruction => instruction,
-- proc_reset => kcpsm3_reset, --JTAG Loader version clk => clk);
kcpsm3_reset <= '0'; --When using normal program ROM ck_25m: process(clk)
begin
if clk'event and clk='1' then
ck25m_cnt<=ck25m_cnt+1; end if; end process ck_25m; rd: process(read_strobe) begin if read_strobe='1' then port_id1<=port_id; end if; end process rd; ck25m<=ck25m_cnt(1); ck_1us: process(clk) begin
if clk'event and clk='1' then
if cnt1us="110001" then cnt1us<="000000";--0--49
else
cnt1us<=cnt1us+1; end if;
if cnt1us<"011000" then ck1us<='0';---0--24/25--49
else
ck1us<='1'; end if; end if;
end process ck_1us; ck_50us: process(ck1us) begin
if ck1us'event and ck1us='1' then
if cnt50us="110001" then cnt50us<="000000";--0--49
else
cnt50us<=cnt50us+1; end if;
if cnt50us<"011000" then ck50us<='0';---0--24/25--49
ck50us<='1'; end if; end if;
end process ck_50us; ck_2_5ms: process(ck50us) begin
if ck50us'event and ck50us='1' then
if cnt2_5ms="110001" then cnt2_5ms<="000000";--0--49 else cnt2_5ms<=cnt2_5ms+1; end if; end if; end process ck_2_5ms; process(clk) begin
if clk 'event and clk='1' then
if cnt2_5ms<"011000" then ck2_5ms<='0';---0--24/25--49 else ck2_5ms<='1'; end if; end if; end process; ck_1s: process(ck2_5ms) begin
if ck2_5ms'event and ck2_5ms='1' then
if cnt1s="011000111" then cnt1s<="000000000";--0--24 else cnt1s<=cnt1s+1; end if; end if; end process ck_1s; process(clk) begin
if clk 'event and clk='1' then
if cnt1s<"001100011" then ck1s<='0';---0--24/25--49
else
ck1s<='1'; end if;
end if;
end process; -- Interrupt --
interrupt_control: process(ck1us) begin
if write_strobe='1' and port_id(5)='1' and (out_port(6)='1' or out_port(7)='1') then interrupt <= '0';
elsif ck1us'event and ck1us='1' then interrupt <= rotary_flag or ck_flag; end if;
end process interrupt_control; interrupt_source0:process(ck1us) begin
if ck1us'event and ck1us='1' then ck_tmp<=ck2_5ms; rotary_tmp<=rotary_q1; end if;
end process interrupt_source0; interrupt_flag0:process(ck1us) begin
if write_strobe='1' and port_id(5)='1' and out_port(7)='1' then ck_flag <='0';
elsif ck1us'event and ck1us='1' then
if ck_tmp='0' and ck2_5ms='1' then ck_flag <='1';
end if;
end if;
end process interrupt_flag0; interrupt_flag1:process(ck1us) begin
if write_strobe='1' and port_id(5)='1' and out_port(6)='1' then rotary_flag <= '0';
elsif ck1us'event and ck1us='1' then
if rotary_q1='1' and rotary_tmp='0' then
rotary_flag <='1';
end if; end if;
end process interrupt_flag1;
--- -- KCPSM3 input ports --
input_ports: process(clk) begin
if clk'event and clk='1' then case port_id(1 downto 0) is
-- read simple toggle switches and buttons at address 00 hex
when "00" => in_port <= btn_west & btn_north & btn_south & btn_east & switch;
-- when "00" => in_port <= cnt1s(3 downto 0)& cnt1s(0) & cnt1s(1)& cnt1s(2)& cnt1s(3);
-- read rotary control signals at address 01 hex
when "01" => in_port <= ck_flag & rotary_flag & "XXXX" & rotary_press_in & rotary_left;
-- read LCD data at address 02 hex
when "10" => in_port <= lcd_d & "XXXX";
-- Don't care used for all other addresses to ensure minimum logic implementation
when others => in_port <= "XXXXXXXX"; end case;
end if;
end process input_ports; -- KCPSM3 output ports -- output_ports: process(clk) begin
if clk'event and clk='1' then if write_strobe='1' then
-- Write to LEDs at address 80 hex. if port_id(7)='1' then
led <= out_port; end if;
-- LCD data output and controls at address 40 hex. if port_id(6)='1' then
lcd_output_data <= out_port(7 downto 4); lcd_drive <= out_port(3); lcd_rs <= out_port(2); lcd_rw_control <= out_port(1); lcd_e <= out_port(0); end if; end if; end if;
end process output_ports; rotary_filter: process(clk) begin
if clk'event and clk='1' then rotary_a_in <= rotary_a; rotary_b_in <= rotary_b;
rotary_press_in <= rotary_press;
rotary_in <= rotary_b_in & rotary_a_in; case rotary_in is
when "00" => rotary_q1 <= '0'; rotary_q2 <= rotary_q2;
when "01" => rotary_q1 <= rotary_q1; rotary_q2 <= '0';
when "10" => rotary_q1 <= rotary_q1; rotary_q2 <= '1';
when "11" => rotary_q1 <= '1'; rotary_q2 <= rotary_q2;
when others => rotary_q1 <= rotary_q1; rotary_q2 <= rotary_q2;
end case; end if;
end process rotary_filter; direction: process(clk) begin
if clk'event and clk='1' then delay_rotary_q1 <= rotary_q1;
if rotary_q1='1' and delay_rotary_q1='0' then rotary_event <= '1'; rotary_left <= rotary_q2; else rotary_event <= '0'; rotary_left <= rotary_left; end if; end if;
end process direction; end Behavioral;
Kết luận
Sau thời gian nghiên cứu và tìm hiểu về các linh kiện logic lập trình đ−ợc mà cụ thể là FPGA của hãng Xilinx, em đã thu đ−ợc một số kết quả sau:
- Nắm đ−ợc ph−ơng pháp thiết kế mới cho các linh kiện logic lập trình đ−ợc. - Có kỹ năng sử dụng ngôn ngữ mô tả phần cứng HDL mà cụ thể là VHDL .
- Tìm hiểu đ−ợc cấu trúc, nguyên lý hoạt động của Kit Xilinx Spartan 3E và sử dụng cho việc thiết kế một số ứng dụng cơ bản.
- Thiết kế thành công một số mạch ứng dụng đơn giản và đồng hồ thời gian thực dùng vi điều khiển nhúng PicoBlaze.
Với mục đích nghiên cứu tìm hiểu công nghệ FPGA phục vụ cho công tác giảng dạy nghiên cứu của bản thân tại tr−ờng Cao đẳng Công nghiệp Nam Định nên sản phẩm thiết kế mới chỉ dừng lại ở một số ứng dụng nhỏ. Tuy nhiên với những kết quả đã đạt đ−ợc trong thời gian làm luận văn vừa qua đã giúp em làm chủ đ−ợc việc thiết kế với FPGA và CPLD của hãng Xilinx cũng nh− các linh kiện logic lập trình khác. Hy vọng luận văn này sẽ giúp ích cho ng−ời bắt đầu tìm hiểu về lĩnh vực này phần nào.
Em xin chân thành cảm ơn TS Nguyễn Nam Quân, ng−ời đã trực tiếp h−ớng dẫn em trong quá trình làm luận văn này. Tập thể các thầy cô trong Khoa Điện tử -Viễn thông tr−ờng, Viện đào tạo sau đại học tr−ờng Đại học Bách Khoa Hà Nội,các thầy cô giáo khoa Điện - Điện tử tr−ờng Cao đẳng Công nghiệp Nam Định đã giúp đỡ em về mặt thời gian cũng nh− sự động viên của bạn bè và ng−ời thân về mặt tinh thần trong thời gian thực hiện luận văn này.
Tài liệu tham khảo:
1.TS Nguyễn Nam Quân, Toán lôgic và kỹ thuật số, NXBKHKT,2006 2.TS Phạm Ngọc Nam, Embedded systems,2006
3.Xillinx, “ISE In-Depth Tutorial”, www.xilinx.com
4.Xilinx,”Spartan 3E Started Kit User Guide”, www.xilinx.com
5.Xilinx, “PicoBlaze8-bitEmbeddedMicrocontrollerUserGuide”, www.xilinx.com
6.Xilinx, “FrequencyGeneratorfor Spartan-3EStarterKit”, www.xilinx.com
7.Volnei A. Pedroni, Circuit Design with VHDL,MIT Press Cambridge, Massachusetts London, England, 2004.