- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Right now, I have a master entity that is sending data to the slave, and the slave is recognizing it and changing the LED according to the bit-stream I send. Hopefully that's not a fluke and is actually working because of the protocol. Here is my problem, when I try to do RD and WR signals, one of them always has to be high or I get that an error saying so and so is getting driven by SDA which has multiple drivers, which makes sense because of the way i2c works. My question is, can I actually implement both so I can practice i2c, or can I only use a master and then use slaves that come with the board already(e.g. the eeprom, accelerometer)?
--synthesis VHDL_INPUT_VERSION VHDL_2008
library ieee;
use ieee.std_logic_1164.all;
entity i2c_slave0 is
generic(
slvAddress : std_logic_vector(6 downto 0) := "0000001";
regAddress : std_logic_vector(7 downto 0) := "10000101"
);
port(
clk50,
SCL,
reset : in std_logic := '0';
SDA : inout std_logic := '1';
output : out std_logic_vector(7 downto 0) := (others => '0')
);
end i2c_slave0;
architecture FSM of i2c_slave0 is
type slaveState is (Idle, Slave_Address, Send_Ack1, Send_Ack2, Register_Address, Read_Data, Write_Data, Wait_Stop);
signal prev_State, next_State : slaveState;
signal i : natural range 0 to 8 := 0;
signal addr : std_logic_vector(7 downto 0) := (others => '0');
signal tempRam : std_logic_vector(7 downto 0) := "00000000";
signal ram : std_logic_vector(7 downto 0) := (others => '0');
signal start, stop : std_logic := '0';
signal syncFF_clk : std_logic_vector(1 downto 0) := "00";
signal syncFF_sda : std_logic_vector(1 downto 0) := "00";
signal edgeDetFF_clk : std_logic := '0';
signal edgeDetFF_SDA : std_logic := '0';
signal rising_edge_clk,
falling_edge_clk : std_logic := '0';
signal regAddr : std_logic_vector(7 downto 0) := (others => '0');
begin
--Synchronize data--
process(clk50)
begin
if(rising_edge(clk50)) then
syncFF_clk(0) <= SCL;
syncFF_clk(1) <= syncFF_clk(0);
syncFF_sda(0) <= SDA; -- <----------------- This is where the error occurs
syncFF_sda(1) <= syncFF_sda(0);
end if;
end process;
--------------------------------
--======Edge detection of SCL=======--
--Pipelining SCL--
process(clk50)
begin
if(rising_edge(clk50)) then edgeDetFF_clk <= syncFF_clk(1);
end if;
end process;
---------------------------------------
--Rising/Falling edge detection--
process(clk50)
begin
if(falling_edge(clk50)) then
rising_edge_clk <= syncFF_clk(1) and not edgeDetFF_clk;
falling_edge_clk <= not syncFF_clk(1) and edgeDetFF_clk;
end if;
end process;
--------------------------------------------------------------
--======Start/Stop detection of SDA=======--
--Pipelining SDA--
process(all)
begin
if(rising_edge(clk50)) then edgeDetFF_SDA <= syncFF_sda(1);
end if;
end process;
--------------------------------------------------------------
--Stop/Start detection--
process(all)
begin
start <= '0';
stop <= '0';
if(syncFF_clk(1) = '1' and edgeDetFF_clk = '1') then
start <= not syncFF_SDA(1) and edgeDetFF_SDA;
stop <= syncFF_SDA(1) and not edgeDetFF_SDA;
end if;
end process;
---------------------------------------------------------------
process(all)
begin
if (reset = '1') then prev_State <= Idle;
i <= 0;
elsif(rising_edge(clk50)) then prev_State <= next_State;
if(prev_State = Idle or start = '1') then i <= 0;
elsif(falling_edge_clk = '1') then
if(i < 8) then i <= i + 1;
else i <= 0;
end if;
end if;
end if;
end process;
process(all)
begin
SDA <= 'Z';
case (prev_State) is
when Idle =>
if(start = '1') then next_State <= Slave_Address;
else next_State <= Idle;
end if;
when Slave_Address =>
if(falling_edge_clk = '1') then
if (i < 8) then next_State <= Slave_Address;
elsif((i = 8) and (addr(7 downto 1) = slvAddress)) then next_State <= Send_Ack1;
else next_State <= Idle;
end if;
else next_State <= Slave_Address;
end if;
when Send_Ack1 =>
SDA <= '0';
if(falling_edge_clk = '1') then
if(addr(0) = '0') then next_State <= Register_Address;
else next_State <= Read_Data;
end if;
else next_State <= Send_Ack1;
end if;
when Register_Address =>
if(falling_edge_clk = '1') then
if (i < 8) then next_State <= Register_Address;
elsif((i = 8) and (regAddr(7 downto 0) = regAddress)) then next_State <= Send_Ack2;
else next_State <= Idle;
end if;
else next_State <= Register_Address;
end if;
when Send_Ack2 =>
SDA <= '0';
if(falling_edge_clk = '1') then next_State <= Write_Data;
else next_State <= Send_Ack2;
end if;
when Write_Data =>
if(falling_edge_clk = '1') then
if (i < 8) then next_State <= Write_Data;
else next_State <= Send_Ack1;
end if;
else next_State <= Write_Data;
end if;
when Read_Data =>
SDA <= ram(8 - i);
if(falling_edge_clk = '1') then
if (i < 8) then next_State <= Read_Data;
else next_State <= Wait_Stop;
end if;
else next_State <= Read_Data;
end if;
when Wait_Stop =>
next_State <= Wait_Stop;
end case;
if (start = '1') then next_State <= Slave_Address;
elsif(stop = '1') then next_State <= Idle;
end if;
end process;
process(all)
begin
if(rising_edge(clk50)) then
if(reset = '1') then addr <= (others => '0');
tempRam <= (others => '0');
regAddr <= (others => '0');
elsif(rising_edge_clk) then
if (prev_State = Slave_Address) then addr(8 - i) <= SDA;
elsif(prev_State = Write_Data) then tempRam(8 - i) <= SDA;
elsif(prev_State = Register_Address) then regAddr(8 - i) <= SDA;
end if;
end if;
if(reset = '1') then
ram <= (others => '0');
elsif(prev_State = Write_Data and i = 8) then ram <= tempRam;
end if;
if(reset = '1') then
output <= (others => '0');
elsif(falling_edge_clk = '1') then
if(prev_State = Write_Data and i = 8) then output <= ram;
end if;
end if;
end if;
end process;
end FSM;
--synthesis VHDL_INPUT_VERSION VHDL_2008
library ieee;
use ieee.std_logic_1164.all;
entity black_box is
port(
clk50,
reset : in std_logic := '0';
output : out std_logic_vector(7 downto 0) := (others => '0')
);
end black_box;
architecture structural of black_box is
component i2c_master is
generic(
clk_freq : integer := 50_000_000;
i2c_freq : integer := 300_000;
slaveWR0 : std_logic_vector(8 downto 0) := "000000010";
slaveRD0 : std_logic_vector(8 downto 0) := "000000011";
reg0WR0 : std_logic_vector(8 downto 0) := "010000101";
reg0RD0 : std_logic_vector(8 downto 0) := "010000101";
slvData0 : std_logic_Vector(8 downto 0) := "001110101"
);
port(
clk50,
-- slvAddress,
WR, RD,
reset : in std_logic;
SCL : out std_logic;
SDA : inout std_logic
-- output : out std_logic_vector(7 downto 0) := (others => '0')
);
end component;
component i2c_slave0 is
generic(
slvAddress : std_logic_vector(6 downto 0) := "0000001";
regAddress : std_logic_vector(7 downto 0) := "10000101"
);
port(
clk50,
SCL,
reset : in std_logic;
SDA : inout std_logic;
output : out std_logic_vector(7 downto 0) := (others => '0')
);
end component;
signal SCL, SDA : std_logic := '0';
signal oneSec : std_logic := '0';
signal wr, rd : std_logic := '0';
begin
process(clk50)
variable counter : natural range 0 to 50_000_000;
begin
if(rising_edge(clk50)) then counter := counter + 1;
if(counter = 50_000_000) then counter := 0;
oneSec <= not oneSec;
end if;
end if;
end process;
process(oneSec)
begin
if(rising_edge(oneSec)) then
WR <= '0';
RD <= '0';
end if;
end process;
mstr: i2c_master port map (clk50, WR, RD, reset, SCL, SDA);
slv : i2c_slave0 port map (clk50, SCL, reset, SDA, output);
end structural;
EDIT: So you can't do it within the FPGA, which makes sense, so what i ended up doing was using the I/O pins. Worked perfectly after that!
- Tags:
- Vhdl
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--synthesis VHDL_INPUT_VERSION VHDL_2008
library ieee;
use ieee.std_logic_1164.all;
entity i2c_master is
generic(
clk_freq : integer := 50_000_000;
i2c_freq : integer := 300_000;
slaveWR0 : std_logic_vector(8 downto 0) := "000000010";
slaveRD0 : std_logic_vector(8 downto 0) := "000000011";
reg0WR0 : std_logic_vector(8 downto 0) := "010000101";
reg0RD0 : std_logic_vector(8 downto 0) := "010000101";
slvData0 : std_logic_Vector(8 downto 0) := "001100101"
);
port(
clk50,
-- slvAddress,
WR, RD,
reset : in std_logic := '0';
SCL : out std_logic := '0';
SDA : inout std_logic := '0'
-- output : out std_logic_vector(7 downto 0) := (others => '0')
);
end i2c_master;
architecture FSM of i2c_master is
type masterState is (
Idle, Start, Slave_Address, Ack1, Stop, Hold,
WR_Address, Ack2, Write_Data, Ack3,
RD_Address, Ack4, restartL, restartR, Initiate_Read, Ack5, Read_Data, noAck
);
signal prev_State, next_State : masterState;
signal i2c_clk : std_logic := '0';
signal i, iReg : natural range 0 to 8;
signal j, jReg : natural range 0 to 7;
signal storeData : std_logic_vector(7 downto 0) := (others => '0');
signal wr_Reg : std_logic := '0';
--constant slaveAddress0 : std_logic_vector(7 downto 0) := slaveWR0;
begin
process(i2c_clk, reset)
begin
if (reset = '1') then prev_State <= Idle;
iReg <= 0;
jReg <= 0;
elsif(falling_edge(i2c_clk)) then prev_State <= next_State;
iReg <= i;
jReg <= j;
end if;
end process;
process(all)
variable clk_counter : natural range 0 to clk_freq/(2*i2c_freq);
begin
if(rising_edge(clk50)) then clk_counter := clk_counter + 1;
if(clk_counter = clk_freq/(2*i2c_freq)) then i2c_clk <= not i2c_clk;
clk_counter := 0;
end if;
end if;
end process;
process(all)
begin
SCL <= i2c_clk;
i <= 0;
j <= 0;
case (prev_State) is
when Idle =>
SCL <= '1';
SDA <= '1';
if(WR = '1') then next_State <= Start;
else next_State <= Idle;
end if;
when Start =>
SCL <= '1';
SDA <= '0';
next_State <= Slave_Address;
when Slave_Address =>
SDA <= slaveWR0(8-i);
i <= iReg + 1;
if(i = 8) then next_State <= Ack1;
else next_State <= Slave_Address;
end if;
when Ack1 =>
SDA <= 'Z';
if(wr_Reg = '1') then next_State <= WR_Address;
else next_State <= RD_Address;
end if;
when Stop =>
SDA <= '0';
next_State <= Hold;
when Hold =>
SCL <= '1';
SDA <= '1';
if(wr = '0' and rd = '0') then next_State <= Idle;
else next_State <= Hold;
end if;
when WR_Address =>
SDA <= reg0WR0(8-i);
i <= iReg + 1;
if(i = 8) then next_State <= Ack2;
else next_State <= WR_Address;
end if;
when Ack2 =>
SDA <= 'Z';
next_State <= Write_Data;
when Write_Data =>
SDA <= slvData0(8-i);
i <= iReg + 1;
if(i = 8) then next_State <= Ack3;
else next_State <= Write_Data;
end if;
when Ack3 =>
SDA <= 'Z';
next_State <= Stop;
when RD_Address =>
SDA <= reg0RD0(8-i);
i <= iReg + 1;
if(i = 8) then next_State <= Ack4;
else next_State <= RD_Address;
end if;
when Ack4 =>
SDA <= 'Z';
next_State <= restartL;
when restartL =>
SCL <= '0';
SDA <= '1';
next_State <= restartR;
when restartR =>
SCL <= '1';
SDA <= not i2c_clk;
next_State <= Initiate_Read;
when Initiate_Read =>
SDA <= slaveRD0(8-i);
i <= iReg + 1;
if(i = 8) then next_State <= Ack5;
else next_State <= Initiate_Read;
end if;
when Ack5 =>
SDA <= 'Z';
next_State <= Read_Data;
when Read_Data =>
SDA <= 'Z';
i <= iReg + 1;
if(i = 8) then next_State <= noAck;
else next_State <= Read_Data;
end if;
when noAck =>
SDA <= '1';
next_State <= Stop;
end case;
end process;
process(clk50)
begin
if(rising_edge(clk50)) then
if(prev_State = Start) then wr_Reg <= WR;
end if;
end if;
end process;
process(i2c_clk)
begin
if(rising_edge(i2c_clk)) then
if(prev_State = Read_Data) then storeData(8-i) <= SDA;
end if;
end if;
--
-- if(falling_edge(i2c_clk)) then
-- if(prev_State = Read_Data and i = 8) then output <= storeData;
-- end if;
-- end if;
end process;
end FSM;
Here is the master just in case.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Your design is accessing SDA from different (unnamed) processes.
So write SDA just in one process, in case signal from one process to other what to do on SDA.
Curing this, can work anyway but you are not guaranteed external devices are high state. To avoid contention, never drive SDA nor SCK High, drive 'Z' or '0'.
FPGA work better on syncronous design, avoid ripple carry or clock crossing domain, generate enable instead.
it is optional but is better style name every process with a name. This can help identify logic and help read code:
example U1_SCK_edge_detect : process(clk, reset)
On my old books where written to avoid elsif rising_edge, goggling around also college site I seen a lot of example using
if reset then
elsif rising_edge(clk) then
This was discouraged on old school with nested if then else instead of if then elsif:
[processname:] process(clk,reset)
begin
if reset then
{reset action}
else
if risng_edge(clk) then
[if clk_enable then else end if]
end if;
end if;
end process;
Aout this no idea if exhibit side effect.
If this cannot solve your issue ask again.
Regards

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page