Skip to content

Commit

Permalink
RTC: Retry I2C transaction in case of error
Browse files Browse the repository at this point in the history
Occasionally the I2C transaction is seen to fail with a NACK. Th e fix
is to wait a short while (20 ms), and then repeat the transaction until
it works.
  • Loading branch information
MJoergen committed Jan 13, 2024
1 parent 42ac705 commit e8bfed6
Showing 1 changed file with 45 additions and 6 deletions.
51 changes: 45 additions & 6 deletions M2M/vhdl/i2c/rtc_master.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ end entity rtc_master;

architecture synthesis of rtc_master is

type cmd_t is (NOP_CMD, WRITE_CMD, WAIT_CMD, SHIFT_IN_CMD, SHIFT_OUT_CMD, END_CMD);
type cmd_t is (NOP_CMD, WRITE_CMD, WAIT_CMD, SHIFT_IN_CMD, SHIFT_OUT_CMD, VERIFY_CMD, END_CMD);
type action_t is record
cmd : cmd_t;
addr : std_logic_vector( 7 downto 0);
Expand Down Expand Up @@ -83,7 +83,7 @@ architecture synthesis of rtc_master is
6 => (WAIT_CMD, X"F1", X"0000"), -- Wait until I2C command is accepted
7 => (WAIT_CMD, X"F1", X"0001"), -- Wait until I2C is idle
8 => (SHIFT_IN_CMD, X"00", X"0004"), -- Read seven bytes from buffer
9 => (END_CMD, X"00", X"0000")
9 => (VERIFY_CMD, X"00", X"0000")
);

constant C_ACTION_LIST_WRITE_R3 : action_list_t := (
Expand Down Expand Up @@ -128,7 +128,7 @@ architecture synthesis of rtc_master is
6 => (WAIT_CMD, X"F1", X"0000"), -- Wait until I2C command is accepted
7 => (WAIT_CMD, X"F1", X"0001"), -- Wait until I2C is idle
8 => (SHIFT_IN_CMD, X"00", X"0004"), -- Read seven bytes from buffer
9 => (END_CMD, X"00", X"0000")
9 => (VERIFY_CMD, X"00", X"0000")
);

constant C_ACTION_LIST_WRITE_R456 : action_list_t := (
Expand Down Expand Up @@ -201,8 +201,8 @@ architecture synthesis of rtc_master is
constant C_ACTION_LIST_READ : action_list_t := get_action_list_read(G_BOARD);
constant C_ACTION_LIST_WRITE : action_list_t := get_action_list_write(G_BOARD);

type state_t is (RESET_ST, IDLE_ST, BUSY_ST);
signal state : state_t := IDLE_ST;
type state_t is (RESET_ST, IDLE_ST, BUSY_ST, VERIFY_ST);
signal state : state_t := RESET_ST;

signal action_idx : natural range 0 to 15;
signal action : action_t;
Expand All @@ -211,6 +211,25 @@ architecture synthesis of rtc_master is
signal rtc_write : std_logic_vector(71 downto 0);
signal write : std_logic;

constant C_SIM : boolean :=
-- synthesis translate_off
not
-- synthesis translate_on
false;

-- This does the same as the ternary operator "cond ? t : f" in the C language
pure function cond_select(cond : boolean; t : natural; f : natural) return natural is
begin
if cond then
return t;
else
return f;
end if;
end function cond_select;

constant C_COUNT_DOWN_MAX : natural := cond_select(C_SIM, 1_000, 1_000_000);
signal count_down : natural range 0 to C_COUNT_DOWN_MAX;

begin

rtc_busy_o <= '0' when state = IDLE_ST else '1';
Expand Down Expand Up @@ -311,12 +330,32 @@ begin
end if;
end if;

when VERIFY_CMD =>
count_down <= C_COUNT_DOWN_MAX;
rtc <= post_read(G_BOARD, rtc);
state <= VERIFY_ST;

when END_CMD =>
rtc <= post_read(G_BOARD, rtc);
state <= IDLE_ST;

end case; -- action.cmd
end if;

when VERIFY_ST =>
if rtc(47 downto 32) = X"0000" then
if count_down = 0 then
-- Reading from RTC did not work. Try again.
action_idx <= 0;
action <= C_ACTION_LIST_READ(0);
next_action <= '0';
state <= BUSY_ST;
write <= '0';
else
count_down <= count_down - 1;
end if;
else
state <= IDLE_ST;
end if;
end case; -- state

if next_action = '1' then
Expand Down

0 comments on commit e8bfed6

Please sign in to comment.