machine/stm32f103xx: support for SPI interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
f71e1bcf03
коммит
dccfae485c
5 изменённых файлов: 176 добавлений и 5 удалений
|
@ -58,4 +58,31 @@ const (
|
||||||
RCC_RTCCLKSource_LSE = 0x00000100
|
RCC_RTCCLKSource_LSE = 0x00000100
|
||||||
RCC_RTCCLKSource_LSI = 0x00000200
|
RCC_RTCCLKSource_LSI = 0x00000200
|
||||||
RCC_RTCCLKSource_HSE_Div128 = 0x00000300
|
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 (
|
const (
|
||||||
LED = PC13
|
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})
|
GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
||||||
default:
|
default:
|
||||||
// use standard TX/RX pins PA9 and PA10
|
// use standard TX/RX pins PA9 and PA10
|
||||||
GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
|
||||||
GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable USART1 clock
|
// Enable USART1 clock
|
||||||
|
@ -143,7 +143,8 @@ func (uart UART) Configure(config UARTConfig) {
|
||||||
|
|
||||||
// SetBaudRate sets the communication speed for the UART.
|
// SetBaudRate sets the communication speed for the UART.
|
||||||
func (uart UART) SetBaudRate(br uint32) {
|
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)
|
stm32.USART1.BRR = stm32.RegValue(divider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,3 +161,132 @@ func (uart UART) WriteByte(c byte) error {
|
||||||
func handleUART1() {
|
func handleUART1() {
|
||||||
bufferPut(byte((stm32.USART1.DR & 0xFF)))
|
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
|
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).
|
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
|
||||||
func initCLK() {
|
func initCLK() {
|
||||||
stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet
|
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
|
stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock
|
||||||
|
|
||||||
// wait for the HSEREADY flag
|
// wait for the HSEREADY flag
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче