Skip to content

Commit

Permalink
Make the Zephyr Kernel Clock the default timing service.
Browse files Browse the repository at this point in the history
Also does following improvements:
- Use timed wait on semaphore instead of a busy-wait
for sleeping
- Use Zephyr API for getting a monotonically increasing time.
  • Loading branch information
erlingrj committed Mar 22, 2024
1 parent aa12f14 commit 3698799
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 31 deletions.
2 changes: 1 addition & 1 deletion low_level_platform/api/platform/lf_zephyr_board_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define LF_ZEPHYR_THREAD_PRIORITY_DEFAULT 5
#define LF_ZEPHYR_STACK_SIZE_DEFAULT 2048

#if defined(CONFIG_LF_ZEPHYR_CLOCK_COUNTER)
#if defined(LF_ZEPHYR_CLOCK_COUNTER)
#if defined(CONFIG_SOC_FAMILY_NRF)
#define LF_TIMER DT_NODELABEL(timer1)
#define LF_WAKEUP_OVERHEAD_US 100
Expand Down
3 changes: 2 additions & 1 deletion low_level_platform/impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ endif()
list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/platform_internal.c)

if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr")
if(${CONFIG_LF_ZEPHYR_CLOCK_COUNTER})
if(${LF_ZEPHYR_CLOCK_COUNTER})
message(STATUS "Building Zephyr library with Counter clock ")
else()
message(STATUS "Building Zephyr library with Kernel clock ")
Expand Down Expand Up @@ -85,3 +85,4 @@ low_level_platform_define(MODAL_REACTORS)
low_level_platform_define(USER_THREADS)
low_level_platform_define(NUMBER_OF_WORKERS)
low_level_platform_define(NUMBER_OF_WATCHDOGS)
low_level_platform_define(LF_ZEPHYR_CLOCK_COUNTER)
2 changes: 1 addition & 1 deletion low_level_platform/impl/src/lf_zephyr_clock_counter.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#if defined(PLATFORM_ZEPHYR)
#include "platform/lf_zephyr_board_support.h"
#if defined(CONFIG_LF_ZEPHYR_CLOCK_COUNTER)
#if defined(LF_ZEPHYR_CLOCK_COUNTER)
/*************
Copyright (c) 2023, Norwegian University of Science and Technology.
Expand Down
68 changes: 40 additions & 28 deletions low_level_platform/impl/src/lf_zephyr_clock_kernel.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#if defined(PLATFORM_ZEPHYR)
#include "platform/lf_zephyr_board_support.h"
#if !defined(CONFIG_LF_ZEPHYR_CLOCK_COUNTER)
#if !defined(LF_ZEPHYR_CLOCK_COUNTER)

/*************
Copyright (c) 2023, Norwegian University of Science and Technology.
Expand Down Expand Up @@ -41,52 +41,62 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "low_level_platform.h"
#include "logging_macros.h"

static int64_t epoch_duration_nsec;
static volatile int64_t last_epoch_nsec = 0;
// Convert Zephyr ticks into an interval_t. According to Zephyr docs the
// ticks are 100Hz for QEMU emulations, and normally a multiple of 10.
#if CONFIG_SYS_CLOCK_TICKS_PER_SEC == 100
#define TICKS_TO_NSEC(ticks) MSEC(10 * ticks)
#elif CONFIG_SYS_CLOCK_TICKS_PER_SEC == 1000
#define TICKS_TO_NSEC(ticks) MSEC(ticks)
#elif CONFIG_SYS_CLOCK_TICKS_PER_SEC == 10000
#define TICKS_TO_NSEC(ticks) USEC(100 * ticks)
#elif CONFIG_SYS_CLOCK_TICKS_PER_SEC == 100000
#define TICKS_TO_NSEC(ticks) USEC(10 * ticks)
#elif CONFIG_SYS_CLOCK_TICKS_PER_SEC == 1000000
#define TICKS_TO_NSEC(ticks) USEC(1 * ticks)
#elif CONFIG_SYS_CLOCK_TICKS_PER_SEC == 10000000
#define TICKS_TO_NSEC(ticks) NSEC(100 * ticks)
#else
#define TICKS_TO_NSEC(ticks) ((SECONDS(1) / CONFIG_SYS_CLOCK_TICKS_PER_SEC) * ticks)
#endif

static uint32_t timer_freq;
static volatile bool async_event = false;

// Statically create an initialize the semaphore used for sleeping.
K_SEM_DEFINE(sleeping_sem, 0, 1)

void _lf_initialize_clock() {
timer_freq = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
timer_freq = CONFIG_SYS_CLOCK_TICKS_PER_SEC;
LF_PRINT_LOG("--- Using LF Zephyr Kernel Clock with a frequency of %u Hz\n", timer_freq);
last_epoch_nsec = 0;
epoch_duration_nsec = ((1LL << 32) * SECONDS(1)) / CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
}

/**
* Detect wraps by storing the previous clock readout. When a clock readout is
* less than the previous we have had a wrap. This only works of `_lf_clock_gettime`
* is invoked at least once per epoch.
*/
/** Uses Zephyr's monotonic increasing uptime count. */
int _lf_clock_gettime(instant_t* t) {
static uint32_t last_read_cycles = 0;
uint32_t now_cycles = k_cycle_get_32();
if (now_cycles < last_read_cycles) {
last_epoch_nsec += epoch_duration_nsec;
}
*t = (SECOND(1) / CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC) * now_cycles + last_epoch_nsec;
last_read_cycles = now_cycles;
interval_t uptime = k_uptime_ticks();
*t = TICKS_TO_NSEC(uptime);
return 0;
}

/**
* Interruptable sleep is implemented using busy-waiting.
*/
/** Interruptable sleep is implemented by a taking a semaphore with a timeout. */
int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) {
async_event = false;

interval_t duration = wakeup - lf_time_physical();
if (wakeup <= 0) {
return 0;
}

if (lf_critical_section_exit(env)) {
lf_print_error_and_exit("Failed to exit critical section.");
}
instant_t now;
do {
_lf_clock_gettime(&now);
} while ((now < wakeup) && !async_event);

int res = k_sem_take(sleeping_sem, K_NSEC(duration));

if (lf_critical_section_enter(env)) {
lf_print_error_and_exit("Failed to exit critical section.");
}

if (async_event) {
if (res < 0 || async_event == true) {
async_event = false;
return -1;
} else {
Expand All @@ -95,11 +105,13 @@ int _lf_interruptable_sleep_until_locked(environment_t* env, instant_t wakeup) {
}

/**
* Asynchronous events are notified by setting a flag which breaks the sleeping
* thread out of the busy-wait.
* Asynchronous events are notified by signalling a semaphore which will wakeup
* the runtime if it is sleeping, and setting a flag to indicate what has
* happened.
*/
int _lf_single_threaded_notify_of_event() {
async_event = true;
k_sem_give(sleeping_sem);
return 0;
}

Expand Down

0 comments on commit 3698799

Please sign in to comment.