From de7bc3edf20a45b045b5e6b060aa815b56b3f87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Emre=20=C3=87elebi?= <85405475+MehmetEmreee@users.noreply.github.com> Date: Tue, 11 Aug 2026 11:53:01 +0300 Subject: [PATCH] Zephyr added. --- docs.json | 2 + en/projects/zephyr-os.mdx | 348 ++++++++++++++++++++++++++++++++++++++ images/zephyr-os.webp | Bin 0 -> 29658 bytes tr/projects/zephyr-os.mdx | 346 +++++++++++++++++++++++++++++++++++++ 4 files changed, 696 insertions(+) create mode 100644 en/projects/zephyr-os.mdx create mode 100644 images/zephyr-os.webp create mode 100644 tr/projects/zephyr-os.mdx diff --git a/docs.json b/docs.json index 3b1b2b2..7d3e4ab 100644 --- a/docs.json +++ b/docs.json @@ -168,6 +168,7 @@ "tr/projects/mediabox", "tr/projects/firewall", "tr/projects/hotspot", + "tr/projects/zephyr-os", { "group": "Teknofest", "pages": [ @@ -341,6 +342,7 @@ "en/projects/mediabox", "en/projects/firewall", "en/projects/hotspot", + "en/projects/zephyr-os", { "group": "Teknofest", "pages": [ diff --git a/en/projects/zephyr-os.mdx b/en/projects/zephyr-os.mdx new file mode 100644 index 0000000..4287349 --- /dev/null +++ b/en/projects/zephyr-os.mdx @@ -0,0 +1,348 @@ +--- +title: 'Zephyr' +description: 'Zephyr Operating System' +--- + + + Zephyr OS + + + +Zephyr support for T3 Gemstone O1 is still under development. It is not yet possible to use all of the peripherals on the +board, such as I2C, SPI, PWM, and CAN Bus. + + +Zephyr is an open-source operating system designed for real-time applications. Developed under the Linux Foundation, +Zephyr is optimized for embedded systems and microcontrollers thanks to its scalable architecture, broad hardware +support, and modular structure. The main reason we chose Zephyr for the R5F cores on the T3 Gemstone O1 board is that it +exhibits deterministic behavior and can reliably manage real-time tasks. + +On the AM67A SoC of the T3 Gemstone O1 board, the Linux operating system runs on four Cortex-A53 cores while the +MAIN-domain Cortex-R5F core sits idle. Zephyr can be run on this core through the `remoteproc` mechanism, without +touching Linux and without any JTAG hardware. Zephyr's AM67A (J722S) support is provided by the +`t3_gem_o1/j722s/main_r5f0_0` board target. + +## 1. Building + +### 1.1. Installing Requirements + +Several requirements must be present on your system to build Zephyr. On Ubuntu/Debian systems, you can install them +using the package manager: + +```bash +sudo apt update +sudo apt install --no-install-recommends -y \ + git cmake ninja-build gperf \ + ccache dfu-util device-tree-compiler wget \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ + make gcc g++ libsdl2-dev libmagic1t64 +``` + + +If you are using an AArch64 (ARM64) host, the `gcc-multilib` and `g++-multilib` packages listed in the standard +Zephyr instructions are not available on this architecture, so they have been removed from the package list. + +The T3 Gemstone O1 board itself is an AArch64 host: all of these steps can be carried out directly on the board, +on the Linux system running on its Cortex-A53 cores. In that case you do not need a separate development machine, +and the `scp` step used to copy the resulting `zephyr.elf` onto the board is unnecessary — you can copy the file +straight into `/lib/firmware`. On the other hand, building on the board is noticeably slower than on an x86_64 +desktop host. Be prepared in terms of storage as well: after `west update` the `~/zephyrproject` directory takes up +about 8.7 GB (`modules` 7.3 GB, `zephyr` 1.4 GB), and the toolchain installed by `west sdk install -t +arm-zephyr-eabi` takes another 812 MB. Together with the Python packages and build output, you should set aside at +least 10 GB of free disk space. + + +After installation, you can verify that the version is 3.20 or later with the `cmake --version` command. + +### 1.2. Downloading the Source Code + +Zephyr uses a tool named `west` to manage its source code and modules. Since Ubuntu 24.04 does not allow `pip install` +directly into the system Python, `west` is installed inside an isolated virtual environment (venv): + +```bash +sudo apt install -y python3-venv +python3 -m venv ~/zephyrproject/.venv +source ~/zephyrproject/.venv/bin/activate +``` + + +In every new terminal you open, activate the virtual environment before running any Zephyr command: +`source ~/zephyrproject/.venv/bin/activate` + + +With the virtual environment active, install `west` and download the Zephyr source code: + +```bash +pip install west +west init ~/zephyrproject +cd ~/zephyrproject +west update +west packages pip --install +``` + +The `west update` command may take 5-15 minutes since it downloads the dozens of modules Zephyr needs. When the +process completes, the `bootloader`, `modules`, `tools`, and `zephyr` directories are created under +`~/zephyrproject`. + +### 1.3. Installing the Toolchain + +For the R5F core, the `arm-zephyr-eabi` toolchain targeting Cortex-R5 (32-bit ARM) is sufficient. The +`west sdk install` command automatically selects the compatible version by reading the `SDK_VERSION` file in the +source tree: + +```bash +cd ~/zephyrproject/zephyr +west sdk install -t arm-zephyr-eabi +``` + +After installation, you can verify that the toolchain is installed with the `west sdk list` command. + +### 1.4. Building the Project + +Let's build the `hello_world` sample for the board's MAIN-R5F core: + +```bash +cd ~/zephyrproject/zephyr +west build -b t3_gem_o1/j722s/main_r5f0_0 samples/hello_world +``` + +The build produces an ELF file named `build/zephyr/zephyr.elf`. This file contains the operating system image to be +loaded onto the R5F core. A successful build ends with a summary of the memory regions: + +``` +[170/170] Linking C executable zephyr/zephyr.elf +Memory region Used Size Region Size %age Used + FLASH: 0 B 0 B + RAM: 26960 B 14 MB 0.18% + ATCM: 76 B 32 KB 0.23% + BTCM: 0 B 32 KB 0.00% + RSC_TABLE: 16 B 1 MB 0.00% +``` + + +The `RSC_TABLE` (Resource Table) section is mandatory for the `remoteproc` mechanism to recognize and load the +firmware; Zephyr's board support adds this section automatically. + + +## 2. Running + +While the Zephyr operating system runs on the R5F core, the Linux operating system runs on the A53 cores. Code can +be loaded onto the R5F cores using the `remoteproc` mechanism present in Linux. The cores on the board are listed +with the `ls /sys/class/remoteproc/` command: + +| remoteproc | Address | Description | +| :--- | :--- | :--- | +| remoteproc0 | `7e000000.dsp` | C7x DSP core for image processing and deep learning applications | +| remoteproc1 | `7e200000.dsp` | C7x DSP core for image processing and deep learning applications | +| remoteproc2 | `79000000.r5f` | MCU-domain R5F core available for user applications (`j722s-mcu-r5f0_0-fw`) | +| remoteproc3 | `78400000.r5f` | MAIN-domain R5F core available for user applications (`j722s-main-r5f0_0-fw`) | + +Both R5F cores are available for user applications, and Zephyr supports both of them: use the +`t3_gem_o1/j722s/main_r5f0_0` board target for the MAIN domain and `t3_gem_o1/j722s/mcu_r5f0_0` for the MCU domain. +Neither of these is the core responsible for power and system management: the Device Manager (TISCI server) +firmware runs on a separate WKUP R5F core, which is started by U-Boot SPL during boot and is not exposed as a +`remoteproc` node under Linux. Working on `remoteproc2` or `remoteproc3` therefore does not interfere with system +management. + +In this guide, Zephyr is run on the MAIN-domain R5F core (`remoteproc3`). By default this core runs TI's Edge AI +(vision) firmware; the steps below back up that firmware and replace it with the Zephyr image. Follow the steps +below to run Zephyr. + +1. Copy the `zephyr.elf` file produced by the build onto the board: + +```bash +scp ~/zephyrproject/zephyr/build/zephyr/zephyr.elf gemstone@192.168.7.2:/tmp/zephyr.elf +``` + +2. On the board, back up the original firmware and point the symbolic link to the Zephyr image. +`j722s-main-r5f0_0-fw` is a symbolic link that points to TI's vision firmware by default: + +```bash +cd /lib/firmware +sudo cp -a j722s-main-r5f0_0-fw j722s-main-r5f0_0-fw.orig-backup +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +sudo rm j722s-main-r5f0_0-fw +sudo ln -s zephyr.elf j722s-main-r5f0_0-fw +``` + +3. Start the R5F core: + +```bash +echo j722s-main-r5f0_0-fw | sudo tee /sys/class/remoteproc/remoteproc3/firmware +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +4. Zephyr's console output is not visible over SSH; you can access the console by connecting a USB-to-TTL device to +the GPIO-14 (TX) and GPIO-15 (RX) pins of UART-MAIN1 located on the 40-pin HAT (115200 baud, 8N1). The following +output appears on the serial terminal: + +``` +*** Booting Zephyr OS build v4.4.0-8172-g1c2bf123944d *** +Hello World! t3_gem_o1/j722s/main_r5f0_0 +``` + +To stop the core, write `stop` to the `state` file: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +When you change the code, you do not need to repeat all the steps; since the symbolic link already points to +`zephyr.elf`, it is enough to stop the core, update the file, and start it again: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + + +Run the commands one at a time, and only copy the file after `cat /sys/class/remoteproc/remoteproc3/state` shows +`offline` following the `stop` command. Otherwise the file is replaced before the core has stopped, which can +result in an incomplete or corrupted load. + + +If you want to return to the original TI firmware, restore the backup: + +```bash +cd /lib/firmware +sudo rm j722s-main-r5f0_0-fw +sudo cp -a j722s-main-r5f0_0-fw.orig-backup j722s-main-r5f0_0-fw +``` + +## 3. Sample Application: Real-Time Jitter Measurement + +The `hello_world` sample shows that the build and load chain works. The sample in this section demonstrates the real +value of the R5F core: predictable and stable timing, i.e. determinism. + +The program wakes up every 100 ms and, by reading the hardware counter, measures how many microseconds have actually +elapsed since the previous wake-up. The difference between the measured time and the 100000 µs target is called +jitter. The program prints the minimum, maximum, and average jitter statistics to the serial port. If the same task +were run on Linux (A53), the deviation could reach thousands of microseconds under system load. + +### 3.1. Project Files + +The application consists of three files under the `~/zephyrproject/rt_demo` directory: + +``` +~/zephyrproject/rt_demo/ +├── CMakeLists.txt +├── prj.conf +└── src/ + └── main.c +``` + +`src/main.c`: + +```c +/* + * Realtime jitter measurement demo - TI AM67A MAIN-R5F (Zephyr) + * Measures the actual duration of each period and computes the deviation (jitter) from the target. + */ +#include +#include +#include + +#define PERIOD_MS 100 +#define TARGET_US (PERIOD_MS * 1000) /* 100000 us */ + +int main(void) +{ + printk("\n========================================\n"); + printk(" R5F Realtime Jitter Demo (Zephyr)\n"); + printk(" Target period: %d ms (%d us)\n", PERIOD_MS, TARGET_US); + printk("========================================\n"); + + timing_init(); + timing_start(); + printk("Timer frequency: %llu Hz\n\n", timing_freq_get()); + + int64_t jitter_min = INT64_MAX, jitter_max = INT64_MIN, jitter_sum = 0; + uint32_t count = 0; + timing_t t_prev = timing_counter_get(); + + while (1) { + k_msleep(PERIOD_MS); + timing_t t_now = timing_counter_get(); + + uint64_t delta_ns = timing_cycles_to_ns(timing_cycles_get(&t_prev, &t_now)); + int64_t delta_us = (int64_t)(delta_ns / 1000ULL); + int64_t jitter = delta_us - TARGET_US; + + if (jitter < jitter_min) jitter_min = jitter; + if (jitter > jitter_max) jitter_max = jitter; + jitter_sum += jitter; + count++; + + if (count % 10 == 0) { + printk("[%5u] last=%lld us | jitter: now=%+lld min=%+lld max=%+lld avg=%+lld us\n", + count, delta_us, jitter, jitter_min, jitter_max, jitter_sum / count); + } + t_prev = t_now; + } + return 0; +} +``` + +`prj.conf`: + +``` +CONFIG_PRINTK=y +CONFIG_TIMING_FUNCTIONS=y +CONFIG_CBPRINTF_FP_SUPPORT=n +``` + +`CMakeLists.txt`: + +```cmake +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rt_demo) +target_sources(app PRIVATE src/main.c) +``` + +### 3.2. Building and Running + +Since we are switching to a different application, the build must be performed cleanly with the `-p always` +(pristine) option; otherwise leftovers from the previous build may interfere with the new one: + +```bash +cd ~/zephyrproject/zephyr +west build -p always -b t3_gem_o1/j722s/main_r5f0_0 ~/zephyrproject/rt_demo +scp build/zephyr/zephyr.elf gemstone@192.168.7.2:/tmp/zephyr.elf +``` + +On the board, stop the core, load the new image, and start it again: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +### 3.3. Sample Output and Evaluation + +``` +*** Booting Zephyr OS build v4.4.0-... *** +======================================== + R5F Realtime Jitter Demo (Zephyr) + Target period: 100 ms (100000 us) +======================================== +Timer frequency: 25000000 Hz +[ 10] last=100178 us | jitter: now=+178 min=+171 max=+210 avg=+181 us +[ 50] last=100170 us | jitter: now=+170 min=+170 max=+6808 avg=+703 us +[ 200] last=100170 us | jitter: now=+170 min=+170 max=+6811 avg=+803 us +[ 230] last=100170 us | jitter: now=+170 min=+170 max=+6811 avg=+807 us +``` + +In each line, `last` shows the time actually elapsed in this cycle, `now` the instantaneous deviation, `min`/`max` +the smallest and largest deviations seen since the start of the measurement, and `avg` the average deviation. + +The instantaneous deviation consistently stays within the 170-179 µs band. A fluctuation of only ~9 µs over a 100 ms +period corresponds to a stability of roughly 90 parts per million; this is exactly what real-time behavior means. +The constant ~170 µs offset is not a flaw; it comes from the fixed cost of wake-up, interrupt handling, and the +`printk` calls. In real-time systems, what matters is not that the deviation is zero, but that it is predictable and +constant. + +The one-time ~6.8 ms spike in the `max` field occurs only when the program first starts and never repeats; this +warm-up phase, caused by cache and initialization costs, is excluded from serious measurements. diff --git a/images/zephyr-os.webp b/images/zephyr-os.webp new file mode 100644 index 0000000000000000000000000000000000000000..50a97180b72c8b6278172501b7e6447d37168dbe GIT binary patch literal 29658 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 literal 0 HcmV?d00001 diff --git a/tr/projects/zephyr-os.mdx b/tr/projects/zephyr-os.mdx new file mode 100644 index 0000000..146cdd6 --- /dev/null +++ b/tr/projects/zephyr-os.mdx @@ -0,0 +1,346 @@ +--- +title: 'Zephyr' +description: 'Zephyr İşletim Sistemi' +--- + + + Zephyr OS + + + +T3 Gemstone O1 için Zephyr desteği henüz geliştirme aşamasındadır. Kartın üzerindeki I2C, SPI, PWM, CAN Bus gibi tüm çevre +birimleri kullanmak mümkün değildir. + + +Zephyr, gerçek zamanlı uygulamalar için tasarlanmış açık kaynaklı bir işletim sistemidir. Linux Foundation çatısı +altında geliştirilen Zephyr; ölçeklenebilir mimarisi, geniş donanım desteği ve modüler yapısıyla özellikle gömülü +sistemler ve mikrodenetleyiciler için optimize edilmiştir. T3 Gemstone O1 kartında bulunan R5F çekirdekleri için Zephyr'i +seçmemizin temel nedeni, deterministik davranış sergilemesi ve gerçek zamanlı görevleri güvenilir şekilde +yönetebilmesidir. + +T3 Gemstone O1 kartındaki AM67A SoC üzerinde Linux işletim sistemi dört adet Cortex-A53 çekirdeğinde çalışırken, +MAIN-domain Cortex-R5F çekirdeği boşta beklemektedir. Bu çekirdek üzerinde, Linux'a müdahale etmeden ve JTAG +donanımına ihtiyaç duymadan, `remoteproc` mekanizması ile Zephyr çalıştırılabilmektedir. Zephyr'in AM67A (J722S) +desteği `t3_gem_o1/j722s/main_r5f0_0` board hedefi ile sunulmaktadır. + +## 1. Derleme + +### 1.1. Gereksinimleri Kurma + +Zephyr'i derleyebilmek için sistemde çeşitli gereksinimlerin bulunması gerekmektedir. Ubuntu/Debian sistemlerde +gereksinimleri paket yöneticisi ile kurabilirsiniz: + +```bash +sudo apt update +sudo apt install --no-install-recommends -y \ + git cmake ninja-build gperf \ + ccache dfu-util device-tree-compiler wget \ + python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \ + make gcc g++ libsdl2-dev libmagic1t64 +``` + + +AArch64 (ARM64) mimarisinde bir host kullanıyorsanız, standart Zephyr talimatında yer alan `gcc-multilib` ve +`g++-multilib` paketleri bu mimaride bulunmadığından paket listesinden çıkarılmıştır. + +T3 Gemstone O1 kartının kendisi de bir AArch64 host'tur; Cortex-A53 çekirdeklerinde çalışan Linux üzerinde bu +adımların tamamı doğrudan kart üzerinde uygulanabilir. Bu durumda ayrı bir geliştirme bilgisayarına ve derleme +sonucunda oluşan `zephyr.elf` dosyasını karta kopyalamak için `scp` adımına gerek kalmaz; dosyayı doğrudan +`/lib/firmware` altına kopyalayabilirsiniz. Buna karşılık kart üzerinde derleme, x86_64 bir masaüstü host'a kıyasla +belirgin şekilde daha yavaştır. Ayrıca yer açısından da hazırlıklı olun: `west update` sonrası `~/zephyrproject` +dizini yaklaşık 8,7 GB (`modules` 7,3 GB, `zephyr` 1,4 GB), `west sdk install -t arm-zephyr-eabi` ile kurulan +toolchain ise 812 MB yer kaplar. Python paketleri ve derleme çıktılarıyla birlikte en az 10 GB boş disk alanı +ayırmanız gerekir. + + +Kurulumun ardından `cmake --version` komutuyla sürümün 3.20 veya üzeri olduğunu doğrulayabilirsiniz. + +### 1.2. Kaynak Kodları İndirme + +Zephyr, kaynak kodlarını ve modüllerini yönetmek için `west` isimli bir araç kullanır. Ubuntu 24.04 sistem +Python'una doğrudan `pip install` yapılmasına izin vermediği için `west` izole bir sanal ortama (venv) kurulur: + +```bash +sudo apt install -y python3-venv +python3 -m venv ~/zephyrproject/.venv +source ~/zephyrproject/.venv/bin/activate +``` + + +Açtığınız her yeni terminalde, Zephyr komutlarını çalıştırmadan önce sanal ortamı etkinleştirin: +`source ~/zephyrproject/.venv/bin/activate` + + +Sanal ortam aktifken `west` kurulur ve Zephyr kaynak kodları indirilir: + +```bash +pip install west +west init ~/zephyrproject +cd ~/zephyrproject +west update +west packages pip --install +``` + +`west update` komutu Zephyr'in ihtiyaç duyduğu onlarca modülü indirdiği için 5-15 dakika sürebilir. İşlem +tamamlandığında `~/zephyrproject` dizini altında `bootloader`, `modules`, `tools` ve `zephyr` klasörleri oluşur. + +### 1.3. Toolchain'i Kurma + +R5F çekirdeği için Cortex-R5 (32-bit ARM) hedefli `arm-zephyr-eabi` toolchain'i yeterlidir. `west sdk install` +komutu, kaynak koddaki `SDK_VERSION` dosyasına bakarak uyumlu sürümü otomatik olarak seçer: + +```bash +cd ~/zephyrproject/zephyr +west sdk install -t arm-zephyr-eabi +``` + +Kurulumun ardından `west sdk list` komutuyla toolchain'in kurulduğunu doğrulayabilirsiniz. + +### 1.4. Projeyi Derleme + +Kartın MAIN-R5F çekirdeği için `hello_world` örneğini derleyelim: + +```bash +cd ~/zephyrproject/zephyr +west build -b t3_gem_o1/j722s/main_r5f0_0 samples/hello_world +``` + +Derleme sonucunda `build/zephyr/zephyr.elf` isimli bir ELF dosyası oluşur. Bu dosya, R5F çekirdeğine yüklenecek +işletim sistemi imajını içerir. Başarılı derleme çıktısının sonunda bellek bölgelerini gösteren bir özet yer alır: + +``` +[170/170] Linking C executable zephyr/zephyr.elf +Memory region Used Size Region Size %age Used + FLASH: 0 B 0 B + RAM: 26960 B 14 MB 0.18% + ATCM: 76 B 32 KB 0.23% + BTCM: 0 B 32 KB 0.00% + RSC_TABLE: 16 B 1 MB 0.00% +``` + + +`RSC_TABLE` (Resource Table) bölümü, `remoteproc` mekanizmasının firmware'i tanıyıp yükleyebilmesi için zorunludur; +Zephyr'in board desteği bu bölümü otomatik olarak ekler. + + +## 2. Çalıştırma + +Zephyr işletim sistemi R5F çekirdeğinde çalışırken A53 çekirdeklerinde de Linux işletim sistemi çalışmaktadır. +Linux'ta yer alan `remoteproc` mekanizması ile R5F çekirdeklerine kod yüklenebilmektedir. Kart üzerindeki +çekirdekler `ls /sys/class/remoteproc/` komutuyla listelenir: + +| remoteproc | Adres | Açıklama | +| :--- | :--- | :--- | +| remoteproc0 | `7e000000.dsp` | Görüntü işleme ve derin öğrenme uygulamaları için C7x DSP çekirdeği | +| remoteproc1 | `7e200000.dsp` | Görüntü işleme ve derin öğrenme uygulamaları için C7x DSP çekirdeği | +| remoteproc2 | `79000000.r5f` | Kullanıcı uygulamaları için MCU-domain R5F çekirdeği (`j722s-mcu-r5f0_0-fw`) | +| remoteproc3 | `78400000.r5f` | Kullanıcı uygulamaları için MAIN-domain R5F çekirdeği (`j722s-main-r5f0_0-fw`) | + +Her iki R5F çekirdeği de kullanıcı uygulamalarına açıktır ve Zephyr her ikisini de destekler: MAIN-domain için +`t3_gem_o1/j722s/main_r5f0_0`, MCU-domain için `t3_gem_o1/j722s/mcu_r5f0_0` board hedefi kullanılır. Güç ve sistem +yönetiminden sorumlu olan çekirdek bunlardan hiçbiri değildir; Device Manager (TISCI server) yazılımı ayrı bir WKUP +R5F çekirdeğinde çalışır, U-Boot SPL tarafından açılış sırasında başlatılır ve Linux tarafında `remoteproc` olarak +görünmez. Dolayısıyla `remoteproc2` ve `remoteproc3` üzerinde çalışmak sistem yönetimini etkilemez. + +Bu rehberde Zephyr, MAIN-domain R5F çekirdeğinde (`remoteproc3`) çalıştırılmaktadır. Bu çekirdek varsayılan olarak +TI'nin Edge AI (vision) firmware'ini çalıştırır; aşağıdaki adımlarda bu firmware yedeklenerek yerine Zephyr imajı +konulmaktadır. Zephyr'i çalıştırmak için aşağıdaki adımları takip edin. + +1. Derleme sonucu oluşan `zephyr.elf` dosyasını karta kopyalayın: + +```bash +scp ~/zephyrproject/zephyr/build/zephyr/zephyr.elf gemstone@192.168.7.2:/tmp/zephyr.elf +``` + +2. Kart üzerinde, orijinal firmware'i yedekleyip sembolik bağlantıyı Zephyr imajına yönlendirin. +`j722s-main-r5f0_0-fw` bir sembolik bağlantıdır ve varsayılan olarak TI'nin vision firmware'ini gösterir: + +```bash +cd /lib/firmware +sudo cp -a j722s-main-r5f0_0-fw j722s-main-r5f0_0-fw.orig-backup +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +sudo rm j722s-main-r5f0_0-fw +sudo ln -s zephyr.elf j722s-main-r5f0_0-fw +``` + +3. R5F çekirdeğini başlatın: + +```bash +echo j722s-main-r5f0_0-fw | sudo tee /sys/class/remoteproc/remoteproc3/firmware +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +4. Zephyr'in konsol çıktısı SSH üzerinden görünmez; UART-MAIN1'in 40-pin HAT'te yer alan GPIO-14 (TX) ve GPIO-15 +(RX) pinlerine USB-to-TTL cihazı bağlayarak konsola erişebilirsiniz (115200 baud, 8N1). Seri terminalde aşağıdaki +çıktı görünür: + +``` +*** Booting Zephyr OS build v4.4.0-8172-g1c2bf123944d *** +Hello World! t3_gem_o1/j722s/main_r5f0_0 +``` + +Çekirdeği durdurmak için `state` dosyasına `stop` yazılır: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +Kodda değişiklik yaptığınızda tüm adımları tekrarlamanız gerekmez; sembolik bağlantı zaten `zephyr.elf` dosyasını +gösterdiği için çekirdeği durdurup dosyayı güncellemek ve yeniden başlatmak yeterlidir: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + + +Komutları tek tek çalıştırın ve `stop` sonrasında `cat /sys/class/remoteproc/remoteproc3/state` çıktısında +`offline` gördükten sonra kopyalama yapın. Aksi halde çekirdek durmadan dosya değiştirilir ve eksik/bozuk yükleme +oluşabilir. + + +Orijinal TI firmware'ine geri dönmek isterseniz yedeği geri yükleyin: + +```bash +cd /lib/firmware +sudo rm j722s-main-r5f0_0-fw +sudo cp -a j722s-main-r5f0_0-fw.orig-backup j722s-main-r5f0_0-fw +``` + +## 3. Örnek Uygulama: Gerçek Zamanlı Jitter Ölçümü + +`hello_world` örneği derleme ve yükleme zincirinin çalıştığını gösterir. Bu bölümdeki örnek ise R5F çekirdeğinin +asıl değerini ortaya koyar: öngörülebilir ve kararlı zamanlama, yani determinizm. + +Program 100 ms'de bir uyanır ve donanım sayacını okuyarak bir önceki uyanıştan bu yana gerçekte kaç mikrosaniye +geçtiğini ölçer. Ölçülen süre ile 100000 µs'lik hedef arasındaki farka jitter (sapma) denir. Program; minimum, +maksimum ve ortalama jitter istatistiklerini seri porta yazar. Aynı görev Linux üzerinde (A53) çalıştırılsaydı, +sistem yükü altında sapma binlerce mikrosaniyeye kadar çıkabilirdi. + +### 3.1. Proje Dosyaları + +Uygulama, `~/zephyrproject/rt_demo` dizini altında üç dosyadan oluşur: + +``` +~/zephyrproject/rt_demo/ +├── CMakeLists.txt +├── prj.conf +└── src/ + └── main.c +``` + +`src/main.c`: + +```c +/* + * Realtime jitter olcum demosu - TI AM67A MAIN-R5F (Zephyr) + * Her periyotta gercek sureyi olcup hedeften sapmayi (jitter) hesaplar. + */ +#include +#include +#include + +#define PERIOD_MS 100 +#define TARGET_US (PERIOD_MS * 1000) /* 100000 us */ + +int main(void) +{ + printk("\n========================================\n"); + printk(" R5F Realtime Jitter Demo (Zephyr)\n"); + printk(" Hedef periyot: %d ms (%d us)\n", PERIOD_MS, TARGET_US); + printk("========================================\n"); + + timing_init(); + timing_start(); + printk("Timer frekansi: %llu Hz\n\n", timing_freq_get()); + + int64_t jitter_min = INT64_MAX, jitter_max = INT64_MIN, jitter_sum = 0; + uint32_t count = 0; + timing_t t_prev = timing_counter_get(); + + while (1) { + k_msleep(PERIOD_MS); + timing_t t_now = timing_counter_get(); + + uint64_t delta_ns = timing_cycles_to_ns(timing_cycles_get(&t_prev, &t_now)); + int64_t delta_us = (int64_t)(delta_ns / 1000ULL); + int64_t jitter = delta_us - TARGET_US; + + if (jitter < jitter_min) jitter_min = jitter; + if (jitter > jitter_max) jitter_max = jitter; + jitter_sum += jitter; + count++; + + if (count % 10 == 0) { + printk("[%5u] son=%lld us | jitter: su_an=%+lld min=%+lld max=%+lld ort=%+lld us\n", + count, delta_us, jitter, jitter_min, jitter_max, jitter_sum / count); + } + t_prev = t_now; + } + return 0; +} +``` + +`prj.conf`: + +``` +CONFIG_PRINTK=y +CONFIG_TIMING_FUNCTIONS=y +CONFIG_CBPRINTF_FP_SUPPORT=n +``` + +`CMakeLists.txt`: + +```cmake +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(rt_demo) +target_sources(app PRIVATE src/main.c) +``` + +### 3.2. Derleme ve Çalıştırma + +Farklı bir uygulamaya geçildiği için derleme `-p always` (pristine) seçeneğiyle temiz olarak yapılır; aksi halde +önceki derlemeden kalan dosyalar yeni derlemeye karışabilir: + +```bash +cd ~/zephyrproject/zephyr +west build -p always -b t3_gem_o1/j722s/main_r5f0_0 ~/zephyrproject/rt_demo +scp build/zephyr/zephyr.elf gemstone@192.168.7.2:/tmp/zephyr.elf +``` + +Kart üzerinde çekirdeği durdurup yeni imajı yükleyin ve tekrar başlatın: + +```bash +echo stop | sudo tee /sys/class/remoteproc/remoteproc3/state +sudo cp /tmp/zephyr.elf /lib/firmware/zephyr.elf +echo start | sudo tee /sys/class/remoteproc/remoteproc3/state +``` + +### 3.3. Örnek Çıktı ve Değerlendirme + +``` +*** Booting Zephyr OS build v4.4.0-... *** +======================================== + R5F Realtime Jitter Demo (Zephyr) + Hedef periyot: 100 ms (100000 us) +======================================== +Timer frekansi: 25000000 Hz +[ 10] son=100178 us | jitter: su_an=+178 min=+171 max=+210 ort=+181 us +[ 50] son=100170 us | jitter: su_an=+170 min=+170 max=+6808 ort=+703 us +[ 200] son=100170 us | jitter: su_an=+170 min=+170 max=+6811 ort=+803 us +[ 230] son=100170 us | jitter: su_an=+170 min=+170 max=+6811 ort=+807 us +``` + +Her satırda `son` bu turda gerçekte geçen süreyi, `su_an` anlık sapmayı, `min`/`max` ölçüm başından beri görülen en +küçük ve en büyük sapmayı, `ort` ise ortalama sapmayı gösterir. + +Anlık sapma sürekli olarak 170-179 µs bandında kalmaktadır. 100 ms'lik periyotta yalnızca ~9 µs'lik dalgalanma, +milyonda ~90 düzeyinde bir kararlılığa karşılık gelir; gerçek zamanlılıktan kastedilen tam olarak budur. Sabit +~170 µs'lik fark bir kusur değildir; uyanma, kesme işleme ve `printk` çağrılarının sabit maliyetinden kaynaklanır. +Gerçek zamanlı sistemlerde önemli olan sapmanın sıfır olması değil, öngörülebilir ve sabit olmasıdır. + +`max` alanındaki tek seferlik ~6.8 ms'lik sıçrama yalnızca programın ilk başladığı anda gerçekleşir ve bir daha +tekrarlanmaz; cache ve başlatma maliyetlerinden kaynaklanan bu ısınma (warm-up) evresi, hassas ölçümlerde +değerlendirmeye alınmaz.