diff --git a/src/machine/board_fe310.go b/src/machine/board_fe310.go index b6e88a3c..08998514 100644 --- a/src/machine/board_fe310.go +++ b/src/machine/board_fe310.go @@ -2,6 +2,8 @@ package machine +import "device/sifive" + const ( P00 Pin = 0 P01 Pin = 1 @@ -36,3 +38,10 @@ const ( P30 Pin = 30 P31 Pin = 31 ) + +// SPI on the HiFive1. +var ( + SPI1 = SPI{ + Bus: sifive.QSPI1, + } +) diff --git a/src/machine/board_hifive1b.go b/src/machine/board_hifive1b.go index 7839214b..be0d7eac 100644 --- a/src/machine/board_hifive1b.go +++ b/src/machine/board_hifive1b.go @@ -6,23 +6,23 @@ const ( D0 = P16 D1 = P17 D2 = P18 - D3 = P19 // Green LED/PWM - D4 = P20 // PWM - D5 = P21 // Blue LED/PWM - D6 = P22 // Red LED/PWM + D3 = P19 // Green LED/PWM (PWM1_PWM1) + D4 = P20 // PWM (PWM1_PWM0) + D5 = P21 // Blue LED/PWM (PWM1_PWM2) + D6 = P22 // Red LED/PWM (PWM1_PWM3) D7 = P16 D8 = NoPin // PWM? D9 = P01 - D10 = P02 - D11 = P03 - D12 = P04 - D13 = P05 + D10 = P02 // SPI1_CS0 + D11 = P03 // SPI1_DQ0 + D12 = P04 // SPI1_DQ1 + D13 = P05 // SPI1_SCK D14 = NoPin // not connected D15 = P09 // does not seem to work? - D16 = P10 // PWM - D17 = P11 // PWM - D18 = P12 // SDA/PWM - D19 = P13 // SDL/PWM + D16 = P10 // PWM (PWM2_PWM0) + D17 = P11 // PWM (PWM2_PWM1) + D18 = P12 // SDA (I2C0_SDA)/PWM (PWM2_PWM2) + D19 = P13 // SDL (I2C0_SCL)/PWM (PWM2_PWM3) ) const ( @@ -40,3 +40,14 @@ const ( UART_TX_PIN = NoPin UART_RX_PIN = NoPin ) + +// SPI pins +const ( + SPI0_SCK_PIN = NoPin + SPI0_MOSI_PIN = NoPin + SPI0_MISO_PIN = NoPin + + SPI1_SCK_PIN = D13 + SPI1_MOSI_PIN = D11 + SPI1_MISO_PIN = D12 +) diff --git a/src/machine/machine_fe310.go b/src/machine/machine_fe310.go index b45d8797..38d46b72 100644 --- a/src/machine/machine_fe310.go +++ b/src/machine/machine_fe310.go @@ -6,18 +6,30 @@ import ( "device/sifive" ) +const CPU_FREQUENCY = 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)) - if config.Mode == PinOutput { + 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)) } } @@ -59,3 +71,93 @@ func (uart UART) WriteByte(c byte) { 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 := CPU_FREQUENCY/(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 +} diff --git a/src/machine/spi.go b/src/machine/spi.go index f9134078..5b794460 100644 --- a/src/machine/spi.go +++ b/src/machine/spi.go @@ -1,4 +1,4 @@ -// +build sam stm32,!stm32f407 +// +build sam stm32,!stm32f407 fe310 package machine