tinygo/src/machine/machine_stm32_spi.go
2020-03-25 16:24:19 +01:00

99 строки
2,3 КиБ
Go

// +build stm32
package machine
// Peripheral abstraction layer for SPI on the stm32 family
import (
"device/stm32"
"unsafe"
)
// 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 STM32 SPI1 interface.
// Features still TODO:
// - support SPI2 and SPI3
// - allow setting data size to 16 bits?
// - allow setting direction in HW for additional optimization?
// - hardware SS pin?
func (spi SPI) Configure(config SPIConfig) {
// enable clock for SPI
enableAltFuncClock(unsafe.Pointer(spi.Bus))
// Get SPI baud rate based on the bus speed it's attached to
var conf uint32 = spi.getBaudRate(config)
// set bit transfer order
if config.LSBFirst {
conf |= stm32.SPI_CR1_LSBFIRST
}
// set polarity and phase on the SPI interface
switch config.Mode {
case Mode0:
conf &^= (1 << stm32.SPI_CR1_CPOL_Pos)
conf &^= (1 << stm32.SPI_CR1_CPHA_Pos)
case Mode1:
conf &^= (1 << stm32.SPI_CR1_CPOL_Pos)
conf |= (1 << stm32.SPI_CR1_CPHA_Pos)
case Mode2:
conf |= (1 << stm32.SPI_CR1_CPOL_Pos)
conf &^= (1 << stm32.SPI_CR1_CPHA_Pos)
case Mode3:
conf |= (1 << stm32.SPI_CR1_CPOL_Pos)
conf |= (1 << stm32.SPI_CR1_CPHA_Pos)
default: // to mode 0
conf &^= (1 << stm32.SPI_CR1_CPOL_Pos)
conf &^= (1 << stm32.SPI_CR1_CPHA_Pos)
}
// set to SPI master
conf |= stm32.SPI_CR1_MSTR
// disable MCU acting as SPI slave
conf |= stm32.SPI_CR1_SSM | stm32.SPI_CR1_SSI
// now set the configuration
spi.Bus.CR1.Set(conf)
// init pins
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
}
spi.configurePins(config)
// enable SPI interface
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
}
// Transfer writes/reads a single byte using the SPI interface.
func (spi SPI) Transfer(w byte) (byte, error) {
// Write data to be transmitted to the SPI data register
spi.Bus.DR.Set(uint32(w))
// Wait until transmit complete
for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) {
}
// Wait until receive complete
for !spi.Bus.SR.HasBits(stm32.SPI_SR_RXNE) {
}
// Wait until SPI is not busy
for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) {
}
// Return received data from SPI data register
return byte(spi.Bus.DR.Get()), nil
}