From 11ee0969b67ca54549c4f556d373b1fdd17e03bc Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 28 Dec 2021 18:16:15 +0100 Subject: [PATCH] machine: merge stm32f405/407 They're no longer functionally different. --- src/machine/machine_stm32f4.go | 188 ++++++++++++++++++++++++++++ src/machine/machine_stm32f405.go | 198 ------------------------------ src/machine/machine_stm32f407.go | 203 ------------------------------- 3 files changed, 188 insertions(+), 401 deletions(-) delete mode 100644 src/machine/machine_stm32f405.go delete mode 100644 src/machine/machine_stm32f407.go diff --git a/src/machine/machine_stm32f4.go b/src/machine/machine_stm32f4.go index cc2dc6c1..4c477cf6 100644 --- a/src/machine/machine_stm32f4.go +++ b/src/machine/machine_stm32f4.go @@ -7,6 +7,7 @@ package machine import ( "device/stm32" + "math/bits" "runtime/interrupt" "runtime/volatile" "unsafe" @@ -592,3 +593,190 @@ func initRNG() { stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_RNGEN) stm32.RNG.CR.SetBits(stm32.RNG_CR_RNGEN) } + +func CPUFrequency() uint32 { + return 168000000 +} + +// Internal use: configured speed of the APB1 and APB2 timers, this should be kept +// in sync with any changes to runtime package which configures the oscillators +// and clock frequencies +const APB1_TIM_FREQ = 42000000 * 2 +const APB2_TIM_FREQ = 84000000 * 2 + +// Alternative peripheral pin functions +const ( + AF0_SYSTEM = 0 + AF1_TIM1_2 = 1 + AF2_TIM3_4_5 = 2 + AF3_TIM8_9_10_11 = 3 + AF4_I2C1_2_3 = 4 + AF5_SPI1_SPI2 = 5 + AF6_SPI3 = 6 + AF7_USART1_2_3 = 7 + AF8_USART4_5_6 = 8 + AF9_CAN1_CAN2_TIM12_13_14 = 9 + AF10_OTG_FS_OTG_HS = 10 + AF11_ETH = 11 + AF12_FSMC_SDIO_OTG_HS_1 = 12 + AF13_DCMI = 13 + AF14 = 14 + AF15_EVENTOUT = 15 +) + +// -- UART --------------------------------------------------------------------- + +func (uart *UART) configurePins(config UARTConfig) { + // enable the alternate functions on the TX and RX pins + config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) + config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) +} + +func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { + var clock uint32 + switch uart.Bus { + case stm32.USART1, stm32.USART6: + clock = CPUFrequency() / 2 // APB2 Frequency + case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: + clock = CPUFrequency() / 4 // APB1 Frequency + } + return clock / baudRate +} + +func (uart *UART) setRegisters() { + uart.rxReg = &uart.Bus.DR + uart.txReg = &uart.Bus.DR + uart.statusReg = &uart.Bus.SR + uart.txEmptyFlag = stm32.USART_SR_TXE +} + +// -- SPI ---------------------------------------------------------------------- + +type SPI struct { + Bus *stm32.SPI_Type + 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) + config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) +} + +func (spi SPI) getBaudRate(config SPIConfig) uint32 { + var clock uint32 + switch spi.Bus { + case stm32.SPI1: + clock = CPUFrequency() / 2 + case stm32.SPI2, stm32.SPI3: + clock = CPUFrequency() / 4 + } + + // limit requested frequency to bus frequency and min frequency (DIV256) + freq := config.Frequency + if min := clock / 256; freq < min { + freq = min + } else if freq > clock { + freq = clock + } + + // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). + // truncation is fine, since it produces a less-than-or-equal divisor, and + // thus a greater-than-or-equal frequency. + // divisors only come in consecutive powers of 2, so we can use log2 (or, + // equivalently, bits.Len - 1) to convert to respective enum value. + div := bits.Len32(clock/freq) - 1 + + // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so + // subtract 1 from the log2 value, keeping a lower bound of 0 + if div < 0 { + div = 0 + } else if div > 0 { + div-- + } + + // finally, shift the enumerated value into position for SPI CR1 + return uint32(div) << stm32.SPI_CR1_BR_Pos +} + +// -- I2C ---------------------------------------------------------------------- + +type I2C struct { + Bus *stm32.I2C_Type + AltFuncSelector uint8 +} + +func (i2c *I2C) configurePins(config I2CConfig) { + config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) + config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) +} + +func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { + // all I2C interfaces are on APB1 + clock := CPUFrequency() / 4 + // convert to MHz + clock /= 1000000 + // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive + var min, max uint32 = 2, 50 + if config.Frequency > 100000 { + min = 4 // fast mode (Fm) + } + if clock < min { + clock = min + } else if clock > max { + clock = max + } + return clock << stm32.I2C_CR2_FREQ_Pos +} + +func (i2c *I2C) getRiseTime(config I2CConfig) uint32 { + // These bits must be programmed with the maximum SCL rise time given in the + // I2C bus specification, incremented by 1. + // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. + // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 + // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with + // 09h (1000 ns / 125 ns = 8 + 1) + freqRange := i2c.getFreqRange(config) + if config.Frequency > 100000 { + // fast mode (Fm) adjustment + freqRange *= 300 + freqRange /= 1000 + } + return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos +} + +func (i2c *I2C) getSpeed(config I2CConfig) uint32 { + ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { + return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk + } + sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) + if s := ccr(pclk, freq, 2); s < 4 { + return 4 + } else { + return s + } + } + fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) + if duty == DutyCycle2 { + return ccr(pclk, freq, 3) + } else { + return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY + } + } + // all I2C interfaces are on APB1 + clock := CPUFrequency() / 4 + if config.Frequency <= 100000 { + return sm(clock, config.Frequency) + } else { + s := fm(clock, config.Frequency, config.DutyCycle) + if (s & stm32.I2C_CCR_CCR_Msk) == 0 { + return 1 + } else { + return s | stm32.I2C_CCR_F_S + } + } +} diff --git a/src/machine/machine_stm32f405.go b/src/machine/machine_stm32f405.go deleted file mode 100644 index ae113dc5..00000000 --- a/src/machine/machine_stm32f405.go +++ /dev/null @@ -1,198 +0,0 @@ -// +build stm32f405 - -package machine - -// Peripheral abstraction layer for the stm32f405 - -import ( - "device/stm32" - "math/bits" -) - -func CPUFrequency() uint32 { - return 168000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 42000000 * 2 -const APB2_TIM_FREQ = 84000000 * 2 - -// Alternative peripheral pin functions -const ( - AF0_SYSTEM = 0 - AF1_TIM1_2 = 1 - AF2_TIM3_4_5 = 2 - AF3_TIM8_9_10_11 = 3 - AF4_I2C1_2_3 = 4 - AF5_SPI1_SPI2 = 5 - AF6_SPI3 = 6 - AF7_USART1_2_3 = 7 - AF8_USART4_5_6 = 8 - AF9_CAN1_CAN2_TIM12_13_14 = 9 - AF10_OTG_FS_OTG_HS = 10 - AF11_ETH = 11 - AF12_FSMC_SDIO_OTG_HS_1 = 12 - AF13_DCMI = 13 - AF14 = 14 - AF15_EVENTOUT = 15 -) - -// -- UART --------------------------------------------------------------------- - -func (uart *UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - var clock uint32 - switch uart.Bus { - case stm32.USART1, stm32.USART6: - clock = CPUFrequency() / 2 // APB2 Frequency - case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: - clock = CPUFrequency() / 4 // APB1 Frequency - } - return clock / baudRate -} - -// Register names vary by ST processor, these are for STM F405 -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.DR - uart.txReg = &uart.Bus.DR - uart.statusReg = &uart.Bus.SR - uart.txEmptyFlag = stm32.USART_SR_TXE -} - -// -- SPI ---------------------------------------------------------------------- - -type SPI struct { - Bus *stm32.SPI_Type - 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) - config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) -} - -func (spi SPI) getBaudRate(config SPIConfig) uint32 { - var clock uint32 - switch spi.Bus { - case stm32.SPI1: - clock = CPUFrequency() / 2 - case stm32.SPI2, stm32.SPI3: - clock = CPUFrequency() / 4 - } - - // limit requested frequency to bus frequency and min frequency (DIV256) - freq := config.Frequency - if min := clock / 256; freq < min { - freq = min - } else if freq > clock { - freq = clock - } - - // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). - // truncation is fine, since it produces a less-than-or-equal divisor, and - // thus a greater-than-or-equal frequency. - // divisors only come in consecutive powers of 2, so we can use log2 (or, - // equivalently, bits.Len - 1) to convert to respective enum value. - div := bits.Len32(clock/freq) - 1 - - // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so - // subtract 1 from the log2 value, keeping a lower bound of 0 - if div < 0 { - div = 0 - } else if div > 0 { - div-- - } - - // finally, shift the enumerated value into position for SPI CR1 - return uint32(div) << stm32.SPI_CR1_BR_Pos -} - -// -- I2C ---------------------------------------------------------------------- - -type I2C struct { - Bus *stm32.I2C_Type - AltFuncSelector uint8 -} - -func (i2c *I2C) configurePins(config I2CConfig) { - config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) - config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) -} - -func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { - // all I2C interfaces are on APB1 (42 MHz) - clock := CPUFrequency() / 4 - // convert to MHz - clock /= 1000000 - // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive - var min, max uint32 = 2, 50 - if config.Frequency > 10000 { - min = 4 // fast mode (Fm) - } - if clock < min { - clock = min - } else if clock > max { - clock = max - } - return clock << stm32.I2C_CR2_FREQ_Pos -} - -func (i2c *I2C) getRiseTime(config I2CConfig) uint32 { - // These bits must be programmed with the maximum SCL rise time given in the - // I2C bus specification, incremented by 1. - // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. - // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 - // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with - // 09h (1000 ns / 125 ns = 8 + 1) - freqRange := i2c.getFreqRange(config) - if config.Frequency > 100000 { - // fast mode (Fm) adjustment - freqRange *= 300 - freqRange /= 1000 - } - return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos -} - -func (i2c *I2C) getSpeed(config I2CConfig) uint32 { - ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { - return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk - } - sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) - if s := ccr(pclk, freq, 2); s < 4 { - return 4 - } else { - return s - } - } - fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) - if duty == DutyCycle2 { - return ccr(pclk, freq, 3) - } else { - return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY - } - } - // all I2C interfaces are on APB1 (42 MHz) - clock := CPUFrequency() / 4 - if config.Frequency <= 100000 { - return sm(clock, config.Frequency) - } else { - s := fm(clock, config.Frequency, config.DutyCycle) - if (s & stm32.I2C_CCR_CCR_Msk) == 0 { - return 1 - } else { - return s | stm32.I2C_CCR_F_S - } - } -} diff --git a/src/machine/machine_stm32f407.go b/src/machine/machine_stm32f407.go deleted file mode 100644 index d59ae668..00000000 --- a/src/machine/machine_stm32f407.go +++ /dev/null @@ -1,203 +0,0 @@ -//go:build stm32f407 -// +build stm32f407 - -package machine - -// Peripheral abstraction layer for the stm32f407 - -import ( - "device/stm32" - "math/bits" -) - -func CPUFrequency() uint32 { - return 168000000 -} - -// Internal use: configured speed of the APB1 and APB2 timers, this should be kept -// in sync with any changes to runtime package which configures the oscillators -// and clock frequencies -const APB1_TIM_FREQ = 42000000 * 2 -const APB2_TIM_FREQ = 84000000 * 2 - -// Alternative peripheral pin functions -const ( - AF0_SYSTEM = 0 - AF1_TIM1_2 = 1 - AF2_TIM3_4_5 = 2 - AF3_TIM8_9_10_11 = 3 - AF4_I2C1_2_3 = 4 - AF5_SPI1_SPI2 = 5 - AF6_SPI3 = 6 - AF7_USART1_2_3 = 7 - AF8_USART4_5_6 = 8 - AF9_CAN1_CAN2_TIM12_13_14 = 9 - AF10_OTG_FS_OTG_HS = 10 - AF11_ETH = 11 - AF12_FSMC_SDIO_OTG_HS_1 = 12 - AF13_DCMI = 13 - AF14 = 14 - AF15_EVENTOUT = 15 -) - -//---------- UART related code - -// Configure the UART. -func (uart *UART) configurePins(config UARTConfig) { - // enable the alternate functions on the TX and RX pins - config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) - config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) -} - -// UART baudrate calc based on the bus and clockspeed -// NOTE: keep this in sync with the runtime/runtime_stm32f407.go clock init code -func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { - var clock uint32 - switch uart.Bus { - case stm32.USART1, stm32.USART6: - clock = CPUFrequency() / 2 // APB2 Frequency - case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: - clock = CPUFrequency() / 4 // APB1 Frequency - } - return clock / baudRate -} - -// Register names vary by ST processor, these are for STM F407 -func (uart *UART) setRegisters() { - uart.rxReg = &uart.Bus.DR - uart.txReg = &uart.Bus.DR - uart.statusReg = &uart.Bus.SR - uart.txEmptyFlag = stm32.USART_SR_TXE -} - -//---------- 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() { - // 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) - config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) -} - -func (spi SPI) getBaudRate(config SPIConfig) uint32 { - var clock uint32 - switch spi.Bus { - case stm32.SPI1: - clock = CPUFrequency() / 2 - case stm32.SPI2, stm32.SPI3: - clock = CPUFrequency() / 4 - } - - // limit requested frequency to bus frequency and min frequency (DIV256) - freq := config.Frequency - if min := clock / 256; freq < min { - freq = min - } else if freq > clock { - freq = clock - } - - // calculate the exact clock divisor (freq=clock/div -> div=clock/freq). - // truncation is fine, since it produces a less-than-or-equal divisor, and - // thus a greater-than-or-equal frequency. - // divisors only come in consecutive powers of 2, so we can use log2 (or, - // equivalently, bits.Len - 1) to convert to respective enum value. - div := bits.Len32(clock/freq) - 1 - - // but DIV1 (2^0) is not permitted, as the least divisor is DIV2 (2^1), so - // subtract 1 from the log2 value, keeping a lower bound of 0 - if div < 0 { - div = 0 - } else if div > 0 { - div-- - } - - // finally, shift the enumerated value into position for SPI CR1 - return uint32(div) << stm32.SPI_CR1_BR_Pos -} - -// -- I2C ---------------------------------------------------------------------- - -type I2C struct { - Bus *stm32.I2C_Type - AltFuncSelector uint8 -} - -func (i2c *I2C) configurePins(config I2CConfig) { - config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector) - config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector) -} - -func (i2c *I2C) getFreqRange(config I2CConfig) uint32 { - // all I2C interfaces are on APB1 (42 MHz) - clock := CPUFrequency() / 4 - // convert to MHz - clock /= 1000000 - // must be between 2 MHz (or 4 MHz for fast mode (Fm)) and 50 MHz, inclusive - var min, max uint32 = 2, 50 - if config.Frequency > 100000 { - min = 4 // fast mode (Fm) - } - if clock < min { - clock = min - } else if clock > max { - clock = max - } - return clock << stm32.I2C_CR2_FREQ_Pos -} - -func (i2c *I2C) getRiseTime(config I2CConfig) uint32 { - // These bits must be programmed with the maximum SCL rise time given in the - // I2C bus specification, incremented by 1. - // For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns. - // If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to 0x08 - // and PCLK1 = 125 ns, therefore the TRISE[5:0] bits must be programmed with - // 09h (1000 ns / 125 ns = 8 + 1) - freqRange := i2c.getFreqRange(config) - if config.Frequency > 100000 { - // fast mode (Fm) adjustment - freqRange *= 300 - freqRange /= 1000 - } - return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos -} - -func (i2c *I2C) getSpeed(config I2CConfig) uint32 { - ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 { - return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk - } - sm := func(pclk uint32, freq uint32) uint32 { // standard mode (Sm) - if s := ccr(pclk, freq, 2); s < 4 { - return 4 - } else { - return s - } - } - fm := func(pclk uint32, freq uint32, duty uint8) uint32 { // fast mode (Fm) - if duty == DutyCycle2 { - return ccr(pclk, freq, 3) - } else { - return ccr(pclk, freq, 25) | stm32.I2C_CCR_DUTY - } - } - // all I2C interfaces are on APB1 (42 MHz) - clock := CPUFrequency() / 4 - if config.Frequency <= 100000 { - return sm(clock, config.Frequency) - } else { - s := fm(clock, config.Frequency, config.DutyCycle) - if (s & stm32.I2C_CCR_CCR_Msk) == 0 { - return 1 - } else { - return s | stm32.I2C_CCR_F_S - } - } -}