element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
FPGA
  • Technologies
  • More
FPGA
Forum Vivado and Zynq: TRI-STATE help
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join FPGA to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • State Not Answered
  • +1 person also asked this people also asked this
  • Replies 31 replies
  • Subscribers 545 subscribers
  • Views 14354 views
  • Users 0 members are here
  • zynq
  • vivado
Related

Vivado and Zynq: TRI-STATE help

Jan Cumps
Jan Cumps over 3 years ago

I'm trying to write i2c code for Zynq, in VHDL.
I have difficulties creating a TRI-STATE pin.

The output logic should be: the pin is either pulled down to 0, or open-collector.
I have a pull-up resistor between that pin and VCC (3.3 V).
I'm expecting that if I write '0', it is low. When I write 'Z', it's open collector and pulled high by my pullup.
But in my design, the pin stays low. 0.62 V.

I thought, from reading up, that I should be done by:

  • defining the pin as INOUT
  • when you want to drive it low, assign '0'.
  • when you want to drive it open collector, assign 'Z'.
  • put an external pullup between pin and VCC

I created a testbed that puts the pin in "Z' mode, except when reset is asserted (via an external button).
In my testbed I also added a test pin, that I attach to an LED, that is high when the reset is asserted.
I connected a multimeter to the output.

The LED behaves as expected. It lights up when I assert the reset.
But the tri-state pin stays low, whether I write '0' or 'Z' to it. 

entity tristate_test is
    Port ( 
    reset_n: in std_logic;
    reset_out: out std_logic;
    tristate_pin : inout std_logic);
end tristate_test;

architecture Behavioral of tristate_test is

begin

reset_active: process (reset_n) is

begin
  if (reset_n = '0') then
    tristate_pin <= '0';
    reset_out <= '1';
  else
    tristate_pin <= 'Z';
    reset_out <= '0';
  end if;
end process reset_active;

end Behavioral;

Here is how I set the constraint:

image

set_property PACKAGE_PIN Y18 [get_ports tristate_pin_0]
set_property IOSTANDARD LVCMOS33 [get_ports tristate_pin_0]
set_property DRIVE 12 [get_ports tristate_pin_0]

Schema:

image

PMOD A pin 1 is PACKAGE_PIN Y18

What am I doing wrong?

  • Sign in to reply
  • Cancel

Top Replies

  • jc2048
    jc2048 over 3 years ago +4
    It might be a problem with hierarchy with the drag-and-drop stuff. An answer to this support question suggests that you need to set the synthesis to flatten the hierachy so that the tristate-ness can propagate…
  • jc2048
    jc2048 over 3 years ago in reply to bhfletcher +4
    Once you understand that the block-based design is an entity that could be used as part of a larger, more traditional design, the issue with the top-level wrapper becomes clearer. If the user is just using…
  • rachaelp
    rachaelp over 3 years ago +3
    Hi Jan, Just create the tristate in an assignment and not in a process. Not sure why what you have isn't working, have you looked at the schematic for what it's creating in Vivado? I guess maybe it's…
Parents
  • rachaelp
    0 rachaelp over 3 years ago

    Hi Jan,

    Just create the tristate in an assignment and not in a process. Not sure why what you have isn't working, have you looked at the schematic for what it's creating in Vivado? I guess maybe it's inferred a latch you aren't expecting maybe?

    tristate_pin <= '0' when reset_n = '0' else 'Z';
    reset_out <= '1' when reset_n = '0' else '0';

    Best Regards,

    Rachael

    • Cancel
    • Vote Up +3 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to rachaelp

    I tried it outside of a process too. Just assigned a fixed value 'Z' in the architecture. The effect was the same.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • rachaelp
    0 rachaelp over 3 years ago in reply to Jan Cumps

    It should be this simple, I've done several Xilinx designs recently, two targeting the Zynq Ultrascale+ and the above works for inferring the tri-state for me. There's nothing special I have needed to do in these to get Vivado to figure out the intention. I do always make sure my tri-states are at the top level of the hierarchy though so if the source is in a lower level I'll take an enable out of the lower level to the top level to control the tri-state.

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to rachaelp

    rachaelp, can you share the constraint file snippet that contains the config for the tri-state pin(s) for one of your Zynq projects?

    And if it's no trade secret: an example of where and how you set the state of that pin, in VHDL. 

    This is how I tried to implement the assignment out of process:
    The LED tied to reset_out works, the tri-state doesn't go to high impedance. 

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    entity tristate_test is
        Port ( 
        reset_n: in std_logic;
        reset_out: out std_logic;
        tristate_pin : inout std_logic);
    end tristate_test;
    
    architecture Behavioral of tristate_test is
    
    begin
    
    reset_active: process (reset_n) is
    
    begin
    null;
    end process reset_active;
    
    tristate_pin <= '0' when reset_n = '0' else 'Z';
    reset_out <= '1' when reset_n = '0' else '0';
    
    end Behavioral;

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • rachaelp
    0 rachaelp over 3 years ago in reply to Jan Cumps

    The constraints file literally has nothing but the IO standard and the pin number assigned to the signal, I don't need to do anything special at all.

    I'll see if I can dig out some code snippets tomorrow, usually my control signals will come out of a clocked process, often a state machine.

    Have you tried looking in the implementation schematic to see what it's actually created? I've had to dig through that to figure out what it's done previously.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to rachaelp

    Checking the schematic. Highest level:

    image

    Drill down (red square is my annotation):

    image

    It indeed does not look like a bidirectional buffer with 3 states ... just a plain output driver with flip-flop in front of it 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Reply
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to rachaelp

    Checking the schematic. Highest level:

    image

    Drill down (red square is my annotation):

    image

    It indeed does not look like a bidirectional buffer with 3 states ... just a plain output driver with flip-flop in front of it 

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
Children
  • jc2048
    0 jc2048 over 3 years ago in reply to Jan Cumps

    What happens if you add to your code a line to also read from the INOUT port (and do something with it so it doesn't get optimised away - perhaps just send it out to another IO pin)? Do you then get an IOBUF on the schematic view or does it leave it with an OBUF and do the readback from before the buffer?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • jc2048
    0 jc2048 over 3 years ago in reply to Jan Cumps

    https://www.xilinx.com/support/documentation/sw_manuals/xilinx2019_1/ug994-vivado-ip-subsystems.pdf

    Page 100 of this document talks about a wrapper around the block design, so it looks like this might be Xilinx's approach to dealing with the top-level entity problem which you'd otherwise have with the block designer tool. It looks like the three connections to the IOBUF need to be brought out of the block in a certain form for the tool to recognise properly. You might just try bringing the signals for the IOBUF out of your port with the external pin name and either '_I', '_O', or '_T' appended for the three signals you'll require to connect to the pin buffer and see if it all magically works. If not, you'll need to read up on wrappers and work out how you apply it or access it, or whatever you're supposed to do.

    Keep in mind I have absolutely no experience of Vivado, nor the block designer tool, so this could be totally wrong and not helpful at all, but it does kind of make sense that they'd need to do something along these lines.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to jc2048

    I'm reading up. There's no IOBUF block that I can add on the block design - been searching for that.

    Keep in mind I have absolutely no experience of Vivado, nor the block designer tool,

    I have experience with the things that work. Once I get into trouble, I'm not familiar enough yet to self-solve.
    Previous mishaps I could fix with a mix of documentation and Google. For this one that path wasn't successful. That's when I branched off into this forum question.

    I'll get back when I have the outcome of the experiments above ...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to Jan Cumps

    Currently at Tristate Description Using Combinatorial Process Implemented with OBUFT Coding Example (VHDL) 

    Page 81

    ...

    --
     port(
     T : in std_logic;
     I : in std_logic;
     O : out std_logic
     );
    --
     process(I, T)
     begin
       if (T = '0') then
         O <= I;
       else
         O <= 'Z';
       end if;
     end process;
    --

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to Jan Cumps

    This hasn't brought me farther.... I tried pins with name_T, name_I, name_O and couldn't get the wrapper to auto_generate a buffer.
    Read some more, tried to instantiate a Utility Buffer myself. But I could not turn it into a working design. 

    Current approach: I cloned Xilinx' PYNQ repository, and I'm regenerating the BASE overlay project.
    It implements an I2C on the Arduino header - hoping that I can learn from that.
    Not sure though - I thought by reviewing this the last time, that they use a bespoke Xilinx I2C IP...

    image

    image: regenerate the PYNQ base overlay project from source, in Windows Sublayer for Linux.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • jc2048
    0 jc2048 over 3 years ago in reply to Jan Cumps

    "I tried pins with name_T, name_I, name_O"

    What did the schematic view show when you did that? Was there still just an OBUF attached to name_O? Did it do anything with the other two?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to jc2048

    When I generated the wrapper - the moment where I was expecting magic to happen -I get errors for unconnected pins.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • jc2048
    0 jc2048 over 3 years ago in reply to Jan Cumps

    What does your tristate_test code in the block look like now? Can you show it to us?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • Jan Cumps
    0 Jan Cumps over 3 years ago in reply to jc2048

    The IP code  - one of the many incarnations. I tried different combinations, directions, with and without process:

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    
    entity tristate_test is
        Port ( 
        reset_n: in std_logic;
        reset_out: out std_logic;
        tri_T : out std_logic;
        tri_I : in std_logic;    
        tri_O : out std_logic);
    end tristate_test;
    
    architecture Behavioral of tristate_test is
    
    begin
    
    reset_active: process (reset_n) is
    
    begin
    null;
    end process reset_active;
    
     
    reset_out <= '1' when reset_n = '0' else '0';
    tri_O <= 'Z' when reset_n = '0' else '0';
    tri_T <= '1' when reset_n = '0' else '0';
    
    end Behavioral;

    The block design - I deliberately do not make ports external or assign a pin to them, because the manual says they need to be unconnected and not external

    image

    The wrapper code and the error message generated while wrapping:

    image

    --Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.
    ----------------------------------------------------------------------------------
    --Tool Version: Vivado v.2020.2 (win64) Build 3064766 Wed Nov 18 09:12:45 MST 2020
    --Date        : Wed Feb  9 11:15:06 2022
    --Host        : paradise3 running 64-bit major release  (build 9200)
    --Command     : generate_target design_1_wrapper.bd
    --Design      : design_1_wrapper
    --Purpose     : IP block netlist
    ----------------------------------------------------------------------------------
    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    library UNISIM;
    use UNISIM.VCOMPONENTS.ALL;
    entity design_1_wrapper is
      port (
        DDR_addr : inout STD_LOGIC_VECTOR ( 14 downto 0 );
        DDR_ba : inout STD_LOGIC_VECTOR ( 2 downto 0 );
        DDR_cas_n : inout STD_LOGIC;
        DDR_ck_n : inout STD_LOGIC;
        DDR_ck_p : inout STD_LOGIC;
        DDR_cke : inout STD_LOGIC;
        DDR_cs_n : inout STD_LOGIC;
        DDR_dm : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        DDR_dq : inout STD_LOGIC_VECTOR ( 31 downto 0 );
        DDR_dqs_n : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        DDR_dqs_p : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        DDR_odt : inout STD_LOGIC;
        DDR_ras_n : inout STD_LOGIC;
        DDR_reset_n : inout STD_LOGIC;
        DDR_we_n : inout STD_LOGIC;
        FIXED_IO_ddr_vrn : inout STD_LOGIC;
        FIXED_IO_ddr_vrp : inout STD_LOGIC;
        FIXED_IO_mio : inout STD_LOGIC_VECTOR ( 53 downto 0 );
        FIXED_IO_ps_clk : inout STD_LOGIC;
        FIXED_IO_ps_porb : inout STD_LOGIC;
        FIXED_IO_ps_srstb : inout STD_LOGIC;
        btnRst : in STD_LOGIC_VECTOR ( 0 to 0 );
        reset_out_0 : out STD_LOGIC
      );
    end design_1_wrapper;
    
    architecture STRUCTURE of design_1_wrapper is
      component design_1 is
      port (
        btnRst : in STD_LOGIC_VECTOR ( 0 to 0 );
        DDR_cas_n : inout STD_LOGIC;
        DDR_cke : inout STD_LOGIC;
        DDR_ck_n : inout STD_LOGIC;
        DDR_ck_p : inout STD_LOGIC;
        DDR_cs_n : inout STD_LOGIC;
        DDR_reset_n : inout STD_LOGIC;
        DDR_odt : inout STD_LOGIC;
        DDR_ras_n : inout STD_LOGIC;
        DDR_we_n : inout STD_LOGIC;
        DDR_ba : inout STD_LOGIC_VECTOR ( 2 downto 0 );
        DDR_addr : inout STD_LOGIC_VECTOR ( 14 downto 0 );
        DDR_dm : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        DDR_dq : inout STD_LOGIC_VECTOR ( 31 downto 0 );
        DDR_dqs_n : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        DDR_dqs_p : inout STD_LOGIC_VECTOR ( 3 downto 0 );
        FIXED_IO_mio : inout STD_LOGIC_VECTOR ( 53 downto 0 );
        FIXED_IO_ddr_vrn : inout STD_LOGIC;
        FIXED_IO_ddr_vrp : inout STD_LOGIC;
        FIXED_IO_ps_srstb : inout STD_LOGIC;
        FIXED_IO_ps_clk : inout STD_LOGIC;
        FIXED_IO_ps_porb : inout STD_LOGIC;
        reset_out_0 : out STD_LOGIC
      );
      end component design_1;
    begin
    design_1_i: component design_1
         port map (
          DDR_addr(14 downto 0) => DDR_addr(14 downto 0),
          DDR_ba(2 downto 0) => DDR_ba(2 downto 0),
          DDR_cas_n => DDR_cas_n,
          DDR_ck_n => DDR_ck_n,
          DDR_ck_p => DDR_ck_p,
          DDR_cke => DDR_cke,
          DDR_cs_n => DDR_cs_n,
          DDR_dm(3 downto 0) => DDR_dm(3 downto 0),
          DDR_dq(31 downto 0) => DDR_dq(31 downto 0),
          DDR_dqs_n(3 downto 0) => DDR_dqs_n(3 downto 0),
          DDR_dqs_p(3 downto 0) => DDR_dqs_p(3 downto 0),
          DDR_odt => DDR_odt,
          DDR_ras_n => DDR_ras_n,
          DDR_reset_n => DDR_reset_n,
          DDR_we_n => DDR_we_n,
          FIXED_IO_ddr_vrn => FIXED_IO_ddr_vrn,
          FIXED_IO_ddr_vrp => FIXED_IO_ddr_vrp,
          FIXED_IO_mio(53 downto 0) => FIXED_IO_mio(53 downto 0),
          FIXED_IO_ps_clk => FIXED_IO_ps_clk,
          FIXED_IO_ps_porb => FIXED_IO_ps_porb,
          FIXED_IO_ps_srstb => FIXED_IO_ps_srstb,
          btnRst(0) => btnRst(0),
          reset_out_0 => reset_out_0
        );
    end STRUCTURE;
    

    The buffer wasn't instantiated. I was expecting that to happen because the pins _I, _O and _T are available

    Schematic after synthesis:

    image

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
  • jc2048
    0 jc2048 over 3 years ago in reply to Jan Cumps

    Line 25. Just set tri_O to '0' (the level you want at the output of the IOBUF, when it's enabled, to give you your pretend open-drain output). The tristating is done by the external buffer, not at the block's port.

    It's possible you might need to do something with the tri_I. Perhaps just take the value that comes from it and then push it back out on another output like you've done with the reset_n. I'm saying that just in case it gets optimised away as not doing anything and then the rest gets upset because it isn't there any longer.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Verify Answer
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube