tinygo/src/machine/machine_fe310.go
Ron Evans 935a293106
machine/i2c: add interface check and implementation where missing for SetBaudRate() (#3406)
* machine/i2c: add interface check and placeholder implementation where missing for SetBaudRate()
2023-10-14 13:17:24 +02:00

368 строки
8,7 КиБ
Go

//go:build fe310
package machine
import (
"device/sifive"
"runtime/interrupt"
"unsafe"
)
const deviceName = sifive.Device
func CPUFrequency() uint32 {
return 320000000 // 320MHz
}
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 when the pin is configured as an
// input or as an output.
func (p Pin) Get() bool {
val := sifive.GPIO0.VALUE.Get() & (1 << uint8(p))
return (val > 0)
}
// Return the register and mask to enable a given GPIO pin. This can be used to
// implement bit-banged drivers.
//
// Warning: only use this on an output pin!
func (p Pin) PortMaskSet() (*uint32, uint32) {
return (*uint32)(unsafe.Pointer(&sifive.GPIO0.PORT)), sifive.GPIO0.PORT.Get() | (1 << uint8(p))
}
// Return the register and mask to disable a given GPIO pin. This can be used to
// implement bit-banged drivers.
//
// Warning: only use this on an output pin!
func (p Pin) PortMaskClear() (*uint32, uint32) {
return (*uint32)(unsafe.Pointer(&sifive.GPIO0.PORT)), sifive.GPIO0.PORT.Get() &^ (1 << uint8(p))
}
type UART struct {
Bus *sifive.UART_Type
Buffer *RingBuffer
}
var (
UART0 = &_UART0
_UART0 = UART{Bus: sifive.UART0, Buffer: NewRingBuffer()}
)
func (uart *UART) Configure(config UARTConfig) {
if config.BaudRate == 0 {
config.BaudRate = 115200
}
// The divisor is:
// fbaud = fin / (div + 1)
// Restating to get the divisor:
// div = fin / fbaud - 1
// But we're using integers, so we should take care of rounding:
// div = (fin + fbaud/2) / fbaud - 1
divisor := (CPUFrequency()+config.BaudRate/2)/config.BaudRate - 1
sifive.UART0.DIV.Set(divisor)
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) error {
for sifive.UART0.TXDATA.Get()&sifive.UART_TXDATA_FULL != 0 {
}
sifive.UART0.TXDATA.Set(uint32(c))
return nil
}
func (uart *UART) flush() {}
// 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
data := spi.Bus.RXDATA.Get()
for data&sifive.QSPI_RXDATA_EMPTY > 0 {
data = spi.Bus.RXDATA.Get()
}
// return data
return byte(data), nil
}
// I2C on the FE310-G002.
type I2C struct {
Bus sifive.I2C_Type
}
var (
I2C0 = (*I2C)(unsafe.Pointer(sifive.I2C0))
)
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
SCL Pin
SDA Pin
}
var i2cClockFrequency uint32 = 32000000
// Configure is intended to setup the I2C interface.
func (i2c *I2C) Configure(config I2CConfig) error {
if config.Frequency == 0 {
config.Frequency = 100 * KHz
}
if config.SDA == 0 && config.SCL == 0 {
config.SDA = I2C0_SDA_PIN
config.SCL = I2C0_SCL_PIN
}
i2c.SetBaudRate(config.Frequency)
config.SDA.Configure(PinConfig{Mode: PinI2C})
config.SCL.Configure(PinConfig{Mode: PinI2C})
return nil
}
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
var prescaler = i2cClockFrequency/(5*br) - 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)
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
}