diff --git a/src/device/stm32/stm32f103xx-bitfields.go b/src/device/stm32/stm32f103xx-bitfields.go index d9901081..e6d6414b 100644 --- a/src/device/stm32/stm32f103xx-bitfields.go +++ b/src/device/stm32/stm32f103xx-bitfields.go @@ -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 ) diff --git a/src/machine/board_bluepill.go b/src/machine/board_bluepill.go index 94e289d6..e9fc54de 100644 --- a/src/machine/board_bluepill.go +++ b/src/machine/board_bluepill.go @@ -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 +) diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go index 480a9e50..8f1c2a0f 100644 --- a/src/machine/machine_stm32f103xx.go +++ b/src/machine/machine_stm32f103xx.go @@ -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}) +} diff --git a/src/machine/spi.go b/src/machine/spi.go index 79454765..beaa2e46 100644 --- a/src/machine/spi.go +++ b/src/machine/spi.go @@ -1,4 +1,4 @@ -// +build nrf +// +build nrf stm32f103xx package machine diff --git a/src/runtime/runtime_stm32f103xx.go b/src/runtime/runtime_stm32f103xx.go index 83b21014..21d87997 100644 --- a/src/runtime/runtime_stm32f103xx.go +++ b/src/runtime/runtime_stm32f103xx.go @@ -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