-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathdio.go
347 lines (303 loc) · 6.71 KB
/
dio.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
// Copyright © 2017 Kent Gibson <[email protected]>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
// Package gpio provides GPIO access on the Raspberry Pi (rev 2 and later, up to but not including Pi5).
//
// Supports simple operations such as:
// - Pin mode/direction (input/output)
// - Pin write (high/low)
// - Pin read (high/low)
// - Pull up/down/off
//
// The package intentionally does not support:
// - the obsoleted rev 1 PCB (no longer worth the effort)
// - active low (to prevent confusion this package reflects only the actual hardware levels)
//
// Example of use:
//
// gpio.Open()
// defer gpio.Close()
//
// pin := gpio.NewPin(gpio.J8p7)
// pin.Low()
// pin.Output()
//
// for {
// pin.Toggle()
// time.Sleep(time.Second)
// }
//
// The library uses the raw BCM2835 pin numbers, not the ports as they are mapped
// on the J8 output pins for the Raspberry Pi.
// A mapping from J8 to BCM is provided for those wanting to use the J8 numbering.
//
// See the spec for full details of the BCM2835 controller:
// http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
package gpio
import (
"time"
)
// Pin represents a single GPIO pin.
type Pin struct {
// Immutable fields
pin int
fsel int
levelReg int
clearReg int
setReg int
pullReg2711 int
bank int
mask uint32
// Mutable fields
shadow Level
}
// Level represents the high (true) or low (false) level of a Pin.
type Level bool
// Mode defines the IO mode of a Pin.
type Mode int
// Pull defines the pull up/down state of a Pin.
type Pull int
const (
memLength = 4096
modeMask uint32 = 7 // pin mode is 3 bits wide
pullMask uint32 = 3 // pull mode is 2 bits wide
// BCM2835 pullReg is the same for all pins.
pullReg2835 = 37
)
// Pin Mode, a pin can be set in Input or Output mode
const (
Input Mode = iota
Output
Alt5
Alt4
Alt0
Alt1
Alt2
Alt3
)
// Level of pin, High / Low
const (
Low Level = false
High Level = true
)
// Pull Up / Down / Off
const (
// Values match bcm pull field.
PullNone Pull = iota
PullDown
PullUp
)
// Convenience mapping from J8 pinouts to BCM pinouts.
const (
J8p27 = iota
J8p28
J8p3
J8p5
J8p7
J8p29
J8p31
J8p26
J8p24
J8p21
J8p19
J8p23
J8p32
J8p33
J8p8
J8p10
J8p36
J8p11
J8p12
J8p35
J8p38
J8p40
J8p15
J8p16
J8p18
J8p22
J8p37
J8p13
MaxGPIOPin
)
// GPIO aliases to J8 pins
const (
GPIO2 = J8p3
GPIO3 = J8p5
GPIO4 = J8p7
GPIO5 = J8p29
GPIO6 = J8p31
GPIO7 = J8p26
GPIO8 = J8p24
GPIO9 = J8p21
GPIO10 = J8p19
GPIO11 = J8p23
GPIO12 = J8p32
GPIO13 = J8p33
GPIO14 = J8p8
GPIO15 = J8p10
GPIO16 = J8p36
GPIO17 = J8p11
GPIO18 = J8p12
GPIO19 = J8p35
GPIO20 = J8p38
GPIO21 = J8p40
GPIO22 = J8p15
GPIO23 = J8p16
GPIO24 = J8p18
GPIO25 = J8p22
GPIO26 = J8p37
GPIO27 = J8p13
)
// NewPin creates a new pin object.
// The pin number provided is the BCM GPIO number.
func NewPin(pin int) *Pin {
if len(mem) == 0 {
panic("GPIO not initialised.")
}
if pin < 0 || pin >= MaxGPIOPin {
return nil
}
// Pre-calculate commonly used register addresses and bit masks.
// Pin fsel register, 0 - 5 depending on pin
fsel := pin / 10
// This seems like overkill given the J8 pins are all on the first bank...
bank := pin / 32
mask := uint32(1 << uint(pin&0x1f))
// Input level register offset (13 / 14 depending on bank)
levelReg := 13 + bank
// Clear register, 10 / 11 depending on bank
clearReg := 10 + bank
// Set register, 7 / 8 depending on bank
setReg := 7 + bank
// Pull register, 57-60 depending on pin
pullReg := 57 + pin/16
shadow := Low
if mem[levelReg]&mask != 0 {
shadow = High
}
return &Pin{
pin: pin,
fsel: fsel,
bank: bank,
mask: mask,
levelReg: levelReg,
clearReg: clearReg,
pullReg2711: pullReg,
setReg: setReg,
shadow: shadow,
}
}
// Input sets pin as Input.
func (pin *Pin) Input() {
pin.SetMode(Input)
}
// Output sets pin as Output.
func (pin *Pin) Output() {
pin.SetMode(Output)
}
// High sets pin High.
func (pin *Pin) High() {
pin.Write(High)
}
// Low sets pin Low.
func (pin *Pin) Low() {
pin.Write(Low)
}
// Mode returns the mode of the pin in the Function Select register.
func (pin *Pin) Mode() Mode {
// read Mode and current value
modeShift := uint(pin.pin%10) * 3
return Mode(mem[pin.fsel] >> modeShift & modeMask)
}
// Shadow returns the value of the last write to an output pin or the last read on an input pin.
func (pin *Pin) Shadow() Level {
return pin.shadow
}
// Pin returns the pin number that this Pin represents.
func (pin *Pin) Pin() int {
return pin.pin
}
// Toggle pin state
func (pin *Pin) Toggle() {
if pin.shadow {
pin.Write(Low)
} else {
pin.Write(High)
}
}
// SetMode sets the pin Mode.
func (pin *Pin) SetMode(mode Mode) {
// shift for pin mode field within fsel register.
modeShift := uint(pin.pin%10) * 3
memlock.Lock()
defer memlock.Unlock()
mem[pin.fsel] = mem[pin.fsel]&^(modeMask<<modeShift) | uint32(mode)<<modeShift
}
// Read pin state (high/low)
func (pin *Pin) Read() (level Level) {
if (mem[pin.levelReg] & pin.mask) != 0 {
level = High
}
pin.shadow = level
return
}
// Set pin state (high/low)
func (pin *Pin) Write(level Level) {
if level == Low {
mem[pin.clearReg] = pin.mask
} else {
mem[pin.setReg] = pin.mask
}
pin.shadow = level
}
// SetPull sets the pull up/down mode for a Pin.
// Unlike the mode, the pull value cannot be read back from hardware and
// so must be remembered by the caller.
func (pin *Pin) SetPull(pull Pull) {
switch chipset {
case BCM2711:
pin.setPull2711(pull)
default:
pin.setPull2835(pull)
}
}
func (pin *Pin) setPull2835(pull Pull) {
clkReg := pin.bank + 38
memlock.Lock()
defer memlock.Unlock()
mem[pullReg2835] = mem[pullReg2835]&^pullMask | uint32(pull)
// Wait for value to clock in, this is ugly, sorry :(
// This wait corresponds to at least 150 clock cycles.
time.Sleep(time.Microsecond)
mem[clkReg] = pin.mask
// Wait for value to clock in
time.Sleep(time.Microsecond)
mem[pullReg2835] = mem[pullReg2835] &^ pullMask
mem[clkReg] = 0
}
func (pin *Pin) setPull2711(pull Pull) {
// 2711 reverses up/down sense
switch pull {
case PullUp:
pull = PullDown
case PullDown:
pull = PullUp
}
shift := uint(pin.pin&0x0f) << 1
memlock.Lock()
defer memlock.Unlock()
mem[pin.pullReg2711] = mem[pin.pullReg2711]&^(pullMask<<shift) | uint32(pull)<<shift
}
// PullUp sets the pull state of the pin to PullUp.
func (pin *Pin) PullUp() {
pin.SetPull(PullUp)
}
// PullDown sets the pull state of the Pin to PullDown.
func (pin *Pin) PullDown() {
pin.SetPull(PullDown)
}
// PullNone disables pullup/down on pin, leaving it floating.
func (pin *Pin) PullNone() {
pin.SetPull(PullNone)
}