stm32: support SPI on L4 series
Этот коммит содержится в:
родитель
b9043b649d
коммит
25f3adb47e
9 изменённых файлов: 138 добавлений и 12 удалений
|
@ -1 +1 @@
|
|||
Subproject commit c6b5be976f440196dcd819a8d9a52c6786f67990
|
||||
Subproject commit 3a0b0829b70bf930c74fb69d887bee28005e7d99
|
|
@ -13,20 +13,53 @@ const (
|
|||
LED_GREEN = PB3
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
// Arduino Pins
|
||||
A0 = PA0
|
||||
A1 = PA1
|
||||
A2 = PA3
|
||||
A3 = PA4
|
||||
A4 = PA5
|
||||
A5 = PA6
|
||||
A6 = PA7
|
||||
A7 = PA2
|
||||
|
||||
D0 = PA10
|
||||
D1 = PA9
|
||||
D2 = PA12
|
||||
D3 = PB0
|
||||
D4 = PB7
|
||||
D5 = PB6
|
||||
D6 = PB1
|
||||
D7 = PC14
|
||||
D8 = PC15
|
||||
D9 = PA8
|
||||
D10 = PA11
|
||||
D11 = PB5
|
||||
D12 = PB4
|
||||
D13 = PB3
|
||||
)
|
||||
|
||||
const (
|
||||
// UART pins
|
||||
// PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP)
|
||||
UART_TX_PIN = PA2
|
||||
UART_RX_PIN = PA15
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
// I2C pins
|
||||
// With default solder bridge settings:
|
||||
// PB6 / Arduino D5 / CN3 Pin 8 is SCL
|
||||
// PB7 / Arduino D4 / CN3 Pin 7 is SDA
|
||||
I2C0_SCL_PIN = PB6
|
||||
I2C0_SDA_PIN = PB7
|
||||
|
||||
// SPI pins
|
||||
SPI1_SCK_PIN = PB3
|
||||
SPI1_SDI_PIN = PB5
|
||||
SPI1_SDO_PIN = PB4
|
||||
SPI0_SCK_PIN = SPI1_SCK_PIN
|
||||
SPI0_SDI_PIN = SPI1_SDI_PIN
|
||||
SPI0_SDO_PIN = SPI1_SDO_PIN
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -40,15 +73,20 @@ var (
|
|||
RxAltFuncSelector: 3,
|
||||
}
|
||||
UART1 = &UART0
|
||||
)
|
||||
|
||||
var (
|
||||
// I2C1 is documented, alias to I2C0 as well
|
||||
I2C1 = &I2C{
|
||||
Bus: stm32.I2C1,
|
||||
AltFuncSelector: 4,
|
||||
}
|
||||
I2C0 = I2C1
|
||||
|
||||
// SPI1 is documented, alias to SPI0 as well
|
||||
SPI1 = &SPI{
|
||||
Bus: stm32.SPI1,
|
||||
AltFuncSelector: 5,
|
||||
}
|
||||
SPI0 = SPI1
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2
|
||||
|
||||
package machine
|
||||
|
||||
|
@ -6,6 +6,7 @@ package machine
|
|||
|
||||
import (
|
||||
"device/stm32"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -86,7 +87,12 @@ func (spi SPI) Configure(config SPIConfig) {
|
|||
|
||||
// now set the configuration
|
||||
spi.Bus.CR1.Set(conf)
|
||||
spi.Bus.CR2.SetBits((conf & stm32.SPI_CR1_SSM_Msk) >> 16)
|
||||
|
||||
// Series-specific configuration to set 8-bit transfer mode
|
||||
spi.config8Bits()
|
||||
|
||||
// enable SPI
|
||||
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
|
||||
}
|
||||
|
||||
// Transfer writes/reads a single byte using the SPI interface.
|
||||
|
@ -103,8 +109,10 @@ func (spi SPI) Transfer(w byte) (byte, error) {
|
|||
// 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI.
|
||||
|
||||
// put output word (8-bit) in data register (DR), which is parallel-loaded
|
||||
// into shift register, and shifted out on MOSI.
|
||||
spi.Bus.DR.Set(uint32(w))
|
||||
// into shift register, and shifted out on MOSI. Some series have 16-bit
|
||||
// register but writes must be strictly 8-bit to output a byte. Writing
|
||||
// 16-bits indicates a packed transfer (2 bytes).
|
||||
(*volatile.Register8)(unsafe.Pointer(&spi.Bus.DR.Reg)).Set(w)
|
||||
|
||||
// wait for SPI bus receive buffer not empty bit (RXNE) to be set.
|
||||
// warning: blocks forever until this condition is met.
|
||||
|
|
|
@ -161,6 +161,10 @@ var (
|
|||
SPI0 = SPI1
|
||||
)
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// no-op on this series
|
||||
}
|
||||
|
||||
// Set baud rate for SPI
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var conf uint32
|
||||
|
|
|
@ -67,6 +67,10 @@ type SPI struct {
|
|||
AltFuncSelector uint8
|
||||
}
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// no-op on this series
|
||||
}
|
||||
|
||||
func (spi SPI) configurePins(config SPIConfig) {
|
||||
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
|
||||
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
|
||||
|
|
|
@ -70,6 +70,10 @@ type SPI struct {
|
|||
AltFuncSelector uint8
|
||||
}
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// no-op on this series
|
||||
}
|
||||
|
||||
// Set baud rate for SPI
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var conf uint32
|
||||
|
|
|
@ -184,6 +184,10 @@ type SPI struct {
|
|||
AltFuncSelector uint8
|
||||
}
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// no-op on this series
|
||||
}
|
||||
|
||||
// Set baud rate for SPI
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var conf uint32
|
||||
|
|
|
@ -182,3 +182,67 @@ func enableAltFuncClock(bus unsafe.Pointer) {
|
|||
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN)
|
||||
}
|
||||
}
|
||||
|
||||
//---------- SPI related types and code
|
||||
|
||||
// SPI on the STM32Fxxx using MODER / alternate function pins
|
||||
type SPI struct {
|
||||
Bus *stm32.SPI_Type
|
||||
AltFuncSelector uint8
|
||||
}
|
||||
|
||||
func (spi SPI) config8Bits() {
|
||||
// Set rx threshold to 8-bits, so RXNE flag is set for 1 byte
|
||||
// (common STM32 SPI implementation does 8-bit transfers only)
|
||||
spi.Bus.CR2.SetBits(stm32.SPI_CR2_FRXTH)
|
||||
}
|
||||
|
||||
// Set baud rate for SPI
|
||||
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
|
||||
var conf uint32
|
||||
|
||||
// Default
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = 4e6
|
||||
}
|
||||
|
||||
localFrequency := config.Frequency
|
||||
|
||||
// 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 80MHz peripheral clock frquency
|
||||
switch {
|
||||
case localFrequency < 312500:
|
||||
conf = stm32.SPI_CR1_BR_Div256
|
||||
case localFrequency < 625000:
|
||||
conf = stm32.SPI_CR1_BR_Div128
|
||||
case localFrequency < 1250000:
|
||||
conf = stm32.SPI_CR1_BR_Div64
|
||||
case localFrequency < 2500000:
|
||||
conf = stm32.SPI_CR1_BR_Div32
|
||||
case localFrequency < 5000000:
|
||||
conf = stm32.SPI_CR1_BR_Div16
|
||||
case localFrequency < 10000000:
|
||||
conf = stm32.SPI_CR1_BR_Div8
|
||||
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
|
||||
// Check the datasheet of the part
|
||||
case localFrequency < 20000000:
|
||||
conf = stm32.SPI_CR1_BR_Div4
|
||||
case localFrequency < 40000000:
|
||||
conf = stm32.SPI_CR1_BR_Div2
|
||||
default:
|
||||
// None of the specific baudrates were selected; choose the lowest speed
|
||||
conf = stm32.SPI_CR1_BR_Div256
|
||||
}
|
||||
|
||||
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.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
|
||||
config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2 fe310 k210 atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
|
||||
|
||||
package machine
|
||||
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче