Custom Meta Tags

2503 Hero Banner

AMD製品に関連する技術ブログ

Long Copy

KR260でデジタル信号処理してみた! (1)

皆さん、こんにちは。新人エンジニアのノリさんです!今回はKR260を用いたデジタル信号処理のハードウェアデザインの一部を作成していきます。

https://www.hackster.io/whitney-knitter/dsp-for-soms-getting-started-with-dds-fir-compiler-ips-947cb4を参考に、デジタルフィルタの動作を確認するまでの作業を行います。

最終的な目標である、デジタルフィルタをKR260で動かすことは、次回行う予定です。

2024-1-4

Long Copy_body

デジタルフィルタについて補足

デジタルフィルタは離散化された音声、画像、電気パルスなどのデジタル信号から雑音を除去し、所望の信号のみを得るためのシステムです。

雑音が高周波である場合、ローパスフィルタを用いて信号の高周波成分を除去することで、雑音の除去を実現できます。

バンドパスフィルタであれば特定の帯域以外の周波数成分を除去し、ハイパスフィルタであれば低周波成分を除去することができます。

Step0:ハードウェア要件

  • KR260 Robotics Starter Kit (/japan/products/product-highlights/xilinx-kr260)
  • KR260用電源(KR260 Robotics Starter Kit に付属)
  • USB-A to micro-B ケーブル(KR260 Robotics Starter Kit に付属)
  • マイクロSDカード(最低16GB、KR260 Robotics Starter Kit に付属しているものでOK)

Step1: ハードウェアデザインの作成

ここでは、信号処理をするためのハードウェアデザインを作っていきます

Vivadoを開きます、今回はVer. 2022.1を用います

  • $ source /tools/Xilinx/Vivado/2022.1/settings64.sh
  • $ vivado

Create Project → Next → プロジェクト名をKR260DSPにしてNext → Next→ BourdタブからKR260を選択して、Connectionsを開いて次のように設定します

Nextを押して下の図と同じ設定になっていることを確認し、Finishをクリックします

画面左にあるFlow NavigatorからCreate Block Designを開いてOKをクリックし、ブロックデザインを作成します

Diagramウィンドウの上部にある+ボタンをクリックし、表示されたウィンドウで「zynq」と検索して、リスト内のZynq UltraScale+ MPSoCをダブルクリックして、IPブロックをデザインに追加します

Run Block Automationをクリックし、表示されたウィンドウの「Apply Board Preset」にチェックが入っていることを確認し、OKをクリックします

Block Automationが完了したら、+ボタンからProcessor System Resetを追加して、K26 のプログラマブル ロジック (PL) を実行するロジックへのリセット信号のタイミングを制御します

Run Connection Automationをクリックし、表示されたウィンドウの「All Automaton」にチェックを入れて、OKをクリックします

Zynq UltraScale+ MPSoC 上のpl_clk0とmaxihpm0_fpd_aclk、pl_clk1とmaxihpm1_fpd_aclkを接続します

下の図のようになっていることを確認します

Sourceウィンドウからブロックデザインファイルを右クリックし、 Create HDL Wrapperを選択して、表示されたウィンドウでOKをクリックします

次に、信号を生成するためのDDS Compilerをデザインに追加します

今回は1MHzから10MHzまで1MHz間隔で変化するチャープ信号を生成します

(何故そのようにするかはhttps://www.hackster.io/whitney-knitter/dsp-for-soms-getting-started-with-dds-fir-compiler-ips-947cb4#toc-chirp-signal-with-dds-compiler-3を参照)

Diagramウィンドウの上部にある+ボタンをクリックし、表示されたウィンドウから「dds」と検索し、リスト内の DDS Compilerをダブルクリックしてブロック デザインに追加します

DDS Compiler IPをダブルクリックしてその構成ウィンドウを開きます

Configurationタブから、Parameter Selectionを「Hardware Parameters」に設定し、「Phase width」を32、「Output Width」を16に設定します

Implementationタブから、Phase Increment Programmabilityを「Streaming」に設定し、Phase Offset ProgrammabilityをNoneのままにします

OutputSelection を「Sine and Cosine」ではなく、「Sine」または「Cosine」に設定します

Detailed Implementationタブから、DATA Has TLASTを「Packet Framing」に設定し、「Output TREADY」チェックボックスをオンにします

「ARESETn」のオプションをチェックして、DDS Compilerにリセットポートを作成します

Summaryタブから反映した設定を確認します

作成したDDS Compilerをクリックしてctrl+cでコピーし、Diagramウィンドウの空白部分をクリックしてctrl+pでペーストします

DDS Compilerを再度コピー&ペーストし、下の図と同じ状態にします

位相増分用のモジュールを追加するためのVerilogコードを作成します

(位相増分については https://www.hackster.io/whitney-knitter/dsp-for-soms-getting-started-with-dds-fir-compiler-ips-947cb4#toc-digital-signal-processing-ips-0を参照)

次のVerilogコードをphase_inc_sm.vとして任意の場所に保存します

`timescale 1ns / 1ps

module phase_inc_sm(
    input clk,
    input reset,
    output reg m_axis_phase_tvalid,
    output reg m_axis_phase_tlast,
    input m_axis_phase_tready,
    output reg [31:0] m_axis_phase_tdata
    );

    reg [31:0] carrier_freq;
    reg [31:0] carrier_period;           
    
    // 100 kHz
    parameter carrier_freq_100k = 32'h418938;
    parameter carrier_period_100k = 32'd1000;
    parameter carrier_freq_incr_100k = 32'h418937;
    
    // 1 MHz
    parameter carrier_freq_1m = 32'h28F5C29; 
    parameter carrier_period_1m = 32'd100; 
    
    // 10 MHz 
    parameter carrier_freq_10m = 32'h19999990;
    
    // 50 MHz - DO NOT USE
    parameter carrier_freq_50m = 32'h80000000;
    
    parameter carrier_period_100ms = 32'd10000000;
    
    reg [2:0] state_reg;
    reg [31:0] period_wait_cnt;
    reg [3:0] cycle_cnt;
    
    parameter init               = 3'd0;
    parameter SetCarrierFreq     = 3'd1;
    parameter SetTvalidHigh      = 3'd2;
    parameter SetSlavePhaseValue = 3'd3;
    parameter CheckTready        = 3'd4;
    parameter WaitState          = 3'd5;   
    parameter SetTlastHigh       = 3'd6;
    parameter SetTlastLow        = 3'd7;
    
    parameter default_tdata      = 32'h0;
    
    always @ (posedge clk)// or posedge reset)
        begin                    
            // Default Outputs   
            
            if (reset == 1'b0)
                begin
                    m_axis_phase_tdata[31:0] <= default_tdata;
                    cycle_cnt <= 4'd0;
                    state_reg <= init;
                end
            else
                begin
                    case(state_reg)
                        init : //0
                            begin
                                cycle_cnt <= 4'd0;
                                period_wait_cnt <= 32'd0;
                                m_axis_phase_tlast <= 1'b0;
                                m_axis_phase_tvalid <= 1'b0;
                                carrier_freq <= 32'h0;
                                state_reg <= SetCarrierFreq;// WaitForStart;
                            end
                            
                        SetCarrierFreq : //1
                            begin         
                                if (carrier_freq > carrier_freq_10m) 
                                    begin
                                        carrier_freq <= carrier_freq_1m;
                                    end
                                else
                                    begin
                                        carrier_freq <= carrier_freq + carrier_freq_1m;
                                    end
                                
                                carrier_period <= carrier_period_1m;
                                state_reg <= SetTvalidHigh;
                            end
                            
                        SetTvalidHigh : //2
                            begin
                                m_axis_phase_tvalid <= 1'b1; //per PG141 - tvalid is set before tready goes high
                                state_reg <= SetSlavePhaseValue;
                            end
                            
                        SetSlavePhaseValue : //3
                            begin
                                m_axis_phase_tdata[31:0] <= carrier_freq;
                                state_reg <= CheckTready;
                            end
                            
                        CheckTready : //4
                            begin
                                if (m_axis_phase_tready == 1'b1)
                                    begin
                                        state_reg <= WaitState;
                                    end
                                else    
                                    begin
                                        state_reg <= CheckTready;
                                    end
                            end
                            
                        WaitState : //5
                            begin
                                if (period_wait_cnt >= carrier_period)
                                    begin
                                        period_wait_cnt <= 32'd0; 
                                        state_reg <= SetTlastHigh;
                                    end
                                else
                                    begin
                                        period_wait_cnt <= period_wait_cnt + 1;
                                        state_reg <= WaitState;
                                    end
                            end
                            
                        SetTlastHigh : //6
                            begin
                                m_axis_phase_tlast <= 1'b1;
                                state_reg <= SetTlastLow;
                            end
                            
                        SetTlastLow : //7
                            begin
                                m_axis_phase_tlast <= 1'b0;
                                state_reg <= SetCarrierFreq;
                            end
                            
                    endcase 
                end
        end
endmodule

Flow NavigatorからAdd Sourcesを開き、Add or create design sourcesが選択されていることを確認してNextをクリックします

Add Filesから先程作成したphase_inc_sm.vを選択し、Finishをクリックします

Diagramウィンドウの空白スペースの任意の場所を右クリックし、メニューAdd ModulesからAdd Modulesを選択します

phase increment smを選択し、OKをクリックします

phase increment smを2回コピー&ペーストして、他の DDS Compilerごとに1つずつ追加します

dds_compiler_0~2のSM AXIS_PHASE0とphase_inc_sm_0~2のm_axis_phaseをそれぞれ接続します

Run Connection Automationをクリックし、表示されたウィンドウの「All Automaton」にチェックを入れて、OKをクリックします

Diagramウィンドウの上部にあるRegenerate Layoutボタンをクリックして、下の図のようになっていることを確認してください

次に、FIRフィルタのためのIPをデザインに追加します

FIRフィルタの出力は、フィルタ係数との重み付き移動平均、即ち積と和の形で表現されます

Diagramウィンドウの上部にある+ボタンをクリックし、表示されるウィンドウで「fir」を検索し、リスト内のFIR Compilerをダブルクリックしてブロック デザインに追加します

FIR Compiler IP ブロックをダブルクリックして、構成ウィンドウを開きます

Channel Specificationタブの「Input Sampling Freqency」と「Clock Freqency」をそれぞれ100MHzに設定します

ImplementationタブのQuantizationを「Quantize Only」に、「Coefficient Fractional Bits」を2に変更します

OKをクリックしてFIRの構成ウィンドウを閉じ、FIR Compiler IPを2回コピー&ペーストします

dds_compiler_0~2のM_AXIS_DATAとfir_compiler_0~2のS_AXIS_DATAを接続し、fir_compiler_0~2のaclkをpl_clk0に接続します

Diagramウィンドウの上部にあるRegenerate Layoutボタンをクリックして、下の図のようになっていることを確認してください

次の3つの係数ファイルを任意の場所に保存します(lpf.coe, bpf.coe, hpf.coeはそれぞれ、ローパスフィルタ、バンドパスフィルタ、ハイパスフィルタのフィルタ係数です)

lpf.coe

Radix=10;
CoefData=
-255,
-260,
-312,
-288,
-144,
153,
616,
1233,
1963,
2739,
3474,
4081,
4481,
4620,
4481,
4081,
3474,
2739,
1963,
1233,
616,
153,
-144,
-288,
-312,
-260,
-255

bpf.coe

Radix=10;
CoefData=
132,
-57,
-61,
-65,
-60,
-45,
-24,
-6,
-8,
-40,
-106,
-196,
-285,
-336,
-310,
-178,
68,
401,
766,
1080,
1251,
1202,
890,
328,
-410,
-1199,
-1884,
-2309,
-2358,
-1981,
-1214,
-175,
953,
1962,
2659,
2907,
2659,
1962,
953,
-175,
-1214,
-1981,
-2358,
-2309,
-1884,
-1199,
-410,
328,
890,
1202,
1251,
1080,
766,
401,
68,
-178,
-310,
-336,
-285,
-196,
-106,
-40,
-8,
-6,
-24,
-45,
-60,
-65,
-61,
-57,
132
hpf.coe
Radix=10;
CoefData=
109,
1,
12,
-33,
-140,
-256,
-298,
-209,
2,
275,
517,
632,
550,
247,
-222,
-722,
-1073,
-1111,
-761,
-88,
716,
1382,
1662,
1415,
673,
-358,
-1351,
-1972,
-1987,
-1360,
-272,
934,
1865,
2214,
1865,
934,
-272,
-1360,
-1987,
-1972,
-1351,
-358,
673,
1415,
1662,
1382,
716,
-88,
-761,
-1111,
-1073,
-722,
-222,
247,
550,
632,
517,
275,
2,
-209,
-298,
-256,
-140,
-33,
12,
1,
109

任意のFIR Compilerをダブルクリックして構成ウィンドウを開き、Filter OptionタブでCOEファイルを指定します

「Select Source」をCOE Fileに設定し、Coefficient Fileに保存したCOEファイルのいずれかを選択します

Freq. Response tabから結果を観察することができます

lpf.coeでの結果

bpf.coeでの結果

hpf.coeでの結果

 

感想

今回はKR260で信号処理を行うためのハードウェアデザインの一部の設計を行い、それを利用してフィルタの動作確認を行いました。

フィルタが理論通りの働きをしたことは大変うれしく感じました。

次回はハードウェアデザインの実装を進めてKR260上で動かしていく予定です(予定は変更されることもあります)。

それでは、また次回お会いしましょう!See you next time!

 

 

2503 Grid Box Light - Blog

ブログ

AMDによる設計およびデバッグ手法のブログ、およびアヴネット社員によるAMD製品を用いた開発チャレンジのブログです。

2503 Grid Box Light - Kria

Kria

Kria SOMはアダプティブSoCデバイスを搭載しており、スマートカメラやエンベデッドビジョンなどに最適です。