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