Electrical – Controlling MAX31855 via SPI with Verilog from FPGA

spitimingverilog

I am trying to create an SPI between the MAX31855 – thermocouple to digital converter, and my FPGA – DE0.

I'm understanding the gist of SPI, and the timing requirements of the MAX31855. My problem is hashing it out in verilog.

BACKGROUND INFO MAX31855: When CS (slave select) is low, data is sent through MISO, for a full reading of temperature and reference junction temperature, 32 cc must pass. 14 cc are required for just the temperature reading.

DATASHEET
https://cdn-shop.adafruit.com/datasheets/MAX31855.pdf

My understanding is that to get a temperature reading, the control signal, CS, must be set low and which point the data will come in serially through the MISO.

My plan of attack was to have two clocks, one for SCK (5 mhz) and one for CS. CS would be 1/14th of SCK. The reason being is that the data for the temperature comes from the first 14 bits through MISO. So, I set CS low for 14 SCK clock cycles to get my temperature reading. The data coming through MISO would go into a 14-bit-serial-in-parallel-out shift register.

I made the clock dividers, and I made the shift register. I am having difficulty writing the verilog code… at least in my mind. I am suspicious of it working.

I am thinking that if at the negative edge of CS, I send zero bytes to the CS input of the MAX31855, that should do it.

I have this code, thoughts? I BELIEVE this is correct, but my intuition is saying no because everything I have read about SPI says I need a MASTER module AND a SLAVE module.

NOTE: any blanks you see in the module instances are for RESET, I am just not going to use it.

//MASTER module for seriel peripheral interface of MAX31855


module SPI_MASTER(CLOCK_50,GPIO0_D[21],GPIO0_D[19],GPIO0_D[15],Temperature);

input CLOCK_50;
input GPIO0_D[19]; //MISO
output reg [13:0] Temperature;
output GPIO0_D[21]; //SCK
output GPIO0_D[15]; //CS i.e. slave select
assign GPIO0_D[15] = 1'b1;

//##########################################################################//
//########################CLOCKS############################################//
//##########################################################################//

/*DE0 clock (CLOCK_50) goes into ADC_CLOCK. ADC_CLOCK outputs a 5 mhz clock
that goes to SCK, and to CS_CLOCK. CS_CLOCK outputs a clock, whose 1 cycle is 
the length of 32 of ADC_CLOCK's.*/ 

ADC_CLOCK SCK_CLOCK(CLOCK_50,,SCK_WIRE);
wire SCK_WIRE;

assign GPIO0_D[21] = SCK_WIRE;

CS_CLOCK CS_SIGNAL(SCK_WIRE,,CS);
wire CS;


//##########################################################################//
//##########################MISO############################################//
//##########################################################################//

/*MISO takes the input from MAX31855 through GPIO0_D[19], goes into shift register
after 14 clock cycles the shift register outputs Temperature. Temperature  goes to 
comparator of thermostat state machine, and state machine of LCD*/


SR Temp_Readings(GPIO0_D[19],SCK_WIRE,,Temperature);

/* @negedge of CS, send signal to GPIO0_D[15] (the slave select) for temperature to 
be read and data be send through MISO*/

always @(negedge CS)
    begin
        GPIO0_D[15] => 1'b0;
    end
endmodule

Best Answer

My plan of attack was to have two clocks, one for SCK and one for CS.

I think this is not a good idea:

Looking at the data sheet you can see that the clock signal must be low when there is an edge in the CS signal.

I would use a counter - for example a 6 bit counter driven by the clock. Depending on the counter value I would do:

  • 0: SCK=low, CS=low
  • 1...32: SCK=clock, CS=low
  • 33: SCK=low, CS=low
  • 34...Max: SCK=low, CS=high

The shift register would shift on the falling edges of the SCK signal; the value in the shift register would be evaluated on the rising edge of the CS signal.