2020/05/19 追記:q <= adc * -sin に修正しました。
2018/07/21 追記:PM-FM変換を修正しました。
2018/07/14 追記:音量調節機能を追加しました。
I2S DACモジュールが手に入ったので、ADCのサンプリング周波数を70MHzから73.75MHzに変更しました。本当は73.728MHzにしてI2S DACのサンプリング周波数をその1/1536の48kHzにしたかったのですが、ALTPLLで73.728MHzを出力できませんでした。なのでI2S DACのサンプリング周波数は48.015kHzになっています。
FMは、CICフィルタ+FIRフィルタで384kHzに間引いて、FM復調して、FIRフィルタで48kHzに間引いてI2S DACへ。
AMは、CICフィルタ+FIRフィルタで48kHzに間引いて、AM復調してI2S DACへ。
FIRフィルタの係数も変更しました。
`define CYCLE_1SEC 50000000
module SPIbridge
(
input wire RST_N,
input wire CLK,
input wire SPI_NSS,
input wire SPI_SCLK,
output wire SPI_MISO,
input wire SPI_MOSI,
output wire [3:0] LED,
input wire [7:0] ADC,
output wire ENCODE,
output wire I2S_SCK,
output wire I2S_BCK,
output wire I2S_LRCK,
output wire I2S_DATA,
output reg [7:0] DACA,
output reg [7:0] DACB
);
localparam CIC_WIDTH = 19;
localparam FIR_WIDTH = 10;
localparam PI = 11'sb0011_0010_010; // pi = 0011 . 0010 0100 0011 1111 0110 1010
wire clk; // 73.75M
wire [31:0] pio0;
wire [31:0] pio1;
wire fm;
wire [11:0] rate;
wire [3:0] gain;
reg [9:0] uadc_r;
wire signed [9:0] adc;
wire signed [9:0] sin;
wire signed [9:0] cos;
reg signed [18:0] i;
reg signed [18:0] q;
wire signed [CIC_WIDTH-1:0] icic;
wire icic_valid;
wire signed [CIC_WIDTH-1:0] qcic;
wire qcic_valid;
wire signed [FIR_WIDTH-1:0] ifir;
wire ifir_valid;
wire signed [FIR_WIDTH-1:0] qfir;
wire qfir_valid;
wire [FIR_WIDTH-1:0] mag;
wire signed [FIR_WIDTH-1:0] phase;
reg signed [FIR_WIDTH-1:0] phase_r;
wire signed [FIR_WIDTH:0] phase_diff;
reg signed [FIR_WIDTH:0] freq;
wire signed [FIR_WIDTH-1:0] freq_mono;
wire freq_mono_valid;
wire [7:0] daca;
wire [7:0] dacb;
pll pll_inst (
.inclk0 (CLK),
.c0 (clk)
);
QsysCore QsysCore_inst (
.clk_clk (clk),
.reset_reset_n (RST_N),
.spi_slave_to_avalon_mm_master_bridge_0_export_0_mosi_to_the_spislave_inst_for_spichain (SPI_MOSI),
.spi_slave_to_avalon_mm_master_bridge_0_export_0_nss_to_the_spislave_inst_for_spichain (SPI_NSS),
.spi_slave_to_avalon_mm_master_bridge_0_export_0_miso_to_and_from_the_spislave_inst_for_spichain (SPI_MISO),
.spi_slave_to_avalon_mm_master_bridge_0_export_0_sclk_to_the_spislave_inst_for_spichain (SPI_SCLK),
.pio_0_external_connection_export (pio0),
.pio_1_external_connection_export (pio1)
);
assign LED = ~pio0[3:0];
assign fm = (pio1 == 0 || pio1 >= 32'd131032901) ? 1 : 0; // (pio1 >= 2.25MHz) ? FM : AM
assign rate = fm ? 192 : 1536; // fm ? 384kSPS : 48kSPS
assign gain = fm ? 0 : 7; // pio0[3:0];
always @(posedge clk) begin
uadc_r <= { ADC, 2'b00 };
end
assign ENCODE = clk;
assign adc = (uadc_r[9] == 0) ? uadc_r + 10'h200 : uadc_r - 10'h200;
MyNCO nco_inst (
.clk (clk),
.reset_n (RST_N),
.clken (1'b1),
.phi_inc_i (pio1),
.fsin_o (sin),
.fcos_o (cos),
.out_valid ()
);
always @(posedge clk) begin
i <= adc * cos;
q <= adc * -sin;
end
MyCIC cic_inst_i (
.clk (clk),
.reset_n (RST_N),
.rate (rate),
.in_error (2'b00),
.in_valid (1'b1),
.in_ready (),
.in_data (i),
.out_data (icic),
.out_error (),
.out_valid (icic_valid),
.out_ready (1'b1)
);
MyCIC cic_inst_q (
.clk (clk),
.reset_n (RST_N),
.rate (rate),
.in_error (2'b00),
.in_valid (1'b1),
.in_ready (),
.in_data (q),
.out_data (qcic),
.out_error (),
.out_valid (qcic_valid),
.out_ready (1'b1)
);
MyFIR #(.DATA_WIDTH(FIR_WIDTH)) fir_inst_i (
.clk (clk),
.reset_n (RST_N),
.ast_sink_data (icic[CIC_WIDTH-1 -gain -: FIR_WIDTH]),
.ast_sink_valid (icic_valid),
.ast_sink_error (2'b00),
.ast_source_data (ifir),
.ast_source_valid (ifir_valid),
.ast_source_error ()
);
MyFIR #(.DATA_WIDTH(FIR_WIDTH)) fir_inst_q (
.clk (clk),
.reset_n (RST_N),
.ast_sink_data (qcic[CIC_WIDTH-1 -gain -: FIR_WIDTH]),
.ast_sink_valid (qcic_valid),
.ast_sink_error (2'b00),
.ast_source_data (qfir),
.ast_source_valid (qfir_valid),
.ast_source_error ()
);
vectran vectran_inst (
.clk (clk),
.areset (~RST_N),
.x (ifir),
.y (qfir),
.q (phase),
.r (mag),
.en (ifir_valid)
);
always @(posedge clk) begin
if (ifir_valid) begin
phase_r <= phase; if (phase_diff > PI) begin
freq <= phase_diff - (PI <<< 1);
end
else if (phase_diff < -PI) begin
freq <= phase_diff + (PI <<< 1);
end
else begin
freq <= phase_diff;
end
end
end
assign phase_diff = phase - phase_r;
MyLPF8 #(.DATA_WIDTH(FIR_WIDTH)) MyLPF8_inst (
.clk (clk),
.reset_n (RST_N),
.ast_sink_data (freq[FIR_WIDTH-1:0]),
.ast_sink_valid (ifir_valid),
.ast_sink_error (2'b00),
.ast_source_data (freq_mono),
.ast_source_valid (freq_mono_valid),
.ast_source_error ()
);
MyI2S #(.IN_WIDTH(FIR_WIDTH)) MyI2S_inst (
.clk (clk),
.reset_n (RST_N),
.volume (4'b1111 - pio0[3:0]),
.in_left (fm ? freq_mono : mag),
.in_right (fm ? freq_mono : mag),
.in_valid (fm ? freq_mono_valid : ifir_valid),
.SCK (I2S_SCK),
.BCK (I2S_BCK),
.LRCK (I2S_LRCK),
.DATA (I2S_DATA)
);
assign daca = cos[9 -: 8];
assign dacb = sin[9 -: 8];
always @(posedge clk) begin
DACA <= (daca[7] == 0) ? daca + 8'h80 : daca - 8'h80;
DACB <= (dacb[7] == 0) ? dacb + 8'h80 : dacb - 8'h80;
end
endmodule