-
Notifications
You must be signed in to change notification settings - Fork 911
/
machine_atsamd51.go
2733 lines (2357 loc) · 80.8 KB
/
machine_atsamd51.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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// +build sam,atsamd51 sam,atsame5x
// Peripheral abstraction layer for the atsamd51.
//
// Datasheet:
// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf
//
package machine
import (
"device/arm"
"device/sam"
"errors"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)
func CPUFrequency() uint32 {
return 120000000
}
const (
PinAnalog PinMode = 1
PinSERCOM PinMode = 2
PinSERCOMAlt PinMode = 3
PinTimer PinMode = 4
PinTimerAlt PinMode = 5
PinTCCPDEC PinMode = 6
PinCom PinMode = 7
PinSDHC PinMode = 8
PinI2S PinMode = 9
PinPCC PinMode = 10
PinGMAC PinMode = 11
PinACCLK PinMode = 12
PinCCL PinMode = 13
PinDigital PinMode = 14
PinInput PinMode = 15
PinInputPullup PinMode = 16
PinOutput PinMode = 17
PinTCCE PinMode = PinTimer
PinTCCF PinMode = PinTimerAlt
PinTCCG PinMode = PinTCCPDEC
PinInputPulldown PinMode = 18
PinCAN PinMode = 19
PinCAN0 PinMode = PinSDHC
PinCAN1 PinMode = PinCom
)
type PinChange uint8
// Pin change interrupt constants for SetInterrupt.
const (
PinRising PinChange = sam.EIC_CONFIG_SENSE0_RISE
PinFalling PinChange = sam.EIC_CONFIG_SENSE0_FALL
PinToggle PinChange = sam.EIC_CONFIG_SENSE0_BOTH
)
// Callbacks to be called for pins configured with SetInterrupt. Unfortunately,
// we also need to keep track of which interrupt channel is used by which pin,
// as the only alternative would be iterating through all pins.
//
// We're using the magic constant 16 here because the SAM D21 has 16 interrupt
// channels configurable for pins.
var (
interruptPins [16]Pin // warning: the value is invalid when pinCallbacks[i] is not set!
pinCallbacks [16]func(Pin)
)
// Hardware pins
const (
PA00 Pin = 0
PA01 Pin = 1
PA02 Pin = 2
PA03 Pin = 3
PA04 Pin = 4
PA05 Pin = 5
PA06 Pin = 6
PA07 Pin = 7
PA08 Pin = 8
PA09 Pin = 9
PA10 Pin = 10
PA11 Pin = 11
PA12 Pin = 12
PA13 Pin = 13
PA14 Pin = 14
PA15 Pin = 15
PA16 Pin = 16
PA17 Pin = 17
PA18 Pin = 18
PA19 Pin = 19
PA20 Pin = 20
PA21 Pin = 21
PA22 Pin = 22
PA23 Pin = 23
PA24 Pin = 24
PA25 Pin = 25
PA26 Pin = 26
PA27 Pin = 27
PA28 Pin = 28
PA29 Pin = 29
PA30 Pin = 30
PA31 Pin = 31
PB00 Pin = 32
PB01 Pin = 33
PB02 Pin = 34
PB03 Pin = 35
PB04 Pin = 36
PB05 Pin = 37
PB06 Pin = 38
PB07 Pin = 39
PB08 Pin = 40
PB09 Pin = 41
PB10 Pin = 42
PB11 Pin = 43
PB12 Pin = 44
PB13 Pin = 45
PB14 Pin = 46
PB15 Pin = 47
PB16 Pin = 48
PB17 Pin = 49
PB18 Pin = 50
PB19 Pin = 51
PB20 Pin = 52
PB21 Pin = 53
PB22 Pin = 54
PB23 Pin = 55
PB24 Pin = 56
PB25 Pin = 57
PB26 Pin = 58
PB27 Pin = 59
PB28 Pin = 60
PB29 Pin = 61
PB30 Pin = 62
PB31 Pin = 63
PC00 Pin = 64
PC01 Pin = 65
PC02 Pin = 66
PC03 Pin = 67
PC04 Pin = 68
PC05 Pin = 69
PC06 Pin = 70
PC07 Pin = 71
PC08 Pin = 72
PC09 Pin = 73
PC10 Pin = 74
PC11 Pin = 75
PC12 Pin = 76
PC13 Pin = 77
PC14 Pin = 78
PC15 Pin = 79
PC16 Pin = 80
PC17 Pin = 81
PC18 Pin = 82
PC19 Pin = 83
PC20 Pin = 84
PC21 Pin = 85
PC22 Pin = 86
PC23 Pin = 87
PC24 Pin = 88
PC25 Pin = 89
PC26 Pin = 90
PC27 Pin = 91
PC28 Pin = 92
PC29 Pin = 93
PC30 Pin = 94
PC31 Pin = 95
PD00 Pin = 96
PD01 Pin = 97
PD02 Pin = 98
PD03 Pin = 99
PD04 Pin = 100
PD05 Pin = 101
PD06 Pin = 102
PD07 Pin = 103
PD08 Pin = 104
PD09 Pin = 105
PD10 Pin = 106
PD11 Pin = 107
PD12 Pin = 108
PD13 Pin = 109
PD14 Pin = 110
PD15 Pin = 111
PD16 Pin = 112
PD17 Pin = 113
PD18 Pin = 114
PD19 Pin = 115
PD20 Pin = 116
PD21 Pin = 117
PD22 Pin = 118
PD23 Pin = 119
PD24 Pin = 120
PD25 Pin = 121
PD26 Pin = 122
PD27 Pin = 123
PD28 Pin = 124
PD29 Pin = 125
PD30 Pin = 126
PD31 Pin = 127
)
const (
pinPadMapSERCOM0Pad0 uint16 = 0x1000
pinPadMapSERCOM1Pad0 uint16 = 0x2000
pinPadMapSERCOM2Pad0 uint16 = 0x3000
pinPadMapSERCOM3Pad0 uint16 = 0x4000
pinPadMapSERCOM4Pad0 uint16 = 0x5000
pinPadMapSERCOM5Pad0 uint16 = 0x6000
pinPadMapSERCOM6Pad0 uint16 = 0x7000
pinPadMapSERCOM7Pad0 uint16 = 0x8000
pinPadMapSERCOM0Pad2 uint16 = 0x1200
pinPadMapSERCOM1Pad2 uint16 = 0x2200
pinPadMapSERCOM2Pad2 uint16 = 0x3200
pinPadMapSERCOM3Pad2 uint16 = 0x4200
pinPadMapSERCOM4Pad2 uint16 = 0x5200
pinPadMapSERCOM5Pad2 uint16 = 0x6200
pinPadMapSERCOM6Pad2 uint16 = 0x7200
pinPadMapSERCOM7Pad2 uint16 = 0x8200
pinPadMapSERCOM0AltPad0 uint16 = 0x0010
pinPadMapSERCOM1AltPad0 uint16 = 0x0020
pinPadMapSERCOM2AltPad0 uint16 = 0x0030
pinPadMapSERCOM3AltPad0 uint16 = 0x0040
pinPadMapSERCOM4AltPad0 uint16 = 0x0050
pinPadMapSERCOM5AltPad0 uint16 = 0x0060
pinPadMapSERCOM6AltPad0 uint16 = 0x0070
pinPadMapSERCOM7AltPad0 uint16 = 0x0080
pinPadMapSERCOM0AltPad1 uint16 = 0x0011
pinPadMapSERCOM1AltPad1 uint16 = 0x0021
pinPadMapSERCOM2AltPad1 uint16 = 0x0031
pinPadMapSERCOM3AltPad1 uint16 = 0x0041
pinPadMapSERCOM4AltPad1 uint16 = 0x0051
pinPadMapSERCOM5AltPad1 uint16 = 0x0061
pinPadMapSERCOM6AltPad1 uint16 = 0x0071
pinPadMapSERCOM7AltPad1 uint16 = 0x0081
pinPadMapSERCOM0AltPad2 uint16 = 0x0012
pinPadMapSERCOM1AltPad2 uint16 = 0x0022
pinPadMapSERCOM2AltPad2 uint16 = 0x0032
pinPadMapSERCOM3AltPad2 uint16 = 0x0042
pinPadMapSERCOM4AltPad2 uint16 = 0x0052
pinPadMapSERCOM5AltPad2 uint16 = 0x0062
pinPadMapSERCOM6AltPad2 uint16 = 0x0072
pinPadMapSERCOM7AltPad2 uint16 = 0x0082
)
// pinPadMapping lists which pins have which SERCOMs attached to them.
// The encoding is rather dense, with each uint16 encoding two pins and both
// SERCOM and SERCOM-ALT.
//
// Observations:
// * There are eight SERCOMs. Those SERCOM numbers can be encoded in 4 bits.
// * Even pad numbers are usually on even pins, and odd pad numbers are usually
// on odd pins. The exception is SERCOM-ALT, which sometimes swaps pad 0 and 1.
// With that, there is still an invariant that the pad number for an odd pin is
// the pad number for the corresponding even pin with the low bit toggled.
// * Pin pads come in pairs. If PA00 has pad 0, then PA01 has pad 1.
// With this information, we can encode SERCOM pin/pad numbers much more
// efficiently. Due to pads coming in pairs, we can ignore half the pins: the
// information for an odd pin can be calculated easily from the preceding even
// pin.
//
// Each word below is split in two bytes. The 8 high bytes are for SERCOM and
// the 8 low bits are for SERCOM-ALT. Of each byte, the 4 high bits encode the
// SERCOM + 1 while the two low bits encodes the pad number (the pad number for
// the odd pin can be trivially calculated by toggling the low bit of the pad
// number). It encodes SERCOM + 1 instead of just the SERCOM number, to make it
// easy to check whether a nibble is set at all.
//
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf
var pinPadMapping = [64]uint16{
// page 32
PA00 / 2: 0 | pinPadMapSERCOM1AltPad0,
// page 33
PB08 / 2: 0 | pinPadMapSERCOM4AltPad0,
PA04 / 2: 0 | pinPadMapSERCOM0AltPad0,
PA06 / 2: 0 | pinPadMapSERCOM0AltPad2,
PC04 / 2: pinPadMapSERCOM6Pad0 | 0,
PC06 / 2: pinPadMapSERCOM6Pad2 | 0,
PA08 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
PA10 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
PB10 / 2: 0 | pinPadMapSERCOM4AltPad2,
PB12 / 2: pinPadMapSERCOM4Pad0 | 0,
PB14 / 2: pinPadMapSERCOM4Pad2 | 0,
PD08 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
PD10 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
PC10 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM7AltPad2,
// page 34
PC12 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
PC14 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
PA12 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
PA14 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
PA16 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
PA18 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
PC16 / 2: pinPadMapSERCOM6Pad0 | pinPadMapSERCOM0AltPad1,
PC18 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM0AltPad2,
PC22 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
PD20 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
PB16 / 2: pinPadMapSERCOM5Pad0 | 0,
PB18 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM7AltPad2,
// page 35
PB20 / 2: pinPadMapSERCOM3Pad0 | pinPadMapSERCOM7AltPad1,
PA20 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM3AltPad2,
PA22 / 2: pinPadMapSERCOM3Pad0 | pinPadMapSERCOM5AltPad1,
PA24 / 2: pinPadMapSERCOM3Pad2 | pinPadMapSERCOM5AltPad2,
PB22 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM5AltPad2,
PB24 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
PB26 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
PB28 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
PC24 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
//PC26 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC26 doesn't support SERCOM, but PC27 does
//PC28 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC29 doesn't exist in the datasheet?
PA30 / 2: 0 | pinPadMapSERCOM1AltPad2,
// page 36
PB30 / 2: 0 | pinPadMapSERCOM5AltPad1,
PB00 / 2: 0 | pinPadMapSERCOM5AltPad2,
PB02 / 2: 0 | pinPadMapSERCOM5AltPad0,
}
// findPinPadMapping looks up the pad number and the pinmode for a given pin and
// SERCOM number. The result can either be SERCOM, SERCOM-ALT, or "not found"
// (indicated by returning ok=false). The pad number is returned to calculate
// the DOPO/DIPO bitfields of the various serial peripherals.
func findPinPadMapping(sercom uint8, pin Pin) (pinMode PinMode, pad uint32, ok bool) {
if int(pin)/2 >= len(pinPadMapping) {
// This is probably NoPin, for which no mapping is available.
return
}
bytes := pinPadMapping[pin/2]
upper := byte(bytes >> 8)
lower := byte(bytes & 0xff)
if upper != 0 {
// SERCOM
if (upper>>4)-1 == sercom {
pinMode = PinSERCOM
pad |= uint32(upper % 4)
ok = true
}
}
if lower != 0 {
// SERCOM-ALT
if (lower>>4)-1 == sercom {
pinMode = PinSERCOMAlt
pad |= uint32(lower % 4)
ok = true
}
}
if ok {
// If the pin is uneven, toggle the lowest bit of the pad number.
if pin&1 != 0 {
pad ^= 1
}
}
return
}
// SetInterrupt sets an interrupt to be executed when a particular pin changes
// state. The pin should already be configured as an input, including a pull up
// or down if no external pull is provided.
//
// This call will replace a previously set callback on this pin. You can pass a
// nil func to unset the pin change interrupt. If you do so, the change
// parameter is ignored and can be set to any value (such as 0).
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
// Most pins follow a common pattern where the EXTINT value is the pin
// number modulo 16. However, there are a few exceptions, as you can see
// below.
extint := uint8(0)
switch p {
case PA08:
// Connected to NMI. This is not currently supported.
return ErrInvalidInputPin
case PB26:
extint = 12
case PB27:
extint = 13
case PB28:
extint = 14
case PB29:
extint = 15
case PC07:
extint = 9
case PD08:
extint = 3
case PD09:
extint = 4
case PD10:
extint = 5
case PD11:
extint = 6
case PD12:
extint = 7
case PD20:
extint = 10
case PD21:
extint = 11
default:
// All other pins follow a normal pattern.
extint = uint8(p) % 16
}
if callback == nil {
// Disable this pin interrupt (if it was enabled).
sam.EIC.INTENCLR.Set(1 << extint)
if pinCallbacks[extint] != nil {
pinCallbacks[extint] = nil
}
return nil
}
if pinCallbacks[extint] != nil {
// The pin was already configured.
// To properly re-configure a pin, unset it first and set a new
// configuration.
return ErrNoPinChangeChannel
}
pinCallbacks[extint] = callback
interruptPins[extint] = p
if !sam.EIC.CTRLA.HasBits(sam.EIC_CTRLA_ENABLE) {
// EIC peripheral has not yet been initialized. Initialize it now.
// The EIC needs two clocks: CLK_EIC_APB and GCLK_EIC. CLK_EIC_APB is
// enabled by default, so doesn't have to be re-enabled. The other is
// required for detecting edges and must be enabled manually.
sam.GCLK.PCHCTRL[4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
// should not be necessary (CLKCTRL is not synchronized)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0 << sam.GCLK_SYNCBUSY_GENCTRL_Pos) {
}
}
// CONFIG register is enable-protected, so disable EIC.
sam.EIC.CTRLA.ClearBits(sam.EIC_CTRLA_ENABLE)
// Configure this pin. Set the 4 bits of the EIC.CONFIGx register to the
// sense value (filter bit set to 0, sense bits set to the change value).
addr := &sam.EIC.CONFIG[0]
if extint >= 8 {
addr = &sam.EIC.CONFIG[1]
}
pos := (extint % 8) * 4 // bit position in register
addr.ReplaceBits(uint32(change), 0xf, pos)
// Enable external interrupt for this pin.
sam.EIC.INTENSET.Set(1 << extint)
sam.EIC.CTRLA.Set(sam.EIC_CTRLA_ENABLE)
for sam.EIC.SYNCBUSY.HasBits(sam.EIC_SYNCBUSY_ENABLE) {
}
// Set the PMUXEN flag, while keeping the INEN and PULLEN flags (if they
// were set before). This avoids clearing the pin pull mode while
// configuring the pin interrupt.
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | (p.getPinCfg() & (sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN)))
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
handleEICInterrupt := func(interrupt.Interrupt) {
flags := sam.EIC.INTFLAG.Get()
sam.EIC.INTFLAG.Set(flags) // clear interrupt
for i := uint(0); i < 16; i++ { // there are 16 channels
if flags&(1<<i) != 0 {
pinCallbacks[i](interruptPins[i])
}
}
}
switch extint {
case 0:
interrupt.New(sam.IRQ_EIC_EXTINT_0, handleEICInterrupt).Enable()
case 1:
interrupt.New(sam.IRQ_EIC_EXTINT_1, handleEICInterrupt).Enable()
case 2:
interrupt.New(sam.IRQ_EIC_EXTINT_2, handleEICInterrupt).Enable()
case 3:
interrupt.New(sam.IRQ_EIC_EXTINT_3, handleEICInterrupt).Enable()
case 4:
interrupt.New(sam.IRQ_EIC_EXTINT_4, handleEICInterrupt).Enable()
case 5:
interrupt.New(sam.IRQ_EIC_EXTINT_5, handleEICInterrupt).Enable()
case 6:
interrupt.New(sam.IRQ_EIC_EXTINT_6, handleEICInterrupt).Enable()
case 7:
interrupt.New(sam.IRQ_EIC_EXTINT_7, handleEICInterrupt).Enable()
case 8:
interrupt.New(sam.IRQ_EIC_EXTINT_8, handleEICInterrupt).Enable()
case 9:
interrupt.New(sam.IRQ_EIC_EXTINT_9, handleEICInterrupt).Enable()
case 10:
interrupt.New(sam.IRQ_EIC_EXTINT_10, handleEICInterrupt).Enable()
case 11:
interrupt.New(sam.IRQ_EIC_EXTINT_11, handleEICInterrupt).Enable()
case 12:
interrupt.New(sam.IRQ_EIC_EXTINT_12, handleEICInterrupt).Enable()
case 13:
interrupt.New(sam.IRQ_EIC_EXTINT_13, handleEICInterrupt).Enable()
case 14:
interrupt.New(sam.IRQ_EIC_EXTINT_14, handleEICInterrupt).Enable()
case 15:
interrupt.New(sam.IRQ_EIC_EXTINT_15, handleEICInterrupt).Enable()
}
return nil
}
// Return the register and mask to enable a given GPIO pin. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskSet() (*uint32, uint32) {
group, pin_in_group := p.getPinGrouping()
return &sam.PORT.GROUP[group].OUTSET.Reg, 1 << pin_in_group
}
// Return the register and mask to disable a given port. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskClear() (*uint32, uint32) {
group, pin_in_group := p.getPinGrouping()
return &sam.PORT.GROUP[group].OUTCLR.Reg, 1 << pin_in_group
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p Pin) Set(high bool) {
group, pin_in_group := p.getPinGrouping()
if high {
sam.PORT.GROUP[group].OUTSET.Set(1 << pin_in_group)
} else {
sam.PORT.GROUP[group].OUTCLR.Set(1 << pin_in_group)
}
}
// Get returns the current value of a GPIO pin when configured as an input or as
// an output.
func (p Pin) Get() bool {
group, pin_in_group := p.getPinGrouping()
return (sam.PORT.GROUP[group].IN.Get()>>pin_in_group)&1 > 0
}
// Toggle switches an output pin from low to high or from high to low.
// Warning: only use this on an output pin!
func (p Pin) Toggle() {
group, pin_in_group := p.getPinGrouping()
sam.PORT.GROUP[group].OUTTGL.Set(1 << pin_in_group)
}
// Configure this pin with the given configuration.
func (p Pin) Configure(config PinConfig) {
group, pin_in_group := p.getPinGrouping()
switch config.Mode {
case PinOutput:
sam.PORT.GROUP[group].DIRSET.Set(1 << pin_in_group)
// output is also set to input enable so pin can read back its own value
p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN)
case PinInput:
sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group)
p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN)
case PinInputPulldown:
sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group)
sam.PORT.GROUP[group].OUTCLR.Set(1 << pin_in_group)
p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN)
case PinInputPullup:
sam.PORT.GROUP[group].DIRCLR.Set(1 << pin_in_group)
sam.PORT.GROUP[group].OUTSET.Set(1 << pin_in_group)
p.setPinCfg(sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN)
case PinSERCOM:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR | sam.PORT_GROUP_PINCFG_INEN)
case PinSERCOMAlt:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR)
case PinCom:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN)
case PinAnalog:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR)
case PinSDHC:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
p.setPMux(val | (uint8(PinSDHC) << sam.PORT_GROUP_PMUX_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
p.setPMux(val | (uint8(PinSDHC) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN)
}
}
// getPMux returns the value for the correct PMUX register for this pin.
func (p Pin) getPMux() uint8 {
group, pin_in_group := p.getPinGrouping()
return sam.PORT.GROUP[group].PMUX[pin_in_group>>1].Get()
}
// setPMux sets the value for the correct PMUX register for this pin.
func (p Pin) setPMux(val uint8) {
group, pin_in_group := p.getPinGrouping()
sam.PORT.GROUP[group].PMUX[pin_in_group>>1].Set(val)
}
// getPinCfg returns the value for the correct PINCFG register for this pin.
func (p Pin) getPinCfg() uint8 {
group, pin_in_group := p.getPinGrouping()
return sam.PORT.GROUP[group].PINCFG[pin_in_group].Get()
}
// setPinCfg sets the value for the correct PINCFG register for this pin.
func (p Pin) setPinCfg(val uint8) {
group, pin_in_group := p.getPinGrouping()
sam.PORT.GROUP[group].PINCFG[pin_in_group].Set(val)
}
// getPinGrouping calculates the gpio group and pin id from the pin number.
// Pins are split into groups of 32, and each group has its own set of
// control registers.
func (p Pin) getPinGrouping() (uint8, uint8) {
group := uint8(p) >> 5
pin_in_group := uint8(p) & 0x1f
return group, pin_in_group
}
// InitADC initializes the ADC.
func InitADC() {
// ADC Bias Calibration
// NVMCTRL_SW0 0x00800080
// #define ADC0_FUSES_BIASCOMP_ADDR NVMCTRL_SW0
// #define ADC0_FUSES_BIASCOMP_Pos 2 /**< \brief (NVMCTRL_SW0) ADC Comparator Scaling */
// #define ADC0_FUSES_BIASCOMP_Msk (_Ul(0x7) << ADC0_FUSES_BIASCOMP_Pos)
// #define ADC0_FUSES_BIASCOMP(value) (ADC0_FUSES_BIASCOMP_Msk & ((value) << ADC0_FUSES_BIASCOMP_Pos))
// #define ADC0_FUSES_BIASR2R_ADDR NVMCTRL_SW0
// #define ADC0_FUSES_BIASR2R_Pos 8 /**< \brief (NVMCTRL_SW0) ADC Bias R2R ampli scaling */
// #define ADC0_FUSES_BIASR2R_Msk (_Ul(0x7) << ADC0_FUSES_BIASR2R_Pos)
// #define ADC0_FUSES_BIASR2R(value) (ADC0_FUSES_BIASR2R_Msk & ((value) << ADC0_FUSES_BIASR2R_Pos))
// #define ADC0_FUSES_BIASREFBUF_ADDR NVMCTRL_SW0
// #define ADC0_FUSES_BIASREFBUF_Pos 5 /**< \brief (NVMCTRL_SW0) ADC Bias Reference Buffer Scaling */
// #define ADC0_FUSES_BIASREFBUF_Msk (_Ul(0x7) << ADC0_FUSES_BIASREFBUF_Pos)
// #define ADC0_FUSES_BIASREFBUF(value) (ADC0_FUSES_BIASREFBUF_Msk & ((value) << ADC0_FUSES_BIASREFBUF_Pos))
// #define ADC1_FUSES_BIASCOMP_ADDR NVMCTRL_SW0
// #define ADC1_FUSES_BIASCOMP_Pos 16 /**< \brief (NVMCTRL_SW0) ADC Comparator Scaling */
// #define ADC1_FUSES_BIASCOMP_Msk (_Ul(0x7) << ADC1_FUSES_BIASCOMP_Pos)
// #define ADC1_FUSES_BIASCOMP(value) (ADC1_FUSES_BIASCOMP_Msk & ((value) << ADC1_FUSES_BIASCOMP_Pos))
// #define ADC1_FUSES_BIASR2R_ADDR NVMCTRL_SW0
// #define ADC1_FUSES_BIASR2R_Pos 22 /**< \brief (NVMCTRL_SW0) ADC Bias R2R ampli scaling */
// #define ADC1_FUSES_BIASR2R_Msk (_Ul(0x7) << ADC1_FUSES_BIASR2R_Pos)
// #define ADC1_FUSES_BIASR2R(value) (ADC1_FUSES_BIASR2R_Msk & ((value) << ADC1_FUSES_BIASR2R_Pos))
// #define ADC1_FUSES_BIASREFBUF_ADDR NVMCTRL_SW0
// #define ADC1_FUSES_BIASREFBUF_Pos 19 /**< \brief (NVMCTRL_SW0) ADC Bias Reference Buffer Scaling */
// #define ADC1_FUSES_BIASREFBUF_Msk (_Ul(0x7) << ADC1_FUSES_BIASREFBUF_Pos)
// #define ADC1_FUSES_BIASREFBUF(value) (ADC1_FUSES_BIASREFBUF_Msk & ((value) << ADC1_FUSES_BIASREFBUF_Pos))
adcFuse := *(*uint32)(unsafe.Pointer(uintptr(0x00800080)))
// uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos;
biascomp := (adcFuse & uint32(0x7<<2)) //>> 2
// uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos;
biasr2r := (adcFuse & uint32(0x7<<8)) //>> 8
// uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos;
biasref := (adcFuse & uint32(0x7<<5)) //>> 5
// calibrate ADC0
sam.ADC0.CALIB.Set(uint16(biascomp | biasr2r | biasref))
// biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos;
biascomp = (adcFuse & uint32(0x7<<16)) //>> 16
// biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos;
biasr2r = (adcFuse & uint32(0x7<<22)) //>> 22
// biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos;
biasref = (adcFuse & uint32(0x7<<19)) //>> 19
// calibrate ADC1
sam.ADC1.CALIB.Set(uint16((biascomp | biasr2r | biasref) >> 16))
}
// Configure configures a ADCPin to be able to be used to read data.
func (a ADC) Configure(config ADCConfig) {
for _, adc := range []*sam.ADC_Type{sam.ADC0, sam.ADC1} {
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) {
} // wait for sync
adc.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos)
var resolution uint32
switch config.Resolution {
case 8:
resolution = sam.ADC_CTRLB_RESSEL_8BIT
case 10:
resolution = sam.ADC_CTRLB_RESSEL_10BIT
case 12:
resolution = sam.ADC_CTRLB_RESSEL_12BIT
case 16:
resolution = sam.ADC_CTRLB_RESSEL_16BIT
default:
resolution = sam.ADC_CTRLB_RESSEL_12BIT
}
adc.CTRLB.SetBits(uint16(resolution << sam.ADC_CTRLB_RESSEL_Pos))
adc.SAMPCTRL.Set(5) // sampling Time Length
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) {
} // wait for sync
// No Negative input (Internal Ground)
adc.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos)
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) {
} // wait for sync
// Averaging (see datasheet table in AVGCTRL register description)
var samples uint32
switch config.Samples {
case 1:
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
case 2:
samples = sam.ADC_AVGCTRL_SAMPLENUM_2
case 4:
samples = sam.ADC_AVGCTRL_SAMPLENUM_4
case 8:
samples = sam.ADC_AVGCTRL_SAMPLENUM_8
case 16:
samples = sam.ADC_AVGCTRL_SAMPLENUM_16
case 32:
samples = sam.ADC_AVGCTRL_SAMPLENUM_32
case 64:
samples = sam.ADC_AVGCTRL_SAMPLENUM_64
case 128:
samples = sam.ADC_AVGCTRL_SAMPLENUM_128
case 256:
samples = sam.ADC_AVGCTRL_SAMPLENUM_256
case 512:
samples = sam.ADC_AVGCTRL_SAMPLENUM_512
case 1024:
samples = sam.ADC_AVGCTRL_SAMPLENUM_1024
default: // 1 sample only (no oversampling nor averaging), adjusting result by 0
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
}
adc.AVGCTRL.Set(uint8(samples<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
(0 << sam.ADC_AVGCTRL_ADJRES_Pos))
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) {
} // wait for sync
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) {
} // wait for sync
// TODO: use config.Reference to set AREF level
// default is 3V3 reference voltage
adc.REFCTRL.SetBits(sam.ADC_REFCTRL_REFSEL_INTVCC1)
}
a.Pin.Configure(PinConfig{Mode: PinAnalog})
}
// Get returns the current value of a ADC pin, in the range 0..0xffff.
func (a ADC) Get() uint16 {
bus := a.getADCBus()
ch := a.getADCChannel()
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) {
}
// Selection for the positive ADC input channel
bus.INPUTCTRL.ClearBits(sam.ADC_INPUTCTRL_MUXPOS_Msk)
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
bus.INPUTCTRL.SetBits((uint16(ch) & sam.ADC_INPUTCTRL_MUXPOS_Msk) << sam.ADC_INPUTCTRL_MUXPOS_Pos)
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
// Enable ADC
bus.CTRLA.SetBits(sam.ADC_CTRLA_ENABLE)
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
// Start conversion
bus.SWTRIG.SetBits(sam.ADC_SWTRIG_START)
for !bus.INTFLAG.HasBits(sam.ADC_INTFLAG_RESRDY) {
}
// Clear the Data Ready flag
bus.INTFLAG.ClearBits(sam.ADC_INTFLAG_RESRDY)
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
// Start conversion again, since first conversion after reference voltage changed is invalid.
bus.SWTRIG.SetBits(sam.ADC_SWTRIG_START)
// Waiting for conversion to complete
for !bus.INTFLAG.HasBits(sam.ADC_INTFLAG_RESRDY) {
}
val := bus.RESULT.Get()
// Disable ADC
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
bus.CTRLA.ClearBits(sam.ADC_CTRLA_ENABLE)
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
}
// scales to 16-bit result
switch (bus.CTRLB.Get() & sam.ADC_CTRLB_RESSEL_Msk) >> sam.ADC_CTRLB_RESSEL_Pos {
case sam.ADC_CTRLB_RESSEL_8BIT:
val = val << 8
case sam.ADC_CTRLB_RESSEL_10BIT:
val = val << 6
case sam.ADC_CTRLB_RESSEL_16BIT:
val = val << 4
case sam.ADC_CTRLB_RESSEL_12BIT:
val = val << 4
}
return val
}
func (a ADC) getADCBus() *sam.ADC_Type {
if (a.Pin >= PB04 && a.Pin <= PB07) || (a.Pin >= PC00) {
return sam.ADC1
}
return sam.ADC0
}
func (a ADC) getADCChannel() uint8 {
switch a.Pin {
case PA02:
return 0
case PB08:
return 2
case PB09:
return 3
case PA04:
return 4
case PA05:
return 5
case PA06:
return 6
case PA07:
return 7
case PB00:
return 12
case PB01:
return 13
case PB02:
return 14
case PB03:
return 15
case PA09:
return 17
case PA11:
return 19
case PB04:
return 6
case PB05:
return 7
case PB06:
return 8
case PB07:
return 9
case PC00:
return 10
case PC01:
return 11
case PC02:
return 4
case PC03:
return 5
case PC30:
return 12
case PC31:
return 13
case PD00:
return 14
case PD01:
return 15
default:
panic("Invalid ADC pin")
}
}
// UART on the SAMD51.
type UART struct {
Buffer *RingBuffer
Bus *sam.SERCOM_USART_INT_Type
SERCOM uint8
Interrupt interrupt.Interrupt // RXC interrupt
}
var (
sercomUSART0 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM0_USART_INT, SERCOM: 0}
sercomUSART1 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM1_USART_INT, SERCOM: 1}
sercomUSART2 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM2_USART_INT, SERCOM: 2}
sercomUSART3 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM3_USART_INT, SERCOM: 3}
sercomUSART4 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM4_USART_INT, SERCOM: 4}
sercomUSART5 = UART{Buffer: NewRingBuffer(), Bus: sam.SERCOM5_USART_INT, SERCOM: 5}
)
func init() {
sercomUSART0.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, sercomUSART0.handleInterrupt)
sercomUSART1.Interrupt = interrupt.New(sam.IRQ_SERCOM1_2, sercomUSART1.handleInterrupt)
sercomUSART2.Interrupt = interrupt.New(sam.IRQ_SERCOM2_2, sercomUSART2.handleInterrupt)
sercomUSART3.Interrupt = interrupt.New(sam.IRQ_SERCOM3_2, sercomUSART3.handleInterrupt)
sercomUSART4.Interrupt = interrupt.New(sam.IRQ_SERCOM4_2, sercomUSART4.handleInterrupt)
sercomUSART5.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, sercomUSART5.handleInterrupt)
}
const (
sampleRate16X = 16
lsbFirst = 1
)
// Configure the UART.
func (uart *UART) Configure(config UARTConfig) error {
// Default baud rate to 115200.
if config.BaudRate == 0 {
config.BaudRate = 115200
}
// determine pins
if config.TX == 0 && config.RX == 0 {
// use default pins
config.TX = UART_TX_PIN
config.RX = UART_RX_PIN
}
// Determine transmit pinout.
txPinMode, txPad, ok := findPinPadMapping(uart.SERCOM, config.TX)
if !ok {
return ErrInvalidOutputPin
}
var txPinOut uint32
// See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how
// pads are mapped to pinout values.
switch txPad {
case 0: