วันจันทร์ที่ 2 กุมภาพันธ์ พ.ศ. 2558

การทดลองที่ 2 ออกแบบวงจรดิจิทัลสร้างสัญญาณ PWM ควบคุมการทำงานของ WS2812 RGB LED โดยใช้ภาษา VHDL



การทดลองที่ 2 ออกแบบวงจรดิจิทัล
สร้างสัญญาณ PWM ควบคุมการทำงานของ WS2812 RGB LED โดยใช้ภาษา VHDL


รายการอุปกรณ์
1. บอร์ด Altera FPGA (WARRIOR CYCLONE3 DEV) ชิปหมายเลข EP3C10E144C8   1 บอร์ด
2. สายดาวน์โหลด ByteBlaster II Cable หรือ สายดาวน์โหลดUSB Blaster Cable             1 ชุด
3. เครื่องคอมพิวเตอร์                                                                                                      1 ชุด
4. ออสซิลโลสโคป                                                                               1 เครื่อง
5. สายวัด Logic Analyzer                                                                   1 เส้น
6. WS2812 RGB LED                                                                  1 ดวง


วิธีการทดลอง
จงออกแบบวงจรดิจิลัทโดยใช้ภาษา VHDL สำหรับนำไปสร้างเป็นวงจรในชิป FPGA โดยใช้บอร์ดที่มีอยู่ในห้องแล็ป วงจรดิจิทัลมี I/O ดังนี้
- CLK (input) มีความถี่ 50MHz ใช้สำหรับกำหนดจังหวะการทำงานของวงจรทั้งหมด (เป็นการออกแบบวงจรดิจิทัลแบบ Synchronous Design)
- RST_B (input) เป็นอินพุตสำหรับใช้รีเซตแบบ Asynchronous สำหรับการทำงานของวงจรโดยรวม (ทำงานแบบ Active-Low) ซึ่งได้จากวงจรปุ่มกด (Push Button)
- PB (input) เป็นอินพุตจากปุ่มกด 1 ปุ่ม ทำงานแบบ Active-low เพื่อใช้ในการเปลี่ยนสีของ WS2812 RGB LED จำนวน 1 ดวง
- DATA (output) เป็นเอาต์พุตสำหรับนำไปควบคุมการทำงานของ WS2812 RGB LED เพียง 1 ดวง ซึ่งเป็นสัญญาณตามข้อกำหนดของชิป WS2812 เพื่อส่งข้อมูลจำนวน 24 บิต

พฤติกรรมการทำงานเป็นดังนี้
- เมื่อเริ่มต้นหรือกดปุ่มรีเซต (RST_B) จะทำให้ค่าสีเป็น 0x000000 (24 บิต) และส่งออกไปยัง WS2812 RGB LED หนึ่งครั้ง
- เมื่อมีการกดปุ่ม PB แล้วปล่อยในแต่ละครั้ง จะมีการเปลี่ยนค่าสี 24 บิต แล้วส่งออกไปยัง RGB LED ใหม่หนึ่งครั้ง ตามลำดับดังนี้
0x000000 -> 0x0000FF -> 0x00FF00 -> 0xFF0000 แล้ววนซ้ำ

แนวทางการออกแบบและทดสอบ
  - ออกแบบวงจรโดยใช้ภาษา VHDL
  - เขียน VHDL Testbench เพื่อทดสอบการทำงาน และจำลองการทำงาน
  - ทดสอบการทำงานในบอร์ด FPGA แล้ววัดสัญญาณโดยใช้ออสซิลโลสโคป
(ยังไม่ต้องต่อวงจร RGB LED จริง)


แนวทางการออกแบบ



รูปแผนภาพ Finite State Machine ออกแบบวงจรสร้างสัญญาณ PWM



block.jpg
รูปแผนภาพ Block Diagram การทำงานของวงจร


โค้ดวงจรดิจิทัลภาษา VHDL


library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity shiftbit is generic ( PWM0H: integer:= 18; PWM0L: integer:= 39; PWM1H: integer:= 35; PWM1L: integer:= 30; RES: integer:= 400 ); port( clk, rst_b, pb : in std_logic; data : out std_logic ); end shiftbit; architecture behave of shiftbit is signal RGBbit : std_logic_vector(23 downto 0):= x"000000"; signal ti,index, count : integer:= 0; signal check : std_logic := '0'; type state_type is (S0,S1,S2,S3); signal state : state_type := S0; begin process(clk, rst_b) begin if rst_b = '0' then RGBbit <= x"000000"; end if; if rising_edge(clk) then case state is when S0 => state <= S1; if pb = '1' and ti > 1000 then ti <= 0; if RGBbit = x"000000" then RGBbit <= x"0000FF"; elsif RGBbit = x"0000FF" then RGBbit <= x"00FF00"; elsif RGBbit = x"00FF00" then RGBbit <= x"FF0000"; elsif RGBbit = x"FF0000" then RGBbit <= x"000000"; end if; elsif pb = '0' then ti <= ti+1; end if; when S1 => if RGBbit(index) = '0' then if count < PWM0H then data <= '1'; count <= count + 1; elsif count < PWM0H+PWM0L then data <= '0'; count <= count + 1; else if index < 23 then index <= index + 1; count <= 0; end if; end if; state <= S3; else state <= S2; end if; when S2 => if RGBbit(index) = '1' then if count < PWM1H then data <= '1'; count <= count + 1; elsif count < PWM1H+PWM1L then data <= '0'; count <= count + 1; else if index < 23 then index <= index + 1; count <= 0; end if; end if; end if; state <= S3; when S3 => if index = 23 then if count > RES then count <= 0; index <= 0; else count <= count + 1; end if; end if; state <= S0; when others => state <= S0; end case; end if; end process; end behave;



โค้ด Testbench วงจร


library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; entity TB_shiftbit is end TB_shiftbit; architecture testbench of TB_shiftbit is component shiftbit is generic ( PWM0H: integer:= 18; PWM0L: integer:= 39; PWM1H: integer:= 35; PWM1L: integer:= 30; RES: integer:= 400 ); port( clk, rst_b, pb : in std_logic; data : out std_logic ); end component; constant PWM0H: integer:= 18; constant PWM0L: integer:= 39; constant PWM1H: integer:= 35; constant PWM1L: integer:= 30; constant RES: integer:= 400; signal t_clk,t_rst_b,t_data,t_pb : std_logic; begin DUT: shiftbit generic map(PWM0H => PWM0H, PWM0L => PWM0L,PWM1H => PWM1H,PWM1L => PWM1L, RES => RES) port map(clk => t_clk, rst_b => t_rst_b, data => t_data ,pb => t_pb ); process begin -- a process for generating the clock signal (50MHz) t_clk <= '1'; wait for 10 ns; t_clk <= '0'; wait for 10 ns; end process; process begin -- a process for generating the UP input signal t_pb <= '1' ;wait for 4 ms; t_pb <= '0' ;wait for 1 ms; t_pb <= '1' ;wait for 4 ms; t_pb <= '0' ;wait for 1 ms; end process; process begin t_rst_b <= '1'; wait for 7 ms;t_rst_b <= '0'; wait for 5 ms;t_rst_b <= '1'; wait; end process; end testbench;



โค้ด component_button

library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all; entity component_button is port( CLK, PB : in std_logic; signal_out : out std_logic ); end component_button; architecture Behavior of component_button is signal count: integer:=0; signal check,signal_sent: std_logic:='0'; begin process (CLK, PB) begin if rising_edge(CLK) then if(PB = '1')then count <= 0; signal_sent <= '0'; else count <= count + 1; end if; if(count > 20000)then check <= '1'; end if; if(PB = '1')and(check = '1')then signal_sent <= '1'; check <= '0'; end if; end if; end process; signal_out <= signal_sent; end Behavior;


โค้ด component_Data

library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all; entity component_Data is port( CLK : in std_logic; RGBbit : in std_logic_vector (23 downto 0) := x"000000"; data_out : out std_logic ); end component_Data; architecture Behavior of component_Data is signal count,index: integer:=0; signal datacheck: std_logic_vector(23 downto 0):=x"000000"; signal data,check: std_logic:='0'; begin process (CLK) begin if rising_edge(CLK) then if index = 24 then if count > 4000 then count <= 0; index <= 0; else count <= count + 1; end if; else if RGBbit(index) = '0' then if count < 18 then data <= '1'; count <= count + 1; elsif count < 47 then data <= '0'; count <= count + 1; else index <= index + 1; count <= 0; end if; else if count < 35 then data <= '1'; count <= count + 1; elsif count < 65 then data <= '0'; count <= count + 1; else index <= index + 1; count <= 0; end if; end if; end if; end if; end process; data_out <= data; end Behavior;  


โค้ด component_fsm

library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all; entity component_fsm is port( CLK,input_data,input_reset : in std_logic; data_out : out std_logic_vector(23 downto 0) ); end component_fsm; architecture Behavior of component_fsm is type state_type is (S0,S1,S2,S3); signal state : state_type :=S0; signal data_t: std_logic_vector(23 downto 0):=x"000000"; signal signal_t : std_logic:= '0'; begin process (CLK, input_data,input_reset) begin if input_reset = '0' then state <= S0; data_t <= x"000000"; elsif rising_edge(CLK) then case state is when S0 => data_t <= x"000000"; if input_data = '1' then state <= S1; elsif input_data = '0' then state <= S0; end if; when S1 => data_t <= x"0000FF"; if input_data = '1' then state <= S2; elsif input_data = '0' then state <= S1; end if; when S2 => data_t <= x"00FF00"; if input_data = '1' then state <= S3; elsif input_data = '0' then state <= S2; end if; when S3 => data_t <= x"FF0000"; if input_data = '1' then state <= S0; elsif input_data = '0'then state <= S3; end if; end case; end if; end process; data_out <= data_t; end Behavior;  


โค้ด เรียกใช้ component ทั้งหมด

library ieee; library work; use ieee.std_logic_1164.all; use ieee.std_logic_arith.all; use ieee.numeric_std.all; entity componentwork2 is port( CLK,PB,RESET : in std_logic; Data : out std_logic ); end componentwork2; architecture structural of componentwork2 is component component_button port( CLK, PB : in std_logic; signal_out : out std_logic ); end component; component component_fsm port( CLK,input_data,input_reset : in std_logic; data_out : out std_logic_vector(23 downto 0) ); end component; component component_Data is port( CLK : in std_logic; RGBbit : in std_logic_vector (23 downto 0) := x"000000"; data_out : out std_logic ); end component; signal dataout24: std_logic_vector(23 downto 0); signal signal_out: std_logic; begin cmp1_inst: component_button port map(CLK => CLK, PB => PB, signal_out => signal_out); cmp2_inst: component_fsm port map(CLK => CLK, input_reset => RESET, input_data => signal_out, data_out => dataout24); cmp3_inst: component_Data port map(CLK => CLK, RGBbit => dataout24, data_out => Data); end structural;    


ผลการทดลอง


ผลการสังเคราะห์VHDL เป็นวงจรในชิปและการใช้ทรัพยากรของบอร์ด FPGA
com_pro2.jpg


ผลการจำลองการทำงานด้วย Modelsim
สัญญาณ 0x000000sim2-000000.jpg

สัญญาณ 0x0000FF
sim2-0000FF.jpg

สัญญาณ 0x00FF00
sim2-00FF00.jpg
สัญญาณ 0xFF0000


sim2-FF0000.jpg

การทดลองที่ 1 ออกแบบวงจรดิจิทัลสร้างสัญญาณ PWM ควบคุมการทำงานของ RGB LED โดยใช้ภาษา VHDL

รายการอุปกรณ์
1. บอร์ด Altera FPGA (WARRIOR CYCLONE3 DEV) ชิปหมายเลข EP3C10E144C8      1 บอร์ด
2. สายดาวน์โหลด ByteBlaster II Cable หรือ สายดาวน์โหลดUSB Blaster Cable                1 ชุด
3. เครื่องคอมพิวเตอร์                                                                                                         1 ชุด
4. ออสซิลโลสโคป                                                                                  1 เครื่อง
5. สายวัด Logic Analyzer                                                                    1 เส้น

วิธีการทดลอง
ออกแบบวงจรดิจิลัทโดยใช้ภาษา VHDL สำหรับนำไปสร้างเป็นวงจรในชิป FPGA โดยวงจรดิจิทัลมี I/O ดังนี้
- CLK (input) มีความถี่ 50MHz ใช้สำหรับกำหนดจังหวะการทำงานของวงจรทั้งหมด (เป็นการออกแบบวงจรดิจิทัลแบบ Synchronous Design)
- RST_B (input) เป็นอินพุตสำหรับใช้รีเซตแบบ Asynchronous สำหรับการทำงานของวงจรโดยรวม (ทำงานแบบ Active-Low) ซึ่งได้จากวงจรปุ่มกด (Push Button)
- PB[2:0] (input) เป็นอินพุตจากปุ่มกด 3 ปุ่ม ทำงานแบบ Active-low เพื่อใช้ในการเปลี่ยนค่า Duty Cycle โดยเพิ่มทีละ 10 ในช่วง 0 ถึง 100 สำหรับสัญญาณ PWM(2:0) ที่มี 3 ช่องสัญญาณ
- PWM[2:0] (output) เป็นเอาต์พุตสำหรับนำไปควบคุมการทำงานของ RGB LED จำนวน 1 ดวง

วงจรดิจิทัลพฤติกรรมการทำงานเป็นดังนี้
- เมื่อเริ่มต้นหรือกดปุ่มรีเซต RST_B ค่า PWM[2:0] จะเป็นลอจิก 0 ทั้ง 3 ช่องสัญญาณ และมีค่า Duty Cycle สำหรับสัญญาณ PWM[i], i=0,1,2 เป็น 0
- เมื่อกดปุ่มใดๆ PB[i], i=0,1,2, แล้วปล่อยในแต่ละครั้ง จะเพิ่มค่า Duty Cycle ของสัญญาณ PWM สำหรับช่องสัญญาณ i ทีละ 10 แต่ถ้าถึง 100 จะกลับไปเริ่มต้นที 0 ใหม่
- สัญญาณ PWM แต่ละช่อง ต้องมีความถี่เท่ากันและคงที่ และสามารถเลือกใช้ความถี่ได้ในช่วง 500Hz ถึง 1kHz


แนวทางการออกแบบและทดสอบ
- ออกแบบวงจรโดยใช้ภาษา VHDL
- เขียน VHDL Testbench เพื่อทดสอบการทำงาน และจำลองการทำงาน
- ทดสอบการทำงานในบอร์ด FPGA แล้ววัดสัญญาณโดยใช้ออสซิลโลสโคป
- บันทึกผลและเขียนรายงานการทดลอง

แนวทางการออกแบบ




h1.jpg


รูปแผนภาพ Block Diagram การทำงานของวงจร



โค้ดวงจรดิจิทัลภาษา VHDL


library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity DutyCycle is generic ( PERIOD : integer := 100; -- count period for PWM STEP : integer := 10 -- increment step for duty cycle ); port( CLK : in std_logic; RST_B : in std_logic; PB : in std_logic_vector (2 downto 0); PWM : out std_logic_vector (2 downto 0)); end DutyCycle; architecture behave of DutyCycle is signal check_0 : std_logic:= '0'; signal check_1 : std_logic:= '0'; signal check_2 : std_logic:= '0'; signal duty_cycle_0 :integer :=0; signal duty_cycle_1 :integer :=0; signal duty_cycle_2 :integer :=0; signal count :integer :=0; signal ti : integer := 0; begin process (CLK,RST_B) begin if rising_edge(CLK) then if RST_B ='0' then duty_cycle_0 <= 0; duty_cycle_1 <= 0; duty_cycle_2 <= 0; end if; if PB(0) = '1' and check_0 = '1' then check_0 <= '0'; duty_cycle_0 <= duty_cycle_0+STEP; if duty_cycle_0 > (PERIOD-1) then duty_cycle_0 <= 0; end if; elsif PB(0) ='0' then if ti < 50000 then ti <= ti+1; else check_0 <= '1'; ti <= 0; end if; end if; ----------------------------------------------- if PB(1) = '1' and check_1 = '1' then check_1 <= '0'; duty_cycle_1 <= duty_cycle_1+STEP; if duty_cycle_1 > (PERIOD-1) then duty_cycle_1 <= 0; end if; elsif PB(1) ='0' then if ti < 50000 then ti <= ti+1; else check_1 <= '1'; ti <= 0; end if; end if; ----------------------------------------- if PB(2) = '1' and check_2 = '1' then check_2 <= '0'; duty_cycle_2 <= duty_cycle_2+STEP; if duty_cycle_2 > (PERIOD-1) then duty_cycle_2 <= 0; end if; elsif PB(2) ='0' then if ti < 50000 then ti <= ti+1; else check_2 <= '1'; ti <= 0; end if; end if; end if; end process; process (CLK) begin if rising_edge(CLK) then if count >99999 then count <= 0; else count <= count+1; end if; end if; end process; PWM(0) <= '1' when (count < duty_cycle_0*1000) else '0'; PWM(1) <= '1' when (count < duty_cycle_1*1000) else '0'; PWM(2) <= '1' when (count < duty_cycle_2*1000) else '0'; end behave;


ผลการทดลอง


ผลการสังเคราะห์ VHDL เป็นวงจรในชิปและการใช้ทรัพยากรของบอร์ด FPGA
com_pro.jpg


ผลการจำลองการทำงานด้วย Modelsim


sim.jpg



ทดลองบนบอร์ด FPGA
20150126_161836.jpg


ผลลัพธ์ที่ได้

การเปลี่ยนแปลงลักษณะสัญญาณเมื่อกดปุ่ม PB ช่องสัญญาณ D0:5 ครั้ง  D1:9 ครั้ง  D2:1 ครั้ง 

NewFile2.jpg

การเปลี่ยนแปลงลักษณะสัญญาณเมื่อกดปุ่ม PB ช่องสัญญาณ D0:8 ครั้ง  D1:4 ครั้ง  D2:1 ครั้ง 
NewFile1.jpg
 

การเปลี่ยนแปลงลักษณะสัญญาณเมื่อกดปุ่ม PB ช่องสัญญาณ D0:1 ครั้ง  D1:5 ครั้ง  D2:8 ครั้ง 

NewFile0.jpg