`timescale 1ns / 1ps module ADC_peripheral( clk, reset, cs, ADC_EOC, ADC_CS, ADC_CSTART, ADC_SCLK, ADC_SDIN, ADC_SDOUT, addr, rdBus, wrBus, we); input clk, reset, ADC_EOC, cs, we; input [8:0] addr; input [7:0] wrBus; output ADC_CS, ADC_CSTART, ADC_SCLK; output [7:0] rdBus; inout ADC_SDIN, ADC_SDOUT; wire [7:0] rdBus2; reg [7:0] wrBus2; reg [8:0] addr2; wire we1; reg we2=0, nSample=0; reg [7:0] auto_count=0; reg [4:0] w_st2=0; reg [3:0] SPI_in_data=0; reg [9:0] SPI_out_data; reg SPI_rd = 0; reg SPI_wr = 0; reg [7:0] buffer_rd1; reg [3:0] ADC_cmd; assign we1 = we & cs; assign ADC_CSTART = 1'b1; // Dual-port RAM instatiation RAMB16_S9_S9 ba0( .DOA(rdBus), // Port A 8-bit Data Output .DOB(rdBus2), // Port B 8-bit Data Output .DOPA(), // Port A 1-bit Parity Output .DOPB(), // Port B 1-bit Parity Output .ADDRA(addr[8:0]), // Port A 11-bit Address Input .ADDRB(addr2[8:0]), // Port B 11-bit Address Input .CLKA(~clk), // Port A Clock .CLKB(~clk), // Port B Clock .DIA(wrBus), // Port A 8-bit Data Input .DIB(wrBus2), // Port B 8-bit Data Input .DIPA(1'b0), // Port A 1-bit parity Input .DIPB(1'b0), // Port-B 1-bit parity Input .ENA(1'b1), // Port A RAM Enable Input .ENB(1'b1), // Port B RAM Enable Input .SSRA(1'b0), // Port A Synchronous Set/Reset Input .SSRB(1'b0), // Port B Synchronous Set/Reset Input .WEA(we1), // Port A Write Enable Input .WEB(we2) ); // Port B Write Enable Input // SPI comunication module instantiation reg ADC_SCLK_buffer = 0; reg ADC_SDIN_buffer = 0; reg busy = 0; reg [3:0] in_buffer=0; reg [9:0] out_buffer; reg [7:0] clkcount = 0; reg [7:0] clkdiv = 255; reg [4:0] count = 0; assign ADC_CS = ~busy; always@(SPI_rd or out_buffer or busy or clkdiv) begin SPI_out_data = 10'bx; if(SPI_rd) begin SPI_out_data = out_buffer; end end always@(negedge clk) begin if(!busy) begin if(SPI_wr) begin in_buffer = SPI_in_data; busy = 1; end end else begin clkcount = clkcount + 1; if(clkcount >= clkdiv) begin clkcount = 0; // Send the ADC CMD on first 4 rising edge of SCLK if((count % 2) == 0) begin ADC_SDIN_buffer = in_buffer[3]; in_buffer = in_buffer << 1; end // We generate 10 cicles of SCLK if(count > 0 && count < 21) begin ADC_SCLK_buffer = ~ADC_SCLK_buffer; end count = count + 1; if(count > 21) begin count = 0; busy = 0; end end end end always@(posedge ADC_SCLK_buffer) begin out_buffer = out_buffer << 1; out_buffer[0] = ADC_SDOUT; end assign ADC_SCLK = ADC_SCLK_buffer; assign ADC_SDIN = ADC_SDIN_buffer; // State Machine for control ADC comunication always @(posedge clk) if(reset) {we2, SPI_wr, SPI_rd, w_st2, auto_count, SPI_in_data} <= 0; else begin case (w_st2) 0: begin addr2 <= 0; w_st2 <= 1; end 1: begin ADC_cmd <= rdBus2[3:0]; if (rdBus2[7:4] == 5) // Send command without read samples begin addr2<= 2; w_st2 <= 2; nSample <= 1; end else if (rdBus2[7:4] == 6) // Read: Stop when buffer full begin addr2<= 2; w_st2 <= 2; nSample <= 0; end else if (rdBus2[7:4] == 9) // Set clkdiv on SPI controller begin addr2<= 1; w_st2 <= 10; end else begin w_st2 <= 0; end end 2: begin if (rdBus2[7:0] == 0) begin auto_count<=0; w_st2 <= 0; end else begin //Send data to ADC buffer_rd1<=rdBus2; auto_count<=auto_count+1; SPI_in_data <= ADC_cmd[3:0]; SPI_wr <= 1; w_st2 <= 3; end end 3: begin SPI_wr <= 0; //Wait for complete convertion if(!ADC_EOC || ADC_CS) begin buffer_rd1<=buffer_rd1-1; SPI_rd <=1; if(nSample) w_st2<= 8; else w_st2<= 4; end end 4: begin //Write data on BRAM (LOW) wrBus2 <= SPI_out_data[7:0]; addr2 <= 2+2*auto_count; we2 <= 1; w_st2 <= 5; end 5: begin we2 <= 0; w_st2 <= 6; end 6: begin //Write data on BRAM (HI) wrBus2 <= SPI_out_data[9:8]; addr2 <= 3+2*auto_count; we2 <= 1; w_st2 <= 7; end 7: begin we2 <= 0; w_st2 <= 8; end 8: begin SPI_rd <=0; //Update Buffer Size value wrBus2 <= buffer_rd1; addr2 <= 2; we2 <= 1; w_st2 <= 9; end 9: begin we2 <= 0; w_st2 <= 0; end //Sent clock divider for speed on SPI comunication 10: begin clkdiv = rdBus2; w_st2 <= 0; end endcase end endmodule