robocar-pca9685/vendor/periph.io/x/host/v3/allwinner/spi.go

208 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package allwinner
import (
"errors"
"fmt"
"log"
"time"
)
const (
// 31:20 reserved
// Set this bit to 1 to make the internal read sample point with a delay of
// half cycle of SPI_CLK. It is used in high speed read operation to reduce
// the error caused by the time delay of SPI_CLK propagating between master
// and slave.
// 1 delay internal read sample point
// 0 normal operation, do not delay internal read sample point
spiR8HalfDelay spiR8Ctl = 1 << 19 // Master Sample Data Control
spiR8TransmitPause spiR8Ctl = 1 << 18 // Transmit Pause Enable
spiR8CSLevel spiR8Ctl = 1 << 17 // SS_LEVEL; Chip Select level
spiR8CSManual spiR8Ctl = 1 << 16 // SS_CTRL; Do not switch CS automatically
spiR8DiscardHash spiR8Ctl = 1 << 15 // DHB
spiR8DummyBurst spiR8Ctl = 1 << 14 // DDB
spiR8CS0 spiR8Ctl = 0 << 12 // SS; Which CS line to use. For SPI0 only
spiR8CS1 spiR8Ctl = 1 << 12 //
spiR8CS2 spiR8Ctl = 2 << 12 //
spiR8CS3 spiR8Ctl = 3 << 12 //
spiR8RapidsReadMode spiR8Ctl = 1 << 11 // RPSM
spiR8ExchangeBurst spiR8Ctl = 1 << 10 // XCH
spiR8RXFIFOReset spiR8Ctl = 1 << 9 // RXFIFO Reset; Write to reset the FIFO as empty
spiR8TXFIFOReset spiR8Ctl = 1 << 8 // TXFIFO Reset; Write to reset the FIFO as empty
spiR8CSBetweenBursts spiR8Ctl = 1 << 7 // SSCTL
spiR8LSB spiR8Ctl = 1 << 6 // LMTF; MSB by default, LSB when set
spiR8DDMA spiR8Ctl = 1 << 5 // DMAM; Use dedicated DMA if set, normal DMA otherwise
spiR8CSActiveLow spiR8Ctl = 1 << 4 // SSPOL; CS line polarity
spiR8ClkActiveLow spiR8Ctl = 1 << 3 // POL; Clock line polarity
spiR8PHA spiR8Ctl = 1 << 2 // PHA; Phase 1 if set (leading edge for setup data)
spiR8Master spiR8Ctl = 1 << 1 // MODE; Slave mode if not set
spiR8Enable spiR8Ctl = 1 << 0 // EN; Enable mode
)
// SPI_CTL
// R8: Page 153-155. Default: 0x0002001C
type spiR8Ctl uint32
// SPI_INTCTL
// R8: Page 155-156.
type spiR8IntCtl uint32
const (
spiR8ClearInterrupt spiR8IntStatus = 1 << 31 // Clear interrupt busy flag
// 30:18 reserved
spiR8InvalidSS spiR8IntStatus = 1 << 17 // SSI
spiR8TC spiR8IntStatus = 1 << 16 // TC; Transfer Completed
)
// SPI_INT_STA
// R8: Page 156-157.
type spiR8IntStatus uint32
const (
// 31:13 reserved
spiR8DMATX3Quarter spiR8DMACtl = 1 << 12 // TXFIFO 3/4 empty
spiR8DMATX1Quarter spiR8DMACtl = 1 << 11 // TXFIFO 1/4 empty
spiR8DMATXByte spiR8DMACtl = 1 << 10 // TXFIFO Not Full
spiR8DMATXHalf spiR8DMACtl = 1 << 9 // TXFIFO 1/2 empty
spiR8DMATXEmpty spiR8DMACtl = 1 << 8 // TXFIFO empty
// 7:5 reserved
spiR8DMARX3Quarter spiR8DMACtl = 1 << 4 // RXFIFO 3/4 empty
spiR8DMARX1Quarter spiR8DMACtl = 1 << 3 // RXFIFO 1/4 empty
spiR8DMARXByte spiR8DMACtl = 1 << 2 // RXFIFO Not Full
spiR8DMARXHalf spiR8DMACtl = 1 << 1 // RXFIFO 1/2 empty
spiR8DMARXEmpty spiR8DMACtl = 1 << 0 // RXFIFO empty
)
// SPI_DMACTL
// R8: Page 158.
type spiR8DMACtl uint32
const (
// 31:13 reserved
spiR8DivRateSelect2 spiR8ClockCtl = 1 << 12 // DRS; Use spiDivXX if set, use mask otherwise
spiR8Div2 spiR8ClockCtl = 0 << 8 // CDR1; Use divisor 2^(n+1)
spiR8Div4 spiR8ClockCtl = 1 << 8 //
spiR8Div8 spiR8ClockCtl = 2 << 8 //
spiR8Div16 spiR8ClockCtl = 3 << 8 //
spiR8Div32 spiR8ClockCtl = 4 << 8 //
spiR8Div64 spiR8ClockCtl = 5 << 8 //
spiR8Div128 spiR8ClockCtl = 6 << 8 //
spiR8Div256 spiR8ClockCtl = 7 << 8 //
spiR8Div512 spiR8ClockCtl = 8 << 8 //
spiR8Div1024 spiR8ClockCtl = 9 << 8 //
spiR8Div2048 spiR8ClockCtl = 10 << 8 //
spiR8Div4096 spiR8ClockCtl = 11 << 8 //
spiR8Div8192 spiR8ClockCtl = 12 << 8 //
spiR8Div16384 spiR8ClockCtl = 13 << 8 //
spiR8Div32768 spiR8ClockCtl = 14 << 8 //
spiR8Div65536 spiR8ClockCtl = 15 << 8 //
spiR8Div1Mask spiR8ClockCtl = 0xFF // CDR2; Use divisor 2*(n+1)
)
// SPI_CCTL
// R8: Page 159.
type spiR8ClockCtl uint32
const (
// 31:25 reserved
spiR8FIFOTXShift = 16 // 0 to 64
// 15:7 reserved
spiR8FIFORXShift = 0 // 0 to 64
)
// SPI_FIFO_STA
// R8: Page 160.
type spiR8FIFOStatus uint32
func (s spiR8FIFOStatus) tx() uint8 {
return uint8((uint32(s) >> 16) & 127)
}
func (s spiR8FIFOStatus) rx() uint8 {
return uint8(uint32(s) & 127)
}
// spiR8Group is the mapping of SPI registers for one SPI controller.
// R8: Page 152-153.
type spiR8Group struct {
rx uint32 // 0x00 SPI_RX_DATA RX Data
tx uint32 // 0x04 SPI_TX_DATA TX Data
ctl spiR8Ctl // 0x08 SPI_CTL Control
intCtl spiR8IntCtl // 0x0C SPI_INTCTL Interrupt Control
status spiR8IntStatus // 0x10 SPI_ST Status
dmaCtl spiR8DMACtl // 0x14 SPI_DMACTL DMA Control
wait uint32 // 0x18 SPI_WAIT Clock Counter; 16 bits
clockCtl spiR8ClockCtl // 0x1C SPI_CCTL Clock Rate Control
burstCounter uint32 // 0x20 SPI_BC Burst Counter; 24 bits
transmitCounter uint32 // 0x24 SPI_TC Transmit Counter; 24 bits
fifoStatus spiR8FIFOStatus // 0x28 SPI_FIFO_STA FIFO Status
reserved [(0x1000 - 0x02C) / 4]uint32
}
func (s *spiR8Group) setup() {
s.intCtl = 0
s.status = 0
//s.dmaCtl = spiR8DMARXByte
s.dmaCtl = 0
s.wait = 2
s.clockCtl = spiR8DivRateSelect2 | spiR8Div1024
// spiR8DDMA
s.ctl = spiR8CSManual | spiR8LSB | spiR8Master | spiR8Enable
}
// spiMap is the mapping of SPI registers.
// R8: Page 152-153.
type spiMap struct {
groups [3]spiR8Group
}
// spi2Write do a write on SPI2_MOSI via polling.
func spi2Write(w []byte) error {
if drvDMA.clockMemory == nil || drvDMA.spiMemory == nil {
return errors.New("subsystem not initialized")
}
// Make sure the source clock is disabled. Set it at 250kHz.
//drvDMA.clockMemory.spi2Clk &^= clockSPIEnable
drvDMA.clockMemory.spi2Clk |= clockSPIEnable
drvDMA.clockMemory.spi2Clk = clockSPIDiv8a | clockSPIDiv12b
ch := &drvDMA.spiMemory.groups[2]
ch.setup()
fmt.Printf("Setup done\n")
for i := 0; i < len(w)/4; i++ {
// TODO(maruel): Access it in 8bit mode.
ch.tx = uint32(w[0])
for ch.fifoStatus.tx() == 0 {
log.Printf("Waiting for bit %# v\n", ch)
time.Sleep(time.Second)
}
}
fmt.Printf("Done\n")
return nil
}
// spi2Read do a read on SPI2_MISO via polling.
func spi2Read(r []byte) error {
if drvDMA.clockMemory == nil || drvDMA.spiMemory == nil {
return errors.New("subsystem not initialized")
}
// Make sure the source clock is disabled. Set it at 250kHz.
//drvDMA.clockMemory.spi2Clk &^= clockSPIEnable
drvDMA.clockMemory.spi2Clk |= clockSPIEnable
drvDMA.clockMemory.spi2Clk = clockSPIDiv8a | clockSPIDiv12b
ch := &drvDMA.spiMemory.groups[2]
ch.setup()
for i := 0; i < len(r)/4; i++ {
ch.tx = 0
for ch.status&spiR8TC == 0 {
}
// TODO(maruel): Access it in 8bit mode.
r[i] = uint8(ch.rx)
}
fmt.Printf("Done\n")
return nil
}