go-rpio/spi.go

158 lines
3.5 KiB
Go
Raw Normal View History

2018-10-04 01:03:17 +02:00
package rpio
import (
"errors"
)
2018-10-05 17:04:53 +02:00
type SpiDev int
// SPI devices.
// Only SPI0 supported for now.
2018-10-04 01:03:17 +02:00
const (
2018-10-05 17:04:53 +02:00
Spi0 SpiDev = iota
Spi1 // aux
Spi2 // aux
2018-10-04 01:03:17 +02:00
)
const (
csReg = 0
fifoReg = 1 // TX/RX FIFO
clkDivReg = 2
)
var (
SpiMapError = errors.New("SPI registers not mapped correctly - are you root?")
)
2018-10-05 17:04:53 +02:00
// 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.
2018-10-05 17:04:53 +02:00
//
// Note that you should disable SPI interface in raspi-config first!
func SpiBegin(dev SpiDev) error {
2018-10-04 01:03:17 +02:00
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
}
2018-10-05 17:04:53 +02:00
// Sets SPI pins of given device to default (Input) mode. See SpiBegin.
func SpiEnd(dev SpiDev) {
2018-10-04 01:03:17 +02:00
var pins = getSpiPins(dev)
for _, pin := range pins {
pin.Mode(Input)
}
}
// Set (maximal) speed [Hz] of SPI clock.
2018-10-04 01:03:17 +02:00
// Param speed may be as big as 125MHz in theory, but
// only values up to 31.25MHz are considered relayable.
func SpiSpeed(speed int) {
const baseFreq = 250 * 1000000
cdiv := uint32(baseFreq / speed)
setSpiDiv(cdiv)
}
// Select chip, one of 0, 1, 2
// for selecting slave on CE0, CE1, or CE2 pin
func SpiChipSelect(chip int) {
2018-10-04 01:03:17 +02:00
const csMask = 3 // chip select has 2 bits
cs := uint32(chip & csMask)
spiMem[csReg] = spiMem[csReg]&^csMask | cs
}
// 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
}
2018-10-04 01:03:17 +02:00
// 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) {
2018-10-04 01:03:17 +02:00
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
2018-10-04 01:03:17 +02:00
for spiMem[csReg]&txd == 0 {
}
// write bytes to SPI_FIFO
2018-10-04 01:03:17 +02:00
spiMem[fifoReg] = uint32(data[i])
// wait for RXD
2018-10-04 01:03:17 +02:00
for spiMem[csReg]&rxd == 0 {
}
// read bytes from SPI_FIFO
2018-10-04 01:03:17 +02:00
data[i] = byte(spiMem[fifoReg])
}
// wait for DONE
for spiMem[csReg]&done == 0 {
}
// Set TA = 0
spiMem[csReg] &^= ta
}
// set spi clock divider value
2018-10-05 17:04:53 +02:00
func setSpiDiv(div uint32) {
const divMask = 1<<16 - 1 - 1 // cdiv have 16 bits and must be odd (for some reason)
2018-10-04 01:03:17 +02:00
spiMem[clkDivReg] = div & divMask
}
// clear both FIFOs
2018-10-04 01:03:17 +02:00
func clearSpiTxRxFifo() {
const clearTxRx = 1<<5 | 1<<4
spiMem[csReg] |= clearTxRx
}
2018-10-05 17:04:53 +02:00
func getSpiPins(dev SpiDev) []Pin {
2018-10-04 01:03:17 +02:00
switch dev {
2018-10-05 17:04:53 +02:00
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
2018-10-05 17:04:53 +02:00
case Spi1:
return []Pin{16, 17, 18, 19, 20, 21}
2018-10-05 17:04:53 +02:00
case Spi2:
return []Pin{40, 41, 42, 43, 44, 45}
2018-10-04 01:03:17 +02:00
default:
return []Pin{}
}
}