ukasol

Blog Zephyr Serisi · 03/07

Zephyr'i neden kullanıyorum

Zephyr'in her parçası diğerlerine dayanıyor ve bu bilinçli bir tasarım. Tek blinky, üç kart, üç driver: bu bütünlük ne kazandırıyor, nerede maliyet çıkarıyor.

Zephyr’in gerçek bir projede ne kadar güçlü olduğunu gördüm ve sonraki tüm projelerimde mümkünse tercih ettim.

İlk öğrenmeye başladığımda şaşırdığım şey, tüm sistemlerin birbirini tamamlayıcı ve uyum içinde çalışıyor olmasıydı. Aslında biri olmadan diğeri düşünülemez. Mesela native_sim‘in bu kadar rahat çalışabilmesinin arkasında Device Tree, generic API’lar ve CMake’in projede zaten var olması yatıyor. Bunlar tesadüf değil, bilinçli tasarım kararları.

Bu bütünlüğü fark edince Zephyr’e bakışım değişti.

“Bütünlük” soyut bir kelime; o yüzden önce somut hâlini, sonra da genelde sayılan özelliklerin her biri için ne anlama geldiğini göstereyim.

Tek uygulama, üç kart, üç driver#

Zephyr’in blinky örneğini alın ve aynı kaynağı birbirinden çok farklı üç hedef için derleyin:

$ west build -b nrf52840dk/nrf52840 samples/basic/blinky
$ west build -b nucleo_f401re samples/basic/blinky
$ west build -b native_sim samples/basic/blinky

Zephyr 4.4.2 ile üçü de aynı main.c‘den, tek bir #ifdef olmadan derleniyor. Farklı olan alttaki katman:

Kart Devicetree’deki led0 Build’in derlediği GPIO driver’ı
Nordic nRF52840 DK P0.13, active low gpio_nrfx.c
STM32 Nucleo F401RE PA5, active high gpio_stm32.c
native_sim emüle edilmiş bir kontrolcünün 0. pini gpio_emul.c

Bu driver’ları kimse elle seçmedi. Onları seçen zincir üç alt sistemden geçiyor ve bir kez takip etmeye değer:

  1. Uygulama devicetree’den led0 takma adını istiyor ve bir GPIO kontrolcü node’u üzerinde bir pin alıyor.
  2. O kontrolcü node’unun bir compatible değeri var: "nordic,nrf-gpio", "st,stm32-gpio" ya da "zephyr,gpio-emul".
  3. Etkin her compatible bir Kconfig sembolüne dönüşüyor. Nucleo build’inde .config içinde CONFIG_DT_HAS_ST_STM32_GPIO_ENABLED=y var.
  4. Driver’ın kendi Kconfig seçeneği, o sembol varsa varsayılan olarak açılıyor.
  5. CMake, CONFIG_GPIO_STM32=y olduğu için gpio_stm32.c‘yi derliyor; driver da kendini main.c‘nin çağırdığı generic GPIO API’sının arkasına kaydediyor.

4. adım, drivers/gpio/Kconfig.stm32 içinde dört satır:

config GPIO_STM32
    bool "GPIO Driver for STM32 family of MCUs"
    default y
    depends on DT_HAS_ST_STM32_GPIO_ENABLED || DT_HAS_ST_STM32MP2_GPIO_ENABLED
main.cgpio_pin_toggle_dt(&led) GPIO APItek arayüz, her kontrolcü gpio_nrfx.cnRF52840 DK, P0.13"nordic,nrf-gpio" gpio_stm32.cNucleo F401RE, PA5"st,stm32-gpio" gpio_emul.cnative_sim, pin 0"zephyr,gpio-emul"
Tek main.c, üç build. Devicetree'deki compatible değeri doğru driver'ı açıyor; uygulama onun adını hiç anmıyor.

native_sim’in zahmetsiz hissettirmesinin bütün sebebi bu. Uygulama için o, dışarıdan eklenmiş bir simülatör değil. GPIO kontrolcüsü emüle edilmiş olan başka bir kart; tam olarak aynı zincirle seçiliyor. Zincirin herhangi bir halkasını çıkarın (devicetree, ondan üretilen Kconfig sembolleri, generic API, ikisini de okuyan build sistemi) ve çalışmayı bırakıyor.

Öne çıkan özellikler ve her birinin diğerlerine nasıl dayandığı#

native_sim: Donanım olmadan firmware geliştirmeye başlayabiliyorsunuz. Donanımı beklemeden iş ilerliyor. Yukarıda gördüğümüz gibi, bir kart yalnızca devicetree node’ları ve generic API’ların arkasındaki driver’lardan ibaret olduğu için var.

Twister ve ztest: Test altyapısı sisteme entegre geliyor. Ayrı bir şey kurmak, entegre etmekle uğraşmıyorsunuz. Bir test suite’i testcase.yaml ile tanımlanıyor ve aynı suite CI’da native_sim üzerinde, gerçek kartta ise twister --device-testing ile çalışıyor. Bu ancak kart koda gömülü bir şey değil de bir build argümanı olduğu için mümkün.

Driver, Kconfig ve Device Tree yapısı: Donanımdan bağımsız, taşınabilir ve bakımı kolay bir kod tabanı ortaya çıkıyor. Yukarıdaki tablo, bu cümlenin ölçülmüş hâli.

BLE ve network stack: Sıfırdan yazmak yerine üzerine inşa ediyorsunuz. Zephyr’in kendi Bluetooth LE host’u ve açık kaynak bir link layer’ı var; TCP ve UDP ile IPv4 ve IPv6 stack’i, üstünde de MQTT, CoAP ve LwM2M gibi protokol kütüphaneleri; Thread ise OpenThread modülüyle geliyor. Hepsi aynı Kconfig ile yapılandırılıyor ve diğer her şeyle aynı driver modeli üzerinde çalışıyor; bu yüzden Bluetooth’u açmak, devicetree’si radyoyu zaten tarif eden bir kartta CONFIG_BT=y ile başlıyor.

Güvenlik: Memory protection, güvenli boot, mbedTLS entegrasyonu hazır geliyor. Thread’ler MPU’nun arkasında user mode’da çalışabiliyor (CONFIG_USERSPACE), MCUboot doğrulanmış boot zincirini sağlıyor, Armv8-M parçalarda ise Trusted Firmware-M bir modül olarak mevcut. Parçalar burada da birbirine oturuyor: MCUboot slot’larını, uygulamanın link edildiği aynı devicetree partition’larında buluyor. nRF52840 DK’da bunların adı mcuboot, image-0 ve image-1; build uygulamayı image-0‘a yerleştiriyor, çünkü devicetree öyle söylüyor.

Düşük güç yönetimi: Kernel seviyesinde entegre, kendiniz yazmak zorunda kalmıyorsunuz. Tickless bir kernel bir sonraki thread’in ne zaman çalışacağını tam olarak biliyor; sistem güç yöneticisi bunu kullanarak bir uyku durumu seçiyor, cihaz güç yönetimini destekleyen driver’lar da kimse kullanmadığında çevre birimlerini kapatıyor.

1000’den fazla board desteği: Zephyr 4.4.2’de west boards 1014 kart listeliyor. Donanım değişince uygulamayı baştan yazmıyorsunuz; yukarıdaki blinky bu sözün küçük bir örneği.

Tamamen açık kaynaklı: Vendor lock-in yok. Zephyr Apache-2.0 lisanslı ve Linux Foundation çatısı altında yönetiliyor; yani dayandığınız kod okuyup debug edip düzeltebileceğiniz bir kod.

Bu maddelerin hiçbiri tek başına belirleyici değil; belirleyici olan hepsinin aynı anda ve birbiriyle uyumlu gelmesi.

Doğru seçim olmadığı yerler#

Yazının ilk cümlesindeki “mümkünse” kelimesi boşuna orada değil. Zephyr bedava değil ve maliyetinin verdiğinden fazla olduğu yerler var.

En küçük parçalar. Zephyr şaşırtıcı derecede küçülebiliyor: STM32F401 üzerinde minimal örnek, tek thread’le 6,1 KB, multithreading ile 8,7 KB flash tutuyor. Ama konsolu, logging’i ve birkaç driver’ı olan gerçekçi bir uygulama hızla onlarca kilobayta çıkıyor; konsoluyla birlikte Hello World tek başına 16,8 KB. 16 ya da 32 KB flash’ı olan bir parçada bu bütçe sıkışık.

Değişmeyecek basit ürünler. Bağlantısı olmayan, tek bir kontrol döngüsünden ibaret ve on yıl boyunca değişmeden üretilecek bir donanım, taşınabilirlikten ve soyutlamadan pek bir şey kazanmıyor. Orada katmanlar, faydası olmayan bir maliyet.

Yepyeni silikon. Yeni bir çipin desteği çoğu zaman upstream Zephyr’e ulaşmadan önce üreticinin kendi SDK’sına geliyor; bazen Nordic’in nRF Connect SDK’sı gibi Zephyr tabanlı bir SDK’ya. Bir takvimi ona bağlamadan önce tam o parçanın kart ve SoC desteğini kontrol edin.

Gelecek ay teslim tarihi. Öğrenme eğrisi gerçek; serinin ilk yazısı bunu anlatıyor. Bir takımı yoğun bir dönemin ortasında Zephyr’e geçirmek, o bedeli ödemek için en kötü zaman.

Bu durumların dışında beni tekrar tekrar Zephyr’e döndüren şey bu bütünlük. Parçaların her biri tek başına başka yerlerde de var. Hepsinin birlikte ve birbirine dayanacak şekilde tasarlanmış olması, Zephyr’i ilk tercihim yapan şey.

Sıradaki · Zephyr fundamentals Şirketler için neden Zephyr