- ZYBOでシンセサイザー作成(1)LチカとHelloWorld
- ZYBOでシンセサイザー作成(2)オーディオコーデックの使用
- ZYBOでシンセサイザー作成(3)波形テーブル(BRAM)による正弦波の合成
- ZYBOでシンセサイザー作成(4)パラシリ変換 IP の作成
- ZYBOでシンセサイザー作成(5)音を出力する
今回は、前回の記事で作成した正弦波生成 IP(sin_gen)の出力をパラシリ変換して、オーディオコーデック(SSM2603)で受け取れるデータ形式にします。
環境
- パソコン:Windows10 64 bit
- Vivado 2020.2 をインストール
- Xilinx Vitis 2020.2 をインストール
- ボード:Zybo Z7-20
パラシリ変換 IP の作成
Vivadoでパラシリ変換 IP のpara2serialを製作していきます。作成の仕方は前回のIPの作成とほとんど同じです。
パラシリ変換 IP について
コーデックへのデータの与え方はいくつかありますが、今回は図1の方法でシリアル変換します。コーデックから図1のBCLKとPBLRCの波形がくるので、これらに同期させて、PBDATに波形を送ります。
パラシリ変換 IPのフォルダの用意
前回と同じように以下のようにフォルダとファイルを配置していきます。para2serial.svはGitHubの「4th」フォルダにあります。
ip_repo_synth └── para2serial └── HDL └── para2serial.sv
para2serial.svの内容を以下に示します。para2serial.svの内容については別の記事でしたいと思います。
para2serial.sv
module para2serial( input logic clk96M, input logic reset, input logic bclk, input logic pblrc, input logic [15:0] din_L, input logic [15:0] din_R, output logic pbdat ); logic [1:0] cnt4; logic load; logic shift; logic [31:0] sreg_ff; // cnt4 always_ff @(posedge clk96M) begin if(reset) cnt4 <= 2'd0; else if(bclk) cnt4 <= cnt4 + 2'd1; else cnt4 <= 2'd0; end // shift register assign shift = (cnt4==2'd3); assign load = shift & pblrc; always_ff @ (posedge clk96M) begin if(reset) sreg_ff <= 32'd0; else if(load) sreg_ff <= {din_L, din_R}; else if(shift) sreg_ff <= {sreg_ff[31:0], 1'b0}; end assign pbdat = sreg_ff[31]; endmodule
VivadoでIPの製作
プロジェクトを以下のようにして作成します。
- 作業フォルダ:para2serial
- プロジェクト名:para2serial
このプロジェクトでIPの製作を行い、IPのシミュレーションも行います。
プロジェクトができたら、前回のVivadoでIPの製作の手順通りに途中まで進めて、IP編集用のVivado画面を起動します。
前回は編集用のVivado画面でいろいろとやりましたが、今回は「Package IP」タブ →「Review and Package」の「Package IP」を押すだけでいいです(図3)。
以上でIPが作成され、元のVivadoプロジェクト画面に戻ります。
パラシリ変換 IP のシミュレーション
パラシリ変換 IPであるpara2serialのシミュレーションをしていきます。
IP インテグレータで回路作成
IPインテグレータで回路を作っていきます。
- 「IP INTEGRATOR」→「Create Block Design」で「Diagram」を作成する。
「PROJECT MANAGER」→「Settings」で「Settings」画面を開き、「Project Settings」→「IP」→「Repository」の「+」で「sin_gen」IPを追加して、「OK」を押す(図3)。
「Add IP」で「sin_gen_v1_0」と「para2serial_v1_0」を追加する。
- 図4のようにして、回路を作成する。
回路ができたら、「Validate Design」をして、回路のチェックを行います。また、「Create HDL Wrapper」でラッパーを作成します。ラッパーの作成では「Copy generated wrapper to allow user edits」を選択します。
テストベンチの追加
テストベンチsim_para2serial.svを前回の記事のテストベンチの追加と同じように追加します。sim_para2serial.svはGitHubにあり、内容は以下です。(2021/5/29 追記:PBLRCの周期が96kHzだったため、48kHzになるようにテストベンチを修正しました)。sim_para2serial.svの説明についても別の記事で書こうと思います。
sim_para2serial.sv
`timescale 1ps / 1ps module sim_para2serial; localparam [63:0] STEP = 10416; localparam [63:0] CLKNUM = 960000*4; logic clk96M; logic [14:0] freq; logic reset; logic bclk; logic pbdat; logic pblrc; logic [1:0] cnt4; logic [8:0] cnt500; design_1_wrapper design_1_wrapper( .bclk(bclk), .clk96M (clk96M), .freq (freq), .pbdat (pbdat), .pblrc (pblrc), .reset (reset) ); // clk96M always begin clk96M = 0; #(STEP/2); clk96M = 1; #(STEP/2); end // cnt4 always_ff @(posedge clk96M) begin if(reset) cnt4 <= 2'd0; else cnt4 <= cnt4 + 2'd1; end // cnt500 always_ff @(posedge clk96M) begin if(reset) cnt500 <= 9'd0; else if(cnt4==2'd2) if(cnt500==9'd499) cnt500 <= 9'd0; else cnt500 <= cnt500 + 9'd1; end // pblrc always_ff @(posedge clk96M) begin if(reset) pblrc <= 1'b0; else if(cnt500==9'd499 | cnt500==9'd498) pblrc <= 1'b1; else pblrc <= 1'b0; end // bclk always_ff @(posedge clk96M) begin if(reset) bclk <= 1'b0; else if(cnt4==2'd3) bclk <= ~bclk; end initial begin reset = 0; freq = 15'd440; #(STEP*600); reset = 1; #(STEP*20); reset = 0; #(STEP*CLKNUM); freq = 15'd600; #(STEP*CLKNUM); $stop; end endmodule
シミュレーションの実行
シミュレーションを実行すると、図6のようになっています。
PBDATが図1のデータ形式通りになっていることが確認できると思います。
おわりに
今回でパラシリ変換 IP を作成して、シミュレーションができました。次回はいよいよ音を出力したいと思います。
参考文献
[1] SSM2603のデータシート
[2] 小林 優、「FPGAプログラミング大全 Xilinx編 第2版」、秀和システム、2021.