@@ -103,6 +103,117 @@ const (
103
103
PB31 Pin = 63
104
104
)
105
105
106
+ const (
107
+ pinPadMapSERCOM0Pad0 byte = (0x10 << 1 ) | 0x00
108
+ pinPadMapSERCOM1Pad0 byte = (0x20 << 1 ) | 0x00
109
+ pinPadMapSERCOM2Pad0 byte = (0x30 << 1 ) | 0x00
110
+ pinPadMapSERCOM3Pad0 byte = (0x40 << 1 ) | 0x00
111
+ pinPadMapSERCOM4Pad0 byte = (0x50 << 1 ) | 0x00
112
+ pinPadMapSERCOM5Pad0 byte = (0x60 << 1 ) | 0x00
113
+ pinPadMapSERCOM0Pad2 byte = (0x10 << 1 ) | 0x10
114
+ pinPadMapSERCOM1Pad2 byte = (0x20 << 1 ) | 0x10
115
+ pinPadMapSERCOM2Pad2 byte = (0x30 << 1 ) | 0x10
116
+ pinPadMapSERCOM3Pad2 byte = (0x40 << 1 ) | 0x10
117
+ pinPadMapSERCOM4Pad2 byte = (0x50 << 1 ) | 0x10
118
+ pinPadMapSERCOM5Pad2 byte = (0x60 << 1 ) | 0x10
119
+
120
+ pinPadMapSERCOM0AltPad0 byte = (0x01 << 1 ) | 0x00
121
+ pinPadMapSERCOM1AltPad0 byte = (0x02 << 1 ) | 0x00
122
+ pinPadMapSERCOM2AltPad0 byte = (0x03 << 1 ) | 0x00
123
+ pinPadMapSERCOM3AltPad0 byte = (0x04 << 1 ) | 0x00
124
+ pinPadMapSERCOM4AltPad0 byte = (0x05 << 1 ) | 0x00
125
+ pinPadMapSERCOM5AltPad0 byte = (0x06 << 1 ) | 0x00
126
+ pinPadMapSERCOM0AltPad2 byte = (0x01 << 1 ) | 0x01
127
+ pinPadMapSERCOM1AltPad2 byte = (0x02 << 1 ) | 0x01
128
+ pinPadMapSERCOM2AltPad2 byte = (0x03 << 1 ) | 0x01
129
+ pinPadMapSERCOM3AltPad2 byte = (0x04 << 1 ) | 0x01
130
+ pinPadMapSERCOM4AltPad2 byte = (0x05 << 1 ) | 0x01
131
+ pinPadMapSERCOM5AltPad2 byte = (0x06 << 1 ) | 0x01
132
+ )
133
+
134
+ // pinPadMapping lists which pins have which SERCOMs attached to them.
135
+ // The encoding is rather dense, with each byte encoding two pins and both
136
+ // SERCOM and SERCOM-ALT.
137
+ //
138
+ // Observations:
139
+ // * There are six SERCOMs. Those SERCOM numbers can be encoded in 3 bits.
140
+ // * Even pad numbers are always on even pins, and odd pad numbers are always on
141
+ // odd pins.
142
+ // * Pin pads come in pairs. If PA00 has pad 0, then PA01 has pad 1.
143
+ // With this information, we can encode SERCOM pin/pad numbers much more
144
+ // efficiently. First of all, due to pads coming in pairs, we can ignore half
145
+ // the pins: the information for an odd pin can be calculated easily from the
146
+ // preceding even pin. And second, if odd pads are always on odd pins and even
147
+ // pads on even pins, we can drop a single bit from the pad number.
148
+ //
149
+ // Each byte below is split in two nibbles. The 4 high bits are for SERCOM and
150
+ // the 4 low bits are for SERCOM-ALT. Of each nibble, the 3 high bits encode the
151
+ // SERCOM + 1 while the low bit encodes whether this is PAD0 or PAD2 (0 means
152
+ // PAD0, 1 means PAD2). It encodes SERCOM + 1 instead of just the SERCOM number,
153
+ // to make it easy to check whether a nibble is set at all.
154
+ var pinPadMapping = [32 ]byte {
155
+ // page 21
156
+ PA00 / 2 : 0 | pinPadMapSERCOM1AltPad0 ,
157
+ PB08 / 2 : 0 | pinPadMapSERCOM4AltPad0 ,
158
+ PA04 / 2 : 0 | pinPadMapSERCOM0AltPad0 ,
159
+ PA06 / 2 : 0 | pinPadMapSERCOM0AltPad2 ,
160
+ PA08 / 2 : pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad0 ,
161
+ PA10 / 2 : pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2 ,
162
+
163
+ // page 22
164
+ PB10 / 2 : 0 | pinPadMapSERCOM4AltPad2 ,
165
+ PB12 / 2 : pinPadMapSERCOM4Pad0 | 0 ,
166
+ PB14 / 2 : pinPadMapSERCOM4Pad2 | 0 ,
167
+ PA12 / 2 : pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad0 ,
168
+ PA14 / 2 : pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2 ,
169
+ PA16 / 2 : pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad0 ,
170
+ PA18 / 2 : pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2 ,
171
+ PB16 / 2 : pinPadMapSERCOM5Pad0 | 0 ,
172
+ PA20 / 2 : pinPadMapSERCOM5Pad2 | pinPadMapSERCOM3AltPad2 ,
173
+ PA22 / 2 : pinPadMapSERCOM3Pad0 | pinPadMapSERCOM5AltPad0 ,
174
+ PA24 / 2 : pinPadMapSERCOM3Pad2 | pinPadMapSERCOM5AltPad2 ,
175
+
176
+ // page 23
177
+ PB22 / 2 : 0 | pinPadMapSERCOM5AltPad2 ,
178
+ PA30 / 2 : 0 | pinPadMapSERCOM1AltPad2 ,
179
+ PB30 / 2 : 0 | pinPadMapSERCOM5AltPad0 ,
180
+ PB00 / 2 : 0 | pinPadMapSERCOM5AltPad2 ,
181
+ PB02 / 2 : 0 | pinPadMapSERCOM5AltPad0 ,
182
+ }
183
+
184
+ // findPinPadMapping looks up the pad number and the pinmode for a given pin,
185
+ // given a SERCOM number. The result can either be SERCOM, SERCOM-ALT, or "not
186
+ // found" (indicated by returning ok=false). The pad number is returned to
187
+ // calculate the DOPO/DIPO bitfields of the various serial peripherals.
188
+ func findPinPadMapping (sercom uint8 , pin Pin ) (pinMode PinMode , pad uint32 , ok bool ) {
189
+ nibbles := pinPadMapping [pin / 2 ]
190
+ upper := nibbles >> 4
191
+ lower := nibbles & 0xf
192
+
193
+ if upper != 0 {
194
+ // SERCOM
195
+ if (upper >> 1 )- 1 == sercom {
196
+ pinMode = PinSERCOM
197
+ pad |= uint32 ((upper & 1 ) << 1 )
198
+ ok = true
199
+ }
200
+ }
201
+ if lower != 0 {
202
+ // SERCOM-ALT
203
+ if (lower >> 1 )- 1 == sercom {
204
+ pinMode = PinSERCOMAlt
205
+ pad |= uint32 ((lower & 1 ) << 1 )
206
+ ok = true
207
+ }
208
+ }
209
+
210
+ if ok {
211
+ // The lower bit of the pad is the same as the lower bit of the pin number.
212
+ pad |= uint32 (pin & 1 )
213
+ }
214
+ return
215
+ }
216
+
106
217
// InitADC initializes the ADC.
107
218
func InitADC () {
108
219
// ADC Bias Calibration
@@ -272,11 +383,6 @@ const (
272
383
sercomTXPad0 = 0 // Only for UART
273
384
sercomTXPad2 = 1 // Only for UART
274
385
sercomTXPad023 = 2 // Only for UART with TX on PAD0, RTS on PAD2 and CTS on PAD3
275
-
276
- spiTXPad0SCK1 = 0
277
- spiTXPad2SCK3 = 1
278
- spiTXPad3SCK1 = 2
279
- spiTXPad0SCK3 = 3
280
386
)
281
387
282
388
// Configure the UART.
@@ -874,13 +980,8 @@ func waitForSync() {
874
980
875
981
// SPI
876
982
type SPI struct {
877
- Bus * sam.SERCOM_SPI_Type
878
- SCK Pin
879
- MOSI Pin
880
- MISO Pin
881
- DOpad int
882
- DIpad int
883
- PinMode PinMode
983
+ Bus * sam.SERCOM_SPI_Type
984
+ SERCOM uint8
884
985
}
885
986
886
987
// SPIConfig is used to store config info for SPI.
@@ -894,30 +995,69 @@ type SPIConfig struct {
894
995
}
895
996
896
997
// Configure is intended to setup the SPI interface.
897
- func (spi SPI ) Configure (config SPIConfig ) {
898
- config .SCK = spi .SCK
899
- config .MOSI = spi .MOSI
900
- config .MISO = spi .MISO
901
-
902
- doPad := spi .DOpad
903
- diPad := spi .DIpad
904
-
905
- pinMode := spi .PinMode
998
+ func (spi SPI ) Configure (config SPIConfig ) error {
999
+ // Use default pins if not set.
1000
+ if config .SCK == 0 && config .MOSI == 0 && config .MISO == 0 {
1001
+ config .SCK = SPI0_SCK_PIN
1002
+ config .MOSI = SPI0_MOSI_PIN
1003
+ config .MISO = SPI0_MISO_PIN
1004
+ }
906
1005
907
1006
// set default frequency
908
1007
if config .Frequency == 0 {
909
1008
config .Frequency = 4000000
910
1009
}
911
1010
1011
+ // Determine the input pinout (for MISO).
1012
+ misoPinMode , misoPad , ok := findPinPadMapping (spi .SERCOM , config .MISO )
1013
+ if ! ok {
1014
+ return ErrInvalidInputPin
1015
+ }
1016
+ dataInPinout := misoPad // mapped directly
1017
+
1018
+ // Determine the output pinout (for MOSI/SCK).
1019
+ // See table 26-7 on page 494 of the datasheet.
1020
+ var dataOutPinout uint32
1021
+ sckPinMode , sckPad , ok := findPinPadMapping (spi .SERCOM , config .SCK )
1022
+ if ! ok {
1023
+ return ErrInvalidOutputPin
1024
+ }
1025
+ mosiPinMode , mosiPad , ok := findPinPadMapping (spi .SERCOM , config .MOSI )
1026
+ if ! ok {
1027
+ return ErrInvalidOutputPin
1028
+ }
1029
+ switch sckPad {
1030
+ case 1 :
1031
+ switch mosiPad {
1032
+ case 0 :
1033
+ dataOutPinout = 0x0
1034
+ case 3 :
1035
+ dataOutPinout = 0x2
1036
+ default :
1037
+ return ErrInvalidOutputPin
1038
+ }
1039
+ case 3 :
1040
+ switch mosiPad {
1041
+ case 2 :
1042
+ dataOutPinout = 0x1
1043
+ case 0 :
1044
+ dataOutPinout = 0x3
1045
+ default :
1046
+ return ErrInvalidOutputPin
1047
+ }
1048
+ default :
1049
+ return ErrInvalidOutputPin
1050
+ }
1051
+
912
1052
// Disable SPI port.
913
1053
spi .Bus .CTRLA .ClearBits (sam .SERCOM_SPI_CTRLA_ENABLE )
914
1054
for spi .Bus .SYNCBUSY .HasBits (sam .SERCOM_SPI_SYNCBUSY_ENABLE ) {
915
1055
}
916
1056
917
1057
// enable pins
918
- config .SCK .Configure (PinConfig {Mode : pinMode })
919
- config .MOSI .Configure (PinConfig {Mode : pinMode })
920
- config .MISO .Configure (PinConfig {Mode : pinMode })
1058
+ config .SCK .Configure (PinConfig {Mode : sckPinMode })
1059
+ config .MOSI .Configure (PinConfig {Mode : mosiPinMode })
1060
+ config .MISO .Configure (PinConfig {Mode : misoPinMode })
921
1061
922
1062
// reset SERCOM
923
1063
spi .Bus .CTRLA .SetBits (sam .SERCOM_SPI_CTRLA_SWRST )
@@ -926,16 +1066,16 @@ func (spi SPI) Configure(config SPIConfig) {
926
1066
}
927
1067
928
1068
// set bit transfer order
929
- dataOrder := 0
1069
+ dataOrder := uint32 ( 0 )
930
1070
if config .LSBFirst {
931
1071
dataOrder = 1
932
1072
}
933
1073
934
1074
// Set SPI master
935
- spi .Bus .CTRLA .Set (uint32 ( (sam .SERCOM_SPI_CTRLA_MODE_SPI_MASTER << sam .SERCOM_SPI_CTRLA_MODE_Pos ) |
936
- (doPad << sam .SERCOM_SPI_CTRLA_DOPO_Pos ) |
937
- (diPad << sam .SERCOM_SPI_CTRLA_DIPO_Pos ) |
938
- (dataOrder << sam .SERCOM_SPI_CTRLA_DORD_Pos )))
1075
+ spi .Bus .CTRLA .Set ((sam .SERCOM_SPI_CTRLA_MODE_SPI_MASTER << sam .SERCOM_SPI_CTRLA_MODE_Pos ) |
1076
+ (dataOutPinout << sam .SERCOM_SPI_CTRLA_DOPO_Pos ) |
1077
+ (dataInPinout << sam .SERCOM_SPI_CTRLA_DIPO_Pos ) |
1078
+ (dataOrder << sam .SERCOM_SPI_CTRLA_DORD_Pos ))
939
1079
940
1080
spi .Bus .CTRLB .SetBits ((0 << sam .SERCOM_SPI_CTRLB_CHSIZE_Pos ) | // 8bit char size
941
1081
sam .SERCOM_SPI_CTRLB_RXEN ) // receive enable
@@ -969,6 +1109,8 @@ func (spi SPI) Configure(config SPIConfig) {
969
1109
spi .Bus .CTRLA .SetBits (sam .SERCOM_SPI_CTRLA_ENABLE )
970
1110
for spi .Bus .SYNCBUSY .HasBits (sam .SERCOM_SPI_SYNCBUSY_ENABLE ) {
971
1111
}
1112
+
1113
+ return nil
972
1114
}
973
1115
974
1116
// Transfer writes/reads a single byte using the SPI interface.
0 commit comments