machine/stm32f103xx: implementation of RTC/TIM based timers
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
		
							родитель
							
								
									fb8dcde2f9
								
							
						
					
					
						коммит
						f71e1bcf03
					
				
					 3 изменённых файлов: 158 добавлений и 8 удалений
				
			
		|  | @ -12,20 +12,32 @@ const ( | ||||||
| 	FLASH_ACR_LATENCY_2 = 0x00000004 | 	FLASH_ACR_LATENCY_2 = 0x00000004 | ||||||
| 
 | 
 | ||||||
| 	// Reset and Clock Control Control Register flag values. | 	// Reset and Clock Control Control Register flag values. | ||||||
|  | 
 | ||||||
|  | 	// System Clock source | ||||||
| 	RCC_CFGR_SW_HSI = 0 | 	RCC_CFGR_SW_HSI = 0 | ||||||
| 	RCC_CFGR_SW_HSE = 1 | 	RCC_CFGR_SW_HSE = 1 | ||||||
| 	RCC_CFGR_SW_PLL = 2 | 	RCC_CFGR_SW_PLL = 2 | ||||||
| 
 | 
 | ||||||
|  | 	// Flags for when System Clock source is set. | ||||||
| 	RCC_CFGR_SWS_HSI = 0x00000000 | 	RCC_CFGR_SWS_HSI = 0x00000000 | ||||||
| 	RCC_CFGR_SWS_HSE = 0x00000004 | 	RCC_CFGR_SWS_HSE = 0x00000004 | ||||||
| 	RCC_CFGR_SWS_PLL = 0x00000008 | 	RCC_CFGR_SWS_PLL = 0x00000008 | ||||||
| 
 | 
 | ||||||
|  | 	// Sets PCLK1 | ||||||
| 	RCC_CFGR_PPRE1_DIV_NONE = 0x00000000 | 	RCC_CFGR_PPRE1_DIV_NONE = 0x00000000 | ||||||
| 	RCC_CFGR_PPRE1_DIV_2    = 0x00000400 | 	RCC_CFGR_PPRE1_DIV_2    = 0x00000400 | ||||||
| 	RCC_CFGR_PPRE1_DIV_4    = 0x00000500 | 	RCC_CFGR_PPRE1_DIV_4    = 0x00000500 | ||||||
| 	RCC_CFGR_PPRE1_DIV_8    = 0x00000600 | 	RCC_CFGR_PPRE1_DIV_8    = 0x00000600 | ||||||
| 	RCC_CFGR_PPRE1_DIV_16   = 0x00000700 | 	RCC_CFGR_PPRE1_DIV_16   = 0x00000700 | ||||||
| 
 | 
 | ||||||
|  | 	// Sets PCLK2 | ||||||
|  | 	RCC_CFGR_PPRE2_DIV_NONE = 0x00000000 | ||||||
|  | 	RCC_CFGR_PPRE2_DIV_2    = 0x00002000 | ||||||
|  | 	RCC_CFGR_PPRE2_DIV_4    = 0x00002800 | ||||||
|  | 	RCC_CFGR_PPRE2_DIV_8    = 0x00003000 | ||||||
|  | 	RCC_CFGR_PPRE2_DIV_16   = 0x00003800 | ||||||
|  | 
 | ||||||
|  | 	// Sets PLL multiplier | ||||||
| 	RCC_CFGR_PLLMUL_2  = 0x00000000 | 	RCC_CFGR_PLLMUL_2  = 0x00000000 | ||||||
| 	RCC_CFGR_PLLMUL_3  = 0x00040000 | 	RCC_CFGR_PLLMUL_3  = 0x00040000 | ||||||
| 	RCC_CFGR_PLLMUL_4  = 0x00080000 | 	RCC_CFGR_PLLMUL_4  = 0x00080000 | ||||||
|  | @ -41,4 +53,9 @@ const ( | ||||||
| 	RCC_CFGR_PLLMUL_14 = 0x00300000 | 	RCC_CFGR_PLLMUL_14 = 0x00300000 | ||||||
| 	RCC_CFGR_PLLMUL_15 = 0x00340000 | 	RCC_CFGR_PLLMUL_15 = 0x00340000 | ||||||
| 	RCC_CFGR_PLLMUL_16 = 0x00380000 | 	RCC_CFGR_PLLMUL_16 = 0x00380000 | ||||||
|  | 
 | ||||||
|  | 	// RTC clock source | ||||||
|  | 	RCC_RTCCLKSource_LSE        = 0x00000100 | ||||||
|  | 	RCC_RTCCLKSource_LSI        = 0x00000200 | ||||||
|  | 	RCC_RTCCLKSource_HSE_Div128 = 0x00000300 | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | @ -137,6 +137,7 @@ func (uart UART) Configure(config UARTConfig) { | ||||||
| 	stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE | 	stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE | ||||||
| 
 | 
 | ||||||
| 	// Enable RX IRQ. | 	// Enable RX IRQ. | ||||||
|  | 	arm.SetPriority(stm32.IRQ_USART1, 0xc0) | ||||||
| 	arm.EnableIRQ(stm32.IRQ_USART1) | 	arm.EnableIRQ(stm32.IRQ_USART1) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,10 +8,10 @@ import ( | ||||||
| 	"machine" | 	"machine" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const tickMicros = 1 // TODO |  | ||||||
| 
 |  | ||||||
| func init() { | func init() { | ||||||
| 	initCLK() | 	initCLK() | ||||||
|  | 	initRTC() | ||||||
|  | 	initTIM() | ||||||
| 	machine.UART0.Configure(machine.UARTConfig{}) | 	machine.UART0.Configure(machine.UARTConfig{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -44,13 +44,145 @@ func initCLK() { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func sleepTicks(d timeUnit) { | const tickMicros = 1000 | ||||||
| 	// TODO: use a real timer here | 
 | ||||||
| 	for i := 0; i < int(d/535); i++ { | var ( | ||||||
| 		arm.Asm("") | 	timestamp        timeUnit // microseconds since boottime | ||||||
|  | 	timerLastCounter uint64 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | //go:volatile | ||||||
|  | type isrFlag bool | ||||||
|  | 
 | ||||||
|  | var timerWakeup isrFlag | ||||||
|  | 
 | ||||||
|  | func initRTC() { | ||||||
|  | 	// Enable the PWR and BKP. | ||||||
|  | 	stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN | ||||||
|  | 
 | ||||||
|  | 	// access to backup register | ||||||
|  | 	stm32.PWR.CR |= stm32.PWR_CR_DBP | ||||||
|  | 
 | ||||||
|  | 	// Enable LSE | ||||||
|  | 	stm32.RCC.BDCR |= stm32.RCC_BDCR_LSEON | ||||||
|  | 
 | ||||||
|  | 	// wait until LSE is ready | ||||||
|  | 	for stm32.RCC.BDCR&stm32.RCC_BDCR_LSERDY == 0 { | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Select LSE | ||||||
|  | 	stm32.RCC.BDCR |= stm32.RCC_RTCCLKSource_LSE | ||||||
|  | 
 | ||||||
|  | 	// set prescaler to "max" per datasheet | ||||||
|  | 	stm32.RTC.PRLH = stm32.RTC_PRLH_PRLH_Msk | ||||||
|  | 	stm32.RTC.PRLL = stm32.RTC_PRLL_PRLL_Msk | ||||||
|  | 
 | ||||||
|  | 	// set count to zero | ||||||
|  | 	stm32.RTC.CNTH = 0x0 | ||||||
|  | 	stm32.RTC.CNTL = 0x0 | ||||||
|  | 
 | ||||||
|  | 	// Enable RTC | ||||||
|  | 	stm32.RCC.BDCR |= stm32.RCC_BDCR_RTCEN | ||||||
|  | 
 | ||||||
|  | 	// Clear RSF | ||||||
|  | 	stm32.RTC.CRL &^= stm32.RTC_CRL_RSF | ||||||
|  | 
 | ||||||
|  | 	// Wait till flag is set | ||||||
|  | 	for stm32.RTC.CRL&stm32.RTC_CRL_RSF == 0 { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ticks() timeUnit { | // Enable the TIM3 clock. | ||||||
| 	return 0 // TODO | func initTIM() { | ||||||
|  | 	stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN | ||||||
|  | 
 | ||||||
|  | 	arm.SetPriority(stm32.IRQ_TIM3, 0xc3) | ||||||
|  | 	arm.EnableIRQ(stm32.IRQ_TIM3) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // sleepTicks should sleep for specific number of microseconds. | ||||||
|  | func sleepTicks(d timeUnit) { | ||||||
|  | 	for d != 0 { | ||||||
|  | 		ticks()            // update timestamp | ||||||
|  | 		ticks := uint32(d) // current scaling only supports 100 usec to 6553 msec | ||||||
|  | 		timerSleep(ticks) | ||||||
|  | 		d -= timeUnit(ticks) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // number of ticks (microseconds) since start. | ||||||
|  | func ticks() timeUnit { | ||||||
|  | 	// convert RTC counter from seconds to microseconds | ||||||
|  | 	timerCounter := uint64(stm32.RTC.CNTH<<16|stm32.RTC.CNTL) * 1000 * 1000 | ||||||
|  | 
 | ||||||
|  | 	// add the fractional part of current time using DIV registers | ||||||
|  | 	timerCounter += (uint64(stm32.RTC.DIVH<<16|stm32.RTC.DIVL) / 1024 * 32 * 32) * 1000 * 1000 | ||||||
|  | 
 | ||||||
|  | 	// change since last measurement | ||||||
|  | 	offset := (timerCounter - timerLastCounter) | ||||||
|  | 	timerLastCounter = timerCounter | ||||||
|  | 	timestamp += timeUnit(offset) | ||||||
|  | 	return timestamp | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ticks are in microseconds | ||||||
|  | func timerSleep(ticks uint32) { | ||||||
|  | 	timerWakeup = false | ||||||
|  | 
 | ||||||
|  | 	// STM32 timer update event period is calculated as follows: | ||||||
|  | 	// | ||||||
|  | 	// 			Update_event = TIM_CLK/((PSC + 1)*(ARR + 1)*(RCR + 1)) | ||||||
|  | 	// | ||||||
|  | 	// Where: | ||||||
|  | 	// | ||||||
|  | 	//			TIM_CLK = timer clock input | ||||||
|  | 	// 			PSC = 16-bit prescaler register | ||||||
|  | 	// 			ARR = 16/32-bit Autoreload register | ||||||
|  | 	// 			RCR = 16-bit repetition counter | ||||||
|  | 	// | ||||||
|  | 	// Example: | ||||||
|  | 	// | ||||||
|  | 	//			TIM_CLK = 72 MHz | ||||||
|  | 	// 			Prescaler = 1 | ||||||
|  | 	// 			Auto reload = 65535 | ||||||
|  | 	// 			No repetition counter RCR = 0 | ||||||
|  | 	// 			Update_event = 72*(10^6)/((1 + 1)*(65535 + 1)*(1)) | ||||||
|  | 	// 			Update_event = 549.3 Hz | ||||||
|  | 	// | ||||||
|  | 	// Set the timer prescaler/autoreload timing registers. | ||||||
|  | 
 | ||||||
|  | 	// TODO: support smaller or larger scales (autoscaling) based | ||||||
|  | 	// on the length of sleep time requested. | ||||||
|  | 	// The current scaling only supports a range of 100 usec to 6553 msec. | ||||||
|  | 
 | ||||||
|  | 	// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency. | ||||||
|  | 	stm32.TIM3.PSC = machine.CPU_FREQUENCY/10000 - 1 // 7199 | ||||||
|  | 
 | ||||||
|  | 	// set duty aka duration | ||||||
|  | 	stm32.TIM3.ARR = stm32.RegValue(ticks/100) - 1 // convert from microseconds to 0.1 ms | ||||||
|  | 
 | ||||||
|  | 	// Enable the hardware interrupt. | ||||||
|  | 	stm32.TIM3.DIER |= stm32.TIM_DIER_UIE | ||||||
|  | 
 | ||||||
|  | 	// Enable the timer. | ||||||
|  | 	stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN | ||||||
|  | 
 | ||||||
|  | 	// wait till timer wakes up | ||||||
|  | 	for !timerWakeup { | ||||||
|  | 		arm.Asm("wfi") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //go:export TIM3_IRQHandler | ||||||
|  | func handleTIM3() { | ||||||
|  | 	if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 { | ||||||
|  | 		// Disable the timer. | ||||||
|  | 		stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN | ||||||
|  | 
 | ||||||
|  | 		// clear the update flag | ||||||
|  | 		stm32.TIM3.SR &^= stm32.TIM_SR_UIF | ||||||
|  | 
 | ||||||
|  | 		// timer was triggered | ||||||
|  | 		timerWakeup = true | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Ron Evans
						Ron Evans