machine/stm32f103xx: support for SPI interface

Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
Ron Evans 2018-12-28 16:55:51 +01:00 коммит произвёл Ayke van Laethem
родитель f71e1bcf03
коммит dccfae485c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
5 изменённых файлов: 176 добавлений и 5 удалений

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

@ -58,4 +58,31 @@ const (
RCC_RTCCLKSource_LSE = 0x00000100
RCC_RTCCLKSource_LSI = 0x00000200
RCC_RTCCLKSource_HSE_Div128 = 0x00000300
// SPI settings
SPI_FirstBit_MSB = 0x0000
SPI_FirstBit_LSB = 0x0080
SPI_BaudRatePrescaler_2 = 0x0000
SPI_BaudRatePrescaler_4 = 0x0008
SPI_BaudRatePrescaler_8 = 0x0010
SPI_BaudRatePrescaler_16 = 0x0018
SPI_BaudRatePrescaler_32 = 0x0020
SPI_BaudRatePrescaler_64 = 0x0028
SPI_BaudRatePrescaler_128 = 0x0030
SPI_BaudRatePrescaler_256 = 0x0038
SPI_Direction_2Lines_FullDuplex = 0x0000
SPI_Direction_2Lines_RxOnly = 0x0400
SPI_Direction_1Line_Rx = 0x8000
SPI_Direction_1Line_Tx = 0xC000
SPI_Mode_Master = 0x0104
SPI_Mode_Slave = 0x0000
SPI_NSS_Soft = 0x0200
SPI_NSS_Hard = 0x0000
SPI_NSSInternalSoft_Set = 0x0100
SPI_NSSInternalSoft_Reset = 0xFEFF
)

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

@ -44,3 +44,16 @@ const (
const (
LED = PC13
)
// UART pins
const (
UART_TX_PIN = PA9
UART_RX_PIN = PA10
)
// SPI pins
const (
SPI0_SCK_PIN = PA5
SPI0_MOSI_PIN = PA7
SPI0_MISO_PIN = PA6
)

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

@ -123,8 +123,8 @@ func (uart UART) Configure(config UARTConfig) {
GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
default:
// use standard TX/RX pins PA9 and PA10
GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
}
// Enable USART1 clock
@ -143,7 +143,8 @@ func (uart UART) Configure(config UARTConfig) {
// SetBaudRate sets the communication speed for the UART.
func (uart UART) SetBaudRate(br uint32) {
divider := CPU_FREQUENCY / br
// first divide by PCK2 prescaler (div 4) and then desired baudrate
divider := CPU_FREQUENCY / 4 / br
stm32.USART1.BRR = stm32.RegValue(divider)
}
@ -160,3 +161,132 @@ func (uart UART) WriteByte(c byte) error {
func handleUART1() {
bufferPut(byte((stm32.USART1.DR & 0xFF)))
}
// SPI on the STM32.
type SPI struct {
Bus *stm32.SPI_Type
}
// There are 3 SPI interfaces on the STM32F103xx.
// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1.
// TODO: implement SPI2 and SPI3.
var (
SPI1 = SPI{Bus: stm32.SPI1}
SPI0 = SPI1
)
// SPIConfig is used to store config info for SPI.
type SPIConfig struct {
Frequency uint32
SCK uint8
MOSI uint8
MISO uint8
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 |= stm32.RCC_APB2ENR_SPI1EN
var conf uint16
// set frequency
switch config.Frequency {
case 125000:
conf |= stm32.SPI_BaudRatePrescaler_128
case 250000:
conf |= stm32.SPI_BaudRatePrescaler_64
case 500000:
conf |= stm32.SPI_BaudRatePrescaler_32
case 1000000:
conf |= stm32.SPI_BaudRatePrescaler_16
case 2000000:
conf |= stm32.SPI_BaudRatePrescaler_8
case 4000000:
conf |= stm32.SPI_BaudRatePrescaler_4
case 8000000:
conf |= stm32.SPI_BaudRatePrescaler_2
default:
conf |= stm32.SPI_BaudRatePrescaler_128
}
// 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 = stm32.RegValue(conf)
// init pins
spi.setPins(config.SCK, config.MOSI, config.MISO)
// enable SPI interface
spi.Bus.CR1 |= 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 = stm32.RegValue(w)
// Wait until transmit complete
for (spi.Bus.SR & stm32.SPI_SR_TXE) == 0 {
}
// Wait until receive complete
for (spi.Bus.SR & stm32.SPI_SR_RXNE) == 0 {
}
// Wait until SPI is not busy
for (spi.Bus.SR & stm32.SPI_SR_BSY) > 0 {
}
// Return received data from SPI data register
return byte(spi.Bus.DR), nil
}
func (spi SPI) setPins(sck, mosi, miso uint8) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
if mosi == 0 {
mosi = SPI0_MOSI_PIN
}
if miso == 0 {
miso = SPI0_MISO_PIN
}
GPIO{sck}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{mosi}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{miso}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
}

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

@ -1,4 +1,4 @@
// +build nrf
// +build nrf stm32f103xx
package machine

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

@ -22,7 +22,8 @@ func putchar(c byte) {
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
func initCLK() {
stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale AHB1 = HCLK/2
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale PCLK1 = HCLK/2
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_4 // prescale PCLK2 = HCLK/4
stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock
// wait for the HSEREADY flag