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  }