1 votos

Controlando el MAX31855 vía SPI con Verilog desde la FPGA

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

Estoy entendiendo la esencia de SPI, y los requisitos de temporización del MAX31855. Mi problema es el de descifrarlo en verilog.

INFORMACIÓN DE FONDO MAX31855: Cuando CS (slave select) está bajo, 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. Para una lectura completa de la temperatura y de la temperatura de la unión de referencia, deben pasar 32 cc.

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

Mi entendimiento es que para obtener una lectura de temperatura, la señal de control, CS, debe ser puesta a bajo y en ese momento los datos entrará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 vienen de los primeros 14 bits a través de MISO. Por lo tanto, puse CS bajo durante 14 ciclos de reloj SCK para obtener mi lectura de la temperatura. Los datos que vienen a través de MISO irían a un registro de desplazamiento de 14 bits en serie en paralelo.

Hice los divisores de reloj y el registro de desplazamiento. Estoy teniendo dificultades para escribir el código verilog... al menos en mi mente. Desconfío de que funcione.

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

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

NOTA: los espacios en blanco que veas en las instancias del módulo son 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

0voto

Martin Rosenau Puntos 196

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

Creo que no es una buena idea:

Mirando la hoja de datos puedes ver que la señal de reloj debe estar baja cuando hay un flanco en la señal CS.

Yo utilizaría un contador, por ejemplo un contador de 6 bits accionado 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...Max: SCK=bajo, CS=alto

El registro de desplazamiento se desplazaría en los flancos 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.

0voto

laptop2d Puntos 331

La forma que he encontrado mejor para escribir estas cosas es tener un contador que divide el reloj global.

A continuación, los registros SR se utilizan para encender en los momentos adecuados.

Dibuja un diagrama de tiempos con el

Algo así (pero esto es para manejar un DAC, o escribir un registro con SPI, tendrás que modificar el código para que el registro de desplazamiento vaya en sentido contrario).

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;

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X