-
Notifications
You must be signed in to change notification settings - Fork 223
/
spi.go
194 lines (164 loc) · 4.46 KB
/
spi.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
package rpio
import (
"errors"
)
type SpiDev int
// SPI devices.
// Only SPI0 supported for now.
const (
Spi0 SpiDev = iota
Spi1 // aux
Spi2 // aux
)
const (
csReg = 0
fifoReg = 1 // TX/RX FIFO
clkDivReg = 2
)
var (
SpiMapError = errors.New("SPI registers not mapped correctly - are you root?")
)
// SpiBegin: Sets all pins of given SPI device to SPI mode
// dev\pin | CE0 | CE1 | CE2 | SCLK | MOSI | MISO |
// Spi0 | 7 | 8 | - | 9 | 10 | 11 |
// Spi1 | 16 | 17 | 18 | 19 | 20 | 21 |
// Spi2 | 40 | 41 | 42 | 43 | 44 | 45 |
//
// It also resets SPI control register.
//
// Note that you should disable SPI interface in raspi-config first!
func SpiBegin(dev SpiDev) error {
spiMem[csReg] = 0 // reset spi settings to default
if spiMem[csReg] == 0 {
// this should not read only zeroes after reset -> mem map failed
return SpiMapError
}
for _, pin := range getSpiPins(dev) {
pin.Mode(Spi)
}
clearSpiTxRxFifo()
setSpiDiv(128)
return nil
}
// SpiEnd: Sets SPI pins of given device to default (Input) mode. See SpiBegin.
func SpiEnd(dev SpiDev) {
var pins = getSpiPins(dev)
for _, pin := range pins {
pin.Mode(Input)
}
}
// SpiSpeed: Set (maximal) speed [Hz] of SPI clock.
// Param speed may be as big as 125MHz in theory, but
// only values up to 31.25MHz are considered relayable.
func SpiSpeed(speed int) {
coreFreq := 250 * 1000000
if isBCM2711() {
coreFreq = 550 * 1000000
}
cdiv := uint32(coreFreq / speed)
setSpiDiv(cdiv)
}
// SpiChipSelect: Select chip, one of 0, 1, 2
// for selecting slave on CE0, CE1, or CE2 pin
func SpiChipSelect(chip uint8) {
const csMask = 3 // chip select has 2 bits
cs := uint32(chip & csMask)
spiMem[csReg] = spiMem[csReg]&^csMask | cs
}
// SpiChipSelectPolarity: Sets polarity (0/1) of active chip select
// default active=0
func SpiChipSelectPolarity(chip uint8, polarity uint8) {
if chip > 2 {
return
}
cspol := uint32(1 << (21 + chip)) // bit 21, 22 or 23 depending on chip
if polarity == 0 { // chip select is active low
spiMem[csReg] &^= cspol
} else { // chip select is active hight
spiMem[csReg] |= cspol
}
}
// SpiMode: Set polarity (0/1) and phase (0/1) of spi clock
// default polarity=0; phase=0
func SpiMode(polarity uint8, phase uint8) {
const cpol = 1 << 3
const cpha = 1 << 2
if polarity == 0 { // Rest state of clock = low
spiMem[csReg] &^= cpol
} else { // Rest state of clock = high
spiMem[csReg] |= cpol
}
if phase == 0 { // First SCLK transition at middle of data bit
spiMem[csReg] &^= cpha
} else { // First SCLK transition at beginning of data bit
spiMem[csReg] |= cpha
}
}
// SpiTransmit takes one or more bytes and send them to slave.
//
// Data received from slave are ignored.
// Use spread operator to send slice of bytes.
func SpiTransmit(data ...byte) {
SpiExchange(append(data[:0:0], data...)) // clone data because it will be rewriten by received bytes
}
// SpiReceive receives n bytes from slave.
//
// Note that n zeroed bytes are send to slave as side effect.
func SpiReceive(n int) []byte {
data := make([]byte, n, n)
SpiExchange(data)
return data
}
// SpiExchange: Transmit all bytes in data to slave
// and simultaneously receives bytes from slave to data.
//
// If you want to only send or only receive, use SpiTransmit/SpiReceive
func SpiExchange(data []byte) {
const ta = 1 << 7 // transfer active
const txd = 1 << 18 // tx fifo can accept data
const rxd = 1 << 17 // rx fifo contains data
const done = 1 << 16
clearSpiTxRxFifo()
// set TA = 1
spiMem[csReg] |= ta
for i := range data {
// wait for TXD
for spiMem[csReg]&txd == 0 {
}
// write bytes to SPI_FIFO
spiMem[fifoReg] = uint32(data[i])
// wait for RXD
for spiMem[csReg]&rxd == 0 {
}
// read bytes from SPI_FIFO
data[i] = byte(spiMem[fifoReg])
}
// wait for DONE
for spiMem[csReg]&done == 0 {
}
// Set TA = 0
spiMem[csReg] &^= ta
}
// set spi clock divider value
func setSpiDiv(div uint32) {
const divMask = 1<<16 - 1 - 1 // cdiv have 16 bits and must be odd (for some reason)
spiMem[clkDivReg] = div & divMask
}
// clear both FIFOs
func clearSpiTxRxFifo() {
const clearTxRx = 1<<5 | 1<<4
spiMem[csReg] |= clearTxRx
}
func getSpiPins(dev SpiDev) []Pin {
switch dev {
case Spi0:
return []Pin{7, 8, 9, 10, 11}
// ommit 35, 36, 37, 38, 39 - only one set of SPI0 can be set in Spi mode at a time
case Spi1:
return []Pin{16, 17, 18, 19, 20, 21}
case Spi2:
return []Pin{40, 41, 42, 43, 44, 45}
default:
return []Pin{}
}
}