From 4b6e0102d20d9ab060ce930e4b846c8be446bb06 Mon Sep 17 00:00:00 2001 From: Vasil Zlatanov Date: Mon, 12 Dec 2016 21:51:10 +0000 Subject: public push --- part_4/mylib/spi2adc.v | 157 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 part_4/mylib/spi2adc.v (limited to 'part_4/mylib/spi2adc.v') diff --git a/part_4/mylib/spi2adc.v b/part_4/mylib/spi2adc.v new file mode 100644 index 0000000..41be7ad --- /dev/null +++ b/part_4/mylib/spi2adc.v @@ -0,0 +1,157 @@ +//------------------------------ +// Module name: spi2adc +// Function: SPI interface for MCP3002 ADC +// Creator: Peter Cheung +// Version: 3.0 +// Date: 8 Dec 2016 +//------------------------------ + +module spi2adc (sysclk, start, channel, data_from_adc, data_valid, + sdata_to_adc, adc_cs, adc_sck, sdata_from_adc); + + input sysclk; // 50MHz system clock of DE0 + input start; // Pulse to start ADC, minimum wide = clock period + input channel; // channel 0 or 1 to be converted + output [9:0] data_from_adc; // 10-bit ADC result + output data_valid; // High indicates that converted data valid + output sdata_to_adc; // Serial commands send to adc chip + output adc_cs; // chip select - low when converting + output adc_sck; // SPI clock - active during conversion + input sdata_from_adc; // Converted serial data from ADC, MSB first + +//-------------Input Ports----------------------------- +// All the input ports should be wires + wire sysclk, start, sdata_from_adc; + +//-------------Output Ports----------------------------- +// Output port can be a storage element (reg) or a wire + reg [9:0] data_from_adc; + reg adc_cs; + wire sdata_to_adc, adc_sck, data_valid; + +//-------------Configuration parameters for ADC -------- + parameter SGL=1'b1; // 0:diff i/p, 1:single-ended + parameter MSBF=1'b1; // 0:LSB first, 1:MSB first + +// --- Submodule: Generate internal clock at 1 MHz ----- + reg clk_1MHz; // 1Mhz clock derived from 50MHz + reg [4:0] ctr; // internal counter + reg tick; // 1MHz clock tick lasting 20ns, i.e. one 50MHz cycle + parameter TIME_CONSTANT = 5'd24; // change this for diff clk freq + initial begin + clk_1MHz = 0; // don't need to reset - don't care if it is 1 or 0 to start + ctr = 5'b0; // ... to start. Initialise to make simulation easier + tick = 1'b0; + end + + always @ (posedge sysclk) // + if (ctr==0) begin + ctr <= TIME_CONSTANT; + if (clk_1MHz==1'b0) + tick <= 1'b1; + clk_1MHz <= ~clk_1MHz; // toggle the output clock for squarewave + end + else begin + ctr <= ctr - 1'b1; + tick <= 1'b0; + end +// ---- end internal clock generator ---------- + +// ---- Detect start is asserted with a small state machine + // .... FF set on positive edge of start + // .... reset when adc_cs goes high again + reg [1:0] sr_state; + parameter IDLE = 2'b00,WAIT_CSB_FALL = 2'b01, WAIT_CSB_HIGH = 2'b10; + reg adc_start; + + initial begin + sr_state = IDLE; + adc_start = 1'b0; // set while sending data to ADC + end + + always @ (posedge sysclk) + case (sr_state) + IDLE: if (start==1'b0) sr_state <= IDLE; + else begin + sr_state <= WAIT_CSB_FALL; + adc_start <= 1'b1; + end + WAIT_CSB_FALL: if (adc_cs==1'b1) sr_state <= WAIT_CSB_FALL; + else sr_state <= WAIT_CSB_HIGH; + + WAIT_CSB_HIGH: if (adc_cs==1'b0) sr_state <= WAIT_CSB_HIGH; + else begin + sr_state <= IDLE; + adc_start <= 1'b0; + end + default: sr_state <= IDLE; + endcase +//------- End circuit to detect start and end of conversion + + +// spi controller designed as a state machine +// .... with 16 states (idle, and S1-S15 indicated by state value + + reg [4:0] state; + reg adc_done, adc_din, shift_ena; + + initial begin + state = 5'b0; adc_cs = 1'b1; adc_done = 1'b0; + adc_din = 1'b0; shift_ena <= 1'b0; + end + + always @(posedge sysclk) + if (tick==1'b1) begin + + // default outputs and state transition + adc_cs <= 1'b0; adc_done <= 1'b0; adc_din <= 1'b0; shift_ena <= 1'b0; + state <= state + 1'b1; + case (state) + 5'd0: begin + if (adc_start==1'b0) begin + state <= 5'd0; // still idle + adc_cs <= 1'b1; // chip select not active + end + else begin + state <= 5'd1; // start converting + adc_din <= 1'b1; // start bit is 1 + end + end + 5'd1: adc_din <= SGL; // SGL bit + 5'd2: adc_din <= channel; // CH bit + 5'd3: adc_din <= MSBF; // MSB first bit + 5'd4: shift_ena <= 1'b1; // start shifting data from adc + 5'd15: begin + shift_ena <= 1'b0; + adc_done <= 1'b1; + end + 5'd16: begin + adc_cs <= 1'b1; // last state - disable chip select + state <= 5'd0; // go back to idle state + end + default: + shift_ena <= 1'b1; // unspecified states are covered by default above + endcase + end // ... always + + // shift register for output data + reg [9:0] shift_reg; + initial begin + shift_reg = 10'b0; + data_from_adc = 10'b0; + end + + always @(negedge sysclk) + if((adc_cs==1'b0)&&(shift_ena==1'b1)&&(tick==1'b1)) // start shifting data_in + shift_reg <= {shift_reg[8:0],sdata_from_adc}; + + // Latch converted output data + always @(posedge sysclk) + if(adc_done) + data_from_adc = shift_reg; + + // Assign outputs to drive SPI interface to DAC + assign adc_sck = !clk_1MHz & !adc_cs; + assign sdata_to_adc = adc_din; + assign data_valid = adc_cs; +endmodule \ No newline at end of file -- cgit v1.2.3-54-g00ecf