// // File: fft_sample.v // Date: 10-Nov-05 // Author: I. Chuang // // Demonstration of the Xilinx FFT module on data from an ADC. // // A 256-point, 8-bit discrete fourier transform is performed continuously // on an incoming buffer of data, and the results are processed and // graphically displayed in a 256x256 window in a VGA display. // // This specific demo uses the Digilent ADC peripheral module, // which has two ADCS7476 chips. See http://www.digilentinc.com // // Connect the board as follows: // // CS = User 3 D3 (user3[3]) // D0 = User 3 D2 (user3[2]) // D1 = User 3 D1 (user3[1]) // CLK = User 3 D0 (user3[0]) // VCC = 3.3V // // The FFT transform is done on the data in channel D0. // // The eight switches are used to set the FFT scaling factors, which are // used to ensure the FFT does not overflow at any stage internal to the // computation. One reasonable starting point is 8'b0110_0110, if the // ADC input is driven full range (0 to 3.3V swing sinusoid input). // // Note that the FFT produces two's complement output, and that the outputs // give the real and imaginary part of the FFT. A more useful output // is the magnitude, which gives the power spectrum. Here, we simply // compute the sum of squares of the real and imaginary output values // (and skip the square root). // // Also note that no input filtering is done, and thus there are // significant aliasing problems. The input data should be filtered to // cut off frequencies higher than the inverse of the sampling window // size (here, 256 points). // // This example uses vga_graph2_buf, which produces a 256 x 256 window // graph of two channels. // // Button 0 selects between FFT display and ADC value display // Button 3 selects the test color bar display // The enter button is reset. `include "vga_sync.v" `include "debounce.v" `include "display_16hex.v" `include "adc_driver.v" `include "vga_graph2_buf.v" `include "fft_256pt_8bit.v" `include "math_8bit_mult.v" `include "twos2off.v" module fft_sample( beep, audio_reset_b, ac97_sdata_out, ac97_sdata_in, ac97_synch, ac97_bit_clock, vga_out_red, vga_out_green, vga_out_blue, vga_out_sync_b, vga_out_blank_b, vga_out_pixel_clock, vga_out_hsync, vga_out_vsync, tv_out_ycrcb, tv_out_reset_b, tv_out_clock, tv_out_i2c_clock, tv_out_i2c_data, tv_out_pal_ntsc, tv_out_hsync_b, tv_out_vsync_b, tv_out_blank_b, tv_out_subcar_reset, tv_in_ycrcb, tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2, tv_in_aef, tv_in_hff, tv_in_aff, tv_in_i2c_clock, tv_in_i2c_data, tv_in_fifo_read, tv_in_fifo_clock, tv_in_iso, tv_in_reset_b, tv_in_clock, ram0_data, ram0_address, ram0_adv_ld, ram0_clk, ram0_cen_b, ram0_ce_b, ram0_oe_b, ram0_we_b, ram0_bwe_b, ram1_data, ram1_address, ram1_adv_ld, ram1_clk, ram1_cen_b, ram1_ce_b, ram1_oe_b, ram1_we_b, ram1_bwe_b, clock_feedback_out, clock_feedback_in, flash_data, flash_address, flash_ce_b, flash_oe_b, flash_we_b, flash_reset_b, flash_sts, flash_byte_b, rs232_txd, rs232_rxd, rs232_rts, rs232_cts, mouse_clock, mouse_data, keyboard_clock, keyboard_data, clock_27mhz, clock1, clock2, disp_blank, disp_data_out, disp_clock, disp_rs, disp_ce_b, disp_reset_b, disp_data_in, button0, button1, button2, button3, button_enter, button_right, button_left, button_down, button_up, switch, led, user1, user2, user3, user4, daughtercard, systemace_data, systemace_address, systemace_ce_b, systemace_we_b, systemace_oe_b, systemace_irq, systemace_mpbrdy, analyzer1_data, analyzer1_clock, analyzer2_data, analyzer2_clock, analyzer3_data, analyzer3_clock, analyzer4_data, analyzer4_clock ); output beep, audio_reset_b, ac97_synch, ac97_sdata_out; input ac97_bit_clock, ac97_sdata_in; output [7:0] vga_out_red, vga_out_green, vga_out_blue; output vga_out_sync_b, vga_out_blank_b, vga_out_pixel_clock, vga_out_hsync, vga_out_vsync; output [9:0] tv_out_ycrcb; output tv_out_reset_b, tv_out_clock, tv_out_i2c_clock, tv_out_i2c_data, tv_out_pal_ntsc, tv_out_hsync_b, tv_out_vsync_b, tv_out_blank_b, tv_out_subcar_reset; input [19:0] tv_in_ycrcb; input tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2, tv_in_aef, tv_in_hff, tv_in_aff; output tv_in_i2c_clock, tv_in_fifo_read, tv_in_fifo_clock, tv_in_iso, tv_in_reset_b, tv_in_clock; inout tv_in_i2c_data; inout [35:0] ram0_data; output [18:0] ram0_address; output ram0_adv_ld, ram0_clk, ram0_cen_b, ram0_ce_b, ram0_oe_b, ram0_we_b; output [3:0] ram0_bwe_b; inout [35:0] ram1_data; output [18:0] ram1_address; output ram1_adv_ld, ram1_clk, ram1_cen_b, ram1_ce_b, ram1_oe_b, ram1_we_b; output [3:0] ram1_bwe_b; input clock_feedback_in; output clock_feedback_out; inout [15:0] flash_data; output [23:0] flash_address; output flash_ce_b, flash_oe_b, flash_we_b, flash_reset_b, flash_byte_b; input flash_sts; output rs232_txd, rs232_rts; input rs232_rxd, rs232_cts; inout mouse_clock, mouse_data; //input mouse_clock, mouse_data; input keyboard_clock, keyboard_data; input clock_27mhz, clock1, clock2; output disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b; input disp_data_in; output disp_data_out; input button0, button1, button2, button3, button_enter, button_right, button_left, button_down, button_up; input [7:0] switch; output [7:0] led; inout [31:0] user1, user2, user3, user4; inout [43:0] daughtercard; inout [15:0] systemace_data; output [6:0] systemace_address; output systemace_ce_b, systemace_we_b, systemace_oe_b; input systemace_irq, systemace_mpbrdy; output [15:0] analyzer1_data, analyzer2_data, analyzer3_data, analyzer4_data; output analyzer1_clock, analyzer2_clock, analyzer3_clock, analyzer4_clock; //////////////////////////////////////////////////////////////////////////// // // I/O Assignments // //////////////////////////////////////////////////////////////////////////// // Audio Input and Output assign beep= 1'b0; assign audio_reset_b = 1'b0; assign ac97_synch = 1'b0; assign ac97_sdata_out = 1'b0; // ac97_sdata_in is an input // VGA Output // assign vga_out_red = 10'h0; // assign vga_out_green = 10'h0; // assign vga_out_blue = 10'h0; assign vga_out_sync_b = 1'b1; // assign vga_out_blank_b = 1'b1; // assign vga_out_pixel_clock = 1'b0; // assign vga_out_hsync = 1'b0; // assign vga_out_vsync = 1'b0; // Video Output assign tv_out_ycrcb = 10'h0; assign tv_out_reset_b = 1'b0; assign tv_out_clock = 1'b0; assign tv_out_i2c_clock = 1'b0; assign tv_out_i2c_data = 1'b0; assign tv_out_pal_ntsc = 1'b0; assign tv_out_hsync_b = 1'b1; assign tv_out_vsync_b = 1'b1; assign tv_out_blank_b = 1'b1; assign tv_out_subcar_reset = 1'b0; // Video Input assign tv_in_i2c_clock = 1'b0; assign tv_in_fifo_read = 1'b0; assign tv_in_fifo_clock = 1'b0; assign tv_in_iso = 1'b0; assign tv_in_reset_b = 1'b0; assign tv_in_clock = 1'b0; assign tv_in_i2c_data = 1'bZ; // tv_in_ycrcb, tv_in_data_valid, tv_in_line_clock1, tv_in_line_clock2, // tv_in_aef, tv_in_hff, and tv_in_aff are inputs // SRAMs assign ram0_data = 36'hZ; assign ram0_address = 19'h0; assign ram0_adv_ld = 1'b0; assign ram0_clk = 1'b0; assign ram0_cen_b = 1'b1; assign ram0_ce_b = 1'b1; assign ram0_oe_b = 1'b1; assign ram0_we_b = 1'b1; assign ram0_bwe_b = 4'hF; assign ram1_data = 36'hZ; assign ram1_address = 19'h0; assign ram1_adv_ld = 1'b0; assign ram1_clk = 1'b0; assign ram1_cen_b = 1'b1; assign ram1_ce_b = 1'b1; assign ram1_oe_b = 1'b1; assign ram1_we_b = 1'b1; assign ram1_bwe_b = 4'hF; assign clock_feedback_out = 1'b0; // clock_feedback_in is an input // Flash ROM assign flash_data = 16'hZ; assign flash_address = 24'h0; assign flash_ce_b = 1'b1; assign flash_oe_b = 1'b1; assign flash_we_b = 1'b1; assign flash_reset_b = 1'b0; assign flash_byte_b = 1'b1; // flash_sts is an input // RS-232 Interface assign rs232_txd = 1'b1; assign rs232_rts = 1'b1; // rs232_rxd and rs232_cts are inputs // PS/2 Ports // mouse_clock, mouse_data, keyboard_clock, and keyboard_data are inputs // LED Displays /* assign disp_blank = 1'b1; assign disp_clock = 1'b0; assign disp_rs = 1'b0; assign disp_ce_b = 1'b1; assign disp_reset_b = 1'b0; assign disp_data_out = 1'b0; */ // disp_data_in is an input // Buttons, Switches, and Individual LEDs //lab3 assign led = 8'hFF; // button0, button1, button2, button3, button_enter, button_right, // button_left, button_down, button_up, and switches are inputs // User I/Os assign user1 = 32'hZ; assign user2 = 32'hZ; assign user3 = 32'hZ; assign user4 = 32'hZ; // Daughtercard Connectors assign daughtercard = 44'hZ; // SystemACE Microprocessor Port assign systemace_data = 16'hZ; assign systemace_address = 7'h0; assign systemace_ce_b = 1'b1; assign systemace_we_b = 1'b1; assign systemace_oe_b = 1'b1; // systemace_irq and systemace_mpbrdy are inputs // Logic Analyzer assign analyzer1_data = 16'h0; assign analyzer1_clock = 1'b1; assign analyzer2_data = 16'h0; assign analyzer2_clock = 1'b1; assign analyzer3_data = 16'h0; assign analyzer3_clock = 1'b1; assign analyzer4_data = 16'h0; assign analyzer4_clock = 1'b1; // use FPGA's digital clock manager to produce a 50 Mhz clock from 27 Mhz // actual frequency: 49.85 MHz wire clock_50mhz_unbuf,clock_50MHz; DCM vclk1(.CLKIN(clock_27mhz),.CLKFX(clock_50mhz_unbuf)); // synthesis attribute CLKFX_DIVIDE of vclk1 is 13 // synthesis attribute CLKFX_MULTIPLY of vclk1 is 24 // synthesis attribute CLK_FEEDBACK of vclk1 is NONE // synthesis attribute CLKIN_PERIOD of vclk1 is 37 BUFG vclk2(.O(clock_50MHz),.I(clock_50mhz_unbuf)); //////////////////////////////////////// // The fft example wire clk = clock_50MHz; wire power_on_reset; SRL16 reset_sr (.D(1'b0), .CLK(clk), .Q(power_on_reset), .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1)); defparam reset_sr.INIT = 16'hFFFF; wire user_reset; debounce dbreset(1'b0,clk,~button_enter,user_reset); wire reset = power_on_reset | user_reset; // generate synchronous clock for DSP system: 806.45 kHz reg [5:0] dcount; wire clk_dsp = (dcount==61) ? 1 : 0; always @(posedge clk) dcount <= clk_dsp ? 0 : dcount+1; // adc driver wire [11:0] adc_v0, adc_v1; wire adc_rdy; wire adc_cs_b, adc_clk, adc_data0, adc_data1; assign user3[0] = adc_clk; assign user3[1] = 1'hZ; assign user3[2] = 1'hZ; assign user3[3] = adc_cs_b; assign adc_data0 = user3[2]; assign adc_data1 = user3[1]; adc_driver ad1(clk,adc_cs_b,adc_clk,adc_data0,adc_data1,adc_v0, adc_v1,adc_rdy); // fft // // Be careful: the FFT module expects data input and output all in two's // complement format. // note that a good value to set the scale to is 8'b1010_1011 reg [7:0] xn_re; wire [7:0] xn_im; wire fft_start; wire fwd_inv = 1; wire fwd_inv_we; wire [7:0] scale_sch = switch; // wired to switches wire scale_sch_we; wire [7:0] xk_re,xk_im; wire [7:0] xn_index, xk_index; wire fft_ce = clk_dsp; wire fft_rfd; wire fft_busy; wire fft_dv; wire fft_edone; wire fft_done; fft_256pt_8bit fft1(xn_re, // real data, input xn_im, // imaginary data, input fft_start, // start data loading & conversion, in fwd_inv, // forward or inverse, input fwd_inv_we, // write enable for fwd_inv, input scale_sch, // scaling schedule, input scale_sch_we, // write enable for scale_sch, input fft_ce, // clock enable clk, // system synchronous clock xk_re, // output real data xk_im, // output imaginary data xn_index, // index of input data (output) xk_index, // index of output data (output) fft_rfd, // ready for data, out fft_busy, // high while core is computing fft fft_dv, // data valid, output fft_edone, // early done strobe, output fft_done); // fft complete strobe, output // fft module initialization: simple sequencer // initclk = 0: nop, 1: load scale and fwd/inv, 3: start fft reg [1:0] initclk; always @(posedge clk) initclk <= reset ? 0 : (((initclk<3) & clk_dsp) ? initclk + 1 : initclk); assign fwd_inv_we = (initclk==2'd1); assign fft_start = (initclk==2'd3); // reload scale factors when changed as well as at init time reg [7:0] old_scale_sch; always @(posedge clk) old_scale_sch <= scale_sch; assign scale_sch_we = initclk[0] | ~(scale_sch==old_scale_sch); // feed data to the FFT : be sure to convert to two's complement. // we assume data from ADC is centered around the mean. assign xn_im = 8'b0; // no imaginary valued data (for now) wire [3:0] adc_scale = 4'd4; // ADC is 12 bits; discard lower four wire [11:0] gdat = adc_v0; // which channel of ADC to transform wire [11:0] pdat = (gdat >> adc_scale); wire [7:0] vdat; // two's complement voltage data to FFT offset_to_twos ott1(pdat[7:0],vdat); always @(posedge clk) // register the data and feed to FFT xn_re <= clk_dsp ? vdat : xn_re; // compute sum of squares of FFT output real and imaginary parts // to get a power spectrum wire [15:0] re_sq, im_sq; math_8bit_mult m8m_signed1(clk,xk_re,xk_re,re_sq); math_8bit_mult m8m_signed2(clk,xk_im,xk_im,im_sq); wire [16:0] fft_out_sum_sq = re_sq + im_sq; // convert FFT outputs to shifted unsigned integer // wire [7:0] fft_out_re, fft_out_im; // twos_to_offset tto1(xk_re,fft_out_re); // twos_to_offset tto2(xk_im,fft_out_im); // 640x480 VGA display wire [2:0] pixel; wire blank; wire pix_clk; wire [9:0] hcount, vcount; assign vga_out_red = {8{pixel[0]}}; assign vga_out_green = {8{pixel[1]}}; assign vga_out_blue = {8{pixel[2]}}; assign vga_out_blank_b = ~blank; assign vga_out_pixel_clock = pix_clk; // vga pixel clock vga_sync vga1(clk,vga_out_hsync,vga_out_vsync,hcount,vcount,pix_clk,blank); // video graph wire [2:0] gpix; wire [7:0] gdat1 = ~button0 ? adc_v0[11:4] : fft_out_sum_sq[15:8]; wire [7:0] gdat2 = ~button0 ? adc_v1[11:4] : 8'b0; vga_graph2_buf vg1(reset,clk,pix_clk,hcount,vcount,gpix, gdat1,gdat2,clk_dsp,fft_done,10'd190,10'd200); defparam vg1.NX = 256; // cumulative video pixel wire fpixel = (hcount==0 | hcount==639 | vcount==0 | vcount==479); wire [2:0] cumpix = {3{fpixel}} | gpix ; assign pixel = (~button3 ? hcount[7:5] : cumpix) & ~{3{blank}}; // debug assign led = ~switch; wire [63:0] dispdata = {adc_v0,4'b0,adc_v1,4'b0,4'b0,4'b0,xn_re, 8'b0,scale_sch}; display_16hex d1(reset, clk, dispdata, disp_blank, disp_clock, disp_rs, disp_ce_b, disp_reset_b, disp_data_out); endmodule