Forum Discussion
Bidirectional SPI switch?
This is a complex problem which I am very unsure of, the basic idea is that I want code that switches between 3 SPIs.
I was startled when I noticed the statement that I was about to write A_SCLK <= C_SCLK C_SCLK <= A_SCLK both are true, but this would induce registers, all I want is a wire connection.
-- The idea is that choose either A or B is exclusively
-- connected to C
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity bidir_SPI_switch is
port(
A_SCLK, B_SCLK, C_SCLK : INOUT STD_LOGIC;
A_SOMI, B_SOMI, C_SOMI : INOUT STD_LOGIC;
A_SIMO, B_SIMO, C_SIMO : INOUT STD_LOGIC;
A_CSn, B_CSn, C_CSn : INOUT STD_LOGIC;
en, S : IN BIT
);
end bidir_SPI_switch;
architecture behaviour of bidir_SPI_switch is
process(en,S)
begin
-- MASTER enable
if en = '0' then
A_SCLK HOW??
C_SCLK
else
-- SELECT either A or B
end if;
end process;
14 Replies
- Altera_Forum
Honored Contributor
Thanks FvM, I've added an extra pin in the design for direction and now it works fine in simulation with the bigger design.
- Altera_Forum
Honored Contributor
In my opinion, the problem is a lack of clarity about the required prerequisites of a bidirectional "switch". A FPGA doesn't offer bidirectional bus switches of analog switch type. It can implement bidirectional buffers, similar e.g. to a 74HC245, that however need a control signal to decide about the actual data direction.
You have to find out, how this direction information can be deterrmined. - Altera_Forum
Honored Contributor
This has been unsuccessful, it seems nothing is going through the switch.
Is there an example code out there that shows how to build a Bidirectional bus and the assumptions required of the entities that connect to it. This is doing me head in. - Altera_Forum
Honored Contributor
Couldn't make full sense of what was happening. However, it did simulate it well.
- Altera_Forum
Honored Contributor
Did you look at the RTL schematic ?
Does it look OK ? - Altera_Forum
Honored Contributor
That code was no good because it created a race condition.
This fixes it:-- The idea is that choose either A or B is exclusively -- connected to C library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity bidir_SPI_switch is port( en, S : IN BIT; A_CSn, A_SCLK, A_SIMO, A_SOMI : INOUT STD_LOGIC; B_CSn, B_SCLK, B_SIMO, B_SOMI : INOUT STD_LOGIC; O_CSn, O_SCLK, O_SIMO, O_SOMI : INOUT STD_LOGIC ); end bidir_SPI_switch; architecture behaviour of bidir_SPI_switch is begin process(en,S, A_CSn, A_SCLK, A_SIMO, A_SOMI, B_CSn, B_SCLK, B_SIMO, B_SOMI, O_CSn, O_SCLK, O_SIMO, O_SOMI) begin -- change default state of each port depending on if -- the port is a Master only, Slave only or both. A_CSn <= 'Z'; A_SCLK <= 'Z'; A_SIMO <= 'Z'; A_SOMI <= 'Z'; B_CSn <= 'Z'; B_SCLK <= 'Z'; B_SIMO <= 'Z'; B_SOMI <= 'Z'; O_CSn <= 'Z'; O_SCLK <= 'Z'; O_SIMO <= 'Z'; O_SOMI <= 'Z'; -- when disabled, A <=> O if en = '0' then if (A_CSn = '0') then O_CSn <= '0'; O_SCLK <= A_SCLK; O_SIMO <= A_SIMO; A_SOMI <= O_SOMI; elsif (O_CSn = '0') then A_CSn <= '0'; A_SCLK <= O_SCLK; A_SIMO <= O_SIMO; O_SOMI <= A_SOMI; end if; -- when enabled else -- S = 0, A <=> O if (S = '0') then if (A_CSn = '0') then O_CSn <= '0'; O_SCLK <= A_SCLK; O_SIMO <= A_SIMO; A_SOMI <= O_SOMI; elsif (O_CSn = '0') then A_CSn <= '0'; A_SCLK <= O_SCLK; A_SIMO <= O_SIMO; O_SOMI <= A_SOMI; end if; -- S = 1, B <=> O else if (B_CSn = '0') then O_CSn <= '0'; O_SCLK <= B_SCLK; O_SIMO <= B_SIMO; B_SOMI <= O_SOMI; elsif (O_CSn = '0') then B_CSn <= '0'; B_SCLK <= O_SCLK; B_SIMO <= O_SIMO; O_SOMI <= B_SOMI; end if; end if; -- S = '1' end if; -- en = '1' end process; end architecture behaviour; - Altera_Forum
Honored Contributor
Here is my implementation. Last question, is it possible to put an internal pull-up on the chip select (CSn) signals?
-- The idea is that choose either A or B is exclusively -- connected to O library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity bidir_SPI_switch is port( en, S : IN BIT; A_CSn, A_SCLK, A_SIMO, A_SOMI : INOUT STD_LOGIC; B_CSn, B_SCLK, B_SIMO, B_SOMI : INOUT STD_LOGIC; O_CSn, O_SCLK, O_SIMO, O_SOMI : INOUT STD_LOGIC ); end bidir_SPI_switch; architecture behaviour of bidir_SPI_switch is begin process(en,S, A_CSn, A_SCLK, A_SIMO, A_SOMI, B_CSn, B_SCLK, B_SIMO, B_SOMI, O_CSn, O_SCLK, O_SIMO, O_SOMI) begin -- change default state of each port depending on if -- the port is a Master only, Slave only or both. A_CSn <= 'Z'; A_SCLK <= 'Z'; A_SIMO <= 'Z'; A_SOMI <= 'Z'; B_CSn <= 'Z'; B_SCLK <= 'Z'; B_SIMO <= 'Z'; B_SOMI <= 'Z'; O_CSn <= 'Z'; O_SCLK <= 'Z'; O_SIMO <= 'Z'; O_SOMI <= 'Z'; -- when disabled, A <=> O if en = '0' then if (A_CSn = '0') then O_CSn <= '0'; O_SCLK <= A_SCLK; O_SIMO <= A_SIMO; A_SOMI <= O_SOMI; end if; if (O_CSn = '0') then A_CSn <= '0'; A_SCLK <= O_SCLK; A_SIMO <= O_SIMO; O_SOMI <= A_SOMI; end if; -- when enabled else -- S = 0, A <=> O if (S = '0') then if (A_CSn = '0') then O_CSn <= '0'; O_SCLK <= A_SCLK; O_SIMO <= A_SIMO; A_SOMI <= O_SOMI; end if; if (O_CSn = '0') then A_CSn <= '0'; A_SCLK <= O_SCLK; A_SIMO <= O_SIMO; O_SOMI <= A_SOMI; end if; -- S = 1, B <=> O else if (B_CSn = '0') then O_CSn <= '0'; O_SCLK <= B_SCLK; O_SIMO <= B_SIMO; B_SOMI <= O_SOMI; end if; if (O_CSn = '0') then B_CSn <= '0'; B_SCLK <= O_SCLK; B_SIMO <= O_SIMO; O_SOMI <= B_SOMI; end if; end if; -- S = '1' end if; -- en = '1' end process; end architecture behaviour; - Altera_Forum
Honored Contributor
Thanks FvM and Kaz, I see your point now.
- Altera_Forum
Honored Contributor
You can't route a bidirectional signal without an explicite direction information.
I asked about the SPI master and slave roles, because I can hardly imagine a SPI network, where the peers change their role spontaneously. At least, it hasn't anything to do with known SPI standards. You have similar problems however with true bidirectional lines, e.g. an I2C bus or simply the data lines of a processor bus. If a FPGA is intended to route a signal of this kind, it must be supplied with an additional direction information, or it has to decode the communication protocol and determine the actual data direction from it's protocol knowledge, if possible at all. - Altera_Forum
Honored Contributor
Try this idea...
you better think of signal driving another than connectivity. remember connectivity in HDL does not mean that each side is driving the other. you will need three choices: if A master then A_sclk <= 'Z'; --driven from A chip B_sclk <= A_sclk; C_sclk <= A_sclk; elsif B master then ....