
Let's use the same default frequency everywhere, for consistency. It could be any frequency, but 4MHz is already used for other chips and it seems like a reasonable frequency to me (not too fast for most chips but still reasonably fast). Oh, and 4MHz is slow enough that it can be inspected by a Saleae Logic 4 (that sadly has been discontinued).
324 строки
7,6 КиБ
Go
324 строки
7,6 КиБ
Go
// +build fe310
|
|
|
|
package machine
|
|
|
|
import (
|
|
"device/sifive"
|
|
"runtime/interrupt"
|
|
)
|
|
|
|
func CPUFrequency() uint32 {
|
|
return 16000000
|
|
}
|
|
|
|
type PinMode uint8
|
|
|
|
const (
|
|
PinInput PinMode = iota
|
|
PinOutput
|
|
PinPWM
|
|
PinSPI
|
|
PinI2C = PinSPI
|
|
)
|
|
|
|
// Configure this pin with the given configuration.
|
|
func (p Pin) Configure(config PinConfig) {
|
|
sifive.GPIO0.INPUT_EN.SetBits(1 << uint8(p))
|
|
switch config.Mode {
|
|
case PinOutput:
|
|
sifive.GPIO0.OUTPUT_EN.SetBits(1 << uint8(p))
|
|
case PinPWM:
|
|
sifive.GPIO0.IOF_EN.SetBits(1 << uint8(p))
|
|
sifive.GPIO0.IOF_SEL.SetBits(1 << uint8(p))
|
|
case PinSPI:
|
|
sifive.GPIO0.IOF_EN.SetBits(1 << uint8(p))
|
|
sifive.GPIO0.IOF_SEL.ClearBits(1 << uint8(p))
|
|
}
|
|
}
|
|
|
|
// Set the pin to high or low.
|
|
func (p Pin) Set(high bool) {
|
|
if high {
|
|
sifive.GPIO0.PORT.SetBits(1 << uint8(p))
|
|
} else {
|
|
sifive.GPIO0.PORT.ClearBits(1 << uint8(p))
|
|
}
|
|
}
|
|
|
|
// Get returns the current value of a GPIO pin.
|
|
func (p Pin) Get() bool {
|
|
val := sifive.GPIO0.VALUE.Get() & (1 << uint8(p))
|
|
return (val > 0)
|
|
}
|
|
|
|
type UART struct {
|
|
Bus *sifive.UART_Type
|
|
Buffer *RingBuffer
|
|
}
|
|
|
|
var (
|
|
UART0 = UART{Bus: sifive.UART0, Buffer: NewRingBuffer()}
|
|
)
|
|
|
|
func (uart UART) Configure(config UARTConfig) {
|
|
// Assuming a 16Mhz Crystal (which is Y1 on the HiFive1), the divisor for a
|
|
// 115200 baud rate is 138.
|
|
sifive.UART0.DIV.Set(138)
|
|
sifive.UART0.TXCTRL.Set(sifive.UART_TXCTRL_ENABLE)
|
|
sifive.UART0.RXCTRL.Set(sifive.UART_RXCTRL_ENABLE)
|
|
sifive.UART0.IE.Set(sifive.UART_IE_RXWM) // enable the receive interrupt (only)
|
|
intr := interrupt.New(sifive.IRQ_UART0, UART0.handleInterrupt)
|
|
intr.SetPriority(5)
|
|
intr.Enable()
|
|
}
|
|
|
|
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
|
rxdata := uart.Bus.RXDATA.Get()
|
|
c := byte(rxdata)
|
|
if uint32(c) != rxdata {
|
|
// The rxdata has other bits set than just the low 8 bits. This probably
|
|
// means that the 'empty' flag is set, which indicates there is no data
|
|
// to be read and the byte is garbage. Ignore this byte.
|
|
return
|
|
}
|
|
uart.Receive(c)
|
|
}
|
|
|
|
func (uart UART) WriteByte(c byte) {
|
|
for sifive.UART0.TXDATA.Get()&sifive.UART_TXDATA_FULL != 0 {
|
|
}
|
|
|
|
sifive.UART0.TXDATA.Set(uint32(c))
|
|
}
|
|
|
|
// SPI on the FE310. The normal SPI0 is actually a quad-SPI meant for flash, so it is best
|
|
// to use SPI1 or SPI2 port for most applications.
|
|
type SPI struct {
|
|
Bus *sifive.QSPI_Type
|
|
}
|
|
|
|
// SPIConfig is used to store config info for SPI.
|
|
type SPIConfig struct {
|
|
Frequency uint32
|
|
SCK Pin
|
|
SDO Pin
|
|
SDI Pin
|
|
LSBFirst bool
|
|
Mode uint8
|
|
}
|
|
|
|
// Configure is intended to setup the SPI interface.
|
|
func (spi SPI) Configure(config SPIConfig) error {
|
|
// Use default pins if not set.
|
|
if config.SCK == 0 && config.SDO == 0 && config.SDI == 0 {
|
|
config.SCK = SPI0_SCK_PIN
|
|
config.SDO = SPI0_SDO_PIN
|
|
config.SDI = SPI0_SDI_PIN
|
|
}
|
|
|
|
// enable pins for SPI
|
|
config.SCK.Configure(PinConfig{Mode: PinSPI})
|
|
config.SDO.Configure(PinConfig{Mode: PinSPI})
|
|
config.SDI.Configure(PinConfig{Mode: PinSPI})
|
|
|
|
// set default frequency
|
|
if config.Frequency == 0 {
|
|
config.Frequency = 4000000 // 4MHz
|
|
}
|
|
|
|
// div = (SPI_CFG(dev)->f_sys / (2 * frequency)) - 1;
|
|
div := CPUFrequency()/(2*config.Frequency) - 1
|
|
spi.Bus.DIV.Set(div)
|
|
|
|
// set mode
|
|
switch config.Mode {
|
|
case 0:
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE)
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY)
|
|
case 1:
|
|
spi.Bus.MODE.SetBits(sifive.QSPI_MODE_PHASE)
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY)
|
|
case 2:
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE)
|
|
spi.Bus.MODE.SetBits(sifive.QSPI_MODE_POLARITY)
|
|
case 3:
|
|
spi.Bus.MODE.SetBits(sifive.QSPI_MODE_PHASE | sifive.QSPI_MODE_POLARITY)
|
|
default: // to mode 0
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_PHASE)
|
|
spi.Bus.MODE.ClearBits(sifive.QSPI_MODE_POLARITY)
|
|
}
|
|
|
|
// frame length
|
|
spi.Bus.FMT.SetBits(8 << sifive.QSPI_FMT_LENGTH_Pos)
|
|
|
|
// Set single line operation, by clearing all bits
|
|
spi.Bus.FMT.ClearBits(sifive.QSPI_FMT_PROTOCOL_Msk)
|
|
|
|
// set bit transfer order
|
|
if config.LSBFirst {
|
|
spi.Bus.FMT.SetBits(sifive.QSPI_FMT_ENDIAN)
|
|
} else {
|
|
spi.Bus.FMT.ClearBits(sifive.QSPI_FMT_ENDIAN)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Transfer writes/reads a single byte using the SPI interface.
|
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
|
// wait for tx ready
|
|
for spi.Bus.TXDATA.HasBits(sifive.QSPI_TXDATA_FULL) {
|
|
}
|
|
|
|
// write data
|
|
spi.Bus.TXDATA.Set(uint32(w))
|
|
|
|
// wait until receive has data
|
|
for spi.Bus.RXDATA.HasBits(sifive.QSPI_RXDATA_EMPTY) {
|
|
}
|
|
|
|
// return data
|
|
return byte(spi.Bus.RXDATA.Get() & sifive.QSPI_RXDATA_DATA_Msk), nil
|
|
}
|
|
|
|
// I2C on the FE310-G002.
|
|
type I2C struct {
|
|
Bus *sifive.I2C_Type
|
|
}
|
|
|
|
// I2CConfig is used to store config info for I2C.
|
|
type I2CConfig struct {
|
|
Frequency uint32
|
|
SCL Pin
|
|
SDA Pin
|
|
}
|
|
|
|
// Configure is intended to setup the I2C interface.
|
|
func (i2c I2C) Configure(config I2CConfig) error {
|
|
var i2cClockFrequency uint32 = 32000000
|
|
if config.Frequency == 0 {
|
|
config.Frequency = TWI_FREQ_100KHZ
|
|
}
|
|
|
|
if config.SDA == 0 && config.SCL == 0 {
|
|
config.SDA = I2C0_SDA_PIN
|
|
config.SCL = I2C0_SCL_PIN
|
|
}
|
|
|
|
var prescaler = i2cClockFrequency/(5*config.Frequency) - 1
|
|
|
|
// disable controller before setting the prescale registers
|
|
i2c.Bus.CTR.ClearBits(sifive.I2C_CTR_EN)
|
|
|
|
// set prescaler registers
|
|
i2c.Bus.PRER_LO.Set(uint32(prescaler & 0xff))
|
|
i2c.Bus.PRER_HI.Set(uint32((prescaler >> 8) & 0xff))
|
|
|
|
// enable controller
|
|
i2c.Bus.CTR.SetBits(sifive.I2C_CTR_EN)
|
|
|
|
config.SDA.Configure(PinConfig{Mode: PinI2C})
|
|
config.SCL.Configure(PinConfig{Mode: PinI2C})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Tx does a single I2C transaction at the specified address.
|
|
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
|
// bytes and stores them in r, and generates a stop condition on the bus.
|
|
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
|
|
var err error
|
|
if len(w) != 0 {
|
|
// send start/address for write
|
|
i2c.sendAddress(addr, true)
|
|
|
|
// ACK received (0: ACK, 1: NACK)
|
|
if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) {
|
|
return errI2CAckExpected
|
|
}
|
|
|
|
// write data
|
|
for _, b := range w {
|
|
err = i2c.writeByte(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if len(r) != 0 {
|
|
// send start/address for read
|
|
i2c.sendAddress(addr, false)
|
|
|
|
// ACK received (0: ACK, 1: NACK)
|
|
if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) {
|
|
return errI2CAckExpected
|
|
}
|
|
|
|
// read first byte
|
|
r[0] = i2c.readByte()
|
|
for i := 1; i < len(r); i++ {
|
|
// send an ACK
|
|
i2c.Bus.CR_SR.Set(^uint32(sifive.I2C_CR_ACK))
|
|
|
|
// read data and send the ACK
|
|
r[i] = i2c.readByte()
|
|
}
|
|
|
|
// send NACK to end transmission
|
|
i2c.Bus.CR_SR.Set(sifive.I2C_CR_ACK)
|
|
}
|
|
|
|
// generate stop condition
|
|
i2c.Bus.CR_SR.Set(sifive.I2C_CR_STO)
|
|
return nil
|
|
}
|
|
|
|
// Writes a single byte to the I2C bus.
|
|
func (i2c I2C) writeByte(data byte) error {
|
|
// Send data byte
|
|
i2c.Bus.TXR_RXR.Set(uint32(data))
|
|
|
|
i2c.Bus.CR_SR.Set(sifive.I2C_CR_WR)
|
|
|
|
// wait until transmission complete
|
|
for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) {
|
|
}
|
|
|
|
// ACK received (0: ACK, 1: NACK)
|
|
if i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_RX_ACK) {
|
|
return errI2CAckExpected
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Reads a single byte from the I2C bus.
|
|
func (i2c I2C) readByte() byte {
|
|
i2c.Bus.CR_SR.Set(sifive.I2C_CR_RD)
|
|
|
|
// wait until transmission complete
|
|
for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) {
|
|
}
|
|
|
|
return byte(i2c.Bus.TXR_RXR.Get())
|
|
}
|
|
|
|
// Sends the address and start signal.
|
|
func (i2c I2C) sendAddress(address uint16, write bool) error {
|
|
data := (address << 1)
|
|
if !write {
|
|
data |= 1 // set read flag in transmit register
|
|
}
|
|
|
|
// write address to transmit register
|
|
i2c.Bus.TXR_RXR.Set(uint32(data))
|
|
|
|
// generate start condition
|
|
i2c.Bus.CR_SR.Set((sifive.I2C_CR_STA | sifive.I2C_CR_WR))
|
|
|
|
// wait until transmission complete
|
|
for i2c.Bus.CR_SR.HasBits(sifive.I2C_SR_TIP) {
|
|
}
|
|
|
|
return nil
|
|
}
|