1 /*
2  * Copyright (c) 2020-2023 Arm Limited. All rights reserved.
3  * SPDX-License-Identifier: BSD-3-Clause
4  */
5 
6 #include "microsecond_timer.h"
7 #include "cmsis.h"
8 
9 /* Maximum count for the SysTick */
10 #define MAX_SYSTICK_VAL (0x00ffffff)
11 
12 typedef struct _systick_us_context {
13     uint64_t overflow_count; /* Number of overflows; Forms high-order bits of 64-bit elapsed time */
14     uint32_t core_clock_per_us; /* Number of core clocks per microsecond */
15 } systick_us_context_t;
16 
17 /* Global state for the systick microsecond timer */
18 static systick_us_context_t s_context = { 0 };
19 
20 /* @brief SysTick interrupt handler.
21  *
22  * Increments the high-order bits of the 64-bit elapsed time every time the 24-bit SysTick
23  * counter rolls over from 0 and starts counting again from the maximum value.
24  */
SysTick_Handler(void)25 void SysTick_Handler(void)
26 {
27     s_context.overflow_count += MAX_SYSTICK_VAL + 1;
28 }
29 
30 /* Initializes the SysTick timer */
microsecond_timer_init(void)31 void microsecond_timer_init(void) {
32     /* Precompute the number of clocks per microsecond */
33     s_context.core_clock_per_us = SystemCoreClock / 1e6;
34 
35     /* First disable SysTick */
36     SysTick->CTRL = 0;
37 
38     /* Init SysTick reload with the maximum count */
39     SysTick->LOAD = MAX_SYSTICK_VAL;
40     SysTick->VAL = 0; /* Writing any value clears */
41 
42     /* Enable the interrupt and start counting */
43     SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
44 }
45 
get_elapsed_us(void)46 uint64_t get_elapsed_us(void)
47 {
48     uint32_t elapsed_microseconds = (MAX_SYSTICK_VAL - SysTick->VAL) / s_context.core_clock_per_us;
49     return s_context.overflow_count + elapsed_microseconds;
50 }
51 
get_elapsed_ms(void)52 static uint64_t get_elapsed_ms(void)
53 {
54     return get_elapsed_us() / 1000;
55 }
56 
sleep_ms(uint32_t delay_ms)57 void sleep_ms(uint32_t delay_ms)
58 {
59     uint64_t start_time = get_elapsed_ms();
60     while (get_elapsed_ms() - start_time < delay_ms) {
61     }
62 }
63