Estoy trabajando con un chip de expansión de E / S SPI MCP23S17 en un proyecto VHDL en mi Basys 2 .
A primera vista, pensé que esto era solo una simple interfaz SPI en la que ponía baja la selección de chip y me proporcionaría los datos en la línea MISO, pero parece que es un poco más complicado con los comandos y la inicialización necesarios.
Agregué algunos bits de configuración ("0100" & "000" & "1") que aparecen en la línea MOSI una vez cuando intentas leer los datos. pero nada ha cambiado. Parece que hay muchos registros para mantener la configuración, pero no tengo idea de cómo configurarlos.
Aquíhayundiagramadecómolotengotodoconectado.LapruebadeE/Sessoloparaasegurarsedequetengoalgunosbitsconocidosquedeberíanaparecersilatransacciónserealizacorrectamente.UsaréelladoBdelchip,asíquesitienequepasaralgoespecialparaleerlo,porfavorexplique.
¿Qué debe pasar para leer los datos del chip?
Aquí está el módulo SPI (SPI.vhd) que he escrito hasta ahora.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity SPI is
Generic (
dataWidthN : positive := 8
);
port(
sck: in std_logic; -- clock
mosi: out std_logic; -- data going into slave
miso: in std_logic; -- data coming out of slave
cs: in std_logic; -- chip select
address: in std_logic_vector(2 downto 0); -- 0 - 7
data: out std_logic_vector(dataWidthN-1 downto 0);
debug: out std_logic_vector(1 downto 0)
);
end SPI;
architecture Behavioral of SPI is
signal data_reg : STD_LOGIC_VECTOR (dataWidthN-1 downto 0);
begin
data <= data_reg;
process (sck)
variable isSetup: std_logic := '0';
variable setupBits: std_logic_vector(7 downto 0) := "0100" & address & "1";
variable setupBitCount: natural := 0;
begin
if rising_edge(sck) then -- rising edge of SCK
if (cs = '0') then -- SPI CS must be selected
if (isSetup = '0' and setupBitCount < 7) then
mosi <= setupBits(7-setupBitCount);
setupBitCount := setupBitCount + 1;
else
isSetup := '1';
setupBitCount := 0;
end if;
if isSetup = '1' then
debug <= "11";
-- shift serial data into dat_reg on each rising edge
-- of SCK, MSB first
data_reg <= data_reg(dataWidthN-2 downto 0) & miso;
else
debug <= "10";
end if;
end if;
end if;
end process;
end Behavioral;
No he encontrado muchos artículos que hablen sobre este chip usando código. Encontré algunas cosas de Arduino pero todas usan la biblioteca SPI que no ayuda a explicar qué está sucediendo exactamente. Aquí están los pocos enlaces que he encontrado:
Editar:
Bien, después de trabajar en lo que Dave Tweed dijo que hiciera. Soy capaz de enviar y producir los comandos en MOSI pero nada vuelve en la línea MISO. Tenga en cuenta que el FPGA debería obtener los datos y tengo un analizador lógico que mostrará los bits si algo sale y mi código de FPGA es incorrecto.
CS: 1111000000000000000000000000
MOSI: xxxx0100aaa10000110000000000
MISO: xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Aquí está la simulación en ISim. ** Esto no devolverá datos en MISO porque es solo una simulación sin chip para enviar los datos correctos. *
Ydesdeunanalizadorlógicoenelmundoreal:
Aquí está la actualización del código del módulo SPI.vhd:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity SPI is
Generic (
dataWidthN : integer := 8
);
port(
sck: in std_logic; -- clock
mosi: out std_logic; -- data going into slave
miso: in std_logic; -- data coming out of slave
cs: in std_logic; -- chip select
address: in std_logic_vector(2 downto 0); -- 0 - 7
data: out std_logic_vector(dataWidthN-1 downto 0);
debug: out std_logic_vector(1 downto 0)
);
end SPI;
architecture Behavioral of SPI is
type state_type is (idle, s_readSetup, s_read);
signal data_reg : STD_LOGIC_VECTOR (dataWidthN-1 downto 0);
begin
data <= data_reg;
spi_read: process (sck)
variable transactionComplete: std_logic := '0';
variable setupBits: std_logic_vector(15 downto 0);
variable setupCmdBitCount: natural := 0; -- setup command is 16 in length
variable readCmdBitCount: natural := 0; -- A command is same as dataWidthN
variable currState: state_type := idle;
begin
setupBits := "0100" & address & "1" & "00001100";
if falling_edge(sck) then -- rising edge of SCK
case currState is
when s_readSetup =>
if (cs = '0') then -- SPI CS must be selected
debug <= "10";
mosi <= setupBits(setupBits'length-1-setupCmdBitCount);
setupCmdBitCount := setupCmdBitCount + 1;
-- Move to the next state
if setupCmdBitCount >= setupBits'length then
setupCmdBitCount := 0;
currState := s_read;
end if;
else
currState := idle;
end if;
when s_read =>
if (cs = '0') then -- SPI CS must be selected
debug <= "11";
-- shift serial data into dat_reg on each rising edge
-- of SCK, MSB first
data_reg <= data_reg(dataWidthN-2 downto 0) & miso;
readCmdBitCount := readCmdBitCount + 1;
if readCmdBitCount >= data'length then
readCmdBitCount := 0;
transactionComplete := '1';
currState := idle;
end if;
else
currState := idle;
end if;
-- Idle state: if the state is unknown then we just go idle
when others =>
debug <= "00";
setupCmdBitCount := 0;
readCmdBitCount := 0;
mosi <= '0';
if cs = '0' and transactionComplete = '0' then
mosi <= setupBits(setupBits'length-1-setupCmdBitCount);
setupCmdBitCount := setupCmdBitCount + 1;
currState := s_readSetup;
elsif cs = '1' and transactionComplete = '1' then
transactionComplete := '0';
end if;
end case;
end if;
end process;
end Behavioral;