GPIO input with PicoSOC on BX


#1

Hi all,

Has anyone tried GPIO input with PicoSOC?

Using the example, I tried to assign pins to the gpio register:

inout pin_4,
inout pin_5,
inout pin_6,
inout pin_7,

and then

assign pin_4 = gpio[1];
assign pin_5 = gpio[2];
assign pin_6 = gpio[3];
assign pin_7 = gpio[4];

But when I read the GPIO register, everything is at zero no matter if I apply 3.3V to the pins or not.


#2

Without seeing the full context it’s hard to guess what’s going on, but as a first guess - are you using the SB_IO block to set the pins to input mode? I believe (through my own experimentation), that the pins default to output only mode.

The code below may help.

wire input_wire;
SB_IO #(
  .PIN_TYPE(6'b0000_01),
  .PULLUP(1'b0)
) input_wire_conf (
  .PACKAGE_PIN(PIN_4),
  .D_IN_0(input_wire)
);

This puts the pin into simple input mode (with output disabled and no pull-up), and assigns the input to “input_wire”.

If you want to use the pin in both input and output mode (as it seems you do with your “inout” declarations), you’ll also need to configure the “OUTPUT_ENABLE” line of the IO block, and use it to switch between input and output mode.

reg oe;
wire input_wire, output_wire;
SB_IO #(
  .PIN_TYPE(6'b0110_01),
  .PULLUP(1'b0)
) io_wire_conf (
  .PACKAGE_PIN(PIN_4),
  .D_IN_0(input_wire),
  .D_OUT_0(output_wire),
  .OUTPUT_ENABLE(oe)
);

You can find details about the SB_IO block, and what the parameters mean in the Lattice ICE Technology Library documentation.

Hope that helps.


#3

It looks to me like the way that the gpio register is implemented in hardware.v, it will only work for output (and reading back the values you set from the C code).

If you want gpio input, you could either create a second 32-bit word (e.g. address 0x3000004) to be input, or make some of the bytes of the gpio register input and other output. E.g. just the least significant byte could be output.

If you want the bits to be inout, you will probably have to set up another 32-bit word to be a control register that sets the direction of the bits and use SB_IO rather like mod_gpio in icoSoC does. icoSoC is an extension of picoSoC for icoBoard.


#4

Thanks for you help guys,

After I posted this question I realized how dump my code was :slight_smile:

What I did instead is to assign the values of the pins in the code than handles the read/write of the register:

if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8’h03) begin
gpio[1] <= pin_23;
gpio[2] <= pin_24;
iomem_ready <= 1;
iomem_rdata <= gpio;
if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0];
if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8];
if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16];
if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24];
end

This works.

Reading your suggestions, I might do a proper GPIO peripheral with direction and pull-up control.


#5

Hi @Fabien, have you tested that code, as it does not look to me as if it will work very well?

The non-blocking assignments do not happen until the end of the cycle, so iomem_rdata will get the old value of gpio. So the first time you do the read, you will get the old value of gpio and not the current value of the pins. The values will then be overwritten by any writes done in the C code. If you have left the led code in firmware.c, there are frequent writes to the whole gpio word.

If there are no intervening writes, the next time you do a read, you will get the value of the pins as they were on the previous read.


#6

Hi Lawrie,

It does work but it could be because I read from / read to this register multiple times.

Definitely have to improve this part.