//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 PinInput: sifive.GPIO0.OUTPUT_EN.ClearBits(1 << uint8(p)) 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 }