Try   HackMD

FPGA 第六組 Lab2 結報

文章網址

組員

姓名 學號
劉永勝 F94089032
蔡宗瑾 E14083137
李宇洋 E24099025

Color Code 解釋

Color code也可稱作hex triplet,而其是由光的三元色RGB(Red, Green, Blue)所組成,每個顏色大小8bit,範圍從0~255,一個顏色有256種組合,透過三元色各個顏色強度的不同可以得到

256256256種顏色組合。Color code就是將每個顏色透過對應的三元色強度編碼而成的code,例如紫色其對應的color code是7F1FFF,代表顏色強度(Red, Green, Blue)=(7F,1F,FF)時,人眼可辨識其顏色為紫色。

Problem 1 [影片連結]

本設計有兩個RGB燈光需要控制,一個是LED4,其為恆亮某種指定顏色;一個是LED5,其為以呼吸燈的方式亮某種指定顏色。

RGB LED4 (Static Lights)

  • 要利用電路展現出三元色以外的顏色時,我們可以使用counter來模擬三元色顏色的強度,想當然而counter會數256次,如同顏色強度的範圍一樣,數到255時下個cycle重新循環,如以下:
// counter count from 0 ~ 255 always @(posedge clk or posedge rst) begin if (rst) counter_256 <= 8'd0; else begin counter_256 <= counter_256 + 8'd1; end end

R_time_in, G_time_in, B_time_in 分別代表RGB的顏色強度,當counter小於個別強度時,RGB都會亮,一旦counter超過其指定強度時,RGB根據其對應強度各自暗掉。

always @(*) begin rgb4[0] = (counter_256 < R_time_in) ? 1'b1 : 1'b0; rgb4[1] = (counter_256 < G_time_in) ? 1'b1 : 1'b0; rgb4[2] = (counter_256 < B_time_in) ? 1'b1 : 1'b0; end
  • 為什麼會恆亮呢?
    因為是利用FPGA的system clk來驅動counter_256,其頻率為125MHz,所以對於人眼來說當counter_256大於X_time_in時,LED對人眼而言並未真正熄滅,只是變弱而已,因此這就是現代電腦模擬現實生活中顏色的方式。

RGB LED5 (Breathing Lights)

相較於上面直接利用system clk驅動counter_256來顯示顏色,我們呼吸燈採用降頻的方式來呈現,使得人眼可以辨認出呼吸的效果。
透過一個16-bit counter來實現降頻,其範圍是0~0xffff,會根據counter_256每當數到255時才加一,兩種counter如以下:

// count 0 ~ 255 always @(posedge clk or posedge rst) begin if (rst) counter_256 <= 8'd0; else begin counter_256 <= counter_256 + 8'd1; end end // count 0 ~ 16777215 always @(posedge clk or posedge rst) begin if (rst) counter_16777215 <= 16'd0; else begin if (counter_256 == 8'd255) counter_16777215 <= counter_16777215 + 16'd1; else counter_16777215 <= counter_16777215; end end

我們呼吸燈的實現方法是將rgb三個PWM 等比例增加到我們想要的顏色,達到亮度遞增的效果。之後再等比例遞減,達到亮度遞減的效果。

  • 如何遞增、遞減?
    本題目要求暗 -> 亮 ->暗至少要32個phase,則可切成暗->亮16 phase、亮->暗16 phase。依照等比例遞增、遞減的方式,將該顏色對應的hex triplet除以16,可得到每個phase需要增加、減少的數值,如下方例子:

    • 紫燈hex triplet對應的rgb PWM分別為7F_1F_FF:
      ( r ) red PWM = 8'h7F
      ( g ) green PWM = 8'h1F
      ( b ) blue PWM = 8'hFF

    • rgb最大值除以16,分成16個phase:
      ( r ) 8'h7F / 16 = 8'h7F >> 4 = 4'h7 =

      Δ R
      ( g ) 8'h1F / 16 = 8'h1F >> 4 = 4'h1 =
      Δ
      G
      ( b ) 8'hFF / 16 = 8'hFF >> 4 = 4'hF =
      Δ
      B
      則上方計算出的數值,為每個phase PWM需要增加的量。因此16個phase即可接進數值,因為shift bit的關係,會有餘數問題。

    • rgb除以16的餘數:
      ( r ) 8'h7F % 16 = 4'hF = mod R
      ( g ) 8'h1F % 16 = 4'hF = mod G
      ( b ) 8'hFF % 16 = 4'hF = mod B

    根據上方的計算可得下方式子:
    ( r )

    Δ R * 16 + mod R = 8'h7F
    ( g )
    Δ
    G * 16 + mod G = 8'h1F
    ( b )
    Δ
    B * 16 + mod B = 8'hFF
    16個phase遞增、遞減,再加一個phase處理餘數

  • Dynamic boundary
    X_breathing不是像上半部的X_time_in是固定的,它是動態改變的邊界,也就是因為這個動態邊界呈現了呼吸燈的效果,讓原先static lights固定的邊界為hex code,在這裡的呼吸燈成為漸漸遞增又遞減的邊界。

// breathing always @(posedge clk or posedge rst) begin if (rst) begin R_breathing <= 8'd0; G_breathing <= 8'd0; B_breathing <= 8'd0; end else if (counter_16777215 == 16'hffff && counter_256 == 8'd0) begin case (mode) INCREASING: begin R_breathing <= R_breathing + R_inc; G_breathing <= G_breathing + G_inc; B_breathing <= B_breathing + B_inc; end ADD_LAST: begin R_breathing <= R_breathing + R_mod; G_breathing <= G_breathing + G_mod; B_breathing <= B_breathing + B_mod; end DECREASING: begin R_breathing <= R_breathing - R_inc; G_breathing <= G_breathing - G_inc; B_breathing <= B_breathing - B_inc; end SUB_LAST: begin R_breathing <= R_breathing - R_mod; G_breathing <= G_breathing - G_mod; B_breathing <= B_breathing - B_mod; end endcase end else begin R_breathing <= R_breathing; G_breathing <= G_breathing; B_breathing <= B_breathing; end end

綜觀counter以及breathing的程式碼,可得知X_breathing改變的頻率是

125MHz/28+16=7.45Hz,X_breathing會一路從0加到相對應的hex code(最大值),再從最大值遞減回0。

  • FSM 說明
    根據上方說明可製作出下方的FSM。
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
state 說明
INCREASING rgb PWM從0開始逐步遞增
ADD_LAST 加上餘數
DECREASING rgb PWM從最大值逐步遞減
SUB_LAST 減去餘數
  • 分割模塊
    這個實作分成兩個模塊,分別為PWM_DecoderBreath_LED個別功能如下:

    1. PWM_Decoder
      輸入訊號switch,決定輸出顏色的PWM,此PWM輸出訊號會讓Breath_LED接收,為呼吸燈的最大亮度。下表為對應顏色:

      switch color
      00 7F_1F_FF - Purple Light
      00 00_FF_FF - Cyan Light
      00 FF_FF_00 - Yellow Light
      00 FF_00_FF - Crimson Light
    2. Breath_LED
      接收PWM_Decoder輸出的顏色PWM最大值,執行上方FSM之功能,達到呼吸燈PWM的遞增遞減

  • Block Design

Problem 2 [影片連結]

Problem 1是手動變換顏色,而Problem 2是自動變換顏色。要實現此功能則模塊PWM_Decoder不能從板子上的switch接收訊號,也就是pynq-z2_v1.0.xdc不能指名switch腳位。而是要系統自行產生switch訊號切換顏色。

  • 各模塊功能
    1. PWM_Decoder
      與problem 1功能相同,只是顏色從4個變成6個,則輸入switch訊號線從2 bit變成3 bit。

    2. Breath_LED
      內部狀態機與problem 1相同,但當state從INCREASIN跑到SUB_LAST時,完成一次暗 -> 亮 ->暗,輸出switch訊號給PWM_Decoder,則PWM_Decoder根據switch的數值,給出對應顏色。簡單來說,FSM跑完一圈,則輸出訊號switch加一,加到5之後歸零。

      switch顏色對應如下:

      switch color
      0 FF_00_00 - Red Light
      1 FF_61_00 - Orange Light
      2 FF_FF_00 - Yellow Light
      3 00_FF_00 - Green Light
      4 00_00_FF - Blue Light
      5 7F_1F_FF - Purple Light
      default FF_00_00 - Red Light
  • Block Design