diff --git a/low_level_platform/api/platform/lf_zephyr_board_support.h b/low_level_platform/api/platform/lf_zephyr_board_support.h index 77834e985..2b6b77e09 100644 --- a/low_level_platform/api/platform/lf_zephyr_board_support.h +++ b/low_level_platform/api/platform/lf_zephyr_board_support.h @@ -35,54 +35,35 @@ 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 -// Unless the user explicitly asks for the kernel clock, then we use a counter -// clock because it is more precise. -#if !defined(LF_ZEPHYR_CLOCK_KERNEL) +#if defined(LF_ZEPHYR_CLOCK_COUNTER) #if defined(CONFIG_SOC_FAMILY_NRF) -#define LF_ZEPHYR_CLOCK_COUNTER #define LF_TIMER DT_NODELABEL(timer1) #define LF_WAKEUP_OVERHEAD_US 100 #define LF_MIN_SLEEP_US 10 #define LF_RUNTIME_OVERHEAD_US 19 #elif defined(CONFIG_BOARD_ATSAMD20_XPRO) #define LF_TIMER DT_NODELABEL(tc4) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_SOC_FAMILY_SAM) #define LF_TIMER DT_NODELABEL(tc0) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_COUNTER_MICROCHIP_MCP7940N) -#define LF_ZEPHYR_CLOCK_COUNTER #define LF_TIMER DT_NODELABEL(extrtc0) #elif defined(CONFIG_COUNTER_RTC0) -#define LF_ZEPHYR_CLOCK_COUNTER #define LF_TIMER DT_NODELABEL(rtc0) #elif defined(CONFIG_COUNTER_RTC_STM32) #define LF_TIMER DT_INST(0, st_stm32_rtc) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_COUNTER_XLNX_AXI_TIMER) #define LF_TIMER DT_INST(0, xlnx_xps_timer_1_00_a) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_COUNTER_TMR_ESP32) #define LF_TIMER DT_NODELABEL(timer0) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_COUNTER_MCUX_CTIMER) #define LF_TIMER DT_NODELABEL(ctimer0) -#define LF_ZEPHYR_CLOCK_COUNTER #elif defined(CONFIG_SOC_MIMXRT1176_CM7) #define LF_TIMER DT_NODELABEL(gpt2) -#define LF_ZEPHYR_CLOCK_COUNTER #else // This board does not have support for the counter clock. If the user // explicitly asked for this cock, then throw an error. -#if defined(LF_ZEPHYR_CLOCK_COUNTER) #error "LF_ZEPHYR_CLOCK_COUNTER was requested but it is not supported by the board" -#else -#define LF_ZEPHYR_CLOCK_KERNEL -#endif -#endif // BOARD #endif - -#if defined(LF_ZEPHYR_CLOCK_COUNTER) #ifndef LF_WAKEUP_OVERHEAD_US #define LF_WAKEUP_OVERHEAD_US 0 #endif @@ -98,10 +79,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef LF_TIMER_ALARM_CHANNEL #define LF_TIMER_ALARM_CHANNEL 0 #endif -#else -#if !defined(LF_ZEPHYR_CLOCK_KERNEL) -#error Neither hi-res nor lo-res clock specified #endif -#endif // LF_ZEPHYR_CLOCK_COUNTER #endif diff --git a/low_level_platform/api/platform/lf_zephyr_support.h b/low_level_platform/api/platform/lf_zephyr_support.h index 49172eb21..0f7ab6b4d 100644 --- a/low_level_platform/api/platform/lf_zephyr_support.h +++ b/low_level_platform/api/platform/lf_zephyr_support.h @@ -49,29 +49,6 @@ typedef struct { } lf_cond_t; typedef struct k_thread* lf_thread_t; -/** - * @brief Add `value` to `*ptr` and return original value of `*ptr` - */ -int _zephyr_atomic_fetch_add(int* ptr, int value); -/** - * @brief Add `value` to `*ptr` and return new updated value of `*ptr` - */ -int _zephyr_atomic_add_fetch(int* ptr, int value); - -/** - * @brief Compare and swap for boolaen value. - * If `*ptr` is equal to `value` then overwrite it - * with `newval`. If not do nothing. Retruns true on overwrite. - */ -bool _zephyr_bool_compare_and_swap(bool* ptr, bool value, bool newval); - -/** - * @brief Compare and swap for integers. If `*ptr` is equal - * to `value`, it is updated to `newval`. The function returns - * the original value of `*ptr`. - */ -int _zephyr_val32_compare_and_swap(uint32_t* ptr, int value, int newval); - #endif // !LF_SINGLE_THREADED #endif // LF_ZEPHYR_SUPPORT_H diff --git a/low_level_platform/impl/CMakeLists.txt b/low_level_platform/impl/CMakeLists.txt index 44c9e9366..2322266ec 100644 --- a/low_level_platform/impl/CMakeLists.txt +++ b/low_level_platform/impl/CMakeLists.txt @@ -48,12 +48,15 @@ endif() list(APPEND LF_LOW_LEVEL_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/src/platform_internal.c) if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") - message("--- Building Zephyr library") + if(${LF_ZEPHYR_CLOCK_COUNTER}) + message(STATUS "Building Zephyr library with Counter clock ") + else() + message(STATUS "Building Zephyr library with Kernel clock ") + endif() zephyr_library_named(lf-low-level-platform-impl) zephyr_library_sources(${LF_LOW_LEVEL_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) else() - message("--- Building non-Zephyr library") add_library(lf-low-level-platform-impl STATIC ${LF_LOW_LEVEL_PLATFORM_FILES}) # Link the platform to a threading library if(NOT DEFINED LF_SINGLE_THREADED OR DEFINED LF_TRACE) @@ -82,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) diff --git a/low_level_platform/impl/src/lf_zephyr_clock_counter.c b/low_level_platform/impl/src/lf_zephyr_clock_counter.c index fcb285d44..42f3de0e7 100644 --- a/low_level_platform/impl/src/lf_zephyr_clock_counter.c +++ b/low_level_platform/impl/src/lf_zephyr_clock_counter.c @@ -24,7 +24,6 @@ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************/ - /** * @brief This implements the timing-related platform API ontop of the Zephyr * Counter API. The Counter API is a generic interface to a timer peripheral. It @@ -43,7 +42,6 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. static int64_t epoch_duration_nsec; static int64_t epoch_duration_usec; -static uint32_t counter_max_ticks; static volatile int64_t last_epoch_nsec = 0; static uint32_t counter_freq; static volatile bool async_event = false; diff --git a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c index 183eebbbe..8c1f5ac1a 100644 --- a/low_level_platform/impl/src/lf_zephyr_clock_kernel.c +++ b/low_level_platform/impl/src/lf_zephyr_clock_kernel.c @@ -1,6 +1,6 @@ #if defined(PLATFORM_ZEPHYR) #include "platform/lf_zephyr_board_support.h" -#if defined(LF_ZEPHYR_CLOCK_KERNEL) +#if !defined(LF_ZEPHYR_CLOCK_COUNTER) /************* Copyright (c) 2023, Norwegian University of Science and Technology. @@ -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; - 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; + timer_freq = CONFIG_SYS_CLOCK_TICKS_PER_SEC; + lf_print("--- Using LF Zephyr Kernel Clock with a frequency of %u Hz", timer_freq); } -/** - * 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 (duration <= 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 { @@ -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; } diff --git a/platform/impl/CMakeLists.txt b/platform/impl/CMakeLists.txt index eadea7764..cef66b5ef 100644 --- a/platform/impl/CMakeLists.txt +++ b/platform/impl/CMakeLists.txt @@ -2,12 +2,10 @@ set(LF_PLATFORM_FILES ${CMAKE_CURRENT_LIST_DIR}/platform.c) if(${CMAKE_SYSTEM_NAME} STREQUAL "Zephyr") - message("--- Building Zephyr library") zephyr_library_named(lf-platform-impl) zephyr_library_sources(${LF_PLATFORM_FILES}) zephyr_library_link_libraries(kernel) else() -message("--- Building non-Zephyr library") add_library(lf-platform-impl STATIC) target_sources(lf-platform-impl PUBLIC ${LF_PLATFORM_FILES}) endif()