FPGAによる女性の日ギフト

みなさんこんにちは! 3月8日を見越して、私は職場で最も頻繁に使用しなければならないツールを使用して、愛する人にささやかな贈り物をすることにしました。 少し自由時間があるので、これについてHabréに関する短い記事を書いてみませんか。 これは、すべての女性、特にhabrahabrコミュニティの少数の女性メンバーを祝福する絶好の機会です。 この記事は「 ただの楽しみのために 」書かれており、科学的な貢献はなく、多くのセマンティックの負荷はありませんが、FPGAの分野の初心者開発者には役立ちます。 最終結果を得るためにどのツールが使用されたのか、それから何が生まれたのかを説明します。 この記事では、小さな古いFPGAで制御されている8x8 LEDマトリックス上で、ちらつきとテキストの実行を確認します。 記事の最後に、FPGAとLEDアレイのコラボレーションのビデオデモがあります。







楽器



このプロジェクトは、FPGA Spartan3Eを搭載したデバッグボードに実装されています。 さまざまなインターフェイス(VGA、PS / 2)による最も単純なバインディングが含まれ、LEDとLEDディスプレイ、トリガースイッチ、ボタン、サードパーティ製のものを接続するためのさまざまな出力を備えています。 料金は非常に安く、中国の店舗の1つでebayから注文しました。 価格-送料込みで135.00ドル (旧価格で〜4000r)。



メーカーの公式ウェブサイトは現在死んでいますが、驚くことではありません。



ボードの主な機能:





FPGA Spartan3E XC3S500Eのリソースを表に示します。







単純なプロジェクトとFPGAデザインの最初の導入では、これで十分です。



LEDマトリクス



LED8x8 LEDのマトリックスがFPGAに接続されています。 明らかに、各LEDは直接接続されていません。64個のFPGAコンタクトを使用する必要があるためです。これは非常に高価で不合理です。 以下は、デバッグボード上の中国語のデータシートの図です。 LEDは8個の列と行で接続されており、接続は直接ではなく、PNPトランジスタを介して接続されていることがわかります。 トランジスタのエミッタは供給電圧に、ベースはFPGAの接点に、コレクタはLEDのマトリックスに接続されています。 合計16の接点がFPGAに接続されています。 論理制御LEDマトリックス- 、つまり、LEDは低論理レベルで点灯します(log。0)。







つまり、特定の行と列に必要なロジックレベルを設定すると、特定のLEDが点灯します。



例:



A)ベクトルLEDY = "11111110"、およびベクトルLEDX = "11111110"の場合、右下隅の唯一のLEDが点灯します。



11111111

11111111

11111111

11111111

11111111

11111111

11111111

11111110



B)ベクトルLEDY = "11111110"、およびベクトルLEDX = "00000000"の場合、ボトムライン全体が点灯します。



11111111

11111111

11111111

11111111

11111111

11111111

11111111

00000000



C )ベクトルLEDY = "00000000"、およびベクトルLEDX = "11111110"の場合、右側の列全体が点灯します。



11111110

11111110

11111110

11111110

11111110

11111110

11111110

11111110



D)ベクトルLEDY = "00000000"、およびベクトルLEDX = "00000000"の場合、LEDのマトリックス全体が点灯します。



これに関して、特定の困難が生じる。 特定の文字が文字または数字の形で表示されるようにLEDのマトリックスを点灯する方法は? これは実際には難しくありません。



LEDへの文字出力



LEDのマトリックスに文字を出力するプロセスは非常に簡単です。 まず、特定のビット容量のカウンターを編成し、その上位3ビットを使用してLEDYベクトルを切り替える必要があります。 なぜ3桁ですか? 8ビットベクトルの切り替えは、3つの制御ビットを使用するステートマシンを使用して記述できます。 VHDLでは、これは次のように行われます。



カウンター



pr_cnt: process(clk, rst) is begin if (rst = '0') then cnt_led <= (others => '0'); elsif rising_edge(clk) then if (rst_reg = '0') then cnt_led <= (others => '0'); else cnt_led <= cnt_led + '1'; end if; end if; end process;
      
      





最初のリセット(最初)はグローバルです。 2番目のリセット(rst_reg)はソフトウェアであり、トリガーによって制御されます。



LEDYのステートマシン



 pr_3x8: process(cnt_cmd) is begin case cnt_cmd is when "000" => en_xhdl <= "11111110"; when "001" => en_xhdl <= "11111101"; when "010" => en_xhdl <= "11111011"; when "011" => en_xhdl <= "11110111"; when "100" => en_xhdl <= "11101111"; when "101" => en_xhdl <= "11011111"; when "110" => en_xhdl <= "10111111"; when others => en_xhdl <= "01111111"; end case; end process;
      
      





カウンタのステータスを変更すると、LEDのLEDY列に1ビットが含まれます。 したがって、 移動ゼロスキームが編成されます。



次に、 LEDXベクトルを整理するためのロジックがまったく同じ2つのステートマシンが必要です。 原則として1つで十分ですが、列ベクトルと同じように視覚的です。



中間宇宙船



 pr_8x4: process(en_xhdl) is begin case en_xhdl is when "11111110" => led_cmd <= "000"; when "11111101" => led_cmd <= "001"; when "11111011" => led_cmd <= "010"; when "11110111" => led_cmd <= "011"; when "11101111" => led_cmd <= "100"; when "11011111" => led_cmd <= "101"; when "10111111" => led_cmd <= "110"; when others => led_cmd <= "111"; end case; end process;
      
      





LEDXベクターのKA



 pr_ledx: process(led_cmd) is begin case led_cmd is when "000" => ledx <= "01111110"; when "001" => ledx <= "10111101"; when "010" => ledx <= "11011011"; when "011" => ledx <= "11100111"; when "100" => ledx <= "11100111"; when "101" => ledx <= "11011011"; when "110" => ledx <= "10111101"; when others =>ledx <= "01111110"; end case; end process;
      
      





これらのアクションの結果として、 LEDXベクトルが形成されます。 LEDマトリックスにシンボルを描くのはこのベクトルであり、LEDYベクトルは不必要なLEDのタイムリーなシャットダウンを担当します。 この例では、十字または「X」記号がLEDマトリックスで点灯するはずです。これは、最後のステートマシンを注意深く見ると視覚的に確認できます。 したがって、列ベクトルは補助になり、行ベクトルは文字を描画し、その助けを借りて、LEDマトリックスに何かを「書き込む」ことができます。



このプロジェクトでは、同じタイプの2つのファイルを作成して、LEDマトリックス用のシンボルを生成しました。 最初のブロックにはハートが表示され、2番目のブロックにはROMメモリ設計の助けを借りて、「MARCH 8!」というテキストが表示されます。 テキスト文字はメモリ内にあり、正しくアドレス指定する必要があります。 表示プロセスは十分に速いので、文字が読めるように出力周波数を調整する必要があります。 これを行うには、27ビット用に追加のカウンターを作成する必要があります。これにより、50 MHzの入力周波数を2 ^ 27で除算し、LEDマトリックス上の文字の変化を観察できます。



文字コードは、2次元配列としてメモリに記録されます。 8ビットの数値は、ステートマシンのロジック(LEDにシンボルを出力するため)とアドレス(LEDのマトリックスのシンボルを変更するため)によって異なります。



 type rom_type is array (7 downto 0) of std_logic_vector(7 downto 0); type rom_8x8 is array (0 to 7) of rom_type; constant ROM_TEXT: rom_8x8:=( ( "11000011", "10011001", "00111101", "00111111", "00111111", "00111101", "10011001", "11000011") ... /cut --      2D-: pr_8x8: process(clk, rst) is begin if (rst = '0') then data_led <= (others => '0'); elsif rising_edge(clk) then data_led <= ROM_TEXT(CONV_INTEGER(addr_txt(Na-1 downto Na-3)))(CONV_INTEGER(led_cmd)); end if; end process;
      
      





特殊効果



マトリックス上のシンボルを照らすだけなら、それは少し退屈ですか? ライトを点滅させて実行するという形で、プロジェクトに特殊効果を追加する必要があります。 とても簡単です。 これには、よく知られたPWMアルゴリズム(パルス幅変調)が必要です。 その助けを借りて、負荷に供給される電力を制御できます(つまり、電流を調整します)。 これは、一定の信号周波数でパルスのデューティサイクルを変更することによって行われます。



FPGAでPWMがどのように作成されるかについては説明しません。これについて多くの記事が書かれています。 基本的な原理は、いくつかの制御されたカウンターで、ゼロと1のパルスの持続時間の変化が組織化されるということです。 私のプロジェクトでは、PWM自体(カウントを増やすことでカウンターの速度を変更することで)と、LEDマトリックスへのデータ出力の速度を変更すること、列ベクトルLEDYのカウンターのビット容量を変更すること(必要なビットフィールドを選択すること)の両方を制御できます。 これにより、フリッカー、減衰、ランニングライトのさまざまな効果を得ることができます。これは、最終ビデオで見ることができます。



FPGAプロジェクト



FPGAプロジェクトはいくつかの部分で構成されています:これらは、マイクロサーキットの動作を記述するVHDLソースコードファイル、およびFPGAコンタクトの接続、それらの標準、出力電流、速度、プロジェクトのクロック周波数制限などを定義するUCF制限ファイルです。



UCFのピン配置



 ## BUTTONS = ## K1-K5 NET "KB[5]" LOC = P54; NET "KB[4]" LOC = P58; NET "KB[3]" LOC = P57; NET "KB[2]" LOC = P159; NET "KB[1]" LOC = P154; ## LEDS = ## LED_MATRIX NET "LED_X<7>" LOC = "P49" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<6>" LOC = "P48" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<5>" LOC = "P40" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<4>" LOC = "P50" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<3>" LOC = "P62" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<2>" LOC = "P98" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<1>" LOC = "P64" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_X<0>" LOC = "P63" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<7>" LOC = "P75" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<6>" LOC = "P78" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<5>" LOC = "P76" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<4>" LOC = "P69" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<3>" LOC = "P74" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<2>" LOC = "P65" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<1>" LOC = "P68" | IOSTANDARD = LVTTL | DRIVE = 8; NET "LED_Y<0>" LOC = "P77" | IOSTANDARD = LVTTL | DRIVE = 8; NET "RESET" LOC = P148 | IOSTANDARD = LVTTL; NET "CLK" LOC = P183 | IOSTANDARD = LVCMOS33; NET "CLK_IN" TNM_NET = "CLK_TN"; TIMESPEC TS_CLK = PERIOD "CLK_TN" 20 ns HIGH 50 %;
      
      





VHDLトップレベルファイル



 entity top_xc3s500e_heart is port( ---- SWITCHES ---- RESET : in std_logic; --! asycnchronous reset: SW(0) SW : in std_logic_vector(7 downto 1); --! other switches ---- CLOCK 50 MHz ---- CLK : in std_logic; --! main clock 50 MHz ---- LED DISPLAY ---- LED_X : out std_logic_vector(7 downto 0); --! LEDs Y LED_Y : out std_logic_vector(7 downto 0); --! LEDs X ---- BUTTONS ---- KB : in std_logic_vector(5 downto 1); --! Five Buttons ); end top_xc3s500e_heart;
      
      





ポートの説明:





合成プロセス後のプロジェクトの概略図を次の図に示します。 入力および出力バッファー、DCMノード、ボタンの接点バウンスを除去するための3つのノードと3つの機能ノード:PWM制御、LED8x8 LEDマトリックス上のシンボルジェネレーター、およびマトリックスへのハート出力が含まれます。







合成、配置、トレースの後、FPGAのプロジェクトは次のようになります。







ご覧のとおり、FPGAは通常空です。 使用されたリソースの結果は、上の図にも示されています。



結果



そのため、正しいファームウェアがFPGAにロードされ、必要なボタンが押され、スイッチが正しい位置に配置されると、LEDマトリックスが有効になり、次の機能が表示されます。



写真:心







ビデオ:ちらつきと走る心





ビデオ:テキスト「MARCH 8!」:





このプロジェクトは、CAD Xilinx ISEのVHDLで作成されました。 人件費:1夕方(プロジェクト作成)+午後2時(記事執筆)。 誰かがこのようなことをすることに興味があるなら、ソースコードはgithub投稿されます。



もう一度、私はすべての女性をこれからの休日にお祝いしたいです。 みなさんの幸せ、暖かさ、愛を祈ります! 特に、私は愛する妻に挨拶します。



ご清聴ありがとうございました!



All Articles