1+ #include "lib.h"
2+ #include <stm32l4xx_hal.h>
3+
4+ static volatile uint64_t monotonic_hi = 0 ;
5+
6+ static void init_monotonic_timer (void )
7+ {
8+ const uint32_t target_hz = 1000000U ;
9+ uint32_t tim_clk = HAL_RCC_GetPCLK1Freq ();
10+
11+ monotonic_hi = 0 ;
12+
13+ // If APB1 prescaler is not 1, timer clocks run at 2x PCLK1.
14+ if ((RCC -> CFGR & RCC_CFGR_PPRE1 ) != RCC_CFGR_PPRE1_DIV1 ) {
15+ tim_clk *= 2U ;
16+ }
17+
18+ const uint32_t prescaler = (tim_clk / target_hz ) - 1U ;
19+
20+ __HAL_RCC_TIM2_CLK_ENABLE ();
21+ __HAL_RCC_TIM2_FORCE_RESET ();
22+ __HAL_RCC_TIM2_RELEASE_RESET ();
23+
24+ HAL_NVIC_DisableIRQ (TIM2_IRQn );
25+ NVIC_ClearPendingIRQ (TIM2_IRQn );
26+
27+ // URS ensures update flags/interrupts are only from real overflows.
28+ TIM2 -> CR1 = TIM_CR1_URS ;
29+ TIM2 -> PSC = prescaler ;
30+ TIM2 -> ARR = 0xFFFFFFFFU ;
31+ TIM2 -> CNT = 0 ;
32+ TIM2 -> EGR = TIM_EGR_UG ;
33+
34+ // Clear pending flags and enable update interrupt for wrap extension.
35+ TIM2 -> SR = 0 ;
36+ TIM2 -> DIER = TIM_DIER_UIE ;
37+
38+ HAL_NVIC_SetPriority (TIM2_IRQn , 15 , 0 );
39+ HAL_NVIC_EnableIRQ (TIM2_IRQn );
40+
41+ TIM2 -> CR1 |= TIM_CR1_CEN ;
42+
43+ // Clear any latent startup update state before first read.
44+ TIM2 -> SR = 0 ;
45+ NVIC_ClearPendingIRQ (TIM2_IRQn );
46+ }
47+
48+ void tim2_hndlr (void )
49+ {
50+ if ((TIM2 -> SR & TIM_SR_UIF ) != 0U ) {
51+ TIM2 -> SR &= ~TIM_SR_UIF ;
52+ monotonic_hi += (1ULL << 32 );
53+ }
54+ }
55+
56+ void SystemClock_Config (void )
57+ {
58+ RCC_OscInitTypeDef RCC_OscInitStruct = {0 };
59+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0 };
60+
61+ /* 80 MHz on STM32L4+ => Range 1 normal mode, not boost */
62+ __HAL_RCC_PWR_CLK_ENABLE ();
63+
64+ if (HAL_PWREx_ControlVoltageScaling (PWR_REGULATOR_VOLTAGE_SCALE1 ) != HAL_OK ) {
65+ while (1 ) {}
66+ }
67+
68+ /* HSI16 -> PLL -> 80 MHz SYSCLK */
69+ RCC_OscInitStruct .OscillatorType = RCC_OSCILLATORTYPE_HSI ;
70+ RCC_OscInitStruct .HSIState = RCC_HSI_ON ;
71+ RCC_OscInitStruct .HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT ;
72+
73+ RCC_OscInitStruct .PLL .PLLState = RCC_PLL_ON ;
74+ RCC_OscInitStruct .PLL .PLLSource = RCC_PLLSOURCE_HSI ;
75+ RCC_OscInitStruct .PLL .PLLM = 1 ;
76+ RCC_OscInitStruct .PLL .PLLN = 10 ;
77+ RCC_OscInitStruct .PLL .PLLR = RCC_PLLR_DIV2 ;
78+ RCC_OscInitStruct .PLL .PLLP = RCC_PLLP_DIV7 ; // arbitrary unless you use PLLP
79+ RCC_OscInitStruct .PLL .PLLQ = RCC_PLLQ_DIV2 ; // arbitrary unless you use PLLQ
80+
81+ if (HAL_RCC_OscConfig (& RCC_OscInitStruct ) != HAL_OK ) {
82+ while (1 ) {}
83+ }
84+
85+ RCC_ClkInitStruct .ClockType =
86+ RCC_CLOCKTYPE_SYSCLK |
87+ RCC_CLOCKTYPE_HCLK |
88+ RCC_CLOCKTYPE_PCLK1 |
89+ RCC_CLOCKTYPE_PCLK2 ;
90+
91+ RCC_ClkInitStruct .SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK ;
92+ RCC_ClkInitStruct .AHBCLKDivider = RCC_SYSCLK_DIV1 ;
93+ RCC_ClkInitStruct .APB1CLKDivider = RCC_HCLK_DIV1 ;
94+ RCC_ClkInitStruct .APB2CLKDivider = RCC_HCLK_DIV1 ;
95+
96+ if (HAL_RCC_ClockConfig (& RCC_ClkInitStruct , FLASH_LATENCY_4 ) != HAL_OK ) {
97+ while (1 ) {}
98+ }
99+
100+ SystemCoreClockUpdate ();
101+ init_monotonic_timer ();
102+ }
103+
104+ unsigned long long monotonic_now (void )
105+ {
106+ uint64_t hi_1 ;
107+ uint64_t hi_2 ;
108+ uint32_t lo ;
109+ uint32_t sr ;
110+
111+ // Retry if the overflow IRQ updates the high word while sampling.
112+ do {
113+ hi_1 = monotonic_hi ;
114+ lo = TIM2 -> CNT ;
115+ sr = TIM2 -> SR ;
116+ hi_2 = monotonic_hi ;
117+ } while (hi_1 != hi_2 );
118+
119+ // If overflow is pending but IRQ has not run yet, include that wrap.
120+ if ((sr & TIM_SR_UIF ) != 0U && lo < 0x80000000U ) {
121+ hi_1 += (1ULL << 32 );
122+ }
123+
124+ return hi_1 | (uint64_t )lo ;
125+ }
126+
127+ unsigned long long monotonic_freq (void )
128+ {
129+ return 1000000ULL ;
130+ }
0 commit comments