This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

PCA9548A: Issue with IIC Configuration Using AXI-IIC: Only One 9-bit Transmission with NACK Signal After RESET

Part Number: PCA9548A

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.