Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20705 Discussions

Bidirectional SPI switch?

Altera_Forum
Honored Contributor II
1,461 Views

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;
0 Kudos
14 Replies
Altera_Forum
Honored Contributor II
634 Views

If I have understood you, you have A,B,C SPI interfaces and you want C to talk to either A or B: 

 

(1) C to A or B  

Since you have chipselect then you can drive both at same time then use chipselect. 

 

(2) A or B to C: use your switch to drive C 

 

This pseudocode may explain my idea: 

if OE = ? A <= C; B <= C; C <= 'Z'; else A <= 'Z'; B <= 'Z'; if select = ? C <= A; else C <= B; end if; end if;
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

Some points of the original post seems confused. SPI implies either master or slave role, for this reason none of the standard SPI signals would be bidirectional respectively inoout normally. It's of course possible to design an SPI interface that changes between master and slave role, but you didn't mention this. 

 

It's also wrong to say that a VHDL assignment involves registers. This is only the case, if it executes under a edge sensitive event condition. You can have combinational process statements as well, they infer multiplexers, as apparently intended here.
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

 

--- Quote Start ---  

Some points of the original post seems confused. SPI implies either master or slave role, for this reason none of the standard SPI signals would be bidirectional respectively inoout normally. It's of course possible to design an SPI interface that changes between master and slave role, but you didn't mention this. 

 

It's also wrong to say that a VHDL assignment involves registers. This is only the case, if it executes under a edge sensitive event condition. You can have combinational process statements as well, they infer multiplexers, as apparently intended here. 

--- Quote End ---  

 

 

Apologies for the confusion. What I intend to do is have 3 SPI ports where any of the nodes connected could either be a master or slave. it is a truly bidirectional system then.
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

I can't make it happen. Have a look at the attachment for the results. 

 

Basically, it should just be a mechanical switch i.e. 

 

when en = 0, wire A should be connected to wire C. 

 

when en = 1, wire B should be connected to wire C. 

 

-- 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; en, S : IN BIT ); end bidir_SPI_switch; architecture behaviour of bidir_SPI_switch is begin process(en,S) begin -- MASTER enable if en = '0' then A_SCLK <= C_SCLK; B_SCLK <= 'Z'; C_SCLK <= A_SCLK; else -- SELECT either A or B A_SCLK <= 'Z'; C_SCLK <= B_SCLK; B_SCLK <= C_SCLK; end if; end process; end architecture behaviour;
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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 

....
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

Thanks FvM and Kaz, I see your point now.

0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

Did you look at the RTL schematic ? 

Does it look OK ?
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

Couldn't make full sense of what was happening. However, it did simulate it well.

0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
634 Views

Thanks FvM, I've added an extra pin in the design for direction and now it works fine in simulation with the bigger design.

0 Kudos
Reply