github.com/aykevl/tinygo@v0.5.0/src/runtime/runtime_stm32f103xx.go (about)

     1  // +build stm32,stm32f103xx
     2  
     3  package runtime
     4  
     5  import (
     6  	"device/arm"
     7  	"device/stm32"
     8  	"machine"
     9  )
    10  
    11  func init() {
    12  	initCLK()
    13  	initRTC()
    14  	initTIM()
    15  	machine.UART0.Configure(machine.UARTConfig{})
    16  }
    17  
    18  func putchar(c byte) {
    19  	machine.UART0.WriteByte(c)
    20  }
    21  
    22  // initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
    23  func initCLK() {
    24  	stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2    // Two wait states, per datasheet
    25  	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2    // prescale PCLK1 = HCLK/2
    26  	stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_NONE // prescale PCLK2 = HCLK/1
    27  	stm32.RCC.CR |= stm32.RCC_CR_HSEON              // enable HSE clock
    28  
    29  	// wait for the HSEREADY flag
    30  	for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 {
    31  	}
    32  
    33  	stm32.RCC.CR |= stm32.RCC_CR_HSION // enable HSI clock
    34  
    35  	// wait for the HSIREADY flag
    36  	for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 {
    37  	}
    38  
    39  	stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC   // set PLL source to HSE
    40  	stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLMUL_9 // multiply by 9
    41  	stm32.RCC.CR |= stm32.RCC_CR_PLLON        // enable the PLL
    42  
    43  	// wait for the PLLRDY flag
    44  	for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 {
    45  	}
    46  
    47  	stm32.RCC.CFGR |= stm32.RCC_CFGR_SW_PLL // set clock source to pll
    48  
    49  	// wait for PLL to be CLK
    50  	for (stm32.RCC.CFGR & stm32.RCC_CFGR_SWS_PLL) == 0 {
    51  	}
    52  }
    53  
    54  const tickMicros = 1000
    55  
    56  var (
    57  	timestamp        timeUnit // microseconds since boottime
    58  	timerLastCounter uint64
    59  )
    60  
    61  //go:volatile
    62  type isrFlag bool
    63  
    64  var timerWakeup isrFlag
    65  
    66  func initRTC() {
    67  	// Enable the PWR and BKP.
    68  	stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN
    69  
    70  	// access to backup register
    71  	stm32.PWR.CR |= stm32.PWR_CR_DBP
    72  
    73  	// Enable LSE
    74  	stm32.RCC.BDCR |= stm32.RCC_BDCR_LSEON
    75  
    76  	// wait until LSE is ready
    77  	for stm32.RCC.BDCR&stm32.RCC_BDCR_LSERDY == 0 {
    78  	}
    79  
    80  	// Select LSE
    81  	stm32.RCC.BDCR |= stm32.RCC_RTCCLKSource_LSE
    82  
    83  	// set prescaler to "max" per datasheet
    84  	stm32.RTC.PRLH = stm32.RTC_PRLH_PRLH_Msk
    85  	stm32.RTC.PRLL = stm32.RTC_PRLL_PRLL_Msk
    86  
    87  	// set count to zero
    88  	stm32.RTC.CNTH = 0x0
    89  	stm32.RTC.CNTL = 0x0
    90  
    91  	// Enable RTC
    92  	stm32.RCC.BDCR |= stm32.RCC_BDCR_RTCEN
    93  
    94  	// Clear RSF
    95  	stm32.RTC.CRL &^= stm32.RTC_CRL_RSF
    96  
    97  	// Wait till flag is set
    98  	for stm32.RTC.CRL&stm32.RTC_CRL_RSF == 0 {
    99  	}
   100  }
   101  
   102  // Enable the TIM3 clock.
   103  func initTIM() {
   104  	stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN
   105  
   106  	arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
   107  	arm.EnableIRQ(stm32.IRQ_TIM3)
   108  }
   109  
   110  const asyncScheduler = false
   111  
   112  // sleepTicks should sleep for specific number of microseconds.
   113  func sleepTicks(d timeUnit) {
   114  	for d != 0 {
   115  		ticks()            // update timestamp
   116  		ticks := uint32(d) // current scaling only supports 100 usec to 6553 msec
   117  		timerSleep(ticks)
   118  		d -= timeUnit(ticks)
   119  	}
   120  }
   121  
   122  // number of ticks (microseconds) since start.
   123  func ticks() timeUnit {
   124  	// convert RTC counter from seconds to microseconds
   125  	timerCounter := uint64(stm32.RTC.CNTH<<16|stm32.RTC.CNTL) * 1000 * 1000
   126  
   127  	// add the fractional part of current time using DIV register
   128  	timerCounter += uint64(0x8000-stm32.RTC.DIVL) * 31
   129  
   130  	// change since last measurement
   131  	offset := (timerCounter - timerLastCounter)
   132  	timerLastCounter = timerCounter
   133  	timestamp += timeUnit(offset)
   134  	return timestamp
   135  }
   136  
   137  // ticks are in microseconds
   138  func timerSleep(ticks uint32) {
   139  	timerWakeup = false
   140  
   141  	// STM32 timer update event period is calculated as follows:
   142  	//
   143  	// 			Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1))
   144  	//
   145  	// Where:
   146  	//
   147  	//			TIM_CLK = timer clock input
   148  	// 			PSC = 16-bit prescaler register
   149  	// 			ARR = 16/32-bit Autoreload register
   150  	// 			RCR = 16-bit repetition counter
   151  	//
   152  	// Example:
   153  	//
   154  	//			TIM_CLK = 72 MHz
   155  	// 			Prescaler = 1
   156  	// 			Auto reload = 65535
   157  	// 			No repetition counter RCR = 0
   158  	// 			Update_event = 72*(10^6)/((1 + 1)*(65535 + 1)*(1))
   159  	// 			Update_event = 549.3 Hz
   160  	//
   161  	// Set the timer prescaler/autoreload timing registers.
   162  
   163  	// TODO: support smaller or larger scales (autoscaling) based
   164  	// on the length of sleep time requested.
   165  	// The current scaling only supports a range of 100 usec to 6553 msec.
   166  
   167  	// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
   168  	stm32.TIM3.PSC = machine.CPU_FREQUENCY/10000 - 1 // 7199
   169  
   170  	// set duty aka duration
   171  	stm32.TIM3.ARR = stm32.RegValue(ticks/100) - 1 // convert from microseconds to 0.1 ms
   172  
   173  	// Enable the hardware interrupt.
   174  	stm32.TIM3.DIER |= stm32.TIM_DIER_UIE
   175  
   176  	// Enable the timer.
   177  	stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN
   178  
   179  	// wait till timer wakes up
   180  	for !timerWakeup {
   181  		arm.Asm("wfi")
   182  	}
   183  }
   184  
   185  //go:export TIM3_IRQHandler
   186  func handleTIM3() {
   187  	if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 {
   188  		// Disable the timer.
   189  		stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN
   190  
   191  		// clear the update flag
   192  		stm32.TIM3.SR &^= stm32.TIM_SR_UIF
   193  
   194  		// timer was triggered
   195  		timerWakeup = true
   196  	}
   197  }