Controlando MAX31855 a través de SPI con Verilog desde FPGA

1

Estoy intentando crear un SPI entre el convertidor de termopar a digital MAX31855 y mi FPGA - DE0.

Comprendo la esencia de SPI y los requisitos de tiempo del MAX31855. Mi problema es el hash en verilog.

INFORMACIÓN DE FONDO MAX31855: Cuando CS (selección de esclavo) es baja, los datos se envían a través de MISO, para una lectura completa de la temperatura y la temperatura de la unión de referencia, deben pasar 32 cc. Se requieren 14 cc solo para la lectura de temperatura.

HOJA DE DATOS enlace

Entiendo que para obtener una lectura de temperatura, la señal de control, CS, debe establecerse en un nivel bajo y en qué punto los datos ingresarán en serie a través del MISO.

Mi plan de ataque era tener dos relojes, uno para SCK (5 mhz) y otro para CS. CS sería 1/14 de SCK. La razón es que los datos para la temperatura provienen de los primeros 14 bits a través de MISO. Por lo tanto, establezco CS bajo para 14 ciclos de reloj SCK para obtener mi lectura de temperatura. Los datos que llegan a través de MISO irían a un registro de desplazamiento de 14 bits de serie en paralelo a salida.

Hice los separadores de reloj, e hice el registro de desplazamiento. Estoy teniendo dificultades para escribir el código verilog ... al menos en mi mente. Soy sospechoso de que funcione.

Estoy pensando que si en el borde negativo de CS, envío cero bytes a la entrada de CS del MAX31855, debería hacerlo.

Tengo este código, pensamientos? CREO que esto es correcto, pero mi intuición dice que no, porque todo lo que he leído sobre SPI dice que necesito un módulo MASTER y un módulo ESCLAVO.

NOTA: cualquier espacio en blanco que vea en las instancias del módulo es para RESET, simplemente no lo voy a usar.

//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
    
pregunta MathWannaBe456

2 respuestas

0
  

Mi plan de ataque era tener dos relojes, uno para SCK y otro para CS.

Creo que esto no es una buena idea:

Mirando la hoja de datos, puede ver que la señal del reloj debe ser baja cuando hay un borde en la señal CS.

Yo usaría un contador, por ejemplo, un contador de 6 bits manejado por el reloj. Dependiendo del valor del contador que haría:

  • 0: SCK = bajo, CS = bajo
  • 1 ... 32: SCK = reloj, CS = bajo
  • 33: SCK = bajo, CS = bajo
  • 34 ... Máx .: SCK = bajo, CS = alto

El registro de desplazamiento se desplazaría en los bordes descendentes de la señal SCK; el valor en el registro de desplazamiento se evaluaría en el flanco ascendente de la señal CS.

    
respondido por el Martin Rosenau
0

La mejor manera de escribir estas cosas es tener un contador que divida el reloj global.

Luego, los registros SR se utilizan para encender en los momentos apropiados.

Dibuja un diagrama de tiempo con el

Algo como esto (pero esto es para conducir un DAC, o escribir un registro con SPI, tendrá que modificar el código para que el registro de desplazamiento vaya a la inversa).

port (
  DAC_START_H    : in std_logic;   -- Serial Data In: shift in config word
  DAC_VALUE      : in std_logic_vector(15 downto 0); -- 16=bit value to load into the DAC

  ARST_L         : in std_logic;   -- Reset for testbench only

  DAC_RST_H      : in std_logic;   -- Software Reset
  SYS_CLK        : in std_logic;   -- system clock

  DAC_CLK        : out std_logic;   -- Input Clock
  DAC_CS_L       : out std_logic;   -- Convert Start
  DAC_SDI_H      : out std_logic   -- Output Serial Data
  );
end DAC2641;



architecture DAC2641 of DAC2641 is
  signal DAC_COUNT            : std_logic_vector(4 downto 0);
  signal DAC_SHIFTOUT         : std_logic_vector(15 downto 0);

  signal DAC_SHIFTOUT_EN_H    : std_logic;
  signal DAC_CS_L_TEMP        : std_logic; 
  signal DAC_CLK_TEMP         : std_logic; 

begin




DACCLK_CNT : process( ARST_L, SYS_CLK)
begin
  if ARST_L = '0'  then
    DAC_COUNT <= conv_std_logic_vector(10#22#, 5);
  elsif rising_edge(SYS_CLK) then
    if DAC_START_H = '1'  or DAC_RST_H = '1'  then
      DAC_COUNT <= conv_std_logic_vector(10#0#, 5);
    elsif (DAC_COUNT < conv_std_logic_vector(10#21#, 5) )     then
      DAC_COUNT <= DAC_COUNT + 1;
    else
      DAC_COUNT <= DAC_COUNT;
    end if;
  end if;
end process;



DAC_CNTLD_REG : process(ARST_L,DAC_COUNT,SYS_CLK)
begin
  if ARST_L = '0'  then
    DAC_CS_L_TEMP <= '1';
  elsif rising_edge(SYS_CLK) then 
    if DAC_COUNT = conv_std_logic_vector(10#01#,6) or DAC_RST_H = '1' then
      DAC_CS_L_TEMP <= '0'; 
    elsif DAC_COUNT = conv_std_logic_vector(10#18#,6) then
      DAC_CS_L_TEMP <= '1'; 
    end if;
  end if;
end process;
DAC_CS_L <= DAC_CS_L_TEMP;


DAC_SHFTOUT_COMB : process(ARST_L,SYS_CLK)
begin
  if ARST_L = '0'  then
    DAC_SHIFTOUT_EN_H <= '0';  
  elsif rising_edge(SYS_CLK) then  
    if DAC_COUNT = conv_std_logic_vector(10#02#,6)  then
      DAC_SHIFTOUT_EN_H <= '1'; 
    elsif DAC_COUNT = conv_std_logic_vector(10#18#,6) then
      DAC_SHIFTOUT_EN_H <= '0'; 
    end if;
  end if;
end process;




DAC_LDVAL_REG : process( ARST_L, SYS_CLK, DAC_START_H)
begin
  if ARST_L = '0' then
    DAC_SHIFTOUT <= conv_std_logic_vector(10#00#, 16);
  elsif DAC_START_H = '1' then
    DAC_SHIFTOUT <= DAC_VALUE;
  elsif falling_edge(SYS_CLK) then
    if DAC_SHIFTOUT_EN_H = '1' then
      DAC_SHIFTOUT <= DAC_SHIFTOUT(14 downto 0) & '0';
    else
      DAC_SHIFTOUT <= DAC_SHIFTOUT;
    end if;
  end if;
end process;

DAC_SDI_H <= DAC_SHIFTOUT(15);


DAC_CLK_COMB : process(SYS_CLK,DAC_SHIFTOUT_EN_H)
begin
  if  DAC_SHIFTOUT_EN_H = '0' then
    DAC_CLK_TEMP <=  '0';
  else
    DAC_CLK_TEMP <=  SYS_CLK;
  end if;
end process;
DAC_CLK <= DAC_CLK_TEMP ;

end DAC2641;
    
respondido por el laptop2d

Lea otras preguntas en las etiquetas