// driver for the MAX1141 ADC used in the board // it has 4 analog inputs, and is configured to automatically // scan them sequentially while being driven by SCK // it divides the input clock by 16 to produce the SPI clock // it writes one configuration word to the ADC and then constantly // polls it for new data module adc_driver( input clk, input rst, input so, output si, output ss, output sck, output [1:0] channel, output [11:0] val, output vld, input ack ); reg [1:0] channel_ff = 0; reg [11:0] adc_val_ff = 0; reg new = 0; assign channel = channel_ff; assign val = adc_val_ff; assign vld = new & ~ack; reg sck_strobe = 0; wire strobe = sck_strobe; wire strobe2 = ~sck_strobe; always @(posedge clk) begin if (~rst) sck_strobe <= sck_strobe + 1; else sck_strobe <= 0; end localparam INIT = 0, CONFIG = 1, ADC = 2; reg [1:0] state = INIT; reg [1:0] state_next; reg [4:0] bit_pos = 0; reg [4:0] bit_pos_next; reg [15:0] so_ff = 0; reg [15:0] so_ff_next; reg write_out; reg sck_next; reg ss_next; reg si_next; reg si_ff = 1; reg ss_ff = 1; reg sck_ff = 1; assign si = si_ff; assign ss = ss_ff; assign sck = sck_ff; wire [15:0] config_word; wire config_bit; assign config_word = { 1'b0, // ADC Mode Control 4'b0100, // Standard_Ext 4'b0011, // Up to AIN3 2'b01, // reset FIFO 2'b00, // normal PM mode 1'b1, // include channel number in output 1'b0, // SWCNV enable, not used in external clock mode 1'b0 // reserved }; assign config_bit = config_word[15-bit_pos[4:1]]; always @* begin state_next = state; bit_pos_next = bit_pos; write_out = 0; so_ff_next = so_ff; sck_next = 1; ss_next = 1; si_next = 0; if (~rst) begin // latch sck and ss state until the strobe happens si_next = si; ss_next = ss; sck_next = sck; if (strobe2) begin if (state == CONFIG || state == ADC) begin // deassert slave select so it can be triggered on the next frame if (bit_pos == 31 & ~ss_next & ~sck) begin ss_next = 1; //bit_pos_next = 0; // don't need this because it's going to // overflow end else begin ss_next = 0; end end end if (strobe) begin case (state) INIT: begin ss_next = 0; state_next = CONFIG; bit_pos_next = 0; end CONFIG: begin sck_next = bit_pos[0]; bit_pos_next = bit_pos + 1; // update on the falling edge if (sck) begin si_next = config_bit; end // switch state on the rising edge after the overflow // and reassert ss to start the next frame if (~sck & (bit_pos == 31)) begin //ss_next = 0; state_next = ADC; end end ADC: begin //ss_next = 0; si_next = 0; sck_next = bit_pos[0]; bit_pos_next = bit_pos + 1; // update bit pos state on the rising edge // shift in data as well if (~sck) begin so_ff_next = {so_ff[14:0], so}; // after reading the last bit // deassert ss so it can be reasserted on the next rising edge if (bit_pos == 31) begin //ss_next = 1; write_out = 1; end end end endcase end end else begin state_next = INIT; bit_pos_next = 0; sck_next = 1; ss_next = 1; end end always @(posedge clk) begin state <= state_next; bit_pos <= bit_pos_next; sck_ff <= sck_next; ss_ff <= ss_next; si_ff <= si_next; so_ff <= so_ff_next; // write the data out when write_out is asserted if (write_out) begin {channel_ff, adc_val_ff} <= so_ff_next[13:0]; new <= 1; end // deassert vld when the data is acknowledged if (ack) new <= 0; end endmodule