Skip to content

Commit

Permalink
add support for in/out GPIO pins on ULX3S
Browse files Browse the repository at this point in the history
The ULX3S has 2x28 IO pins that can be used either individually or as
differential pairs. Currently we're going to assume an individual setup (you can
configure their behaviour in the .lpf file).

The convention is to see them as gp[27] (GPIO positive) and gn[28] (GPIO
negative) arrays. This is how they're numbered on the board itself. To work with
this convention, we split out the GPIO address space into 0x00XX and 0x02XX for
setting in/output values of gp and gn pins respectively, and use 0x01XX and
0x3XX for setting the direction of the gn and gp pins.

We define pinModeGp and pinModeGn to set the pin direction. pinMode becomes an
alias for pinModeGn.
  • Loading branch information
stuij committed Nov 5, 2022
1 parent 9a92f21 commit 8524a3a
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 14 deletions.
38 changes: 33 additions & 5 deletions j1b/ulx3s/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,53 @@ low-hanging fruit like GPIOs should follow shortly.

PWR button resets the board


memory map:

0x00XX: gp GPIOs
read/write
either write bit to or read bit from address corresponding to the gp pin numbers
on the board

0x01XX: gp GPIO in/out direction
read/write
set direction of corresponding gp pin; 0 = input (default), 1 = output

example:
$001b io@ \ read gn[27]
OUTPUT $011b io! \ set direction of gn[27] to output
1 $001b io! \ set gn[27] to high


0x02XX: gn GPIOs
read/write
either write bit to or read bit from address corresponding to the gn pin numbers
on the board

0x03XX: gn GPIO in/out direction
read/write
set direction of corresponding gn pin; 0 = input (default), 1 = output

example:
$021b io@ \ read gn[27]
OUTPUT $031b io! \ set direction of gn[27] to output
1 $021b io! \ set gn[27] to high


0x0400: buttons (excluding PWR)
direction: in
read
each button occupies one bit in the bottom 6 bits

as per silkscreen labels on the board:
| 32 - 6 | 5 | 4 | 3 | 2 | 1 | 0 |
unused RIGHT LEFT DOWN UP F2 F1

example:

$0400 io@ .



0x0404: leds
direction: out
write
each led occupies one bit in the bottom 8 bits

as per silkscreen labels on the board:
Expand All @@ -53,4 +82,3 @@ example:
again
;
led-counter

51 changes: 42 additions & 9 deletions j1b/verilog/ulx3s_top.v
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module ulx3s_top(

input wire [6:0] btn,
output wire [7:0] led,
output wire [3:0] audio_l, audio_r, audio_v,
inout wire [27:0] gp, gn,

input wire ftdi_txd,
output wire ftdi_rxd,
Expand Down Expand Up @@ -95,6 +97,11 @@ module ulx3s_top(
{io_wr_, io_rd_, mem_addr_, dout_} <= {io_wr, io_rd, mem_addr, dout};

/* READ WRITE
00xx GP rd GP wr
01xx GP direction GP direction
02xx GN rd GN wr
03xx GP direction GN direction
0400 buttons rd
0404 LEDs wr
Expand All @@ -111,31 +118,57 @@ module ulx3s_top(

reg [63:0] counter_;

reg [27:0] gp_o;
wire [27:0] gp_i;
reg [27:0] gp_dir; // 1:output, 0:input
reg [27:0] gn_o;
wire [27:0] gn_i;
reg [27:0] gn_dir; // 1:output, 0:input

always @(posedge fclk) begin
casez (mem_addr)
16'h0400: din <= {27'd0, btn[6:1]};
16'h00??: din <= gp_i[mem_addr[6:0]];
16'h01??: din <= gp_dir[mem_addr[6:0]];
16'h02??: din <= gn_i[mem_addr[6:0]];
16'h03??: din <= gn_dir[mem_addr[6:0]];

16'h1000: din <= {24'd0, uart0_data};
16'h1008: din <= uart_baud;
16'h2000: din <= {30'd0, uart0_valid, !uart0_busy};
16'h0400: din <= {27'd0, btn[6:1]};

16'h1010: din <= MHZ * 1000000;
16'h1014: din <= counter_[31:0];
16'h1018: din <= counter_[63:32];
16'h101c: din <= ms;
16'h1000: din <= {24'd0, uart0_data};
16'h1008: din <= uart_baud;
16'h2000: din <= {30'd0, uart0_valid, !uart0_busy};

default: din <= 32'bx;
16'h1010: din <= MHZ * 1000000;
16'h1014: din <= counter_[31:0];
16'h1018: din <= counter_[63:32];
16'h101c: din <= ms;

default: din <= 32'bx;
endcase

if (io_wr_) begin
casez (mem_addr_)
16'h00??: gp_o[mem_addr_[6:0]] <= dout_[0];
16'h01??: gp_dir[mem_addr_[6:0]] <= dout_[0];
16'h02??: gn_o[mem_addr_[6:0]] <= dout_[0];
16'h03??: gn_dir[mem_addr_[6:0]] <= dout_[0];

16'h0404: led <= dout_;

16'h1008: uart_baud <= dout_;
16'h1010: counter_ <= counter;
endcase
end
end

genvar i;
for (i = 0; i <= 27; i = i + 1) begin
assign gp[i] = gp_dir[i] ? gp_o[i] : 1'bz;
assign gp_i[i] = gp[i];
assign gn[i] = gn_dir[i] ? gn_o[i] : 1'bz;
assign gn_i[i] = gn[i];
end

assign uart0_wr = io_wr_ & (mem_addr_ == 16'h1000);
assign uart0_rd = io_rd_ & (mem_addr_ == 16'h1000);

Expand Down

0 comments on commit 8524a3a

Please sign in to comment.