Inout pins and high-Z


#1

Firstly, I received my B2 yesterday and I was able to bring up my Crazy Small CPU in a couple of hours. Thanks to Luke for the platform and to Clifford and others for the toolchain! A wiring image is here, the schematic is here and the Verilog is here.

I’ve got the B2 connected up to a UM245R UART: 8 bidirectional bits of data. Right now I’m only doing output, but soon I want to do input. I assume that I set the relevant pins to “inout”, but can I do high-Z on these pins, and how? I was led to believe that Verilog doesn’t synthesize high-Z very well.

Many thanks in advance, Warren

P.S I’m still a Verilog n00b but learning quickly!


#2

Verilog handles high-z well. It even has modelling for various strengths of pull-up and pull-down resistors. However, FPGAs and synthesis tools have some limitations on what they support from Verilog.

Modern FPGAs support tristate values on IO pins, but not on internal signals. I believe icestorm supports tristate IO pins as long as they are driven from the top level. You could do something like this:

// 1: drive data on inout pin, 0: drive high-z
wire output_enable;

// data to drive on inout pin when output_enable is '1'
wire out_data;

// you can use a ternary operator to drive the tristate pin
assign tristate_pin = output_enable ? out_data : 1'bz;

// the value of the tristate_pin will always be the current value 
// whether it is being driven from the FPGA or external logic
assign in_data = tristate_pin;

Good luck!


#3

Luke, thanks for the reply. This is probably not the right place to ask for troubleshooting help, but if it’s an obvious error…

I’ve got the UART wired up: 8 inout pins, one output wire is active low to transmit, another active low output wire to receive. There’s a 4-state FSM which reads, echoes a char, does nothing, sends an ‘A’. Code snippets look like:

inout pin4,     ....
wire [7:0] data;  ...
assign pin4=  data[3]; ....

// UART input and output
reg  [7:0] echoed_data;
reg        TX=1;
reg        RX=1;   ...

assign data= (!TX) ? echoed_data : 8'bz;

case (state)
  READ: begin
    state= ECHO;
    TX=1;
    RX=0;
    echoed_data= data;
  end

What I’m seeing is characters being read, as I can see the RX line strobing low, and the UART has a separate pin which is low when there is data, high when no data.

I’m seeing the code transmitting the ‘A’ in the 4th FSM state. What I’m not seeing is the input character in the READ state above being echoed in the next state. TX=0 and RX=1 in the ECHO state.

So, is the echoed_data= data; line not actually storing the input value from the inout pins?

Anyway, I’m not expecting a solution, just hoping someone might spot it!

Cheers, Warren


#4

I solved it. It had nothing to do with tri-state and inout. I had to assert the RX line and then wait an FSM state before I could load the incoming data into the reg.

  always @(posedge clk) begin
    case (state)
      RDYTOREAD: begin
        state= READ;
        TX=1;				// Ask UART to give us a character
        RX=0;
      end

      READ: begin
        state= ECHO;
        echoed_data= outdata;		// Store any received character
      end
      ...

Cheers, Warren


#5

You might want to change that portion to be:

assign {pin4, pin5, pin6, pin7, pin8, pin9, pin10, pin11} = (!TX) ? echoed_data : 8'bzzzzzzzz;

The curly braces are the verilog concatenation operator: http://verilog.renerta.com/mobile/source/vrg00009.htm

You also want to make sure that you are driving the full 8 bits to high-z. You’ll notice there are 8 zs in the updated code above.


#6

Thanks Luke, all these useful Verilog tips!
Cheers, Warren