Skip to content

Commit 8524a3a

Browse files
committed
add support for in/out GPIO pins on ULX3S
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.
1 parent 9a92f21 commit 8524a3a

2 files changed

Lines changed: 75 additions & 14 deletions

File tree

j1b/ulx3s/README.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,53 @@ low-hanging fruit like GPIOs should follow shortly.
2020

2121
PWR button resets the board
2222

23+
2324
memory map:
2425

26+
0x00XX: gp GPIOs
27+
read/write
28+
either write bit to or read bit from address corresponding to the gp pin numbers
29+
on the board
30+
31+
0x01XX: gp GPIO in/out direction
32+
read/write
33+
set direction of corresponding gp pin; 0 = input (default), 1 = output
34+
35+
example:
36+
$001b io@ \ read gn[27]
37+
OUTPUT $011b io! \ set direction of gn[27] to output
38+
1 $001b io! \ set gn[27] to high
39+
40+
41+
0x02XX: gn GPIOs
42+
read/write
43+
either write bit to or read bit from address corresponding to the gn pin numbers
44+
on the board
45+
46+
0x03XX: gn GPIO in/out direction
47+
read/write
48+
set direction of corresponding gn pin; 0 = input (default), 1 = output
49+
50+
example:
51+
$021b io@ \ read gn[27]
52+
OUTPUT $031b io! \ set direction of gn[27] to output
53+
1 $021b io! \ set gn[27] to high
54+
55+
2556
0x0400: buttons (excluding PWR)
26-
direction: in
57+
read
2758
each button occupies one bit in the bottom 6 bits
2859

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

3364
example:
34-
3565
$0400 io@ .
3666

3767

38-
3968
0x0404: leds
40-
direction: out
69+
write
4170
each led occupies one bit in the bottom 8 bits
4271

4372
as per silkscreen labels on the board:
@@ -53,4 +82,3 @@ example:
5382
again
5483
;
5584
led-counter
56-

j1b/verilog/ulx3s_top.v

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ module ulx3s_top(
55

66
input wire [6:0] btn,
77
output wire [7:0] led,
8+
output wire [3:0] audio_l, audio_r, audio_v,
9+
inout wire [27:0] gp, gn,
810

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

9799
/* READ WRITE
100+
00xx GP rd GP wr
101+
01xx GP direction GP direction
102+
02xx GN rd GN wr
103+
03xx GP direction GN direction
104+
98105
0400 buttons rd
99106
0404 LEDs wr
100107
@@ -111,31 +118,57 @@ module ulx3s_top(
111118

112119
reg [63:0] counter_;
113120

121+
reg [27:0] gp_o;
122+
wire [27:0] gp_i;
123+
reg [27:0] gp_dir; // 1:output, 0:input
124+
reg [27:0] gn_o;
125+
wire [27:0] gn_i;
126+
reg [27:0] gn_dir; // 1:output, 0:input
127+
114128
always @(posedge fclk) begin
115129
casez (mem_addr)
116-
16'h0400: din <= {27'd0, btn[6:1]};
130+
16'h00??: din <= gp_i[mem_addr[6:0]];
131+
16'h01??: din <= gp_dir[mem_addr[6:0]];
132+
16'h02??: din <= gn_i[mem_addr[6:0]];
133+
16'h03??: din <= gn_dir[mem_addr[6:0]];
117134

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

122-
16'h1010: din <= MHZ * 1000000;
123-
16'h1014: din <= counter_[31:0];
124-
16'h1018: din <= counter_[63:32];
125-
16'h101c: din <= ms;
137+
16'h1000: din <= {24'd0, uart0_data};
138+
16'h1008: din <= uart_baud;
139+
16'h2000: din <= {30'd0, uart0_valid, !uart0_busy};
126140

127-
default: din <= 32'bx;
141+
16'h1010: din <= MHZ * 1000000;
142+
16'h1014: din <= counter_[31:0];
143+
16'h1018: din <= counter_[63:32];
144+
16'h101c: din <= ms;
145+
146+
default: din <= 32'bx;
128147
endcase
129148

130149
if (io_wr_) begin
131150
casez (mem_addr_)
151+
16'h00??: gp_o[mem_addr_[6:0]] <= dout_[0];
152+
16'h01??: gp_dir[mem_addr_[6:0]] <= dout_[0];
153+
16'h02??: gn_o[mem_addr_[6:0]] <= dout_[0];
154+
16'h03??: gn_dir[mem_addr_[6:0]] <= dout_[0];
155+
132156
16'h0404: led <= dout_;
157+
133158
16'h1008: uart_baud <= dout_;
134159
16'h1010: counter_ <= counter;
135160
endcase
136161
end
137162
end
138163

164+
genvar i;
165+
for (i = 0; i <= 27; i = i + 1) begin
166+
assign gp[i] = gp_dir[i] ? gp_o[i] : 1'bz;
167+
assign gp_i[i] = gp[i];
168+
assign gn[i] = gn_dir[i] ? gn_o[i] : 1'bz;
169+
assign gn_i[i] = gn[i];
170+
end
171+
139172
assign uart0_wr = io_wr_ & (mem_addr_ == 16'h1000);
140173
assign uart0_rd = io_rd_ & (mem_addr_ == 16'h1000);
141174

0 commit comments

Comments
 (0)