Zephyr

From Wiki at Neela Nurseries
Revision as of 21:59, 13 June 2023 by Ted (talk | contribs) (syntax fix)
Jump to: navigation, search

Zephyr RTOS :: Device Tree :: Kconfig :: cmake


Overview

This NN page a holding point for notes and links to external references regarding Zephyr RTOS, and Zephyr RTOS Project. Some key features of Zephyr RTOS include its designers' incorporation of Device Tree Source and Kconfig frameworks in this real time operating system.

As of 2023 April this page under reorganization, pulling multiple local pages into this page and removing older and defunct content - TMH

For device tree and Kconfig see also:


^ Zephyr Releases

Zephyr RTOS project itself, one of some one hundred twenty projects on Zephyr's Github page, has stable releases which become available once or twice a year. The Zephyr RTOS repository itself is generally at a cutting edge of development. It is `git tagged` or identified as a release candidate, until that point where the work has been finished to review all open issues and developments and create and tag a new stable release.

Nordic Semi forks a recent, but not necessarily most recent stable release of Zephyr RTOS Project as part of its NCS Software Development Kit.

A local NN wiki page with some early Zephyr release notes is Zephyr RTOS releases. There may not be much to save from this article, but contributor Ted to review it.

As of 2023 Q2 Zephyr RTOS stable release is v3.3.0.


^ Zephyr Toolchain Installation

Complete notes for Zephyr toolchain installation and config are provided at Zephyr Project's "Getting Started Guide".


^ Zephyr Build Process

Possible to use Kconfig to pass along compiler options, such as `CONFIG_COMPILER_OPT`:


^ Zephyr Threads

An important executing element of a Zephyr based app is an application defined thread. Zephyr based applications written in C will normally have at least one app side thread , which Zephyr will default to giving the name `main`. This name reflects that application code begins executing from a function named `main()`, as is a long standing convention of C language.

Zephyr based applications can define threads of their own. This is a multi-step action in the code, both at time of development and at run time. Application defined threads are given numeric identifiers by Zephyr at run time; only "main line" code of the app gets a named thread by default. Developers however may optionally call a _Zephyr_API_ to give additional threads human meaningful names.

^ Anatomy of a Zephyr thread

To create a Zephyr thread in an app involves declarations of certain thread elements, a call to Zephyr's thread_create API function, and at minimum an entry point function for the given thread. The following pieces:

    • thread data structure
    • thread priority
    • thread stack size
    • call to Zephyr "create thread" API
    • thread entry point function

In English language, creation of a Zephyr application thread in simple terms involves the steps:

(1) create a thread's data structure of type `struct k_thread`
(2) pound define given thread's priority
(3) pound define given thread's static memory stack size in bytes
(4) call Zephyr's thread creation API function with its required ten parameters
(5) define an entry point function for the thread, which other application code most likely to call to start thread execution

A bit of repetition: Zephyr thread's data structure, priority and stack size are programmed in a declarative way. Stack size and thread data are typically declared as follows, the first of these involves a function like macro:

K_THREAD_STACK_DEFINE(thread_led_stack_area, THREAD_LED_STACK_SIZE);

struct k_thread thread_led_data;

Interestingly, the stack area parameter first parameter to macro like function is defined in the above macro, and then referenced typically only one or two times, in the call to Zephyr's `k_thread_create()` API.

The call to `thread_create` <- REVIEW looks like this:

int initialize_thread_led(void)
{
    int rstatus = 0;

    k_tid_t task_led_tid = k_thread_create(&thread_led_data,
                                           thread_led_stack_area,
                                           K_THREAD_STACK_SIZEOF(thread_led_stack_area),
                                           thread_led_entry_point,
                                           NULL, NULL, NULL,
                                           THREAD_LED_PRIORITY,
                                           0,
                                           K_MSEC(1000)); // K_NO_WAIT);

// REF https://docs.zephyrproject.org/2.6.0/reference/kernel/threads/index.html?highlight=k_thread_create#c.k_thread_name_set
// int k_thread_name_set(k_tid_t thread, const char *str)

    rstatus = k_thread_name_set(task_led_tid, MODULE_ID__THREAD_LED);
    if ( rstatus == 0 ) { } // avoid compiler warning about unused variable - TMH

    return (int)task_led_tid;
}




^ Some Zephyr thread API references


^ Zephyr Drivers

Zephyr documentation and some Zephyr app developers speak of "in tree" and "out of tree" drivers, in the context of Zephyr RTOS project and Zephyr based apps. In-tree drivers exist within the source code of Zephyr RTOS proper, and development to these drivers is captured in commits to Zephyr RTOS repository. In contrast out-of-tree drivers which work with Zephyr are factored into their own respective code repositories, not Zephyr RTOS' source tree. It is even possible an out-of-tree driver is not version controlled, but this would be a driver that's hard to share and likely not widely used.

To some extent Zephyr in-tree drivers cover the set of peripherals which are on the silicon of a given target microcontroller or MCU that Zephyr RTOS supports. This is not a hard and fast rule, but it is less common that an in-tree Zephyr driver covers the driver needs of a device or peripheral that is off chip, or off SoC or SiP.


^ Some specific Zephyr in-tree drivers

On the topic of Zephyr UART via DMA support:


^ Driver Code Factoring

In-tree Zephyr drivers exist as part of Zephyr's source code tree, in other words, the code repo that entails Zephyr RTOS itself. Out-of-tree drivers written to cooperate with Zephyr exist outside of Zephyr's source code tree and are often their own independent code projects.

Example Zephyr app and supporting code base which entails an out-of-tree driver factored along side app code:


^ Zephyr RTOS Logger and Backend Features

Zephyr's thread_analyzer when not configured to dump reports to printk() instead sends thread data to LOG_INF(). Excerpt from Zephyr file `./zephyr/subsys/debug/thread_analyzer.c`:

 11 #include <kernel.h>
 12 #include <debug/thread_analyzer.h>
 13 #include <debug/stack.h>
 14 #include <kernel.h>
 15 #include <logging/log.h>
 16 #include <stdio.h>
 17 
 18 LOG_MODULE_REGISTER(thread_analyzer, CONFIG_THREAD_ANALYZER_LOG_LEVEL);
 19 
 20 #if IS_ENABLED(CONFIG_THREAD_ANALYZER_USE_PRINTK)
 21 #define THREAD_ANALYZER_PRINT(...) printk(__VA_ARGS__)
 22 #define THREAD_ANALYZER_FMT(str)   str "\n"
 23 #define THREAD_ANALYZER_VSTR(str)  (str)
 24 #else
 25 #define THREAD_ANALYZER_PRINT(...) LOG_INF(__VA_ARGS__)
 26 #define THREAD_ANALYZER_FMT(str)   str
 27 #define THREAD_ANALYZER_VSTR(str)  log_strdup(str)
 28 #endif

Zephyr macro `LOG_INF` is in turn defined:

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr LOG_INF ./* | grep define

./include/logging/log.h:61:#define LOG_INF(...)   Z_LOG(LOG_LEVEL_INF, __VA_ARGS__)

Define of Z_LOG:

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr 'Z_LOG[^_]' ./*

./include/logging/log_core.h:295:#define Z_LOG2(_level, _source, _dsource, ...) do { \
./include/logging/log_core.h:329:#define Z_LOG(_level, ...) \


$ grep -nr 'Z_LOG[^_]' ./*

$ vi ./include/logging/log_core.h

329 #define Z_LOG(_level, ...) \
330         Z_LOG2(_level, __log_current_const_data, __log_current_dynamic_data, __VA_ARGS__)


A Zephyr RTOS sample to check out:

`ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr/samples/subsys/logging/logger$`


- 2022-10-05 -

Zephyr v2.6.0 source file `log_core.h` may also define `log_strdup()`:

./subsys/logging/log_core.c:1017:char *z_log_strdup(const char *str)

But it looks like the routine is statically in-lined in Zephyr header file `log.h`:

./include/logging/log.h:290:static inline char *log_strdup(const char *str)


^ Zephyr thread_analyzer_cb And Related

Zephyr 2.6.0's thread_analyzer_cb() routine gathers and populates a structure with all pertinent, reported run-time thread statistics. This is however a static routine so we cannot call it directly. Nor does it return the summary thread resource use data to its direct calling routine. There is yet hope, and to understand a path forward here excerpted is the definition of this important thread reporting routine from file `./zephyr/subsys/debug/thread_analyzer.c`:

 59 static void thread_analyze_cb(const struct k_thread *cthread, void *user_data)
 60 {
 61         struct k_thread *thread = (struct k_thread *)cthread;
 62 #ifdef CONFIG_THREAD_RUNTIME_STATS
 63         k_thread_runtime_stats_t rt_stats_all;
 64         k_thread_runtime_stats_t rt_stats_thread;
 65         int ret;
 66 #endif
 67         size_t size = thread->stack_info.size;
 68         thread_analyzer_cb cb = user_data;
 69         struct thread_analyzer_info info;
 70         char hexname[PTR_STR_MAXLEN + 1];
 71         const char *name;
 72         size_t unused;
 73         int err;
 74 
 75 
 76 
 77         name = k_thread_name_get((k_tid_t)thread);
 78         if (!name || name[0] == '\0') {
 79                 name = hexname;
 80                 snprintk(hexname, sizeof(hexname), "%p", (void *)thread);
 81         }
 82 
 83         err = k_thread_stack_space_get(thread, &unused);
 84         if (err) {
 85                 THREAD_ANALYZER_PRINT(
 86                         THREAD_ANALYZER_FMT(
 87                                 " %-20s: unable to get stack space (%d)"),
 88                         name, err);

 88                         name, err);
 89 
 90                 unused = 0;
 91         }
 92 
 93         info.name = name;
 94         info.stack_size = size;
 95         info.stack_used = size - unused;
 96 
 97 #ifdef CONFIG_THREAD_RUNTIME_STATS
 98         ret = 0;
 99 
100         if (k_thread_runtime_stats_get(thread, &rt_stats_thread) != 0) {
101                 ret++;
102         }
103 
104         if (k_thread_runtime_stats_all_get(&rt_stats_all) != 0) {
105                 ret++;
106         }
107         if (ret == 0) {
108                 info.utilization = (rt_stats_thread.execution_cycles * 100U) /
109                         rt_stats_all.execution_cycles;
110         }
111 #endif
112         cb(&info);
113 }

The routine which calls this is:

115 void thread_analyzer_run(thread_analyzer_cb cb)
116 {
117         if (IS_ENABLED(CONFIG_THREAD_ANALYZER_RUN_UNLOCKED)) {
118                 k_thread_foreach_unlocked(thread_analyze_cb, cb);
119         } else {
120                 k_thread_foreach(thread_analyze_cb, cb);
121         }
122 }

We should be able to directly call thread_analyzer_run(thread_analyzer_cb cb). If yes, and if we can learn how &info is defined, we should be able to redirect thread_analyzer reports to an arbitrary UART . . .


^ struct thread_analyzer_info

ted@localhost:~/projects/zephyr-based/z4-sandbox-kionix-work/zephyr$ grep -nr 'struct thread_analyzer_info' ./*
./include/debug/thre[[#top|^]] ad_analyzer.h:23:struct thread_analyzer_info {
./include/debug/thread_analyzer.h:44:typedef void (*thread_analyzer_cb)(struct thread_analyzer_info *info);

Structure definition for &info passed to thread_analyzer_cb() function above:

/** @defgroup thread_analyzer Thread analyzer
 *  @brief Module for analyzing threads
 *
 *  This module implements functions and the configuration that simplifies
 *  thread analysis.
 *  @{
 */

struct thread_analyzer_info {
        /** The name of the thread or stringified address of the thread handle
         * if name is not set.
         */
        const char *name;
        /** The total size of the stack*/
        size_t stack_size;
        /** Stack size in used */
        size_t stack_used;

#ifdef CONFIG_THREAD_RUNTIME_STATS
        unsigned int utilization;
#endif
};


^ Zephyr Shell

This section started 2023-06-12. Growth goal at this time is to learn how Zephyr shell supports multiple shell sessions, across one or many interfaces.

First reference noting here relates to develop needing to separate shell communications from Zephyr logging. Not quite multi-session / multi-context shell support but somewhere in the ballpark:

This link asks salient questions to topic of multiple shell session support in Zephyr shell facility:


----- ----- ----- ----- ----- ----- ----- ----- -----

Zephyr Memory Management


^ Zephyr Kernel Timing

Following link at Zephyr Project documentation pages has valuable info on various Zephyr timing and work queueing facilities:

Related:

Important to follow up on this bug report relating to above mentioned Zephyr timing features:


^ Zephyr Application Code Relocation

!-- comentario -->