stm32 add SPI for stm32f4
Этот коммит содержится в:
родитель
ac73430502
коммит
b4dddfe439
6 изменённых файлов: 217 добавлений и 93 удалений
|
@ -43,3 +43,15 @@ const (
|
||||||
GPIOPUPDRPullUp = 1
|
GPIOPUPDRPullUp = 1
|
||||||
GPIOPUPDRPullDown = 2
|
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() {
|
func init() {
|
||||||
UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, UART0.handleInterrupt)
|
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
Обычный файл
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
|
return divider
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPI on the STM32.
|
//---------- SPI related types and code
|
||||||
|
|
||||||
type SPI struct {
|
type SPI struct {
|
||||||
Bus *stm32.SPI_Type
|
Bus *stm32.SPI_Type
|
||||||
}
|
}
|
||||||
|
@ -161,26 +162,8 @@ var (
|
||||||
SPI0 = SPI1
|
SPI0 = SPI1
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPIConfig is used to store config info for SPI.
|
// Set baud rate for SPI
|
||||||
type SPIConfig struct {
|
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||||
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)
|
|
||||||
|
|
||||||
var conf uint32
|
var conf uint32
|
||||||
|
|
||||||
// set frequency dependent on PCLK2 prescaler (div 1)
|
// set frequency dependent on PCLK2 prescaler (div 1)
|
||||||
|
@ -203,82 +186,18 @@ func (spi SPI) Configure(config SPIConfig) {
|
||||||
default:
|
default:
|
||||||
conf |= stm32.SPI_BaudRatePrescaler_256
|
conf |= stm32.SPI_BaudRatePrescaler_256
|
||||||
}
|
}
|
||||||
|
return conf
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transfer writes/reads a single byte using the SPI interface.
|
// Configure SPI pins for input output and clock
|
||||||
func (spi SPI) Transfer(w byte) (byte, error) {
|
func (spi SPI) configurePins(config SPIConfig) {
|
||||||
// Write data to be transmitted to the SPI data register
|
config.SCK.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
spi.Bus.DR.Set(uint32(w))
|
config.MOSI.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
||||||
|
config.MISO.Configure(PinConfig{Mode: PinInputModeFloating})
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (spi SPI) setPins(sck, mosi, miso Pin) {
|
//---------- I2C related types and code
|
||||||
if sck == 0 {
|
|
||||||
sck = SPI0_SCK_PIN
|
|
||||||
}
|
|
||||||
if mosi == 0 {
|
|
||||||
mosi = SPI0_MOSI_PIN
|
|
||||||
}
|
|
||||||
if miso == 0 {
|
|
||||||
miso = SPI0_MISO_PIN
|
|
||||||
}
|
|
||||||
|
|
||||||
sck.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
|
||||||
mosi.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
|
|
||||||
miso.Configure(PinConfig{Mode: PinInputModeFloating})
|
|
||||||
}
|
|
||||||
|
|
||||||
// I2C on the STM32F103xx.
|
|
||||||
type I2C struct {
|
type I2C struct {
|
||||||
Bus *stm32.I2C_Type
|
Bus *stm32.I2C_Type
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,3 +108,62 @@ func (uart UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
||||||
}
|
}
|
||||||
return clock / baudRate
|
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
|
package machine
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
|
// SPI phase and polarity configs CPOL and CPHA
|
||||||
|
const (
|
||||||
|
Mode0 = 0
|
||||||
|
Mode1 = 1
|
||||||
|
Mode2 = 2
|
||||||
|
Mode3 = 3
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||||
)
|
)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче