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