
These all-caps constants aren't in the Go style, so rename it to CPUFrequency (which is more aligned with Go style). Additionally, make it a function so that it is possible to add support for changing the frequency in the future. Tested by running `make smoketest`. None of the outputs did change.
165 строки
3,8 КиБ
Go
165 строки
3,8 КиБ
Go
// +build fe310
|
|
|
|
package machine
|
|
|
|
import (
|
|
"device/sifive"
|
|
)
|
|
|
|
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))
|
|
println(sifive.GPIO0.VALUE.Get())
|
|
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)
|
|
}
|
|
|
|
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
|
|
MOSI Pin
|
|
MISO 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.MOSI == 0 && config.MISO == 0 {
|
|
config.SCK = SPI0_SCK_PIN
|
|
config.MOSI = SPI0_MOSI_PIN
|
|
config.MISO = SPI0_MISO_PIN
|
|
}
|
|
|
|
// enable pins for SPI
|
|
config.SCK.Configure(PinConfig{Mode: PinSPI})
|
|
config.MOSI.Configure(PinConfig{Mode: PinSPI})
|
|
config.MISO.Configure(PinConfig{Mode: PinSPI})
|
|
|
|
// set default frequency
|
|
if config.Frequency == 0 {
|
|
config.Frequency = 4000000
|
|
}
|
|
|
|
// 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
|
|
}
|