github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_stm32l0.go (about) 1 //go:build stm32l0 2 3 package machine 4 5 // Peripheral abstraction layer for the stm32l0 6 7 import ( 8 "device/stm32" 9 "runtime/interrupt" 10 ) 11 12 func CPUFrequency() uint32 { 13 return 32000000 14 } 15 16 var deviceIDAddr = []uintptr{0x1FF80050, 0x1FF80054, 0x1FF80058} 17 18 // Internal use: configured speed of the APB1 and APB2 timers, this should be kept 19 // in sync with any changes to runtime package which configures the oscillators 20 // and clock frequencies 21 const APB1_TIM_FREQ = 32e6 // 32MHz 22 const APB2_TIM_FREQ = 32e6 // 32MHz 23 24 const ( 25 PA0 = portA + 0 26 PA1 = portA + 1 27 PA2 = portA + 2 28 PA3 = portA + 3 29 PA4 = portA + 4 30 PA5 = portA + 5 31 PA6 = portA + 6 32 PA7 = portA + 7 33 PA8 = portA + 8 34 PA9 = portA + 9 35 PA10 = portA + 10 36 PA11 = portA + 11 37 PA12 = portA + 12 38 PA13 = portA + 13 39 PA14 = portA + 14 40 PA15 = portA + 15 41 42 PB0 = portB + 0 43 PB1 = portB + 1 44 PB2 = portB + 2 45 PB3 = portB + 3 46 PB4 = portB + 4 47 PB5 = portB + 5 48 PB6 = portB + 6 49 PB7 = portB + 7 50 PB8 = portB + 8 51 PB9 = portB + 9 52 PB10 = portB + 10 53 PB11 = portB + 11 54 PB12 = portB + 12 55 PB13 = portB + 13 56 PB14 = portB + 14 57 PB15 = portB + 15 58 59 PC0 = portC + 0 60 PC1 = portC + 1 61 PC2 = portC + 2 62 PC3 = portC + 3 63 PC4 = portC + 4 64 PC5 = portC + 5 65 PC6 = portC + 6 66 PC7 = portC + 7 67 PC8 = portC + 8 68 PC9 = portC + 9 69 PC10 = portC + 10 70 PC11 = portC + 11 71 PC12 = portC + 12 72 PC13 = portC + 13 73 PC14 = portC + 14 74 PC15 = portC + 15 75 76 PD0 = portD + 0 77 PD1 = portD + 1 78 PD2 = portD + 2 79 PD3 = portD + 3 80 PD4 = portD + 4 81 PD5 = portD + 5 82 PD6 = portD + 6 83 PD7 = portD + 7 84 PD8 = portD + 8 85 PD9 = portD + 9 86 PD10 = portD + 10 87 PD11 = portD + 11 88 PD12 = portD + 12 89 PD13 = portD + 13 90 PD14 = portD + 14 91 PD15 = portD + 15 92 93 PE0 = portE + 0 94 PE1 = portE + 1 95 PE2 = portE + 2 96 PE3 = portE + 3 97 PE4 = portE + 4 98 PE5 = portE + 5 99 PE6 = portE + 6 100 PE7 = portE + 7 101 PE8 = portE + 8 102 PE9 = portE + 9 103 PE10 = portE + 10 104 PE11 = portE + 11 105 PE12 = portE + 12 106 PE13 = portE + 13 107 PE14 = portE + 14 108 PE15 = portE + 15 109 110 PH0 = portH + 0 111 PH1 = portH + 1 112 ) 113 114 func (p Pin) getPort() *stm32.GPIO_Type { 115 switch p / 16 { 116 case 0: 117 return stm32.GPIOA 118 case 1: 119 return stm32.GPIOB 120 case 2: 121 return stm32.GPIOC 122 case 3: 123 return stm32.GPIOD 124 case 4: 125 return stm32.GPIOE 126 case 7: 127 return stm32.GPIOH 128 default: 129 panic("machine: unknown port") 130 } 131 } 132 133 // enableClock enables the clock for this desired GPIO port. 134 func (p Pin) enableClock() { 135 switch p / 16 { 136 case 0: 137 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPAEN) 138 case 1: 139 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPBEN) 140 case 2: 141 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPCEN) 142 case 3: 143 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPDEN) 144 case 4: 145 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPEEN) 146 case 7: 147 stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPHEN) 148 default: 149 panic("machine: unknown port") 150 } 151 } 152 153 func (p Pin) registerInterrupt() interrupt.Interrupt { 154 pin := uint8(p) % 16 155 156 switch pin { 157 case 0: 158 return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(0) }) 159 case 1: 160 return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(1) }) 161 case 2: 162 return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(2) }) 163 case 3: 164 return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(3) }) 165 case 4: 166 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(4) }) 167 case 5: 168 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(5) }) 169 case 6: 170 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(6) }) 171 case 7: 172 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(7) }) 173 case 8: 174 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(8) }) 175 case 9: 176 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(9) }) 177 case 10: 178 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(10) }) 179 case 11: 180 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(11) }) 181 case 12: 182 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(12) }) 183 case 13: 184 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(13) }) 185 case 14: 186 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(14) }) 187 case 15: 188 return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(15) }) 189 } 190 191 return interrupt.Interrupt{} 192 } 193 194 //---------- UART related types and code 195 196 // Configure the UART. 197 func (uart *UART) configurePins(config UARTConfig) { 198 // enable the alternate functions on the TX and RX pins 199 config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector) 200 config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector) 201 } 202 203 // UART baudrate calc based on the bus and clockspeed 204 func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 { 205 var clock, rate uint32 206 switch uart.Bus { 207 case stm32.LPUART1: 208 clock = CPUFrequency() / 2 // APB1 Frequency 209 rate = uint32((256 * clock) / baudRate) 210 case stm32.USART1: 211 clock = CPUFrequency() / 2 // APB2 Frequency 212 rate = uint32(clock / baudRate) 213 case stm32.USART2: 214 clock = CPUFrequency() / 2 // APB1 Frequency 215 rate = uint32(clock / baudRate) 216 } 217 218 return rate 219 } 220 221 // Register names vary by ST processor, these are for STM L0 family 222 func (uart *UART) setRegisters() { 223 uart.rxReg = &uart.Bus.RDR 224 uart.txReg = &uart.Bus.TDR 225 uart.statusReg = &uart.Bus.ISR 226 uart.txEmptyFlag = stm32.USART_ISR_TXE 227 } 228 229 //---------- SPI related types and code 230 231 // SPI on the STM32Fxxx using MODER / alternate function pins 232 type SPI struct { 233 Bus *stm32.SPI_Type 234 AltFuncSelector uint8 235 } 236 237 func (spi SPI) config8Bits() { 238 // no-op on this series 239 } 240 241 // Set baud rate for SPI 242 func (spi SPI) getBaudRate(config SPIConfig) uint32 { 243 var conf uint32 244 245 localFrequency := config.Frequency 246 247 // Default 248 if config.Frequency == 0 { 249 config.Frequency = 4e6 250 } 251 252 if spi.Bus != stm32.SPI1 { 253 // Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so 254 // we want to pretend to request 2x the baudrate asked for 255 localFrequency = localFrequency * 2 256 } 257 258 // set frequency dependent on PCLK prescaler. Since these are rather weird 259 // speeds due to the CPU freqency, pick a range up to that frquency for 260 // clients to use more human-understandable numbers, e.g. nearest 100KHz 261 262 // These are based on APB2 clock frquency (84MHz on the discovery board) 263 // TODO: also include the MCU/APB clock setting in the equation 264 switch { 265 case localFrequency < 328125: 266 conf = stm32.SPI_CR1_BR_Div256 267 case localFrequency < 656250: 268 conf = stm32.SPI_CR1_BR_Div128 269 case localFrequency < 1312500: 270 conf = stm32.SPI_CR1_BR_Div64 271 case localFrequency < 2625000: 272 conf = stm32.SPI_CR1_BR_Div32 273 case localFrequency < 5250000: 274 conf = stm32.SPI_CR1_BR_Div16 275 case localFrequency < 10500000: 276 conf = stm32.SPI_CR1_BR_Div8 277 // NOTE: many SPI components won't operate reliably (or at all) above 10MHz 278 // Check the datasheet of the part 279 case localFrequency < 21000000: 280 conf = stm32.SPI_CR1_BR_Div4 281 case localFrequency < 42000000: 282 conf = stm32.SPI_CR1_BR_Div2 283 default: 284 // None of the specific baudrates were selected; choose the lowest speed 285 conf = stm32.SPI_CR1_BR_Div256 286 } 287 288 return conf << stm32.SPI_CR1_BR_Pos 289 } 290 291 // Configure SPI pins for input output and clock 292 func (spi SPI) configurePins(config SPIConfig) { 293 config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector) 294 config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector) 295 config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector) 296 } 297 298 //---------- I2C related types and code 299 300 // Gets the value for TIMINGR register 301 func (i2c I2C) getFreqRange() uint32 { 302 // This is a 'magic' value calculated by STM32CubeMX 303 // for 80MHz PCLK1. 304 // TODO: Do calculations based on PCLK1 305 return 0x00303D5B 306 }