RP2040'da RTOS'a Geçiş
(blog.brixit.nl)- Raspberry Pi Pico tabanlı video ekipmanı denetleyicisi çok sayıda eşzamanlı görev gerektirmeye başlayınca, yalnızca pico-sdk ve çift çekirdek ayrımıyla yazılım yapısını sürdürmek zorlaştı
- Denetleyici aynı anda RS-485 VISCA, Ethernet, 9 RGB düğme, joystick ve ekranı yönetiyor; ayrıca DHCP, mDNS ve UDP tabanlı ATEM protokolünü de işlemesi gerekiyor
- FreeRTOS, zamanlayıcı ve görevler arası iletişim sayesinde bazı bölümlerin uygulanmasına izin verdi, ancak
printfkaynaklı kilitlenmeler ve donanım soyutlamasının eksikliği nedeniyle hata ayıklama ve kodun yeniden kullanımı zorlaştı - Apache NuttX, kabuk, dosya sistemi,
/dev/i2c0gibi aygıt soyutlamaları ve Kconfig yapılandırması sundu; ancak I2C sorununun daha sonra bir yapılandırma hatası olduğu anlaşılınca, o dönemdeki değerlendirmenin önemli bir kısmı geçersiz kalmış olabilir - Zephyr, 5 GB'lık depo ve SDK, kart tanımları ile derleme karmaşıklığına takıldı; sonuçta mevcut ortama en basit şekilde eklenebilen seçenek olarak FreeRTOS ile devam etme eğilimi ağır bastı
Neden RTOS gerekli hale geldi
- Birden fazla küçük mikrodenetleyici projesi Raspberry Pi Pico kartı etrafında geliştiriliyor
- Pico; uygun bir SDK, ucuz donanım ve gdb/openocd hata ayıklama desteği sayesinde IDE entegrasyonunu kolaylaştırıyor
- Mevcut proje, çeşitli video ekipmanlarını kontrol eden bir donanım denetleyicisi
- Kontrol edilen cihazlar iki motorlu PTZ kamera, bir sabit kamera ve bağlı video switching ekipmanı
- Mevcut PTZ kamera denetleyicisi, Marshall VS-PTC-200'e benzeyen markasız bir panel
- Birkaç yıl önce fiyatı €650 idi, ancak düğme hissi ve analog joystick kalitesi iyi değil
- Pek çok düğme, şu anda kullanılan kameralarda çalışmıyor ve güvenlik kameraları için optimize edilmiş görünüyor
- Kameralara RS-485 veri yolu ile bağlanıyor
- ATEM video switcher kontrolü şu anda yalnızca bilgisayardaki yazılım paneli üzerinden yapılıyor
- Blackmagic Design'ın donanım panelleri çok pahalı
Denetleyici donanım yapısı
- Asgari tasarım 9 düğme, bir joystick ve kullanıcı arayüzü için bir ekran olarak belirlendi
- Bir yıl boyunca donanım tasarımı birkaç kez yinelendikten sonra PCB elde edildi
- 9 RGB düğme
- Marshall kopyası panelde de bulunan 10 dolarlık joystick
- PTZ kameralarla RS-485 üzerinden iletişim kurmak için TP8485E
- Video switcher ile Ethernet üzerinden iletişim kurmak için Wiznet W5500 modülü
- Kart üzerindeki düzeltmeler tamamlandıktan sonra tüm donanım bileşenleri çalıştı, ancak daha zor kısım yazılımdı
Yalnızca pico-sdk ile zorlaşan yazılım
- Mevcut RP2040 projelerinde olduğu gibi, cmake projesi içinde pico-sdk'yı içe aktarma yaklaşımıyla başlandı
- Çalışan bir seviye elde etmek için Pico'nun ikinci çekirdeği Wiznet modülünü işlemeye ayrıldı, birinci çekirdek ise kullanıcı arayüzü I/O'sunu yürüttü
- LED yakıp söndürme ve ikinci çekirdekte çalışan bir DHCP istemcisi uygulamak mümkün oldu
- Sistemin geri kalanını uygulamak çok daha karmaşık hale geldi
- Aynı anda ele alınması gereken işler hızla arttı
- Ekranda bir ölçüde akıcı bir kullanıcı arayüzü çizmek
- RS-485 arayüzü üzerinden VISCA komutları göndermek
- Düğme girişlerine tepki vermek
- Birden fazla bağlantı içeren ağ yığınını ayakta tutmak
- Ağ tarafı ayrı arka plan görevleri gerektiriyor
- Standartlara uygun DHCP desteği, son kullanma zamanlarını izlemeli ve kira durumunu korumak için ara sıra DHCP sunucusuyla iletişim kurmalı
- mDNS, ATEM video switcher IP'sini otomatik keşfetmek için gerekli ve kontrol panelinin varlığını da duyurabilmesi faydalı olurdu
- ATEM protokolü basit, ancak bazen Wiznet modülünün tampon boyutunu aşan veri alınıyor ve UDP datagram aktarımı durursa bağlantı koparma zaman aşımı çok kısa
- Bu koşullarda, elle daha fazla döngü kurmak yerine işleri RTOS ile görevlere bölmek daha uygun görünüyordu
FreeRTOS: basit ama soyutlama yetersiz
- FreeRTOS teknik olarak pico-sdk içinde yer alıyor, ancak eğitimlerde yeni bir kopya indirme yöntemi kullanıldığı için aynı yol izlendi
- İncelenen RTOS'lar arasında en basit görüneniydi ve esas olarak zamanlayıcı ile görevler arası iletişim sağlıyordu
- Yapı,
xTaskCreateile görev oluşturupvTaskStartSchedulerile zamanlayıcıyı başlatmaya dayanıyor - Düğme durumunu LED görevine iletmek için kuyruk kullanan bir IPC modeli uygulanabiliyor
- Yapı,
- Birkaç günlük kullanımın ardından, kod tabanı hâlâ az sayıda gerçek işleve sahip olmasına rağmen çok sayıda göreve bölünmüş durumdaydı
buttonsTask: I2C GPIO genişleticisini poll ederek düğme girişlerini kontrol ediyor ve düğme kuyruğuna mesaj koyuyorledTask:ledQueuemesajlarıyla belirli düğmelerin RGB rengini ayarlıyormainTask: düğme girişlerine göre proje durumunu güncelleyen ana döngüyü çalıştırıyornetworkTask: Wiznet modülüyle iletişim kuruyordhcpTask: ağ kablosu bağlandığındanetworkTasktarafından oluşturuluyormdnsTask: IP adresi alındıktan sonradhcpTasktarafından oluşturuluyoratemTask: mDNS, ATEM aygıtından yanıt aldığında oluşturuluyorviscaTask: henüz bir şey yapmıyor ama RS-485 portundan veri göndermesi gerekecek
- Donanım henüz ağda görünmenin dışında hiçbir iş yapmamasına rağmen görev sayısı büyüdü
- En can sıkıcı sorun, printf'nin her seferinde kilitlenmeye yol açmasıydı
- gdb hata ayıklayıcı çalışıyor, ancak DHCP trafiğini çıktı alarak kontrol etme yaklaşımına uygun değil
- FreeRTOS donanım soyutlaması sağlamadığından, çeşitli çiplerle iletişim için yazılan kodu kolayca yeniden kullanmak zor
- Daha sonra temiz bir FreeRTOS projesi oluşturup işlevleri taşımaya çalışıldı, ancak seri çıktı olmadan körlemesine hata ayıklama yapma zorluğu yüzünden başka seçeneklere bakıldı
Apache NuttX: Unix benzeri yapı ve yapılandırma hatası
- Apache NuttX, genel amaçlı bir işletim sistemine daha yakın görünüyor ve mikrodenetleyiciyi Unix sistemi gibi ele alıyor
- Eğitimde pico-sdk'yı içe aktarmak ve ortam değişkenleri ayarlamak gerektiği söyleniyordu
- SDK zaten
/usr/shareiçindeydi ve ortam değişkenleri de vardı, ancak NuttX pico-sdk'nınversion.hdosyasının üzerine yazmaya çalışınca yetki sorunu nedeniyle derleme başarısız oldu
- SDK zaten
- Asgari NuttX firmware'i derlendikten sonra seri porta bağlanınca gerçekten bir kabuk göründü
uptime,uname,uname -agibi komutlar çalışıyordu- Görünen sürüm
NuttX 12.5.1, hedef isearm raspberrypi-pico
- Unix yaklaşımı izlendiği için, bir uygulama yazıp açılışta otomatik çalıştırmak mümkünmüş gibi görünüyordu
- Dosya sistemi var ve donanım
/dev/i2c0,/dev/adc0gibi soyutlamalar üzerinden sunuluyor
- Dosya sistemi var ve donanım
- Beğenilen kısım menuconfig/Kconfig tabanlı yapılandırmaydı
- Linux geliştirmeden tanıdık bir yaklaşım
- Gerçek bir donanım sürücü sistemi var ve düğmeler için kullanılan GPIO genişletici çipinin sürücüsü de zaten mevcut
- RP2040 pin mux ayarı da menuconfig içinde yapılabildiğinden, ayrıca pin numarası sabitleri tutmak veya çok sayıda I2C veri yolu başlatma kodu yazmak gerekmiyor
- I2C test yardımcı araçları da firmware'e eklenebiliyor
- İlk başta I2C'nin temel işleyişi çalışmıyor gibi göründü
- Daha sonra bir güncellemede aslında düzgün çalıştığı ve I2C veri yolunun bir yapılandırma hatasıyla bozulduğu düzeltildi
- NuttX bölümündeki geri kalan değerlendirmenin büyük kısmının geçersiz olabileceği açıkça belirtildi
- O sırada GPIO düğmelerinin GPIO genişleticinin arkasında olduğunu NuttX'e nasıl anlatacağı ve GPIO genişleticiyi I2C veri yoluna nasıl bağlayacağı anlaşılamadı
configure.shbaşarısız olduktan sonra depo tutarsız bir duruma geldi ve NuttX deposu birkaç kez yeniden klonlanmak zorunda kaldıdistcleande aynı nedenle düzgün çalışmayan durumlar yaşandı
- Unix benzeri yaklaşım ilk başta iyi görünse de, mikrodenetleyicide sahte dosya sistemi yollarıyla uğraşmak istenmiyor
- Üretim sisteminde kabuğa da ihtiyaç yok; kodun çalışması yeterli
Zephyr: büyük SDK ve kart tanımı engeli
- Sıradaki seçenek Zephyr oldu ve proje kurulumu için Python yardımcı araçları sunuyordu
- İlk adımda yaklaşık 5 GB'lık bir Git deposu çekildi
- Buna birçok çip için HAL kütüphaneleri de dahil
- Kullanıcının genel cmake ayarlarını da etkiliyor
- Eğitimler Zephyr SDK kurulumu gerektiriyordu
- Zephyr SDK; desteklenen mimariler için toolchain, derleyici, assembler, linker ve derleme araçlarını içeriyor
- QEMU ve OpenOCD gibi host araçları da dahil
- Zaten birkaç ARM toolchain bulunduğundan, tüm mimariler için derleyicileri derlemek veya önceden derlenmiş paketleri indirmek istenmedi
- Zephyr SDK olmadan derlemek için çapraz derleme seçenekleri ayarlandı
ZEPHYR_TOOLCHAIN_VARIANT=cross-compileCROSS_COMPILE=/usr/bin/arm-none-eabi-west build -p always -b sparkfun_pro_micro_rp2040 samples/basic/blinky
- Raspberry Pi Pico aslında desteklenmiyor; yalnızca aynı SoC'yi kullanan başka kartlar destekleniyor
- Aynı SoC kullanıldığı için pratikte benzer bir kart kabul edilerek devam edildi
- Hemen ardından
blinkydemosunun derlenememesi sorunu çıktı- Demo, yanıp sönecek hedef olarak
led0tanımı istiyordu - Sparkfun Pro Micro RP2040'da basit bir GPIO LED yerine WS2812B adreslenebilir LED bulunuyor
- Demo, yanıp sönecek hedef olarak
- Özel kart kılavuzu izlenerek başka bir kart tanımını kopyalama yoluna gidildi, ancak derleme hataları ve uyarılar düzeltildikten sonra bile hedef kart için başarılı bir derleme elde edilemedi
Sonunda yeniden FreeRTOS
- Üç RTOS arasında gerçek uygulamanın bir kısmını gerçekten derleyebilen tek seçenek FreeRTOS oldu
printfsorununun, çevrimiçi yönergelerde önerildiği gibi farklı birprintfuygulamasına geçip gereken yerlerde başka bir fonksiyon çağırarak çözülebileceği düşünülüyor- Bundan sonra FreeRTOS ile devam etmeyi planlıyor
- Çünkü diğer RTOS'larda olduğu gibi geliştirme ortamını RTOS'a uydurmak yerine, mevcut ortama görece basit biçimde entegre edilebilen tek seçenek buydu
1 yorum
Hacker News yorumları
Bu yazıyı yazan kişi RTOS'u Arduino ortamıyla aynı, ya da biraz kurcalayınca çalışmasını bekleyebileceği bir şey olarak görmüş gibi. Çoğu öyle değil.
Günümüzde Arduino'ların önemli bir kısmının içinde mbed ya da FreeRTOS kurulu ve bunları açığa çıkarmanın yolları da var; yazarın tarzına bu taraf daha uygun olabilirdi.
Zephyr kullanımı kolay ve CLion desteği de iyi, ama araç zincirini kurmadan her şeyin çalışmasını bekleyemezsiniz. Pi Pico'yu da kesinlikle destekliyor; bizzat kullandığımda sorun yaşamadım.
Kısaca özetlersek FreeRTOS neredeyse her yerde desteklenir, ancak sürücüler genelde SoC/cihaz özelinde olduğu için uğraştırır; API'si de pek kullanıcı dostu değildir ama alışılabilir. Bluetooth kullanmak istiyorsanız yığını kendiniz bulmanız gerekir.
Zephyr gerçek donanım soyutlamasını destekler ve çoğu SoC'yi destekler, ama kart tarafında biraz çalışma yapmanız gerekebilir. Bluetooth yığını sağlanır; HCI desteğini biraz eklemeniz gerekebilir.
NuttX'in desteği harika değildir, ama çalışır hâle getirebilirseniz oldukça güzel bir seçenektir. Sektör desteği henüz güçlü değil. mbed de var ama burada onu geçiyorum.
Gerçek RTOS tarafında genelde SoC üreticisinin desteklediği şey seçilir. Nordic ise Zephyr, NXP ise FreeRTOS gibi; böylece iyi destek alabilirsiniz.
OEM cihazlara yönelik firmware projelerinde geliştiricilerin Zephyr'le boğuşmadığı bir duruma hiç rastlamadım. Piyasaya çıkan ürünlerin gerçek firmware'ini yapan geliştiriciler arasında Zephyr'in donanım soyutlamasının işe yaradığını düşünen biriyle de henüz karşılaşmadım.
Böyle biri yok demek değil, ama son yaklaşık 5 yılda karşıma çıkmadı.
Bana göre Zephyr'in pazarlama materyalleri çok güzel. Ama o gösterişin arkasında aşırı şişkinlik, çok yavaş derleme ve başlaması zor bir ortam var.
Araç zincirini geleneksel UNIX tarzında sistem geneline kurmak acı verici ve açıkçası pek akıllıca bir yaklaşım da değil.
Tek başına sorunsuz çalışsa iyi, ama birden fazla geliştirici farklı hedeflere sahip birden fazla projeyle uğraştığında, derleme ve yapılandırma sorunlarını anlamaya çok zaman harcanıyor.
Araçlarda sürekli Python kullanmak da yardımcı olmuyor. Kendi sürüm sorunlarını getiren ve her geliştiricinin bilgisayarında farklı davranan bir dili neden özellikle kullanmak isteyelim, anlamıyorum.
Gömülü geliştirmeyi hobi ve iş olarak yaklaşık 10 yıldır yapıyorum; bir projede herkesin ortamını aynı hâle getirmek için bir hafta harcayıp yine de bunu sorun olarak görmeyen tavrı anlayamıyorum.
Bu gerçek bir sorun; sinir bozucu, zaman kaybettiriyor ve gereksiz.
Araçlar statik linklenmiş ikili dosyalar olmalı. Rust, Go, C, C++ hangisiyle yazıldıkları önemli değil; ama geçici çözümlerle geliştirme yerine, bilgisayarda kurulu olanlardan bağımsız olarak aynı şekilde çalışacağına güvenebileceğimiz sağlam araçlara öncelik verilmesini isterim.
Python bunu sağlayamıyor; bu sorunu daha ciddiye almak yerine öfkelenip savunmaya geçmek de yardımcı olmuyor.
Yine de PlatformIO gibi şeyler doğru yönde. Bir Python projesi olduğunu biliyorum ve arada sorun çıkarıyor, ama diğer araçlara göre daha az; fikir doğru.
Araç zincirleri, SDK'ler ve kütüphaneler yönetilmeli; proje yapılandırması basit olmalı ve derlemeler her yerde, her zaman yeniden üretilebilir olmalı.
Gömülü sektörünün ortak ve yapılandırılmış bir çabanın değerini daha çok fark etmesini isterdim. Büyük MCU üreticilerinde çalışan birçok kişi tanıyorum; genelde kendi anlık sorunlarını çözmekle meşgul olup geliştirici ihtiyaçlarına dar bir açıdan bakıyorlar gibi görünüyor, bu da beni hep hayal kırıklığına uğratıyor.
RP2040 üzerinde çalışan bir klavye projem var ve firmware'i Rust ile yazılmış. Elinizde yalnızca depo varken, Rust araç zinciri yoksa, flash etme süreci şöyle:
(rustup kurulumu)
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh$ rustup target add thumbv6m-none-eabi$ cargo install elf2uf2-rs* klavyeyi bootloader moduna geçirin *$ cargo run --releaseBurada rustup ve Cargo araç zinciri yönetimiyle derlemeyi büyük ölçüde hallediyor; ikisi de gerçekten harika. Python projeleri yanına bile yaklaşamaz.
Tek bir komut çalıştırınca, yerelde de CI'da da aynı sürümdeki derleme araçları ve kütüphanelerle tamamen aynı şekilde kurulup çalışıyor.
Bu yüzden tekrar CMake ve Make ile uğraşıp kütüphane kurmaya çalıştığım her seferinde eziyet çekiyorum.
compile 'library-name-here'gibi bir yöntemden çok farklı.Bunun yerine kütüphane ekosistemi yüzünden seçiyorlar. Veri analizi, görselleştirme ve bilimsel hesaplamada başka dillerde buna denk seçenek yok.
Bunlar baştan yeniden uygulamak istemeyeceğiniz alanlar. Sayısal kararlılık gibi konularda hata eklemek kolaydır; sonuçların %99'u doğruyken %1'i makul görünüp tamamen yanlış olabilir.
Kişisel olarak RP2040 projelerimi Rust ve Embassy'ye taşımaya başladım
Rust biraz alışma gerektirdi ama oldukça hoşuma gitti. RTOS değil, ancak RTOS ihtiyacı doğuran pek çok gereksinimi karşılıyor
Rust ve Cargo, RP2040 ya da STM32 derleme ve flash etme zahmetini ortadan kaldırıyor. Şimdiye kadar kullandığım gömülü ortamlar içinde en rahat olanıydı
Birçok uygulama MPU kullanmıyor. Buna Rust'ın bellek güvenliğini ve RTOS olmadan azalan genel firmware karmaşıklığını da katmak yeterli
Embassy executor'ın async yapısı da çok iyi çalışıyor ve RTOS tasarım sürecindeki acının büyük kısmını azaltıyor
RP2040 için PIO arayüzünü de ekleyince kod son derece basit ve güzel hale geliyor; başka işlemcilerle ulaşması zor bir yapı ortaya çıkıyor
Pi Pico, Zephyr'de %100 destekleniyor. https://github.com/zephyrproject-rtos/zephyr/tree/main/board... belgelerine bakmamış olabilir mi? https://docs.zephyrproject.org/latest/boards/raspberrypi/rpi...
Ayrıca, pek çok durumda tek bir “main” Zephyr kurulumu kullanmak yerine gerekli dış modülleri projenin
west.ymldosyasına dahil etmek amaçlanan kullanım biçimiBirden fazla projenin aynı Zephyr kurulumunu paylaşması ayrı bir tartışma, ama mümkün olan tüm toolchain'leri ve HAL'leri kurmak tek yol değil
Artık açık kaynak olan ThreadX'ten söz edilmemiş
https://github.com/eclipse-threadx/threadx/
https://github.com/RIOT-OS/RIOT
RTOS seçenekleri karşılaştırması iyiydi
Kişisel olarak MicroPython'ın daha kolay bir yol olduğunu düşünüyorum.
async/awaittabanlı işbirlikçi çoklu görev bana iyi uyuyorSon projemde 6 step motoru, çeşitli LED'leri ve buton taramasını birlikte yönettim; kullanıcıya gerçek zamanlı gibi görünüyordu
O zamanlar elimizde ne kadar az kaynak olduğunu, buna rağmen üst seviye dil kullandığımızı hâlâ birçok kişinin tam olarak kavrayamaması şaşırtıcı
ESP32'de MicroPython kullandığımda, interrupt handler'ları Python'a yakışır şekilde desteklemesi hoşuma gitmişti. RP2040'ın da benzer şekilde desteklendiğini düşünüyorum
Mikroskobumda neredeyse gerçek zamana yakın step motor kontrolünü FluidNC kartı üstleniyor, ben de hafif bir seri protokolle kontrol ediyorum
Yine de https://pypi.org/project/micropython-stepper/'a bakıyorum; bu donanım zamanlayıcısı ve Python kodu kullanıyor gibi görünüyor
Düzgün bir projede Hubris'i bir kez denemek isterim (https://hubris.oxide.computer/reference/)
Mimari yaklaşımı, gömülü alanda hedeflediğim şeye oldukça iyi uyuyor. Sadece ben bunu C ile daha acılı hale getiriyorum
Barındırılan ortamlarda Erlang/Elixir ile yapılan yöntemden de çok farklı değil
Belleğin daha kısıtlı olduğu ve birden fazla stack'i kaldıramadığı durumlarda Embassy iyi bir seçenek gibi görünüyor
Yeni bir gömülü proje her zaman, gerçekten her zaman, sanal makinede başlamalı. Aynı sistemde araçları karıştırmamak gerek
Ticari projelerimde kalite sorunlarının bir numaralı nedeni tam olarak buydu
Yeni bir yonga seti, yeni bir tedarikçiyle projeye başlıyorsanız yeni bir VM oluşturmalı, o VM'e yalnızca tedarikçi araçlarını kurmalı ve derlemeyi orada yapmalısınız
Deneysel geliştirmeyi kendi yerel, VM olmayan makinenizde yapmak sorun değil. Ama sürüm mutlaka VM'de yapılmalı. Ve lütfen VM ile geliştirme iş istasyonunu senkronize tutun
Şu anda asıl geliştirici tatildeyken mutlaka düzeltilmesi gereken bir firmware derlemesiyle uğraşırken büyük acı çekiyorum. Kimse o kişinin iş istasyonuna erişemiyor, hazırlanmış VM 6 ay geriden geliyor ve müşteri, dünyada yalnızca tek bir özel programcının yapabildiği bir iş için neden tüm ekibin maliyetini ödemesi gerektiğini soruyor
Sürümleri CI sisteminin derlemesi gerektiğini düşünüyorum. git'te sürüm etiketi koyunca, testler geçtikten sonra binary çıkmalı
FreeRTOS seçerseniz büyük ölçüde yanlış yapmanız zor. Bu noktada fiilen sektör standardı sayılır
printf()'in çalışmasını sağlama sorununa nasıl bir çözüm olabilir?Epey baş ağrıtıcı görünüyor
Orijinal yazıdakine benzer bir deneyim yaşamıştım
Bu yüzden basit bir green thread timer'ı kendim yaptım
Gerçek bir kernel gibi gerçek süreç yönetimi desteği sunmuyor ve hiçbir garanti vermiyor ama beni bare-metal scheduling'in ötesine taşıdı ve RTOS karmaşasından kaçınmamı sağladı
Bunu C'de isteğe bağlı bir context struct'ı alan JavaScript timer callback'i gibi düşünebilirsiniz
Çeşitli sensörleri sorgulama, gelen sinyalleri işleme, kontrol kararları alma ve komutları dışarı gönderme işlerini farklı periyotlarda yürütebildim
Hayatınızı bu tür yavaş ve soyut bir mimariyle mahvetmeden önce, önce bu yaklaşımı denemenizi şiddetle tavsiye ederim