Этот коммит содержится в:
GeoffThomas 2020-03-22 10:28:47 -05:00 коммит произвёл Ron Evans
родитель ac73430502
коммит b4dddfe439
6 изменённых файлов: 217 добавлений и 93 удалений

Просмотреть файл

@ -43,3 +43,15 @@ const (
GPIOPUPDRPullUp = 1
GPIOPUPDRPullDown = 2
)
// SPI prescaler values fPCLK / X
const (
SPI_PCLK_2 = 0
SPI_PCLK_4 = 1
SPI_PCLK_8 = 2
SPI_PCLK_16 = 3
SPI_PCLK_32 = 4
SPI_PCLK_64 = 5
SPI_PCLK_128 = 6
SPI_PCLK_256 = 7
)

Просмотреть файл

@ -129,3 +129,30 @@ var (
func init() {
UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, UART0.handleInterrupt)
}
// SPI pins
const (
SPI1_SCK_PIN = PA5
SPI1_MISO_PIN = PA6
SPI1_MOSI_PIN = PA7
SPI0_SCK_PIN = SPI1_SCK_PIN
SPI0_MISO_PIN = SPI1_MISO_PIN
SPI0_MOSI_PIN = SPI1_MOSI_PIN
)
// MEMs accelerometer
const (
MEMS_ACCEL_CS = PE3
MEMS_ACCEL_INT1 = PE0
MEMS_ACCEL_INT2 = PE1
)
// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1.
// TODO: implement SPI2 and SPI3.
var (
SPI0 = SPI{
Bus: stm32.SPI1,
AltFuncSelector: stm32.AF5_SPI1_SPI2,
}
SPI1 = &SPI0
)

99
src/machine/machine_stm32_spi.go Обычный файл
Просмотреть файл

@ -0,0 +1,99 @@
// +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
}

Просмотреть файл

@ -148,7 +148,8 @@ func (uart UART) getBaudRateDivisor(br uint32) uint32 {
return divider
}
// SPI on the STM32.
//---------- SPI related types and code
type SPI struct {
Bus *stm32.SPI_Type
}
@ -161,26 +162,8 @@ var (
SPI0 = SPI1
)
// 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
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN)
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
// set frequency dependent on PCLK2 prescaler (div 1)
@ -203,82 +186,18 @@ func (spi SPI) Configure(config SPIConfig) {
default:
conf |= stm32.SPI_BaudRatePrescaler_256
}
// set bit transfer order
if config.LSBFirst {
conf |= stm32.SPI_FirstBit_LSB
}
// set mode
switch config.Mode {
case 0:
conf &^= (1 << stm32.SPI_CR1_CPOL_Pos)
conf &^= (1 << stm32.SPI_CR1_CPHA_Pos)
case 1:
conf &^= (1 << stm32.SPI_CR1_CPOL_Pos)
conf |= (1 << stm32.SPI_CR1_CPHA_Pos)
case 2:
conf |= (1 << stm32.SPI_CR1_CPOL_Pos)
conf &^= (1 << stm32.SPI_CR1_CPHA_Pos)
case 3:
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_Mode_Master
// now set the configuration
spi.Bus.CR1.Set(conf)
// init pins
spi.setPins(config.SCK, config.MOSI, config.MISO)
// enable SPI interface
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
return conf
}
// 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
// Configure SPI pins for input output and clock
func (spi SPI) configurePins(config SPIConfig) {
config.SCK.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
config.MOSI.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
config.MISO.Configure(PinConfig{Mode: PinInputModeFloating})
}
func (spi SPI) setPins(sck, mosi, miso Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
if mosi == 0 {
mosi = SPI0_MOSI_PIN
}
if miso == 0 {
miso = SPI0_MISO_PIN
}
//---------- I2C related types and code
sck.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
mosi.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
miso.Configure(PinConfig{Mode: PinInputModeFloating})
}
// I2C on the STM32F103xx.
type I2C struct {
Bus *stm32.I2C_Type
}

Просмотреть файл

@ -108,3 +108,62 @@ func (uart UART) getBaudRateDivisor(baudRate uint32) uint32 {
}
return clock / baudRate
}
//---------- SPI related types and code
// SPI on the STM32Fxxx using MODER / alternate function pins
type SPI struct {
Bus *stm32.SPI_Type
AltFuncSelector stm32.AltFunc
}
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
localFrequency := config.Frequency
if spi.Bus != stm32.SPI1 {
// Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so
// we want to pretend to request 2x the baudrate asked for
localFrequency = localFrequency * 2
}
// set frequency dependent on PCLK prescaler. Since these are rather weird
// speeds due to the CPU freqency, pick a range up to that frquency for
// clients to use more human-understandable numbers, e.g. nearest 100KHz
// These are based on APB2 clock frquency (84MHz on the discovery board)
// TODO: also include the MCU/APB clock setting in the equation
switch true {
case localFrequency < 328125:
conf = stm32.SPI_PCLK_256
case localFrequency < 656250:
conf = stm32.SPI_PCLK_128
case localFrequency < 1312500:
conf = stm32.SPI_PCLK_64
case localFrequency < 2625000:
conf = stm32.SPI_PCLK_32
case localFrequency < 5250000:
conf = stm32.SPI_PCLK_16
case localFrequency < 10500000:
conf = stm32.SPI_PCLK_8
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
// Check the datasheet of the part
case localFrequency < 21000000:
conf = stm32.SPI_PCLK_4
case localFrequency < 42000000:
conf = stm32.SPI_PCLK_2
default:
// None of the specific baudrates were selected; choose the lowest speed
conf = stm32.SPI_PCLK_256
}
return conf << stm32.SPI_CR1_BR_Pos
}
// Configure SPI pins for input output and clock
func (spi SPI) configurePins(config SPIConfig) {
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
config.MOSI.ConfigureAltFunc(PinConfig{Mode: PinModeSPIMOSI}, spi.AltFuncSelector)
config.MISO.ConfigureAltFunc(PinConfig{Mode: PinModeSPIMISO}, spi.AltFuncSelector)
}

Просмотреть файл

@ -1,9 +1,17 @@
// +build !baremetal sam stm32,!stm32f407 fe310
// +build !baremetal sam stm32 fe310
package machine
import "errors"
// SPI phase and polarity configs CPOL and CPHA
const (
Mode0 = 0
Mode1 = 1
Mode2 = 2
Mode3 = 3
)
var (
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
)