แนะนำการใช้งานบอร์ด QMTECH Cyclone 10 LP Starter Kit#

Keywords: Intel / Altera Cyclone 10 LP, Quartus Prime Lite Edition


บอร์ด Cyclone 10 LP Starter Kit#

บอร์ด Cyclone 10 LP Starter Kit ออกแบบโดยบริษัท QMTECH ในประเทศจีน บอร์ดเวอร์ชันได้ผลิตออกมาในปีค.ศ. 2019 และมีรายละเอียดเชิงเทคนิค ดังนี้

  • FPGA: 10CL016YU484C8G
  • Clock Input: 50MHz
  • On-board Memory:
    • QSPI Flash: Winbond W25Q64 (64MBits, 3.3V) for user configuration code
    • SDRAM: Winbond W9825G6KH-6 (256Mbits, 16-bit data wide, 3.3V)
  • Power Supply / DC-DC Switching Voltage Regulators:
    • VIN: 5V (DC Plug)
    • MP2315: 3.3V
    • NCP1529: 2.5V & 1.2V 
  • USB-to-Serial Bridge IC: Silicon Labs CP2102N / WCH CH340N
  • 1x Mini-USB connector
  • 1x JTAG port
  • 3x Switches (Push Buttons)
  • 3x LEDs
  • 3x 7-Segment LEDs
  • 1x HDMI Port: TI TPD12S016
  • 1x GbE Ethernet Transceiver: Realtek RTL8211EG (GMII Ethernet Interface)
  • GitHub: ChinaQMTECH/CYCLONE_10_STARTER_KIT/

รูป: บอร์ด Cyclone 10 LP Starter Kit (v1.0) (Blue-color PCB, 10CL016YU484C8G)

รูป: บอร์ด Cyclone 10 LP Starter Kit (v3.0) (Black-color PCB, 10CL080YU484C8G)

บอร์ดไม่ได้รวมวงจร USB Blaster ไว้บนบอร์ด ดังนั้นผู้ใช้จะต้องหาอุปกรณ์ USB Blaster มาใช้ร่วมด้วย

รูป: ตัวอย่างการใช้งานบอร์ด FPGA ร่วมกับอุปกรณ์ Low-cost USB Blaster (Clone)

แรงดันไฟเลี้ยงสำหรับการทำงานของบอร์ดได้จาก DC Plug (center-positive, 5V)

แนะนำให้ผู้อ่าน ศึกษารายละเอียดของบอร์ดและวงจรที่เกี่ยวข้องจากไฟล์ Schematic และตัดบางส่วนมานำเสนอในบทความนี้

รูป: ไอซีสัญญาณ CLK 50MHz (3.3V) ไอซี Winbond W25Q64 QSPI Flash (3.3V) และคอนเนกเตอร์ 2x5 JTAG Socket

รูป: ปุ่มกด Switches (active-low, 3.3V) และวงจร LEDs (active-low, 3.3V)

วงจรปุ่มกด SW1 (IO_P4) และ SW4 (IO_P3) เป็น User Switches มีตัวต้านทานแบบ Pullup ขนาด 4.7k โอห์ม แต่ปุ่มกด SW3 (nCONFIG) เป็นการรีโหลดข้อมูลบิตสตรีม (Reconfiguration) สำหรับ FPGA (ข้อมูลได้จาก Serial Flash Configuration Device)

วงจร LED มีตัวต้านทานจำกัดกระแส 1k โอห์ม ใช้แสดงสถานะลอจิกได้เฉพาะสำหรับขา IO_W17 และ IO_Y17 (เป็น User LEDs) แต่มีอีกหนึ่ง LED ใช้เฉพาะแสดงสถานะ Power ON (3.3V)

รูป: วงจรสำหรับ 7-Segment Display แบบ 3 ตำแหน่ง

การทำงานของวงจร 7-Segment Display ซึ่งมี 3 ตำแหน่ง อาศัยวงจรทรานซิสเตอร์ NPN BJT (S9014) เป็นตัวควบคุมหรือเปิด-ปิดการไหลของกระแสไฟฟ้าใหักับโมดูล 7-Segment แต่ละตำแหน่ง การต่อใช้งานเป็นแบบ Common-Anode (CA) แต่ละเซกเมนต์มีตัวต้านทานจำกัดกระแส 330โอห์ม ทั้งสามตำแหน่งแชร์ใช้ข้อมูลอินพุตขนาด 8 บิต ร่วมกัน ดังนั้นจึงต้องมีขาสัญญาณควบคุมแยกกัน 3 สัญญาณ

รูป: ขา I/O สำหรับไอซีหน่วยความจำ Winbond W9825G6KH-6 SDRAM

รูป: คอนเนกเตอร์ Male Pin Headers (2x20 และ 2x9) และคอนเนกเตอร์ 2x6-Pin PMOD (J10 & J11)

รูป: วงจรที่ใช้ไอซี MP2315 แปลงแรงดันไฟฟ้าจาก VIN=5V ให้ได้ 3.3V

รูป: วงจรที่ใช้ไอซี NCP1529 แปลงแรงดันไฟฟ้าจาก 3.3V ให้ได้ 2.5V และ 1.2V

รูป: ไอซี CP2102N USB-to-Serial IC และคอนเนกเตอร์ Mini-USB

รูป: ไอซี TPD12S016 (HDMI Interface Device) และพอร์ต HDMI

รูป: วงจรมีไอซี Realtek RTL8211EG

ข้อสังเกต: บอร์ด FPGA รุ่นนี้ มีวงจรต่อไปนี้

  • วงจรสำหรับเชื่อมต่อกับพอร์ต USB โดยใช้ไอซี CP2102 เป็นตัวแปลง USB-to-Serial ดังนั้นจึงสะดวกต่อการใช้งาน ไม่จำเป็นต้องหาอุปกรณ์หรือโมดูลมาต่อเพิ่ม แต่ต้องใช้สาย Mini-USB Cable วงจรดิจิทัลของผู้ใช้จะต้องมีส่วนที่เรียกว่า UART TX/RX Controller ทำหน้าที่รับหรือส่งข้อมูลไปยังคอมพิวเตอร์
  • ชิปหน่วยความจำประเภท SDRAM ความจุ 32MB ดังนั้นเหมาะสำหรับการออกแบบวงจรดิจิทัลที่มีการใช้ข้อมูลจำนวนมาก แต่ในการออกแบบวงจรเพื่อใช้งาน จะต้องมีวงจรที่เรียกว่า SDRAM Controller สำหรับการเขียนหรืออ่านข้อมูล
  • วงจรสำหรับเชื่อมต่อกับ Ethernet ด้วยพอร์ต RJ45 และมีไอซี Realtek RTL8211EG ทำหน้าที่เป็น Ethernet Transceiver หากต้องการใช้งาน วงจรดิจิทัลของผู้ใช้จะต้องมีส่วนที่เรียกว่า Ethernet MAC Controller
  • วงจรสำหรับสร้างสัญญาณเอาต์พุตให้กับพอร์ต HDMI โดยใช้ไอซี TI TPD12S016 และในกรณีนี้ วงจรดิจิทัลของผู้ใช้จะต้องมีส่วนที่เรียกว่า HDMI Controller

บริษัท QMTECH ได้จัดทำตัวอย่างโปรเจกต์สาธิตการใช้งานบอร์ด ** Cyclone 10 LP Starter Kit ** ซึ่งสามารถดูได้จาก Github และมีตัวอย่างที่น่าสนใจ เช่น

  • Test04_SDRAM: สาธิตการเขียนอ่านข้อมูลในหน่วยความจำ SDRAM
  • Test09_project_Ethernet: สาธิตการส่งข้อมูลด้วย Ethernet
  • Test13_project_HDMI: สาธิตการสร้างสัญญาณภาพไปยังพอร์ต HDMI

 


ตัวอย่างโค้ด VHDL เพื่อลองใช้บอร์ด FPGA: Dual-LED Blinking#

ถัดไปเป็นตัวอย่างวงจรดิจิทัลสำหรับนำไปทดลองใช้กับบอร์ด Cyclone 10 LP Starter Kit เขียนโค้ดด้วยภาษา VHDL วงจรนี้มีสัญญาณอินพุต CLK (50MHz) และนำไปสร้างสัญญาณควบคุมการนับของวงจรตัวนับ ด้วยอัตราที่ต่ำ เช่น 10Hz มีการใช้ปุ่มกดสำหรับการรีเซตการทำงานของวงจรด้วยสัญญาณอินพุต NRST และใช้ LEDs จำนวน 2 ชุด สำหรับแสดงสถานะลอจิกสลับกัน

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity qmtech_cyc10_demo is
  port (
     CLK   : in  std_logic;   -- 50 MHz clock input
     NRST  : in  std_logic;   -- Active-low asynchronous reset
     LEDS  : out std_logic_vector(1 downto 0)
  );
end qmtech_cyc10_demo;

architecture behavioral of qmtech_cyc10_demo is
  constant CLK_DIV   : integer := (50e6 / 10) - 1;
  signal clk_div_cnt : integer := 0;
  signal ce          : std_logic := '0';
  signal toggle      : std_logic := '0';

begin

  clk_div_proc: process (CLK, NRST)
  begin
    if NRST = '0' then
       clk_div_cnt <= 0;
       ce <= '0';
   toggle <= '0';
    elsif rising_edge(CLK) then
       if clk_div_cnt = CLK_DIV then
          ce <= '1';
          clk_div_cnt <= 0; 
       else
          ce <= '0';
          clk_div_cnt <= clk_div_cnt + 1;
       end if;
   if ce = '1' then
      toggle <= not toggle;
   end if;
    end if;
  end process;

  LEDS <= "11" when NRST = '0' else toggle & (not toggle);

end behavioral;

ไฟล์ Tcl Script สำหรับการเลือกใช้ขา I/O ของชิป FPGA มีดังนี้

# set_global_assignment -name FAMILY "Cyclone 10 LP"
# set_global_assignment -name DEVICE 10CL016YU484C8G

set_location_assignment PIN_G1 -to CLK
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLK

# SW1
set_location_assignment PIN_P4 -to NRST
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to NRST

# LEDs
set_location_assignment PIN_Y17 -to LEDS[0]
set_location_assignment PIN_W17 -to LEDS[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDS[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDS[1]

 


ตัวอย่างโค้ด VHDL: 3-Digit BCD Counter Demo#

อีกตัวอย่างหนึ่งเป็นโค้ด VHDL สำหรับวงจรดิจิทัลที่มีสัญญาณอินพุต CLK (50MHz) และนำไปสร้างสัญญาณควบคุมการนับของวงจรตัวนับแบบ BCD Counter จำนวน 3 ตำแหน่ง และมีการใช้ปุ่มกดสำหรับการรีเซตการทำงานของวงจรด้วยสัญญาณอินพุต NRST

ในส่วนของการแสดงผลค่าของตัวเลข 3-Digit BCD Counter จะใช้ 7-Segment Display บนบอร์ด FPGA และเนื่องจากทั้งสาม 3 ตำแหน่ง แชร์การใช้ขาสัญญาณข้อมูล 8 บิต ร่วมกัน (SEG7[7:0]) จึงต้องใช้วิธี Time-Multiplexing ในการส่งข้อมูลไปยังวงจรสำหรับแต่ละหลัก และมีขาสัญญาณควบคุม 3 ขา (DIGITS[2:0]) ให้เลือกทีละตำแหน่งและส่งข้อมูลไบต์ใช้กับตำแหน่งดังกล่าว แล้วเปลี่ยนไปตำแหน่งถัดไปตามลำดับ ทำไปจนครบแล้ววนซ้ำไปเรื่อย ๆ ดังนั้นสัญญาณควบคุม DIGITS[2:0] จะมีค่าตามลำดับดังนี้ 001 > 010 > 100 > ...

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity qmtech_cyc10_7seg_disp is
  generic( 
    CLK_HZ     : natural := 50000000;
    NUM_DIGITS : natural := 3
  );
  port(
    CLK        : in std_logic;
    NRST       : in std_logic;
    SEG7       : out std_logic_vector(7 downto 0);
    DIGITS     : out std_logic_vector(2 downto 0) 
  );
end qmtech_cyc10_7seg_disp;

architecture behavioral of qmtech_cyc10_7seg_disp is
  constant CNT_MAX1   : natural := (CLK_HZ/200) - 1;
  constant CNT_MAX2   : natural := (CLK_HZ/10) - 1;

  type bcd_counter_t is array(0 to NUM_DIGITS-1) of integer range 0 to 9;
  signal bcd_count    : bcd_counter_t; 

  signal data_buf     : std_logic_vector(7 downto 0);
  signal digits_sel   : std_logic_vector(NUM_DIGITS-1 downto 0);
  signal digit_index  : natural range 0 to NUM_DIGITS-1 := 0;

  subtype nibble is unsigned(3 downto 0);
  -- This function implements a BCD to 7-Segment decoder.
  function BCD2SEG7( data: nibble ) return std_logic_vector is
     variable seg7bits : std_logic_vector(6 downto 0);
  begin
     case data is
        when "0000" => seg7bits := "0111111"; -- 0
        when "0001" => seg7bits := "0000110"; -- 1
        when "0010" => seg7bits := "1011011"; -- 2
        when "0011" => seg7bits := "1001111"; -- 3
        when "0100" => seg7bits := "1100110"; -- 4
        when "0101" => seg7bits := "1101101"; -- 5
        when "0110" => seg7bits := "1111101"; -- 6
        when "0111" => seg7bits := "0000111"; -- 7
        when "1000" => seg7bits := "1111111"; -- 8
        when "1001" => seg7bits := "1101111"; -- 9
        when others => seg7bits := "0000000"; -- off
     end case;
     return seg7bits;
  end BCD2SEG7;

begin
  -- This process implements a N-digit BCD counter.
  process (NRST,CLK)
    variable wait_cnt    : natural range 0 to CNT_MAX2 := 0;
    variable clk_enabled : boolean;
    variable carry       : boolean; 
  begin
    if NRST = '0' then
      wait_cnt := 0;
      for i in bcd_count'range loop
         bcd_count(i) <= 0;
      end loop;
    elsif rising_edge(CLK) then 
       if wait_cnt = CNT_MAX2 then
          wait_cnt := 0;
          clk_enabled := true;
       else 
          wait_cnt := wait_cnt + 1;
          clk_enabled := false;
       end if;
       if clk_enabled then
          carry := true;
          for i in 0 to NUM_DIGITS-1 loop
             if carry then
                if bcd_count(i)=9 then
                   bcd_count(i) <= 0;
                   carry := true;
                else
                   bcd_count(i) <= bcd_count(i)+1;
                   carry := false;
                end if;
             else
                carry := false;
             end if;
          end loop;
       end if;
    end if;
  end process; 

  -- This process implements a 7-segment driver using time-multiplexing.
  process (NRST, CLK) 
    variable wait_cnt    : natural range 0 to CNT_MAX1 := 0;
    variable clk_enabled : boolean;
    variable bcd_value   : unsigned(3 downto 0);
  begin
    if NRST = '0' then
       wait_cnt := 0;
       data_buf    <= x"00";
       digits_sel  <= (others => '0');
       digit_index <= 0;
    elsif rising_edge(CLK) then     
       if wait_cnt = CNT_MAX1 then
          wait_cnt := 0;
          clk_enabled := true;
       else 
          wait_cnt := wait_cnt + 1;
          clk_enabled := false;
       end if;
       if clk_enabled then
          if digit_index = NUM_DIGITS-1 then 
             digit_index <= 0;
          else 
             digit_index <= digit_index + 1;
          end if;
          for i in 0 to NUM_DIGITS-1 loop
             if i = digit_index then
               digits_sel(i) <= '1';
             else 
               digits_sel(i) <= '0';
             end if;
          end loop;
          bcd_value := to_unsigned(bcd_count(digit_index),4);
          data_buf <= '0' & BCD2SEG7( bcd_value );
       end if;
    end if;
  end process;

  DIGITS <= (others => '0') when NRST = '0' else digits_sel; -- active-high
  SEG7   <= not data_buf; -- for common-anode 7-segment LEDs

end behavioral;

ไฟล์ Tcl Script สำหรับการตั้งค่าการใช้งานขา I/O มีดังนี้

# set_global_assignment -name FAMILY "Cyclone 10 LP"
# set_global_assignment -name DEVICE 10CL016YU484C8G

# 50MHz clock
set_location_assignment PIN_G1 -to CLK
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLK

# SW1 (push button)
set_location_assignment PIN_P4 -to NRST
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to NRST

# 3-digit 7-segment display (common-anode)
set_location_assignment PIN_W19  -to SEG7[7]
set_location_assignment PIN_R20  -to SEG7[6]
set_location_assignment PIN_W20  -to SEG7[5]
set_location_assignment PIN_AA18 -to SEG7[4]
set_location_assignment PIN_AB19 -to SEG7[3]
set_location_assignment PIN_U20  -to SEG7[2]
set_location_assignment PIN_R19  -to SEG7[1]
set_location_assignment PIN_AA19 -to SEG7[0]
set_location_assignment PIN_R18  -to DIGITS[0]
set_location_assignment PIN_U19  -to DIGITS[1]
set_location_assignment PIN_AB18 -to DIGITS[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SEG7[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DIGITS[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DIGITS[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to DIGITS[2]

 


ตัวอย่างโค้ด VHDL: UART TX Demo#

ตัวอย่างถัดไปสาธิตการส่งข้อความ Hello World! ทีละตัวอักขระ ASCII ไปยังคอมพิวเตอร์ของผู้ใช้ โดยใช้วงจรที่เรียกว่า UART-TX (ใช้เฉพาะการส่งข้อมูล แต่ไม่มีการรับข้อมูล)

การส่งข้อมูลด้วย UART จะต้องมีการกำหนดความเร็ว หรือ Baudrate ในตัวอย่างนี้ตั้งค่าไว้เท่ากับ 115200 และการส่งข้อมูลสำหรับ ASCII Character หนึ่งตัว จะทำทีละบิต โดยการเลื่อนบิตออกไป (Bit Shifting) ทางขาเอาต์พุต TXD เริ่มต้นด้วย Start Bit (0) ตามด้วยข้อมูลไบต์ (เริ่มด้วยบิต LSB ตามลำดับไปจนถึงบิต MSB) และจบด้วย Stop Bit (1) และไม่มีการใช้ Parity Bit การเว้นระยะเวลาในการส่งข้อมูลทีละบิต จะต้องเป็นไปตามค่า Baudrate ที่เลือกใช้

ในตัวอย่างนี้ จะส่งข้อความออกไปหนึ่งครั้ง ก็ต่อเมื่อมีการกดปุ่ม SW4 แล้วปล่อย และใช้ปุ่ม SW1 เป็นปุ่มรีเซตการทำงานของวงจร

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity cyc10_uart_tx_demo is
  port (
    CLK   : in  std_logic;   -- 50 MHz clock
    NRST  : in  std_logic;   -- Active-low reset
    BTN   : in  std_logic;   -- Active-low user button
    RXD   : in  std_logic;   -- UART RX pin (not used)
    TXD   : buffer std_logic; -- UART TX pin
    LEDS  : out std_logic_vector(1 downto 0)
  );
end cyc10_uart_tx_demo;

architecture behavioral of cyc10_uart_tx_demo is
   -- Define constants
   constant CLK_FREQ     : integer := 50e6;    -- 50 MHz clock
   constant BAUD_RATE    : integer := 115200;  -- 115200 baud rate
   constant BAUD_PERIOD  : integer := CLK_FREQ / BAUD_RATE - 2;

   -- ASCII message to be transmitted
   type ascii_array_t is array (0 to 13) of std_logic_vector(7 downto 0);
   constant MESSAGE : ascii_array_t := (
      x"48", -- H
      x"65", -- e
      x"6C", -- l
      x"6C", -- l
      x"6F", -- o
      x"20", -- (space)
      x"57", -- W
      x"6F", -- o
      x"72", -- r
      x"6C", -- l
      x"64", -- d
      x"21", -- !
      x"0D", -- \r
      x"0A"  -- \n
   );

   -- FSM states
   type state_t is (ST_IDLE, ST_LOAD_DATA, ST_SEND_DATA, ST_STOP, ST_WAIT);
   signal state        : state_t := ST_IDLE;
   signal next_state   : state_t := ST_IDLE;
   signal wait_counter : integer := 0;
   signal bit_counter  : integer range 0 to 9 := 0;
   signal char_counter : integer range 0 to MESSAGE'length := 0;
   signal shift_reg    : std_logic_vector(9 downto 0) := (others => '1');
   signal btn_capture  : std_logic_vector(1 downto 0) := (others => '1');

begin

  LEDS <= TXD & RXD;

  process(CLK, NRST)
  begin
    if NRST = '0' then
      state        <= ST_IDLE;
      bit_counter  <= 0;
      wait_counter <= 0;
      char_counter <= 0;
      btn_capture  <= "11";
      shift_reg    <= (others => '1');
      TXD          <= '1'; -- TXD idle (high)

    elsif rising_edge(CLK) then

      btn_capture <= btn_capture(0) & BTN;

      case state is
         when ST_IDLE =>
            TXD <= '1'; 
            if btn_capture = "01" then -- button click
              state <= ST_LOAD_DATA;
              char_counter <= 0;
            end if;

         when ST_LOAD_DATA =>
            shift_reg <= '1' & MESSAGE(char_counter) & '0'; 
            state <= ST_SEND_DATA;
            bit_counter <= 0;

         when ST_SEND_DATA =>
            TXD       <= shift_reg(0); -- LSB bit 
            shift_reg <= '1' & shift_reg(9 downto 1); -- Shift data
            state     <= ST_WAIT;
            wait_counter <= BAUD_PERIOD;
            if bit_counter = 9 then
              next_state   <= ST_STOP;
              bit_counter  <= 0;
            else
              next_state   <= ST_SEND_DATA;
              bit_counter  <= bit_counter + 1;
            end if;

         when ST_STOP =>
            TXD <= '1'; 
            if char_counter = MESSAGE'length-1 then
              state <= ST_IDLE;
            else
              char_counter <= char_counter + 1;
              state <= ST_LOAD_DATA;
            end if;

         when ST_WAIT =>
            if wait_counter = 0 then
              state <= next_state;
            else
              wait_counter <= wait_counter - 1;
            end if;

         when others =>
            state <= ST_IDLE;
       end case;
    end if;
  end process;
end behavioral;

ตัวอย่างไฟล์ Tcl Script สำหรับการเลือกใช้งานขา I/O

# set_global_assignment -name FAMILY "Cyclone 10 LP"
# set_global_assignment -name DEVICE 10CL016YU484C8G

set_location_assignment PIN_G1 -to CLK
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLK

# SW1
set_location_assignment PIN_P4 -to NRST
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to NRST

# SW4
set_location_assignment PIN_P3 -to BTN
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to BTN

set_location_assignment PIN_AA22 -to RXD
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to RXD

set_location_assignment PIN_AA21 -to TXD
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to TXD

# LEDs
set_location_assignment PIN_Y17 -to LEDS[0]
set_location_assignment PIN_W17 -to LEDS[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDS[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LEDS[1]

รูป: ตัวอย่างการรับข้อความจากบอร์ด FPGA โดยใช้ซอฟต์แวร์ Arduino IDE - Serial Monitor

 

ผู้ใช้สามารถเพิ่มวงจร Signal Tap Logic Analyzer ซึ่งเป็นวงจรดิจิทัลที่ช่วยในการบันทึกและวิเคราะห์สัญญาณภายในวงจร FPGA มีการตั้งค่าการใช้งานดังนี้ เลือกใช้สัญญาณ CLK สำหรับการทำงานของวงจร การตั้งค่าเงื่อนไขทริกเกอร์ ได้เลือกเป็นการเกิดขอบขาขึ้นของสัญญาณที่ขาอินพุต BTN จากวงจรปุ่มกดบนบอร์ด สัญญาณที่เลือกมาบันทึกและวิเคราะห์ คือ สัญญาณ BTN และสัญญาณ TXD

รูป: ตัวอย่างการตั้งค่าการใช้งาน Signal Tap Logic Analyzer

รูป: ตัวอย่างข้อมูลที่บันทึกได้และแสดงผลในรูปคลื่นสัญญาณดิจิทัล

ตัวอย่าง VHDL Testbench สำหรับการจำลองการทำงานด้วยซอฟต์แวร์ Questa Simulator (Intel Starter FPGA Edition) v2021.2

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity cyc10_uart_tx_demo_tb is
end cyc10_uart_tx_demo_tb;

architecture testbench of cyc10_uart_tx_demo_tb is
    -- Testbench signals
    signal clk   : std_logic := '0';
    signal nrst  : std_logic := '0';  -- Active-low reset
    signal btn   : std_logic := '1';  -- Active-low button (starts high)
    signal rxd   : std_logic := '1';  -- RXD not used
    signal txd   : std_logic;
    signal leds  : std_logic_vector(1 downto 0);

    -- Clock period (50 MHz clock, 20 ns period)
    constant CLK_PERIOD : time := 20 ns;

    -- Component under test (DUT)
    component cyc10_uart_tx_demo
        port (
            CLK   : in  std_logic;
            NRST  : in  std_logic;
            BTN   : in  std_logic;
            RXD   : in  std_logic;
            TXD   : buffer std_logic;
            LEDS  : out std_logic_vector(1 downto 0)
        );
    end component;

begin
    -- Instantiate the design under test (DUT)
    uut: cyc10_uart_tx_demo
       port map ( CLK => clk, NRST => nrst, BTN => btn,
            RXD => rxd, TXD => txd, LEDS => leds );

    clk_proc : process -- Clock generation process
    begin
      clk <= '0'; wait for CLK_PERIOD / 2;
      clk <= '1'; wait for CLK_PERIOD / 2;
    end process;

    stim_proc : process -- Stimulus process
    begin
        -- Reset the system
        nrst <= '0';
        wait for 50 ns;  -- Hold reset low for some time
        nrst <= '1';
        wait for 100 ns; -- Wait for some time after reset

        -- Simulate button press (active-low)
        btn <= '0';  -- Button pressed
        wait for 1 us;
        btn <= '1';  -- Button released

        -- Wait for some time to observe UART transmission
        wait for 1 ms;
        wait;
    end process;

end testbench;

ไฟล์ sim.do ซึ่งเป็นตัวอย่างโค้ด Tcl Script สำหรับการรันคำสั่งเพื่อการจำลองการทำงาน

transcript on

# Delete the 'rtl_work' if it exists.
if {[file exists rtl_work]} {
    vdel -lib rtl_work -all
}

# Create 'rtl_work' library and use it as the 'work' library.
vlib rtl_work
vmap work rtl_work

# Compile VHDL code
vcom -2008 -work work {./cyc10_uart_tx_demo/cyc10_uart_tx_demo.vhd}
vcom -2008 -work work {./cyc10_uart_tx_demo/cyc10_uart_tx_demo_tb.vhd}

# Load the VHDL testbench
vsim -voptargs="+acc" work.cyc10_uart_tx_demo_tb(testbench) 

# Add all I/O signals to the waveform
add wave /cyc10_uart_tx_demo_tb/*

# Run the simulation for 1msec
run 1ms

รูป: ผลการจำลองการทำงานและแสดงรูปคลื่นสัญญาณดิจิทัล

จากผลการจำลองการทำงาน จะเห็นได้ว่า ความกว้างของหนึ่งบิตเท่ากับ 8680 ns หรือ คิดเป็นค่า Baudrate เท่ากับ (1e9 /8680) หรือ 115207.37

 


กล่าวสรุป#

บทความนี้ได้นำเสนอข้อมูลเชิงเทคนิคเกี่ยวกับบอร์ด QMTECH Cyclone 10 LP Starter Kit ซึ่งมีชิป Intel / Altera Cyclone 10 LP และถือว่าเป็นบอร์ดที่มีราคาไม่แพง แม้ว่าจะไม่ใช่บอร์ดรุ่นใหม่ แต่ก็เป็นอีกหนึ่งตัวเลือกสำหรับผู้ที่สนใจทดลองเรียนรู้ FPGA

ในบทความมีการนำเสนอตัวอย่างโค้ด VHDL สำหรับวงจรดิจิทัลที่นำไปทดลองใช้กับซอฟต์แวร์ Quartus Prime Lite Edition และบอร์ด FPGA

 


This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Created: 2024-10-22 | Last Updated: 2024-10-27