Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zephyr make kernel clock default + improvements #400

Merged
merged 11 commits into from
Apr 12, 2024
25 changes: 1 addition & 24 deletions low_level_platform/api/platform/lf_zephyr_board_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
23 changes: 0 additions & 23 deletions low_level_platform/api/platform/lf_zephyr_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 6 additions & 2 deletions low_level_platform/impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
2 changes: 0 additions & 2 deletions low_level_platform/impl/src/lf_zephyr_clock_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
70 changes: 41 additions & 29 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(LF_ZEPHYR_CLOCK_KERNEL)
#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;
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 {
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
2 changes: 0 additions & 2 deletions platform/impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading