The default read values for each register should always be the same. If you get the same read read values every time, then it can be concluded that the I2C is working as expected.But sometime I get the value zero for other register set such as accelerometer or magnetometer.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY u_logic IS
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reset
i2c_busy : IN STD_LOGIC; --i2c busy signal (talking to i2c slave)
i2c_data_rd : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --data received from i2c slave
--i2c acknowledge error flag
i2c_ena : OUT STD_LOGIC; --latch command into i2c master
i2c_addr : OUT STD_LOGIC_VECTOR(6 DOWNTO 0); --i2c slave address
i2c_rw : OUT STD_LOGIC; --i2c read/write command
i2c_data_wr : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
data_in : IN STD_LOGIC_VECTOR(23 DOWNTO 0);
data_lcd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
); --data to write over the i2c bus
END u_logic;
ARCHITECTURE behavior OF u_logic IS
TYPE machine IS(ready, i2c, combine); --state machine datatype
SIGNAL state : machine; --current state
SIGNAL i2c_busy_prev : STD_LOGIC; --previous busy signal for i2c transactions
SIGNAL spi_rx_data : STD_LOGIC_VECTOR(24 DOWNTO 0);
BEGIN
PROCESS(clk, reset_n)
VARIABLE i2c_busy_cnt : INTEGER := 0; --keeps track of i2c busy signals during transaction
BEGIN
IF(reset_n = '0') THEN --reset asserted
i2c_busy_cnt := 0;
i2c_ena <= '0';
state <= ready;
ELSIF(clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN ready =>
state <= i2c;
WHEN i2c =>
i2c_busy_prev <= i2c_busy; --capture the value of the previous i2c busy signal
IF(i2c_busy_prev = '0' AND i2c_busy = '1') THEN --i2c busy just went high
i2c_busy_cnt := i2c_busy_cnt + 1; --counts the times busy has gone from low to high during transaction
END IF;
CASE i2c_busy_cnt IS --busy_cnt keeps track of which command we are on
WHEN 0 => --no command latched in yet
i2c_ena <= '1'; --initiate the transaction
i2c_addr <= data_in(23 DOWNTO 17); --slave address is this 7 bits of message
i2c_rw <= '0'; --write the name of the slave register to access
i2c_data_wr <= data_in(15 DOWNTO 8); --the slave register to access is these 8 bits
WHEN 1 => --1st busy high: command 1 latched, okay to issue command 2
i2c_ena <= '1';
i2c_rw <= data_in(16); --command to read or right the slave register is bit 16
i2c_data_wr <= data_in(7 DOWNTO 0); --data to write to register (i2c master ignores if it's a read)
WHEN 2 => --2nd busy high: command 2 latched, ready to stop
i2c_ena <= '0'; --deassert enable to stop transaction after command 2
IF(i2c_busy = '0') THEN --indicates command 2 is finished and any data is ready
IF(data_in(16) = '1') THEN --if it was a read
data_lcd(7 DOWNTO 0) <= i2c_data_rd; --retrieve data from command 2 into 8 LSBs of message
END IF;
i2c_busy_cnt := 0; --reset busy_cnt for next transaction
state <= ready; --transaction complete, load outcome into spi slave
END IF;
WHEN OTHERS => NULL;
END CASE;
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS;
END behavior;
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mpu6050_regs is
port (
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
i2c_busy : IN STD_LOGIC;
reg_data : OUT STD_LOGIC_VECTOR(23 downto 0)
);
end mpu6050_regs;
architecture behv_cd of mpu6050_regs is
TYPE machine IS(configs, reader);
SIGNAL state : machine;
SIGNAL i2c_busy_prev : STD_LOGIC;
begin
PROCESS(clk, reset)
VARIABLE count : INTEGER := 0;
BEGIN
IF(reset = '1') THEN
count := 0;
state <= configs;
ELSIF rising_edge(clk) THEN
CASE state IS
WHEN configs =>
i2c_busy_prev <= i2c_busy;
IF(i2c_busy_prev = '0' AND i2c_busy = '1') THEN count := count + 1; END IF;
CASE count IS
WHEN 0 => reg_data <= "1101000"&"0"&"00011001"&"00000111";--(0x19)
WHEN 1 => reg_data <= "1101000"&"0"&"01101011"&"00000001";--(0x6B)
WHEN 2 => reg_data <= "1101000"&"0"&"01101100"&"00000000";--(0x6C)
WHEN 3 => reg_data <= "1101000"&"0"&"00011010"&"00000000";--(0x1A)
WHEN 4 => reg_data <= "1101000"&"0"&"00011011"&"00011000";--(0x1B)
WHEN 5 => reg_data <= "1101000"&"0"&"00011100"&"00000000";--(0x1C)
WHEN 6 => reg_data <= "1101000"&"0"&"00100011"&"00000000";--(0x23)
WHEN 7 => reg_data <= "1101000"&"0"&"00111000"&"00000001";--(0x38)
WHEN 8 => reg_data <= "1101000"&"0"&"01101000"&"00000000";--(0x68)
WHEN 9 => reg_data <= "1101000"&"0"&"01101010"&"00000000";--(0x6A)
-- WHEN 10 => reg_data <= "1101000"&"1"&"01110101"&"00000000";--(0x75) who am I
WHEN 10 => state <= reader; count := 0;
WHEN OTHERS => NULL;
END CASE;
WHEN reader =>
i2c_busy_prev <= i2c_busy;
IF(i2c_busy_prev = '0' AND i2c_busy = '1') THEN count := count + 1; END IF;
CASE count IS
WHEN 0 => reg_data <= "1101000"&"1"&"01110101"&"00000000";--(0x75)
WHEN 1 => reg_data <= "1101000"&"1"&"00111011"&"00000000";--(0x3B)
WHEN 2 => reg_data <= "1101000"&"1"&"00111100"&"00000000";--(0x3c)
WHEN 3 => reg_data <= "1101000"&"1"&"00111101"&"00000000";--(0x3d)
WHEN 4 => reg_data <= "1101000"&"1"&"00111110"&"00000000";--(0x3e)
WHEN 5 => reg_data <= "1101000"&"1"&"00111111"&"00000000";--(0x3f)
WHEN 6 => reg_data <= "1101000"&"1"&"01000000"&"00000000";--(0x40)
WHEN 7 => reg_data <= "1101000"&"1"&"01000001"&"00000000";--(0x41)
WHEN 8 => reg_data <= "1101000"&"1"&"01000010"&"00000000";--(0x42)
WHEN 9 => state <= reader; count := 0;
WHEN OTHERS => NULL;
END CASE;
WHEN OTHERS => NULL;
END CASE;
END IF;
END PROCESS;
end behv_cd;
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY i2c_master IS
GENERIC(
input_clk : INTEGER := 50_000_000; --input clock speed from user logic in Hz
bus_clk : INTEGER := 400_000); --speed the i2c bus (scl) will run at in Hz
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reset
ena : IN STD_LOGIC; --latch in command
addr : IN STD_LOGIC_VECTOR(6 DOWNTO 0); --address of target slave
rw : IN STD_LOGIC; --'0' is write, '1' is read
data_wr : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --data to write to slave
busy : OUT STD_LOGIC; --indicates transaction in progress
data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave
ack_error : BUFFER STD_LOGIC; --flag if improper acknowledge from slave
sda : INOUT STD_LOGIC; --serial data output of i2c bus
scl : INOUT STD_LOGIC); --serial clock output of i2c bus
END i2c_master;
ARCHITECTURE logic OF i2c_master IS
CONSTANT divider : INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl
TYPE machine IS(ready, start, command, slv_ack1, wr, rd, slv_ack2, mstr_ack, stop); --needed states
SIGNAL state : machine; --state machine
SIGNAL data_clk : STD_LOGIC; --data clock for sda
SIGNAL data_clk_prev : STD_LOGIC; --data clock during previous system clock
SIGNAL scl_clk : STD_LOGIC; --constantly running internal scl
SIGNAL scl_ena : STD_LOGIC := '0'; --enables internal scl to output
SIGNAL sda_int : STD_LOGIC := '1'; --internal sda
SIGNAL sda_ena_n : STD_LOGIC; --enables internal sda to output
SIGNAL addr_rw : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in address and read/write
SIGNAL data_tx : STD_LOGIC_VECTOR(7 DOWNTO 0); --latched in data to write to slave
SIGNAL data_rx : STD_LOGIC_VECTOR(7 DOWNTO 0); --data received from slave
SIGNAL bit_cnt : INTEGER RANGE 0 TO 7 := 7; --tracks bit number in transaction
SIGNAL stretch : STD_LOGIC := '0'; --identifies if slave is stretching scl
BEGIN
--generate the timing for the bus clock (scl_clk) and the data clock (data_clk)
PROCESS(clk, reset_n)
VARIABLE count : INTEGER RANGE 0 TO divider*4; --timing for clock generation
BEGIN
IF(reset_n = '0') THEN --reset asserted
stretch <= '0';
count := 0;
ELSIF(clk'EVENT AND clk = '1') THEN
data_clk_prev <= data_clk; --store previous value of data clock
IF(count = divider*4-1) THEN --end of timing cycle
count := 0; --reset timer
ELSIF(stretch = '0') THEN --clock stretching from slave not detected
count := count + 1; --continue clock generation timing
END IF;
CASE count IS
WHEN 0 TO divider-1 => --first 1/4 cycle of clocking
scl_clk <= '0';
data_clk <= '0';
WHEN divider TO divider*2-1 => --second 1/4 cycle of clocking
scl_clk <= '0';
data_clk <= '1';
WHEN divider*2 TO divider*3-1 => --third 1/4 cycle of clocking
scl_clk <= '1'; --release scl
IF(scl = '0') THEN --detect if slave is stretching clock
stretch <= '1';
ELSE
stretch <= '0';
END IF;
data_clk <= '1';
WHEN OTHERS => --last 1/4 cycle of clocking
scl_clk <= '1';
data_clk <= '0';
END CASE;
END IF;
END PROCESS;
--state machine and writing to sda during scl low (data_clk rising edge)
PROCESS(clk, reset_n)
BEGIN
IF(reset_n = '0') THEN --reset asserted
state <= ready; --return to initial state
busy <= '1'; --indicate not available
scl_ena <= '0'; --sets scl high impedance
sda_int <= '1'; --sets sda high impedance
ack_error <= '0'; --clear acknowledge error flag
bit_cnt <= 7; --restarts data bit counter
data_rd <= "00000000"; --clear data read port
ELSIF(clk'EVENT AND clk = '1') THEN
IF(data_clk = '1' AND data_clk_prev = '0') THEN --data clock rising edge
CASE state IS
WHEN ready => --idle state
IF(ena = '1') THEN --transaction requested
busy <= '1'; --flag busy
addr_rw <= addr & rw; --collect requested slave address and command
data_tx <= data_wr; --collect requested data to write
state <= start; --go to start bit
ELSE --remain idle
busy <= '0'; --unflag busy
state <= ready; --remain idle
END IF;
WHEN start => --start bit of transaction
busy <= '1'; --resume busy if continuous mode
sda_int <= addr_rw(bit_cnt); --set first address bit to bus
state <= command; --go to command
WHEN command => --address and command byte of transaction
IF(bit_cnt = 0) THEN --command transmit finished
sda_int <= '1'; --release sda for slave acknowledge
bit_cnt <= 7; --reset bit counter for "byte" states
state <= slv_ack1; --go to slave acknowledge (command)
ELSE --next clock cycle of command state
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
sda_int <= addr_rw(bit_cnt-1); --write address/command bit to bus
state <= command; --continue with command
END IF;
WHEN slv_ack1 => --slave acknowledge bit (command)
IF(addr_rw(0) = '0') THEN --write command
sda_int <= data_tx(bit_cnt); --write first bit of data
state <= wr; --go to write byte
ELSE --read command
sda_int <= '1'; --release sda from incoming data
state <= rd; --go to read byte
END IF;
WHEN wr => --write byte of transaction
busy <= '1'; --resume busy if continuous mode
IF(bit_cnt = 0) THEN --write byte transmit finished
sda_int <= '1'; --release sda for slave acknowledge
bit_cnt <= 7; --reset bit counter for "byte" states
state <= slv_ack2; --go to slave acknowledge (write)
ELSE --next clock cycle of write state
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
sda_int <= data_tx(bit_cnt-1); --write next bit to bus
state <= wr; --continue writing
END IF;
WHEN rd => --read byte of transaction
busy <= '1'; --resume busy if continuous mode
IF(bit_cnt = 0) THEN --read byte receive finished
IF(ena = '1' AND addr_rw = addr & rw) THEN --continuing with another read at same address
sda_int <= '0'; --acknowledge the byte has been received
ELSE --stopping or continuing with a write
sda_int <= '1'; --send a no-acknowledge (before stop or repeated start)
END IF;
--
-- if(enable = '1') then
-----------
bit_cnt <= 7; --reset bit counter for "byte" states
data_rd <= data_rx; --output received data
state <= mstr_ack; --go to master acknowledge
----------------
-- else
-- data_rd <= "00000000";
-- end if;
ELSE --next clock cycle of read state
bit_cnt <= bit_cnt - 1; --keep track of transaction bits
state <= rd; --continue reading
END IF;
WHEN slv_ack2 => --slave acknowledge bit (write)
IF(ena = '1') THEN --continue transaction
busy <= '0'; --continue is accepted
addr_rw <= addr & rw; --collect requested slave address and command
data_tx <= data_wr; --collect requested data to write
IF(addr_rw = addr & rw) THEN --continue transaction with another write
sda_int <= data_wr(bit_cnt); --write first bit of data
state <= wr; --go to write byte
ELSE --continue transaction with a read or new slave
state <= start; --go to repeated start
END IF;
ELSE --complete transaction
state <= stop; --go to stop bit
END IF;
WHEN mstr_ack => --master acknowledge bit after a read
IF(ena = '1') THEN --continue transaction
busy <= '0'; --continue is accepted and data received is available on bus
addr_rw <= addr & rw; --collect requested slave address and command
data_tx <= data_wr; --collect requested data to write
IF(addr_rw = addr & rw) THEN --continue transaction with another read
sda_int <= '1'; --release sda from incoming data
state <= rd; --go to read byte
ELSE --continue transaction with a write or new slave
state <= start; --repeated start
END IF;
ELSE --complete transaction
state <= stop; --go to stop bit
END IF;
WHEN stop => --stop bit of transaction
busy <= '0'; --unflag busy
state <= ready; --go to idle state
END CASE;
ELSIF(data_clk = '0' AND data_clk_prev = '1') THEN --data clock falling edge
CASE state IS
WHEN start =>
IF(scl_ena = '0') THEN --starting new transaction
scl_ena <= '1'; --enable scl output
ack_error <= '0'; --reset acknowledge error output
END IF;
WHEN slv_ack1 => --receiving slave acknowledge (command)
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
ack_error <= '1'; --set error output if no-acknowledge
END IF;
WHEN rd => --receiving slave data
data_rx(bit_cnt) <= sda; --receive current slave data bit
WHEN slv_ack2 => --receiving slave acknowledge (write)
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
ack_error <= '1'; --set error output if no-acknowledge
END IF;
WHEN stop =>
scl_ena <= '0'; --disable scl
WHEN OTHERS =>
NULL;
END CASE;
END IF;
END IF;
END PROCESS;
--set sda output
WITH state SELECT
sda_ena_n <= data_clk_prev WHEN start, --generate start condition
NOT data_clk_prev WHEN stop, --generate stop condition
sda_int WHEN OTHERS; --set to internal sda signal
--set scl and sda outputs
scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0') ELSE 'Z';
sda <= '0' WHEN sda_ena_n = '0' ELSE 'Z';
END logic;
LIBRARY ieee;
USE ieee.std_logic_1164.all;
Library UNISIM;
use UNISIM.vcomponents.all;
ENTITY I2C_top IS
GENERIC(
sys_clk_frq : INTEGER := 50_000_000; --system clock speed in Hz
i2c_scl_frq : INTEGER := 400_000 --speed the i2c bus (scl) will run at in Hz
); --spi clock phase mode
PORT(
clk100 : IN STD_LOGIC; --system clock
reset : IN STD_LOGIC; --active low reset
scl : INOUT STD_LOGIC; --i2c serial clock
sda : INOUT STD_LOGIC;
i2c_ack_err : OUT STD_LOGIC;
led : OUT STD_LOGIC;
data_lcd : out STD_LOGIC_VECTOR(7 DOWNTO 0)
--node_scl : inout std_logic; --set pullups for these in ucf
-- node_sda : inout std_logic--set pullups for these in ucf
); --i2c serial data
END I2C_top;
ARCHITECTURE logic OF I2C_top IS
---components starts from here
--I2C slave component
--component I2C_slave is
-- generic (
-- SLAVE_ADDR : std_logic_vector(6 downto 0) := "0000011"); -- I added := "0000000" to get it to compile
-- port (
-- scl : inout std_logic;
-- sda : inout std_logic;
-- clk : in std_logic;
-- rst : in std_logic;
-- -- User interface
-- read_req : out std_logic;
-- data_to_master : in std_logic_vector(7 downto 0);
-- data_valid : out std_logic;
-- data_from_master : out std_logic_vector(7 downto 0));
--end component;
component mpu6050_regs is
port (
clk : IN STD_LOGIC;
reset : IN STD_LOGIC;
i2c_busy : IN STD_LOGIC;
reg_data : OUT STD_LOGIC_VECTOR(23 downto 0)
);
end component;
component i2c_master IS
GENERIC(
input_clk : INTEGER := 50_000_000; --input clock speed from user logic in Hz
bus_clk : INTEGER := 400_000); --speed the i2c bus (scl) will run at in Hz
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reset
ena : IN STD_LOGIC; --latch in command
addr : IN STD_LOGIC_VECTOR(6 DOWNTO 0); --address of target slave
rw : IN STD_LOGIC; --'0' is write, '1' is read
data_wr : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --data to write to slave
busy : OUT STD_LOGIC; --indicates transaction in progress
data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave
ack_error : BUFFER STD_LOGIC; --flag if improper acknowledge from slave
sda : INOUT STD_LOGIC; --serial data output of i2c bus
scl : INOUT STD_LOGIC); --serial clock output of i2c bus
END component;
component u_logic IS
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reset
i2c_busy : IN STD_LOGIC; --i2c busy signal (talking to i2c slave)
i2c_data_rd : IN STD_LOGIC_VECTOR(7 DOWNTO 0); --data received from i2c slave
--i2c acknowledge error flag
i2c_ena : OUT STD_LOGIC; --latch command into i2c master
i2c_addr : OUT STD_LOGIC_VECTOR(6 DOWNTO 0); --i2c slave address
i2c_rw : OUT STD_LOGIC; --i2c read/write command
i2c_data_wr : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
data_in : IN STD_LOGIC_VECTOR(23 DOWNTO 0);
data_lcd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)
); --data to write over the i2c bus
END component;
CONSTANT spi_d_width : INTEGER := 25; --spi data width in bits
SIGNAL i2c_ena : STD_LOGIC;
SIGNAL i2c_addr : STD_LOGIC_VECTOR(6 DOWNTO 0);
SIGNAL i2c_rw : STD_LOGIC;
SIGNAL i2c_data_wr : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL i2c_data_rd : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL i2c_busy : STD_LOGIC;
SIGNAL clock : STD_LOGIC;
SIGNAL reset_n : STD_LOGIC;
SIGNAL reg_data : STD_LOGIC_VECTOR(23 DOWNTO 0);
signal read_req : std_logic := '0';
signal data_to_master : std_logic_vector (7 downto 0) := "01010101";
signal data_valid : std_logic := '0';
signal data_from_master : std_logic_vector (7 downto 0) := (others => '0');
signal data_reg: std_logic_vector (7 downto 0);
signal ackerr: std_logic;
BEGIN
reset_n <= not reset;
led <= i2c_busy;
i2c_ack_err <= ackerr;
-- --- I2C slave
-- i2cSlave: I2C_slave generic map (
-- SLAVE_ADDR => "0000011")
-- port map(
-- scl => node_scl,
-- sda => node_sda,
-- clk => clk100,
-- rst => reset,
-- -- User interface
-- read_req => read_req,
-- data_to_master => data_to_master,
-- data_valid => data_valid,
-- data_from_master => data_from_master);
logic: u_logic PORT MAP(
clk => clk100,
reset_n => reset_n,
i2c_busy => i2c_busy,
i2c_data_rd => i2c_data_rd,
i2c_ena => i2c_ena,
i2c_addr => i2c_addr,
i2c_rw => i2c_rw,
i2c_data_wr => i2c_data_wr,
data_in => reg_data,
data_lcd => open
);
--instantiate registers for MPU6050
regs: mpu6050_regs PORT MAP(
clk => clk100,
reset => reset,
i2c_busy => i2c_busy,
reg_data => reg_data
);
--instantiate the i2c master
i_master: i2c_master
GENERIC MAP( input_clk => sys_clk_frq,
bus_clk => i2c_scl_frq )
PORT MAP(
clk => clk100,
reset_n => reset_n,
ena => i2c_ena,
addr => i2c_addr,
rw => i2c_rw,
data_wr => i2c_data_wr,
busy => i2c_busy,
data_rd => data_lcd,
-- data_rd => data_to_master,
-- ack_error => i2c_ack_err,
ack_error => ackerr,
sda => sda,
scl => scl
);
END logic;
Looking at state machine you never leave reader state! Unless reset.but sometimes it starts reading the registers, then it contiuously read.
With regards to your addressing.
Why do you only list the middle section?
WHEN 0 => reg_data <= "1101000"&"1"&"01110101"&"00000000";--(0x75)
24x"D1_75_00"
I would recommend chip scoping (integrated logic analyser) the signals of interest.
You're getting back data, Is the address what you expect it to be?
Looking at state machine you never leave reader state! Unless reset.
Review the burst read transaction description. You'll write a start register address, then read a number of consecutive registers while the address is auto-incremented. Stop the burst read transaction and repeat.I want to stay in the reader state as I am reading data continuously after the configuration.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?