Improve usleep function and add a "usleep_short()" function, to be used only for...
authorNathael Pajani <nathael.pajani@ed3l.fr>
Wed, 9 Sep 2015 19:13:42 +0000 (21:13 +0200)
committerNathael Pajani <nathael.pajani@ed3l.fr>
Tue, 8 Nov 2022 16:03:04 +0000 (17:03 +0100)
core/systick.c
include/core/systick.h

index 35adfb6..81872ec 100644 (file)
@@ -36,6 +36,7 @@ static volatile uint32_t sleep_count = 0;
 static volatile uint32_t tick_ms = 0;
 static volatile uint32_t systick_running = 0;
 static volatile uint32_t tick_reload = 0;
+static uint32_t usleep_us_count = 0;
 
 /* Wraps every 50 days or so with a 1ms tick */
 static volatile uint32_t global_wrapping_system_ticks = 0;
@@ -237,6 +238,11 @@ void systick_timer_on(uint32_t ms)
        systick->control = LPC_SYSTICK_CTRL_TICKINT;
        systick_running = 0;
 
+       /* Perform this division now for the usleep function. */
+       usleep_us_count = get_main_clock() / (1000 * 1000);
+       /* For the LPC1224 the system tick clock is fixed to half the frequency of the system clock */
+       usleep_us_count = (usleep_us_count >> 1); /* Divide by two */
+
        /* FIXME : document this */
        NVIC_SetPriority(SYSTICK_IRQ, ((1 << LPC_NVIC_PRIO_BITS) - 1));
 }
@@ -299,6 +305,9 @@ void msleep(uint32_t ms)
        sleep();
 }
 
+/* This usleep function tries to sleep at most the required amount of time.
+ * The setup is so long that it cannot sleep for less than 10us when running at 48MHz
+ */
 void usleep(uint32_t us)
 {
        struct lpc_system_tick* systick = LPC_SYSTICK;
@@ -318,11 +327,32 @@ void usleep(uint32_t us)
                        systick_start();
                }
        }
-       count = get_main_clock() / (1000 * 1000) * us;
+       count = usleep_us_count * us;
+        /* Remember that systick is a decrementing counter */
+       if (count > start) {
+               end = (systick->reload_val - (count - start));
+               do { } while (systick_counted_to_zero() == 0); /* Wait for timer loop */
+               do { } while (systick->value > end); /* Wait for remaining part of sleep duration */
+       } else {
+               end = start - count;
+               /* Wait for sleep duration.
+                * If the counter looped, it means we already waited too much */
+               do { } while ((systick->value > end) && (systick_counted_to_zero() == 0));
+       }
+}
+
+void usleep_short(uint32_t us)
+{
+       struct lpc_system_tick* systick = LPC_SYSTICK;
+       uint32_t start = systick->value; /* Grab the starting (call time) value now */
+       uint32_t count = usleep_us_count * us;
+       uint32_t end = systick_counted_to_zero(); /* Erase loop indicator */
+
+        /* Remember that systick is a decrementing counter */
        if (count > start) {
                end = (systick->reload_val - (count - start));
                do { } while (systick_counted_to_zero() == 0); /* Wait for timer loop */
-               do { } while (systick->value > end); /* Wait for sleep duration */
+               do { } while (systick->value > end); /* Wait for remaining part of sleep duration */
        } else {
                end = start - count;
                /* Wait for sleep duration.
index f36f05a..f643414 100644 (file)
@@ -95,4 +95,11 @@ int add_systick_callback(void (*callback) (uint32_t), uint16_t period);
 int remove_systick_callback(void (*callback) (uint32_t));
 
 
+
+/* This function can be used when you are absolutly certain that systick timer is running, and when
+ * you need to sleep less than 1000us (1ms)
+ */
+void usleep_short(uint32_t us);
+
+
 #endif /* CORE_SYSTEM_H */