การสร้างสัญญาณเอาต์พุตสำหรับ VGA Display#
Keywords: VGA, Intel / Altera MAX 10 FPGA, DE10-Lite FPGA Board
ความรู้และทักษะพื้นฐานที่เกี่ยวข้อง
- อิเล็กทรอนิกส์ (Electronics): วงจรเครือข่ายตัวต้านทาน (Resistor Network) และการใช้งาน VGA DAC
- การออกแบบวงจรลอจิก (Logic Design): วงจรตัวนับ การสร้างสัญญาณแอนะล็อกและดิจิทัลสำหรับ VGA
- การวัด (Measurement): การใช้ Signal Tap Logic Analyzer และการตั้งค่า Trigger Conditions
- การเขียนโค้ดและการใช้ซอฟต์แวร์ (Software/Coding): การเขียนโค้ดด้วย VHDL และการใช้งานซอฟต์แวร์ Intel Quartus Prime (Lite Edition)
▷ การสร้างสัญญาณสำหรับจอภาพ VGA#
VGA (Video Graphics Array) เป็นมาตรฐานการส่งข้อมูลกราฟิกสำหรับจอมอนิเตอร์แบบ CRT หรือจอภาพแบบ LCD แต่ในปัจจุบันมีการใช้งานมาตรฐาน VGA น้อยลง และถูกแทนที่ด้วยมาตรฐานอื่น เช่น DVI-D และ HDMI
VGA ทำงานโดยการสแกนสัญญาณทีละเส้นจากซ้ายไปขวา (Horizontal Scan) และจากบนลงล่าง (Vertical Scan) ผ่านการทำงานร่วมกันระหว่างสัญญาณ RGB, HSYNC และ VSYNC
สัญญาณที่ใช้สำหรับ VGA มีดังนี้
- สัญญาณดิจิทัล Horizontal Sync (HSYNC): เป็นสัญญาณพัลส์แบบ Active-Low ใช้กำหนดช่วงเวลาในการสแกนเส้นแนวนอนแต่ละเส้นบนจอภาพ
- สัญญาณดิจิทัล Vertical Sync (VSYNC): เป็นสัญญาณพัลส์แบบ Active-Low ใช้กำหนดช่วงเวลาในการสแกนเฟรมใหม่ เริ่มจากด้านบนสุดของจอภาพ
- สัญญาณแอนะล็อกสำหรับสีแดง สีน้ำเงิน และสีเขียว (RGB): กำหนดค่าสีสำหรับแต่ละพิกเซล เช่น ถ้าใช้ 4 บิต สำหรับแต่ละสี (R,G,B) ก็จะได้ 16^3 = 4096 สี แต่ถ้าใช้ 8 บิต ก็จะได้ 256^3 = 16,777,216 สี ที่ใช้ในการแสดงผลแต่ละพิกเซลได้
ข้อกำหนดในเชิงเวลา (Signal Timing Spec) สำหรับ VGA มีความสำคัญในการแสดงผลภาพให้ถูกต้องตามมาตรฐาน VGA โดยแบ่งเป็นข้อกำหนดเชิงเวลาสำหรับแนวนอนและแนวตั้ง
Horizontal Timing (แนวนอน) เป็นการสแกนแต่ละเส้นจากซ้ายไปขวา มีการแบ่งช่วงเวลาตามลำดับดังนี้:
- Horizontal Visible Area (Active Video): เป็นช่วงเวลาที่แสดงผลพิกเซลจริงในแต่ละเส้น (Line)
- Front Porch: เป็นช่วงเวลาหลังการแสดงผลของเส้นแต่ละเส้น และก่อนถึงสัญญาณพัลส์ HSYNC
- Horizontal Sync (HSYNC Pulse, Active-Low): ช่วงเวลาที่ให้สัญญาณเพื่อบอกให้เริ่มเส้นถัดไปในจอภาพ
- Back Porch: ช่วงเวลาหลัง HSYNC ที่ไม่แสดงผล ใช้เพื่อให้เวลาในจอภาพเตรียมพิกเซลใหม่
Vertical Timing (แนวตั้ง) การกำหนดเฟรมจากบนลงล่าง มีการแบ่งช่วงและลำดับดังนี้:
- Vertical Visible Area (Active Video): เป็นช่วงเวลาที่แสดงผลพิกเซลจริงของเฟรมในแนวตั้ง
- Front Porch: เป็นช่วงเวลาหลังจากการแสดงผลทุกเส้น ก่อนถึงสัญญาณพัลส์ VSYNC
- Vertical Sync (VSYNC Pulse, Active-Low): สัญญาณที่บอกให้เริ่มเฟรมใหม่ตั้งแต่ด้านบนของจอภาพ
- Back Porch: ช่วงเวลาหลัง VSYNC ที่ไม่แสดงผล ใช้เพื่อให้เวลาจอภาพเตรียมการแสดงผลเฟรมใหม่
รูป: การแบ่งช่วงสัญญาณตามข้อกำหนดของ VGA Timing Spec
ตัวอย่าง VGA Timing Spec ที่มีความละเอียด 640x480 @ 60Hz
Timing Parameter | Horizontal (Pixels) | Vertical (Lines) |
---|---|---|
Active Video | 640 | 480 |
Front Porch | 16 | 10 |
**Sync Pulse ** | 96 | 2 |
Back Porch | 48 | 33 |
Total Period | 800 | 525 |
การทำงานของ VGA 640x480 @ 60Hz จะใช้ความถี่ 25.175MHz (Pixel Clock)
- อัตราการอัปเดตเฟรม (Frame refresh rate): 60 Hz
- ความถี่ของพิกเซล (Pixel frequency): 25.175 MHz (800 pixels * 525 lines * 60 Hz = 25.20 Mpixels/s)
ตัวอย่าง VGA Timing Spec ที่มีความละเอียด 800x600 @ 72Hz
Timing Parameter | Horizontal (Pixels) | Vertical (Lines) |
---|---|---|
Active Video | 800 | 600 |
Front Porch | 56 | 37 |
Sync Pulse | 120 | 6 |
Back Porch | 64 | 23 |
Total Period | 1040 | 666 |
- อัตราการอัปเดตเฟรม (Frame refresh rate): 72 Hz
- ความถี่ของพิกเซล (Pixel frequency): 50 MHz (1040 pixels * 666 lines * 72 Hz = 49.87 Mpixels/s)
▷ การใช้งาน VGA สำหรับบอร์ด Terasic DE10-Lite FPGA#
บอร์ด FPGA อย่างเช่น Terasic DE10-Lite FPGA มีวงจรและคอนเนกเตอร์สำหรับการเชื่อมต่อสัญญาณ VGA ดังนั้นจึงสามารถนำไปใช้งานได้อย่างสะดวก และมีผังวงจรบางส่วนดังนี้
รูป: วงจรตัวต้านทานและคอนเนกเตอร์ D-Sub (15-pin) สำหรับ VGA
จากผังวงจร จะเห็นได้ว่า มีการใช้ตัวต้านทานแบบ R-2R DAC ในการแปลงสัญญาณดิจิทัล 4 บิต ให้เป็นสัญญาณแอนะล็อก สำหรับแต่ละสี (R,G,B)
ถัดไปเป็นโค้ด VHDL เพื่อสาธิตการสร้างสัญญาณ VGA ขนาด 800x600 พิกเซล
และใช้สัญญาณ Clock เท่ากับ 50MHz ซึ่งสามารถใช้กับบอร์ด DE10-Lite ได้
โดยไม่ต้องใช้วงจร ALTPLL
(PLL: Phase-Locked Loop)
เพื่อสร้างสัญญาณความถี่อื่น และใช้งานภายในชิป FPGA
ในตัวอย่างนี้มีการใช้สัญญาณ h_count
กับ v_count
สำหรับตัวนับแนวนอน และตัวนับแนวตั้ง ตามลำดับ
และจะมีการตรวจสอบในระหว่างการนับ เพื่อกำหนดช่วงเวลาและสร้างสัญญาณพัลส์
vga_hs
(HSYNC) และ vga_vs
(VSYNC) เป็นเอาต์พุต ตามลำดับ
และมี vga_r
, vga_g
และ vga_b
เป็นสัญญาณเอาต์พุต ขนาด 4 บิต
วงจรนี้สาธิตการกำหนดค่าสี RGB (อย่างละ 4 บิต รวม 12 บิต) ให้แต่ละพิกเซล
โดยพิจารณาจากค่าของตัวนับ h_count
และ v_count
สำหรับค่าในแกน x และ y ตามลำดับ
การกำหนดค่าสี RGB จะเกิดขึ้นเมื่อสัญญาณ visible_area=1
(Active Video)
แต่ถ้ามีค่า visible_area=0
จะให้ RGB มีค่าเป็น 0 ทั้งหมด (Blank)
-- DATE: 2024-10-31
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY de10_lite_vga_demo IS
PORT (
clk : IN STD_LOGIC; -- 50MHz clock input
reset_n : IN STD_LOGIC; -- active-low asynchronous reset
vga_hs : OUT STD_LOGIC; -- VGA Hsync output
vga_vs : OUT STD_LOGIC; -- VGA Vsync output
vga_r, vga_g, vga_b : OUT STD_LOGIC_VECTOR(3 DOWNTO 0) -- 4-bit R,G,B
);
END de10_lite_vga_demo;
ARCHITECTURE behavioral OF de10_lite_vga_demo IS
-- VGA timing constants (see: http://www.tinyvga.com/vga-timing)
CONSTANT H_ACTIVE_AREA : INTEGER := 800;
CONSTANT V_ACTIVE_AREA : INTEGER := 600;
-- Horizontal timing
CONSTANT H_FRONT_PORCH : INTEGER := 56;
CONSTANT H_SYNC_PULSE : INTEGER := 120;
CONSTANT H_BACK_PORCH : INTEGER := 64;
CONSTANT H_TOTAL : INTEGER
:= H_ACTIVE_AREA + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;
-- Vertical timing
CONSTANT V_FRONT_PORCH : INTEGER := 37;
CONSTANT V_SYNC_PULSE : INTEGER := 6;
CONSTANT V_BACK_PORCH : INTEGER := 23;
CONSTANT V_TOTAL : INTEGER
:= V_ACTIVE_AREA + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;
CONSTANT CENTER_Y : INTEGER := V_ACTIVE_AREA / 2;
CONSTANT CENTER_X : INTEGER := H_ACTIVE_AREA / 2;
-- Internal signals for counters
SIGNAL h_count, v_count : INTEGER := 0;
SIGNAL visible_area : STD_LOGIC := '0';
SIGNAL vga_clk : STD_LOGIC := '0'; -- VGA clock
SIGNAL hsync, vsync : STD_LOGIC := '1';
BEGIN
vga_clk <= clk; -- Use 50MHz clock for VGA pixel clock
vga_sync_proc : PROCESS (vga_clk, reset_n)
BEGIN
IF reset_n = '0' THEN
h_count <= 0;
v_count <= 0;
ELSIF rising_edge(vga_clk) THEN
-- Horizontal counter
IF h_count = H_TOTAL - 1 THEN
h_count <= 0;
-- Vertical counter
IF v_count = V_TOTAL - 1 THEN
v_count <= 0;
ELSE
v_count <= v_count + 1;
END IF;
ELSE
h_count <= h_count + 1;
END IF;
END IF;
END PROCESS;
-- Generate Hsync pulse (combinatioral)
hsync <= '0' WHEN (h_count >= H_ACTIVE_AREA + H_FRONT_PORCH
AND h_count < H_ACTIVE_AREA + H_FRONT_PORCH + H_SYNC_PULSE)
ELSE '1';
-- Generate Vsync pulse (combinatioral)
vsync <= '0' WHEN (v_count >= V_ACTIVE_AREA + V_FRONT_PORCH
AND v_count < V_ACTIVE_AREA + V_FRONT_PORCH + V_SYNC_PULSE)
ELSE '1';
-- Determine if the current pixel is in the visible area
visible_area <= '1' WHEN (h_count < H_ACTIVE_AREA
AND v_count < V_ACTIVE_AREA) ELSE '0';
PROCESS (vga_clk)
BEGIN
-- Update Hsync & Vsync outputs synchronized with the pixel clock
IF rising_edge(vga_clk) THEN
vga_hs <= hsync;
vga_vs <= vsync;
END IF;
END PROCESS;
-- Simple waveform drawing demo
PROCESS (vga_clk)
VARIABLE r_value : STD_LOGIC_VECTOR(3 DOWNTO 0);
VARIABLE g_value : STD_LOGIC_VECTOR(3 DOWNTO 0);
VARIABLE b_value : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
IF rising_edge(vga_clk) THEN
r_value := "0000";
g_value := "0000";
b_value := "0000";
IF visible_area = '1' THEN
-- Use the h_count and v_count values to the set RGB value
IF h_count < v_count THEN
IF h_count < H_ACTIVE_AREA/2 THEN
r_value := "0000";
g_value := "1111";
b_value := "0000";
ELSE
r_value := "1111";
g_value := "0000";
b_value := "0000";
END IF;
ELSE
IF h_count < H_ACTIVE_AREA/2 THEN
r_value := "1111";
g_value := "1111";
b_value := "0000";
ELSE
r_value := "1111";
g_value := "0000";
b_value := "1111";
END IF;
END IF;
END IF;
-- Update the RGB output
vga_r <= r_value;
vga_g <= g_value;
vga_b <= b_value;
END IF;
END PROCESS;
END behavioral;
ไฟล์ Tcl Script สำหรับการตั้งค่าเพื่อเลือกใช้ขา I/O ของ MAX 10 FPGA บนบอร์ด DE10-Lite มีดังนี้
#set_global_assignment -name DEVICE 10M50DAF484C7G
#set_global_assignment -name FAMILY "MAX 10"
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to *
set_instance_assignment -name IO_STANDARD "3.3 V Schmitt Trigger" -to reset_n
set_location_assignment PIN_P11 -to clk
set_location_assignment PIN_B8 -to reset_n
set_location_assignment PIN_P1 -to vga_b[0]
set_location_assignment PIN_T1 -to vga_b[1]
set_location_assignment PIN_P4 -to vga_b[2]
set_location_assignment PIN_N2 -to vga_b[3]
set_location_assignment PIN_W1 -to vga_g[0]
set_location_assignment PIN_T2 -to vga_g[1]
set_location_assignment PIN_R2 -to vga_g[2]
set_location_assignment PIN_R1 -to vga_g[3]
set_location_assignment PIN_AA1 -to vga_r[0]
set_location_assignment PIN_V1 -to vga_r[1]
set_location_assignment PIN_Y2 -to vga_r[2]
set_location_assignment PIN_Y1 -to vga_r[3]
set_location_assignment PIN_N3 -to vga_hs
set_location_assignment PIN_N1 -to vga_vs
ไฟล์สำหรับกำหนด Timing Spec สำหรับสัญญาณ Clock
# Synopsys design constraints file (.sdc)
# timing spec for clocks signals
# the main clock of 50MHz (period = 20 ns)
create_clock -name clk -period 20.0 [get_ports clk]
# derived clock with a period of 20 ns
create_generated_clock -name vga_clk -source [get_ports clk] \
-divide_by 1 [get_ports vga_clk]
รูป: หน้าจอ LCD แสดงผลที่ได้จากการกำหนดค่าสีให้พิกเซล
การทดสอบการทำงานของวงจร จะต้องใช้สัญญาณ VGA จากบอร์ด DE10-Lite นำไปต่อกับจอภาพ LCD ที่รองรับการใช้งาน VGA ได้
คำแนะนำ: หากต้องการนำสัญญาณ VGA ไปใช้กับจอภาพแบบ HDMI ก็สามารถใช้อุปกรณ์เสริม ที่เป็นตัวแปลงสัญญาณ VGA ให้เป็นสัญญาณ HDMI ได้
นอกจากนั้น การใช้ Signal Tap IP Core เป็นอีกหนึ่งตัวช่วยในการวิเคราะห์การทำงานของวงจร ตามตัวอย่างการใช้งานต่อไปนี้
รูป: การตั้งค่าการใช้งาน Signal Tap
รูป: ตัวอย่างสัญญาณที่ได้จากการทำงานของ Signal Tap
รูป: ตัวอย่างสัญญาณที่ได้จากการทำงานของ Signal Tap เมื่อซูมขยายสัญญาณ
การตั้งค่าทริกเกอร์ (Trigger) สำหรับ Signal Tap ในตัวอย่างนี้ เป็นดังนี้
ทริกเกอร์จะเกิดขึ้นเมื่อสัญญาณ visible_area
เปลี่ยนจาก 0->1
หรือ เกิดขอบขาขึ้น
▷ กล่าวสรุป#
บทความนี้ได้นำเสนอตัวอย่างการเขียนโค้ด VHDL เพื่อสร้างสัญญาณดิจิทัล และนำไปใช้สำหรับการแสดงผลบนจอภาพแบบ VGA ขนาด 800 x 600 พิกเซล โดยได้ทดลองใช้กับบอร์ด Terasic DE10-Lite (MAX 10 FPGA) และสาธิตการสร้างรูปคลื่นสัญญาณสามเหลี่ยมบนจอภาพ
บทความที่เกี่ยวข้อง
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Created: 2024-10-31 | Last Updated: 2024-11-01