@@ -4,6 +4,8 @@ package machine
4
4
5
5
import (
6
6
"device/nxp"
7
+ "math/bits"
8
+ "runtime/interrupt"
7
9
"runtime/volatile"
8
10
)
9
11
@@ -17,29 +19,56 @@ type PinMode uint8
17
19
18
20
const (
19
21
// GPIO
20
- PinInput PinMode = iota
21
- PinInputPullUp
22
- PinInputPullDown
23
- PinOutput
24
- PinOutputOpenDrain
25
- PinDisable
22
+ PinInput PinMode = 0
23
+ PinInputPullUp PinMode = 1
24
+ PinInputPullDown PinMode = 2
25
+ PinOutput PinMode = 3
26
+ PinOutputOpenDrain PinMode = 4
27
+ PinDisable PinMode = 5
26
28
27
29
// ADC
28
- PinInputAnalog
30
+ PinInputAnalog PinMode = 6
29
31
30
32
// UART
31
- PinModeUARTTX
32
- PinModeUARTRX
33
+ PinModeUARTTX PinMode = 7
34
+ PinModeUARTRX PinMode = 8
33
35
34
36
// SPI
35
- PinModeSPISDI
36
- PinModeSPISDO
37
- PinModeSPICLK
38
- PinModeSPICS
37
+ PinModeSPISDI PinMode = 9
38
+ PinModeSPISDO PinMode = 10
39
+ PinModeSPICLK PinMode = 11
40
+ PinModeSPICS PinMode = 12
39
41
40
42
// I2C
41
- PinModeI2CSDA
42
- PinModeI2CSCL
43
+ PinModeI2CSDA PinMode = 13
44
+ PinModeI2CSCL PinMode = 14
45
+ )
46
+
47
+ type PinChange uint8
48
+
49
+ const (
50
+ PinLow PinChange = 0
51
+ PinHigh PinChange = 1
52
+ PinRising PinChange = 2
53
+ PinFalling PinChange = 3
54
+ PinToggle PinChange = 4
55
+ )
56
+
57
+ // pinJumpTable represents a function lookup table for all 128 GPIO pins.
58
+ //
59
+ // There are 4 GPIO ports (A-D) and 32 pins (0-31) on each port. The uint8 value
60
+ // of a Pin is used as table index. The number of pins with a defined (non-nil)
61
+ // function is recorded in the uint8 field numDefined.
62
+ type pinJumpTable struct {
63
+ lut [4 * 32 ]func (Pin )
64
+ numDefined uint8
65
+ }
66
+
67
+ // pinISR stores the interrupt callbacks for GPIO pins, and pinInterrupt holds
68
+ // an interrupt service routine that dispatches the interrupt callbacks.
69
+ var (
70
+ pinISR pinJumpTable
71
+ pinInterrupt * interrupt.Interrupt
43
72
)
44
73
45
74
// From the i.MXRT1062 Processor Reference Manual (Chapter 12 - GPIO):
@@ -301,6 +330,101 @@ func (p Pin) Toggle() {
301
330
gpio .DR_TOGGLE .Set (p .getMask ())
302
331
}
303
332
333
+ // dispatchInterrupt invokes the user-provided callback functions for external
334
+ // interrupts generated on the high-speed GPIO pins.
335
+ //
336
+ // Unfortunately, all four high-speed GPIO ports (A-D) are connected to just a
337
+ // single interrupt control line. Therefore, the interrupt status register (ISR)
338
+ // must be checked in all four GPIO ports on every interrupt.
339
+ func (jt * pinJumpTable ) dispatchInterrupt (interrupt.Interrupt ) {
340
+ handle := func (gpio * nxp.GPIO_Type , port Pin ) {
341
+ if status := gpio .ISR .Get () & gpio .IMR .Get (); status != 0 {
342
+ gpio .ISR .Set (status ) // clear interrupt
343
+ for status != 0 {
344
+ p := Pin (bits .TrailingZeros32 (status ))
345
+ i := Pin (port + p )
346
+ jt.lut [i ](i )
347
+ status &^= 1 << p
348
+ }
349
+ }
350
+ }
351
+ if jt .numDefined > 0 {
352
+ handle (nxp .GPIO6 , portA )
353
+ handle (nxp .GPIO7 , portB )
354
+ handle (nxp .GPIO8 , portC )
355
+ handle (nxp .GPIO9 , portD )
356
+ }
357
+ }
358
+
359
+ // set associates a function with a given Pin in the receiver lookup table. If
360
+ // the function is nil, the given Pin's associated function is removed.
361
+ func (jt * pinJumpTable ) set (pin Pin , fn func (Pin )) {
362
+ if int (pin ) < len (jt .lut ) {
363
+ if nil != fn {
364
+ if nil == jt .lut [pin ] {
365
+ jt .numDefined ++
366
+ }
367
+ jt .lut [pin ] = fn
368
+ } else {
369
+ if nil != jt .lut [pin ] {
370
+ jt .numDefined --
371
+ }
372
+ jt .lut [pin ] = nil
373
+ }
374
+ }
375
+ }
376
+
377
+ // SetInterrupt sets an interrupt to be executed when a particular pin changes
378
+ // state. The pin should already be configured as an input, including a pull up
379
+ // or down if no external pull is provided.
380
+ //
381
+ // This call will replace a previously set callback on this pin. You can pass a
382
+ // nil func to unset the pin change interrupt. If you do so, the change
383
+ // parameter is ignored and can be set to any value (such as 0).
384
+ func (p Pin ) SetInterrupt (change PinChange , callback func (Pin )) error {
385
+ _ , gpio := p .getGPIO () // use fast GPIO for all pins
386
+ mask := p .getMask ()
387
+ if nil != callback {
388
+ switch change {
389
+ case PinLow , PinHigh , PinRising , PinFalling :
390
+ gpio .EDGE_SEL .ClearBits (mask )
391
+ var reg * volatile.Register32
392
+ var pos uint8
393
+ if pos = p .getPos (); pos < 16 {
394
+ reg = & gpio .ICR1 // ICR1 = pins 0-15
395
+ } else {
396
+ reg = & gpio .ICR2 // ICR2 = pins 16-31
397
+ pos -= 16
398
+ }
399
+ reg .ReplaceBits (uint32 (change ), 0x3 , pos * 2 )
400
+ case PinToggle :
401
+ gpio .EDGE_SEL .SetBits (mask )
402
+ }
403
+ pinISR .set (p , callback ) // associate the callback with the pin
404
+ gpio .ISR .Set (mask ) // clear any pending interrupt (W1C)
405
+ gpio .IMR .SetBits (mask ) // enable external interrupt
406
+ } else {
407
+ pinISR .set (p , nil ) // remove any associated callback from the pin
408
+ gpio .ISR .Set (mask ) // clear any pending interrupt (W1C)
409
+ gpio .IMR .ClearBits (mask ) // disable external interrupt
410
+ }
411
+ // enable or disable the interrupt based on number of defined callbacks
412
+ if pinISR .numDefined > 0 {
413
+ if nil == pinInterrupt {
414
+ // create the Interrupt if it is not yet defined
415
+ irq := interrupt .New (nxp .IRQ_GPIO6_7_8_9 , pinISR .dispatchInterrupt )
416
+ pinInterrupt = & irq
417
+ pinInterrupt .Enable ()
418
+ }
419
+ } else {
420
+ if nil != pinInterrupt {
421
+ // disable the interrupt if it is defined
422
+ pinInterrupt .Disable ()
423
+ }
424
+ }
425
+ return nil
426
+ }
427
+
304
428
// getGPIO returns both the normal (IPG_CLK_ROOT) and high-speed (AHB_CLK_ROOT)
305
429
// GPIO peripherals to which a given Pin is connected.
306
430
//
0 commit comments