- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all,
I am a beginner, trying to implement a One-wire CAN bus coupler logic on a Cyclone IV FPGA. The FPGA communicates to a disconnectable external slave device via a pin using CAN bus. The pin can be configured as an Input/Output or Bidirectional at anytime. However I am facing issues trying to simulate just the IO pin on modelsim. Setup:- slave device drives the wire using open drain (bus is normally high, slave device pulls it down during communication)
- weak pull up resistor enabled for IO pin on FPGA. (to pull the pin high when the slave device is removed)
LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY bidir_port IS
PORT(
bidir : INOUT STD_LOGIC; --to bidirectional pin
oe_ie : IN STD_LOGIC_VECTOR(1 downto 0); --direction select
clk : IN STD_LOGIC; --to clock the registers
inp : IN STD_LOGIC; --input from logic
outp : OUT STD_LOGIC --output to logic
);
END bidir_port;
ARCHITECTURE logic OF bidir_port IS
SIGNAL a : STD_LOGIC; -- DFF that stores
SIGNAL b : STD_LOGIC; -- DFF that stores
BEGIN
PROCESS(clk)
BEGIN
if clk='1' and clk'event then
a <= inp;
outp <= b;
END IF;
END PROCESS;
PROCESS (oe_ie, bidir,a,inp) -- Behavioral representation
BEGIN -- of tri-states.
case oe_ie is
when "00" => -- no connection
bidir <= 'Z';
b <= '1';
when "01" => -- output
bidir <= a;
b <='1' ;
when "10" => -- input
bidir <= 'Z';
b <= to_X01(bidir);
when "11" =>
bidir <= a;
b <= to_X01(bidir);
when others =>
bidir <= 'Z';
b <= to_X01(bidir);
end case;
END PROCESS;
END logic;
I have driven the bidirectional pin on the test bench using 'H' logic to signify weak pull up. In simulation the output will be "X" undefined if the both devices are driving the wire as well. Picture: https://www.alteraforum.com/forum/attachment.php?attachmentid=7712 I realised that if i changed my code to use 'H' instead of '1' when driving the bus, the simulation appears better. LIBRARY ieee;
USE ieee.std_logic_1164.all;
ENTITY bidir_port IS
PORT(
bidir : INOUT STD_LOGIC;
oe_ie : IN STD_LOGIC_VECTOR(1 downto 0);
clk : IN STD_LOGIC;
inp : IN STD_LOGIC;
outp : OUT STD_LOGIC
);
END bidir_port;
ARCHITECTURE logic OF bidir_port IS
SIGNAL a : STD_LOGIC; -- DFF that stores
SIGNAL b : STD_LOGIC; -- DFF that stores
BEGIN
PROCESS(clk)
BEGIN
if clk='1' and clk'event then
a <= inp;
outp <= b;
END IF;
END PROCESS;
PROCESS (oe_ie, bidir,a,inp) -- Behavioral representation
BEGIN -- of tri-states.
case oe_ie is
when "00" => -- no connection
bidir <= 'Z';
b <= '1';
when "01" => -- output
if a = '1' then
bidir <= 'H';
else
bidir <= '0';
end if;
b <='1' ;
when "10" => -- input
bidir <= 'Z';
b <= to_X01(bidir);
when "11" =>
if a = '1' then
bidir <= 'H';
else
bidir <= '0';
end if;
--bidir <= a;
b <= to_X01(bidir);
when others =>
bidir <= 'Z';
b <= to_X01(bidir);
end case;
END PROCESS;
END logic;
Picture: https://www.alteraforum.com/forum/attachment.php?attachmentid=7713 My question is: - Is it correct to use 'H' in my code just because it does not appear right in the simulation. The RTL block diagram does not appear different between the two versions of my code. I cannot understand having a 'weak pull up' signal in the FPGA.
- I also learnt that to convert the 'H' to a 'strong' logic level of '0' or '1' I am supposed to use the to_X01() function. How is this function handled during synthesizing?
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The first thing is that you need to model the open-drain and the pull-up separately.
You should have a testbench which models the pull up by always driving the signal with a weak high, while also connecting it to slaves.bidir_bus_signal <= 'H';
slave1 : my_slave
port map (
...
bidir_port => bidir_signal,
...
);
Then, inside your slave_controller, you implement the open drain by driving the port with either '0' or 'Z'.
bidir_port_i <= to_x01(bidir_port);
bidir_port <= '0' when bidir_port_oe = '1' and bidir_port_o = '0' else 'Z';
Your slave logic should drive the bidir_port_oe and bidir_port_o signals to drive the output and it should read from bidir_port_i to read the input. A couple of implementation details: - Quartus knows the code template above and it will set the I/O driver to open-drain. - In FPGAs, do not use tri-state logic outside the top level module. Instead, if you need to connect your bidir_port to modules inside your toplevel, use the trio of bidir_port_i, bidir_port_oe and bidir_port_o.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks! I will try it out and update here.
--- Quote Start --- In FPGAs, do not use tri-state logic outside the top level module. Instead, if you need to connect your bidir_port to modules inside your toplevel, use the trio of bidir_port_i, bidir_port_oe and bidir_port_o. --- Quote End --- On the above point, is it important for me to put the tristate code on the top level, even if my bidir_port module's bidir signal is connected directly to the output pin on the top level?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
For those simple cases, Quartus seems to do the correct thing.
So, I would say it's not important. But I'd still advise it.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have some queries on bidirectional port as per the code is in post# 1.
Is it possible receive data from the slave without driving the bidirectional port with 'Z' on the master side? What I am trying to do here is: 1. The slave replies with a '0' bit on the bidirectional line to acknowledge data received. The port works fine when its configured as input port (bidir <= 'Z') but when its bidirectional, I cannot get the response from the slave. My guess is because register 'A' is driving register 'B' high, while the bus is '0' This is the RTL representation of the bidir port in Quartus: https://www.alteraforum.com/forum/attachment.php?attachmentid=7739 I tried to use something similar to the below code to replace the bidirection portion of the bidir_port:
bidir <= '0' when output = '0' and else 'Z';
however the waveforms from the pin appear distorted for some reason. The pin cannot be driven high. I need to investigate this further. For now I can only switch the port permanently as an input port an use another pin to drive the bus with the output to the slave.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have another question, unrelated to bidirectional ports.
my device has a set of registers, which can be written by an external SPI interface, as well as user logic. This will result in multiple drivers for the registers, driven by the SPI slave process, and the user logic process. Two methods that I have thought of to resolve this: 1. Use a true dual port RAM, and do read writes from the RAM. 2. inplement a signal on the SPI logic, which the User logic will read and update the register. I am more in favor of 1 , as it looks like a more modular implementation but i will need to watch out for write contentions and the two clock cycles to read the registers. Are there any generic methods (better method) to resolve this?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I have another question, unrelated to bidirectional ports. --- Quote End --- I think, the question can't be answered without an exact specification of intended behaviour. Particularly: - intended reaction on conflicting writes - presumed SPI bus and user logic are unrelated clock domains, you might read inconsistent data when a register is updated at the same time. What's the expected behaviour in this regard? --- Quote Start --- Is it possible receive data from the slave without driving the bidirectional port with 'Z' on the master side? --- Quote End --- Obviously it's impossible for a bidirectional output with tristate driver. --- Quote Start --- This is the RTL representation of the bidir port in Quartus: --- Quote End --- The tristate driver in front of a register is useless (and won't be synthesized). Tristate driver can be only implemented on external pins, internal tristate drivers are converted to multiplexers (if meaningful at all). I'm not familiar with "single wire" can, but I guess it should use majority logic as standard can bus. Using FPGA, an open drain driver with pull-up would be the nearest equivalent.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- I think, the question can't be answered without an exact specification of intended behaviour. --- Quote End --- The register that I am concerned about: A simple system connection: MCU <====SPI====> FPGA <==1-wire CAN=> SLAVE device(s) 1. The FPGA detects one or more slave devices (i.e. max of 8). 2. FPGA updates its register for each of the 8 devices. (i.e. 1' for connected, '0', for disconnected) 3. FPGA sends an interrupt to notify the MCU about new devices 4. MCU uses SPI to read the registers FPGA, and writes back to the same register with respective '0's once it has processed the newly connected device(s). The point to note is that it might be possible for devices to be connected at any time. Meaning there is a chance there is write contention on the register. Unfortunately I am unable to change the process on how the device registration takes place, as this is specified in the specifications. --- Quote Start --- Obviously it's impossible for a bidirectional output with tristate driver. --- Quote End --- Thanks, I thought it might sound stupid but I'd ask anyway.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
CAN is designed to detect bus contention by the dominant/recessive level concept.
I'm not sure how your actual hardware is related to single wire CAN specification, obviously a FPGA pin never meet the specification. I understand you are implementing a similar function on a board level. But it would use somehow the dominant/recessive signalling concept, e.g. an open drain 'H' driver together with a pulldown resistor. In this case, you can readback the pin level while driving out. Contention will be detected if you drive recessive state '0' but read '1'.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page