I am experiencing an issue while configuring the IIC with AXI-IIC. After I set the RESET pin high, only one 9-bit piece of information is transmitted on the SCL and SDA lines. The last bit of this transmission is a NACK signal. Despite multiple attempts, I am unable to successfully configure the IIC.
Here are the codes and cores I've used:
-- Title : IIC Controller for KC705 clock setup
-- Project : cpri_v6_1
-----------------------------------------------------------------------
-- File : iic_controller.vhd
-- Author : Xilinx
-----------------------------------------------------------------------
-- Description:
-- This module generates IIC commands to set up the Si570 and Si5326
-- Clock generation on the KC705 board to provide CPRI GT reference
-- clock
--
-----------------------------------------------------------------------
-- (c) Copyright 2004 - 2012 Xilinx, Inc. All rights reserved.
--
-- This file contains confidential and proprietary information
-- of Xilinx, Inc. and is protected under U.S. and
-- international copyright and other intellectual property
-- laws.
--
-- DISCLAIMER
-- This disclaimer is not a license and does not grant any
-- rights to the materials distributed herewith. Except as
-- otherwise provided in a valid license issued to you by
-- Xilinx, and to the maximum extent permitted by applicable
-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
-- (2) Xilinx shall not be liable (whether in contract or tort,
-- including negligence, or under any other theory of
-- liability) for any loss or damage of any kind or nature
-- related to, arising under or in connection with these
-- materials, including for any direct, or any indirect,
-- special, incidental, or consequential loss or damage
-- (including loss of data, profits, goodwill, or any type of
-- loss or damage suffered as a result of any action brought
-- by a third party) even if such damage or loss was
-- reasonably foreseeable or Xilinx had been advised of the
-- possibility of the same.
--
-- CRITICAL APPLICATIONS
-- Xilinx products are not designed or intended to be fail-
-- safe, or for use in any application requiring fail-safe
-- performance, such as life-support or safety devices or
-- systems, Class III medical devices, nuclear facilities,
-- applications related to the deployment of airbags, or any
-- other applications that could lead to death, personal
-- injury, or severe property or environmental damage
-- (individually and collectively, "Critical
-- Applications"). Customer assumes the sole risk and
-- liability of any use of Xilinx products in Critical
-- Applications, subject only to applicable laws and
-- regulations governing limitations on product liability.
--
-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
-- PART OF THIS FILE AT ALL TIMES.
-----------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity iic_controller is
port (
reset : in std_logic;
clk100 : in std_logic; -- 100 MHz system clock
iic_sda : inout std_logic;
iic_scl : inout std_logic;
done : out std_logic
);
end iic_controller;
architecture rtl of iic_controller is
-- AXI IIC controller component (from EDK)
component axi_iic_control
port (
S_AXI_ACLK : in std_logic;
S_AXI_ARESETN : in std_logic;
IIC2INTC_Irpt : out std_logic;
S_AXI_AWADDR : in std_logic_vector(31 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
S_AXI_WDATA : in std_logic_vector(31 downto 0);
S_AXI_WSTRB : in std_logic_vector(3 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
S_AXI_BRESP : out std_logic_vector(1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
S_AXI_ARADDR : in std_logic_vector(31 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
S_AXI_RDATA : out std_logic_vector(31 downto 0);
S_AXI_RRESP : out std_logic_vector(1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic;
tx_fifo_empty : out std_logic;
bus_busy : out std_logic;
Sda_I : in std_logic;
Sda_O : out std_logic;
Sda_T : out std_logic;
Scl_I : in std_logic;
Scl_O : out std_logic;
Scl_T : out std_logic;
Gpo : out std_logic_vector(0 downto 0)
);
end component;
-------------------------------------------------------------------------------
-- Command look up table format
-------------------------------------------------------------------------------
--
-- The total number of IIC commands is indicated in the first entry.
-- Each subsequent entry indicates the AXI IIC core target address and target data.
--
-- Refer to AXI IIC core DS756 for addresses and tx_fifo format.
--
-- for example,
-- - entry 1 writes 0x0001 to address 0x100
-- - entry 2 writes 0x01e8 to address 0x108
--
-- AXI IIC controller registers :
-- x0100 - Control Register
-- x0108 - Tx FIFO bit 8 = Start, Bit 9 = Stop, 7:0 = Data
signal cmd_rom : t_cmd_rom := (
0 => X"0000_0039", -- Total IIC commands in table
--
1 => X"0100_0001", -- enable AXI IIC core
-----------------------------------------------
-- PCA9548 IIC switch Addr = 74
-----------------------------------------------
2 => X"0108_01e8", -- addr = 74 (shifted up 1 bit - bit 0 = rw)
3 => X"0108_0281", -- channel 7 enabled (Si5324/Si5326)
-- channel 0 enabled (Si570)
-----------------------------------------------
-- Si5326 Jitter Attenuator Addr = 68
-----------------------------------------------
4 => X"0108_01d0", -- Register 0
5 => X"0108_0000", -- setup Si5326 for
6 => X"0108_0254", -- free run mode
-- Set N1_HS output divider
7 => X"0108_01d0",
8 => X"0108_0019", -- Register 25
9 => X"0108_0280", -- N1_HS = 8 (0b101)
-- Transceiver is clocked from CLKOUT1 from Si5324/5326.
-- Set the CLKOUT1 divider here.
10 => X"0108_01d0",
11 => X"0108_001f", -- Register 31
12 => X"0108_0200", -- NC1_LS[19:16] = 4 (0x00)
13 => X"0108_01d0",
14 => X"0108_0020", -- Register 32
15 => X"0108_0200", -- NC1_LS[15:8] = 4 (0x00)
16 => X"0108_01d0",
17 => X"0108_0021", -- Register 33
18 => X"0108_0203", -- NC1_LS[7:0] = 4 (0x03)
-- Set the PLL divider to 8 * 312
19 => X"0108_01d0",
20 => X"0108_0028", -- Register 40
21 => X"0108_0280", -- N2_HS = 8, N2_LS[19:16] = 336 (0x00)
22 => X"0108_01d0",
23 => X"0108_0029", -- Register 41
24 => X"0108_0201", -- N2_LS[15:8] = 336 (0x51)
25 => X"0108_01d0",
26 => X"0108_002A", -- Register 42
27 => X"0108_024F", -- N2_LS[7:0] = 336 (0x4F)
-- The recovered clock from the FPGA to the CLKIN1 input of the Si5324/5326
-- is set at 30.72MHz. Divide this by 1301 to get the correct input
-- to the PLL.
28 => X"0108_01d0",
29 => X"0108_002B", -- Register 43
30 => X"0108_0200", -- N31[18:16] = 84 (0x00)
31 => X"0108_01d0",
32 => X"0108_002C", -- Register 44
33 => X"0108_0200", -- N31[15:8] = 84 (0x05)
34 => X"0108_01d0",
35 => X"0108_002D", -- Register 45
36 => X"0108_0253", -- N31[7:0] = 84 (0x14)
-- The free running oscillator runs at 114.285MHz. Divide this by
-- 4840 to get the correct input to the PLL
37 => X"0108_01d0",
38 => X"0108_002E", -- Register 46
39 => X"0108_0200", -- N32[18:16] = 60 (0x00)
40 => X"0108_01d0",
41 => X"0108_002F", -- Register 47
42 => X"0108_0200", -- N32[18:16] = 60 (0x12)
43 => X"0108_01d0",
44 => X"0108_0030", -- Register 48
45 => X"0108_023B", -- N32[7:0] = 60 (0xE7)
-- Set the auto-select mode to "Automatic Revertive" and
-- program LOCK settings
46 => X"0108_01d0",
47 => X"0108_0004", -- Register 4
48 => X"0108_0292", -- AUTOSEL_REG[1:0] = 0b10
49 => X"0108_01d0",
50 => X"0108_0013", -- Register 19
51 => X"0108_0229", -- LOCKT[2:0] = 0b001
52 => X"0108_01d0",
53 => X"0108_0089", -- Register 137
54 => X"0108_0201", -- FASTLOCK = 1
-- Perform an internal calibration
55 => X"0108_01d0",
56 => X"0108_0088", -- Register 136
57 => X"0108_0240", -- ICAL = 1
others => (others => '0')
);
type state_type is (START, IDLE, AXI_WRITE, AXI_RESP, FINISH);
signal axi_state : state_type := START;
signal lut_address : unsigned(LUT_AWIDTH-1 downto 0);
signal lut_commands : unsigned(LUT_AWIDTH-1 downto 0);
signal lut_data : std_logic_vector(31 downto 0);
signal axi_areset_n : std_logic;
signal iic2intc_irpt : std_logic;
signal s_axi_awaddr : std_logic_vector(31 downto 0);
signal s_axi_awvalid : std_logic;
signal s_axi_awready : std_logic;
signal s_axi_wdata : std_logic_vector(31 downto 0);
signal s_axi_wstrb : std_logic_vector( 3 downto 0);
signal s_axi_wvalid : std_logic;
signal s_axi_wready : std_logic;
signal s_axi_bresp : std_logic_vector( 1 downto 0);
signal s_axi_bvalid : std_logic;
signal s_axi_bready : std_logic;
signal s_axi_araddr : std_logic_vector(31 downto 0);
signal s_axi_arvalid : std_logic;
signal s_axi_arready : std_logic;
signal s_axi_rdata : std_logic_vector(31 downto 0);
signal s_axi_rresp : std_logic_vector( 1 downto 0);
signal s_axi_rvalid : std_logic;
signal s_axi_rready : std_logic;
signal tx_fifo_empty : std_logic;
signal bus_busy : std_logic;
signal sda_buf : std_logic;
signal scl_buf : std_logic;
signal sda_o : std_logic;
signal scl_o : std_logic;
signal sda_t : std_logic;
signal scl_t : std_logic;
signal sda_i : std_logic;
signal scl_i : std_logic;
begin
-- Synchronous read on rom to improve timing
process(clk100)
begin
if rising_edge(clk100) then
-- register rom data output
lut_data <= cmd_rom(to_integer(lut_address));
end if;
end process;
-------------------------------------------------------------------------------
-- State machine for controlling writes to the AXI IIC core
p_mgmnt_states : process(clk100, reset)
begin
if (reset = '1') then
axi_state <= START;
s_axi_awaddr <= (others => '0');
s_axi_awvalid <= '0';
s_axi_wstrb <= (others => '0');
s_axi_wvalid <= '0';
s_axi_bready <= '0';
s_axi_araddr <= (others => '0');
s_axi_arvalid <= '0';
s_axi_rready <= '0';
lut_address <= (others => '0');
done <= '0';
elsif rising_edge(clk100) then
case axi_state is
when START =>
-- Read the command count from location 0 in the LUT
if (lut_address = 1) then
axi_state <= IDLE;
end if;
lut_commands <= unsigned(lut_data(LUT_AWIDTH-1 downto 0));
lut_address <= to_unsigned(1, lut_address'length);
done <= '0';
when IDLE =>
-- write
s_axi_awaddr <= (others => '0');
s_axi_awvalid <= '0';
s_axi_wstrb <= (others => '0');
s_axi_wvalid <= '0';
s_axi_bready <= '0';
-- read
s_axi_araddr <= (others => '0');
s_axi_arvalid <= '0';
s_axi_rready <= '0';
done <= '0';
if (lut_commands = 0) then
axi_state <= FINISH;
else
-- bit 8 from LUT is 'START' bit indicating a new IIC command
-- so we ensure the bus is not busy and the Tx FIFO is empty
-- otherwise, just write data to the Tx FIFO
if ( (lut_data(8) = '1') and (tx_fifo_empty = '1') and (bus_busy = '0') ) or
( (lut_data(8) = '0') ) then
-- Write operation, post address and data
axi_state <= AXI_WRITE;
s_axi_awaddr(15 downto 0) <= lut_data(31 downto 16);
s_axi_awvalid <= '1';
s_axi_wdata(15 downto 0) <= lut_data(15 downto 00);
s_axi_wstrb <= (others => '1');
s_axi_wvalid <= '1';
end if;
end if;
when AXI_WRITE =>
if (s_axi_wready = '1') and (s_axi_awready = '1') then
axi_state <= AXI_RESP;
s_axi_wstrb <= (others => '0');
s_axi_awvalid <= '0';
s_axi_wvalid <= '0';
s_axi_bready <= '1';
lut_commands <= lut_commands - 1;
lut_address <= lut_address + 1;
end if;
when AXI_RESP =>
if (s_axi_bvalid = '1') then
axi_state <= IDLE;
s_axi_bready <= '0';
end if;
when FINISH =>
-- all commands executed, flag complete and hibernate
done <= '1';
end case;
end if;
end process;
-------------------------------------------------------------------------------
-- IIC control - uses AXI IIC controller
axi_areset_n <= not reset;
iic_ctrl : axi_iic_control
port map (
S_AXI_ACLK => clk100,
S_AXI_ARESETN => axi_areset_n,
IIC2INTC_Irpt => iic2intc_irpt,
-- write port
S_AXI_AWADDR => s_axi_awaddr,
S_AXI_AWVALID => s_axi_awvalid,
S_AXI_AWREADY => s_axi_awready,
S_AXI_WDATA => s_axi_wdata,
S_AXI_WSTRB => s_axi_wstrb,
S_AXI_WVALID => s_axi_wvalid,
S_AXI_WREADY => s_axi_wready,
S_AXI_BRESP => s_axi_bresp,
S_AXI_BVALID => s_axi_bvalid,
S_AXI_BREADY => s_axi_bready,
-- read port
S_AXI_ARADDR => s_axi_araddr,
S_AXI_ARVALID => s_axi_arvalid,
S_AXI_ARREADY => s_axi_arready,
S_AXI_RDATA => s_axi_rdata,
S_AXI_RRESP => s_axi_rresp,
S_AXI_RVALID => s_axi_rvalid,
S_AXI_RREADY => s_axi_rready,
-- extra status signals
tx_fifo_empty => tx_fifo_empty,
bus_busy => bus_busy,
Sda_I => sda_i,
Sda_O => sda_o,
Sda_T => sda_t,
Scl_I => scl_i,
Scl_O => scl_o,
Scl_T => scl_t,
Gpo => open
);
-- tristate buffers for IIC interface
sda_i <= iic_sda;
scl_i <= iic_scl;
sda_buf <= sda_o when (sda_t = '0') else 'Z';
scl_buf <= scl_o when (scl_t = '0') else 'Z';
iic_sda <= sda_buf;
iic_scl <= scl_buf;
end rtl;
within which I invoke the file AXI-IIC.
Here are the steps I've taken:
- I have set up the hardware as per the manufacturer's guidelines.
- For configuration, I followed the steps outlined in the datasheet, including setting specific registers and initialization sequences. The IIC slave bus address I use is 74(hexadecimal).
- I observed the SCL and SDA lines using an oscilloscope, which confirmed the single 9-bit transmission with the final bit as a NACK.
I am unsure what might be causing this problem and would appreciate any insights or suggestions on how to resolve it.
Thank you in advance for your help! Best regards.