Verilog DSDによるH-Fi Audioへの挑戦
いままでのAudio関係のVerilogコードを使って、Hi-Fi Audioに挑戦します。
内容は、DE1-SOCのADCから入力したものをシリアルパラレル変換し、それをDSD出力するまでをまとめます。
DE1-SOCにはWolfsonの24bit Audio Codec WM8731があります。このADCを使用して、アナログからデジタルへ変換します。
WM8731のデータシートはこちら。
WM8731にはクロックを与える必要があります。これはDE1-SOCで生成してMCLK,BCLK,LRCKを与えます。
WM8731は96kHZのレートまで入れることが可能ですが、今回は44.1kHzの倍の88.1kHzでサンプリングしてみます。
MCLKを88.1kHzの256倍である、22.5792MHzを生成する必要がありますが、Megawizardで生成することができる周波数は
22.573527MHzですが、これで良しとします。これでも充分にHiFiです。というのも今回は、ADC -> DSDなので、問題になりません。
Audio Clock Block
Generate MCLK
Quartus-IIのメニューから、Tools->IP Catalog->Installed IP->Library->Basic Funcitons->PLL->Altera PLLを選んで、Megawizardを起動します。
Device Speed Grade:6
PLL Mode: Fractional-N PLL
Reference Clock Frequency: 50.0MHz
Channel Spacing: 0.0 kHz
Operation Mode: direct
Enable locked output port : off
Enable physcial output clock parameters : off
Output Clocks-
Number Of Clocks : 1
outclk0 -
Desired Frequency : 22.5792 MHz
Actual Frequency : 22.573527MHz
Phase Shift units: ps
Phase Shift : 0 ps
Actual Phase Shift : 0 ps
Duty Cycle: 50 %
これで、22.57352MHzのクロックが生成されました。
Generate BCLK, LRCK
つぎにここから、BCLK, LRCKを生成します。これはVerilogで分周器を作成します。
audio_clockモジュール
module audio_clock (
input AUD_MCLK,
input rstn,
output AUD_LRCK,
output AUD_BCLK
);
reg [7:0] lrck_divider;
reg [1:0] bclk_divider;
reg [15:0] shift_out;
wire lrck = !lrck_divider[7];
assign AUD_LRCK = lrck;
assign AUD_BCLK = bclk_divider[1];
always @(posedge AUD_MCLK) begin
if (!rstn) begin
lrck_divider <= 8'hff;
bclk_divider <= 2'b11;
end else begin
lrck_divider <= lrck_divider + 1'b1;
bclk_divider <= bclk_divider + 1'b1;
end
end
endmodule
これで、ADCを動作させるのに必要なクロック、MCLK,BCLK,LRCKができました。
ピンにアサインします。
MCLK : G7
BCLK : H7
LRCK : K8
I2S to 24bit x 2 PCM
次に、ADCから入ってきたI2Sを48bitのL/R PCMにして、それをL 24bit, R 24bitに分けます。
i2s_to_lr48 モジュール
module i2s_to_lr48(bclk,lrck,din,latch, lr48);
input bclk;
input lrck;
input din;
output [47:0]lr48;
reg [47:0]lr48;
reg [64:0]lr64_tmp;
output latch;
reg latch;
reg [8:0]counter;
reg prv_lrck;
always @ (posedge bclk)
begin
lr64_tmp = lr64_tmp << 1;
lr64_tmp[0] = din;
if (prv_lrck == 1 && lrck == 0)
begin
lr48[47:24] <= lr64_tmp[63:40];
lr48[23:0] <= lr64_tmp[31:8];
latch <= 1;
counter = 0;
end
if (counter == 1)
begin
latch <= 0;
end
counter = counter + 1;
prv_lrck = lrck;
end
endmodule
lr48_to_dac24lrモジュール
module lr48_to_dac24lr(latch, lr48,l24,r24);
input latch;
input [47:0]lr48;
output reg [23:0]l24;
output reg [23:0]r24;
always@(negedge latch)
begin
l24 <= lr48[47:24];
r24 <= lr48[23:0];
end
endmodule
PCM to DSD
最後にDSD出力を行います。
出力先は、PIN/AD21, PIN/AC22, PIN/AF23で、GPIO_1[31],GPIO_1[33],GPIO_1[35]となります。
DSD_Modモジュール
module DSD_Mod(Clkin, DAin, DSDout);
input Clkin;
input [23:0] DAin;
output DSDout;
reg [25:0] DSD_accumulator;
always @(posedge Clkin)
begin
DSD_accumulator <= DSD_accumulator[24:0] + (DAin ^ 24'b1000_0000_0000_0000_0000_0000);
end
assign DSDout = DSD_accumulator[25];
endmodule