STM32 cube IDE platformu üzerinde proje oluşturarak gömülü uygulama geliştirme konularında epeyi yol aldık. Artık sıra biraz daha ileri konulara geldi.
Bu başlangıç, bundan böyle hayatımızı daha zorlaştıracak işlere el atacakmışız izlenimi veriyor ama öyle değil. Tersine, şimdiye kadar kullanmadığımız bazı teknikleri öğrenip, çalışmalarımızı kolaylaştıracak yeni araçlar keşfedeceğiz.
Bu yayında ARM Cortex M çekirdeğinin SWV ve ITM araçlarını kullanmayı öğreniyoruz. Bu serinin ilk bölümünde konuya giriş yapıp, başlangıç ayarlarına ve bir kod blokunun çalışma süresinin SWV ile nasıl ölçülebileceğine bakacağız.
HATA AYIKLAMA ARAÇLARI
Konumuz: hata ayıklama, İngilizce karşılığıyla “Debugging”. Yazılım geliştirme sürecinin önemli bir bölümünü hata ayıklama çalışmaları oluşturuyor. Yaygın olarak kullandığımız teknik ise koşmakta olan kodumuzu muhtelif noktalarda durdurarak, ya da ekrana, seri porta gönderdiğimiz mesajlarla değişkenlerimizin değerlerini gözlemek oluyor.
Bunun için elimizin altında bulduğumuz ilk araçlar kullandığımız geliştirme platformunun bize sundukları oluyor. STM32 cubeIDE nin Debug modunda iken yukarıda görülen penceresini ve benzerlerini hepimiz kullanmaktayız.
Yalnız, programımızın çalışmasını duraklatarak yapılan bir hata ayıklama süreci, kesmeler, zamanlayıcılar, bunların olaylara yanıt sürelerinin devrede olduğu bir curcuna içinde pek işe yaramıyor.
Bu yayında, başlangıç dönemini geçirmiş her yazılımcının zaten bildiği bu IDE araçları ile, ya da program içine serpiştirdiğimiz duraksatma-görüntüleme yöntemlerine dayanan hata ayıklama tekniklerini anlatmayacağım.
Onun yerine ARM Cortex çekirdeklerinin sunduğu biraz gözden ırak kalmış SWV ve ITM olarak anılan araçların kullanımını anlatacağım.
SWV ve ITM ARAÇLARI – NEDEN KULLANALIM
ARM Cortex-M çekirdeklerinde bulunan SWV – Serial Wire Viewing ve bunun bir parçası olan ITM-Instrumentation Trace Macrocell araçları bazı durumlarda alışılmış hata ayıklama yöntemlerine göre daha kullanışlı ve yetenekliler:
- Program parçacıklarının çalışma sürelerinin çok hassas şekilde ölçülmesi
- Anormal değerler alan değişkenler ve bellek konumlarının üzerinde iz sürülmesi
- Program akışının durdurulmasından etkilenen süreçlerin analizi (Örneğin kesme’ler)
- Görüntüleme yapılacak bir ekran bulunmaması
- Debug verisi gönderilebilecek bir seri port bulunmaması
SWV ve ITM KULLANILARAK YAPILABİLENLER
- ST-Link debugger’a, bir kod blokunun başlangıcında ve bitişinde birer karakter göndererek arada geçen süreyi nanosaniyeler çözünürlüğünde ölçebiliriz
- CPU yu en çok meşgul eden süreçleri istatistiksel verilerle sıralayıp, optimizasyon için nerelere odaklanacağımızı belirleyebiliriz.
- Seçtiğimiz değişken ya da bellek adreslerindeki değişiklikleri “time stamp” dediğimiz zaman etiketleri ile birlikte kaydedip (log) inceleyebiliriz.
- Program akışını kesmeden, oluşan kesmeleri (Interrupt) kaydedip inceleyebiliriz
- İlave bir UART bağlantısı ya da ekran kullanmaksızın program akışı içinden cubeIDE konsollarına text mesajlar gönderebiliriz.
- Değişkenlerin zaman eksenindeki değişimlerini osiloskop benzeri bir pencerede grafik olarak görüntüleyebiliriz.
- Hepsinden önemlisi, Bütün bunları CPU ya hemen hiç bir yük getirmeden ve meşgul etmeden yapabiliriz.
Bunların karşılığında bu araçların kullanımını öğrenmek için biraz vakit ve enerji ayırmak gerekiyor elbette.
ST Link V2 YE İLAVE BAĞLANTI – SWO TELİ
Ha, bir de; ST-Link SWD modunda kullandığımız 4 tele (GND, VCC, SWDIO, SWCLK) ilaveten SWO hattını da kullanacağız. Bu teli eklemek için elimize havyayı almamız gerekebilir.
13 Nolu SWO pinini, STM32F103 de PB3 pinine bağlamak gerekiyor.
Öte yandan bu “öğrenme ve bir adet tel ekleme” çalışması geri dönüşü çok hızlı bir yatırım, bir koyup beş alıyorsunuz karşılığında.
Bu yayın serisinde, mikro denetleyicilerle uğraştığım bunca yıldan sonra, hadi artık bunu da kullanayım artık, iyi bir şey galiba dediğim, sonunda da daha önce niye kullanmamışım diye hayıflandığım bu geliştirme araçlarını anlatacağım.
Bu anlattıklarımı Magnus Unemyr’nın buradan erişebileceğiniz Blog Sitesinden öğrendim.
KULLANDIĞIM DONANIM ve PROJE KURULUMU
Son iki yıldır Apple MacOS üzerinde, STM32 Cube IDE platformunda çalışıyorum. Bu sunum için kullandığım STM32F103C8 Pico modülü. Modül ile PC birbirine ST Link V2 debugger/programlama probu ile bağlı.
Fotoda ST-Link in SWD modunda kullanılması için yeterli olan 4 telli konnektörünün dışında iki tane daha tel görünüyor. Bunlardan Mavi renkli olanı NRST teli. Bu uygulamada fonksiyonel değil, olmasa da olur. Diğer ilave tel ise Beyaz renkli olan, PB3 ile ST-Link’in SWO pinlerini birleştiriyor.
Görüldüğü gibi, burada anlatacağım izleme, görüntüleme işleri için gereken her şey bunlardan ibaret. Osiloskop yok, PC ye veri aktarmak için UART bağlantısı yok, kodu izleyebilmek için mesajların gönderileceği bir ekran da yok. STM32 Modülün beslemesi de PC nin USB sinden olunca, çalışırken masaya oturmanıza bile gerek yok.
STM32 Yİ SWV MODUNDA ÇALIŞTIRMAK
Bu paragrafta yeni proje oluşturarak başlayıp ilerleyeceğim. İlk bir kaç sayfayı hızlıca geçebilirsiniz.
Önce yeni bir proje başlatarak, STM32F103C8 MCU için kurulumunu yapalım.
MCU seçimini yaptıktan sonra Next tuşuna basılınca aşağıdaki CubeMX penceresi geliyor.
Bir sonraki adımda SYS sekmesi altındaki Debug ayarlarını yapacağız. Burada daha öncekilere göre biraz farklı bir seçim yapacağız. Hep “Serial Wire” seçeceğini seçerdik. Bu defa 5. seçenek olan “Trace Asynchronous Sw” yi seçeceğiz. Böylece cube MX, PB3 pininin SWO olarak kullanılacağını bilecek.
Yukarıdaki seçim yapıldığında her zaman alışık olduğumuz PA13-PA14 SWD pinlerine ek olarak PB3 pinin de yeni görevi olan SWO ile etiketlendiğini göreceğiz.
Sırada Osilatör seçimi var. Kullandığım Pico modülde harici kristal olduğundan ben seçimimi aşağıdaki gibi yaptım.
Şimdi de sistem saat ayarlarını yapalım. Sistem frekansı 72MHz olacak şekilde aşağıdaki ayarları yapalım.
Artık Project/Generate Code komutu ile proje kodlarımızı oluşturabiliriz.
TEST PROGRAMIMIZ
Bu kod parçacığı ile bir for() çevrimi içinde a,b,c değişkenlerine periyodik olarak değerler atıyoruz. Bu işlemin hemen başında ve sonunda ITM Port 0, yani PB3 pini üzerinden ST Link debugger’a, zamanlarıyla etiketlenmiş iki işaretlericiyi ‘A’ ve ‘B’ harflerini gönderiyoruz. Bu iki harf arasında geçen süreyi basit bir çıkarma işlemi ile hesaplayarak for() çevrimimizin süresini öğreneceğiz.
Aralardaki iki adet HAL_Delay() fonksiyonunu bu ilk bölümdeki süre ölçüm çalışması sırasında kapalı tutacağız. Onlar daha sonraki bölümlerde, SWV den daha fazla veri almaya kalkıştığımızda oluşabilecek “overFlow” lara karşı süreci yavaşlatmak için gerekecekler.
Şimdi debug yapılandırmalarını yapalım. Böceğin yanındaki aşağı yönlü oka basarak debug menüsünü açalım.
Burada Debug Configurations, ardından da sol taraftaki pencereden projemizin ismine tıklayacağız, açılan penceredeki “debugger” sekmesini tıklayalım.
Burada SWD kutucuğu seçilmiş olarak gelmiş olmalı, öyle değilse tıklayarak seçelim. Pencereyi biraz yukarı kaydıralım, alt tarafı görünsün.
Burada SWV enable kutucuğunu tıklayarak işaretliyoruz. Core Clock olarak başlangıçta yapmış olduğumuz ayarlara uygun olarak 72MHz yazıyoruz. SWO Clock, bizim ST_Link probumuz için 2000 kHz.
Kalan ayarlarda değişikliğe gerek yok. Debug tuşuna basarak programımızı MCU ya yükleyelim. Her zaman olduğu gibi program çalışmaya başlayıp “HAL_INIT” adımına kadar gelir, ve orada bekler.
SWV KONSOLLARININ AÇILMASI
Programımız burada bekler durumda iken, SWV bilgilerini görüntüleyeceğimiz paneli açalım. Bunun için Window sekmesi altında Show View alt menüsünü seçelim, bu seçim yapıldığında türlü çeşitli bilgi konsollarını içeren bir liste penceresi açılıyor.
Açılan listede SWV panelleri her zaman görünmeyebilir, bu durumda “Other” seçeneği ile listenin devamını açmamız gerekir. İlk olarak “SWV ITM Data Console” panelini seçelim.
Ekranın alt bölümünde aşağıdaki gibi SWV ITM Data Konsolu açılır.
Bu panel, programımızın içinden ITM_SendChar() fonksiyonu ile göndereceğimiz kodların görüntüleneceği bir konsol. Verilerimiz burada sadece text olarak görüntülenecekler. Her bir karakterin geliş zamanı ile birlikte listeleneceği panel ise “SWV Trace Log” adlı bir başka konsol, birazdan ona da geleceğiz.
ITM PORT 0 IN ETKİNLEŞTİRİLMESİ
Şimdi burada iken ITM_SendChar() fonksiyonunun verileri göndereceği 0 nolu ITM Portunu açalım.
Bunun için bu konsolun sağ üst tarafındaki küçük imgelerden yapılandırma anlamına geleni tornavida-anahtarlı olanını tıklayalım.
Şimdi ITM ayarlarını yapacağımız bu pencere açılmış olmalı:
Burada sadece sağ alt taraflarda olan port 0 a ait kutucuğu işaretleyelim. Görüldüğü gibi ITM 32 farklı porta veri gönderebiliyor. Bizim işimiz şimdilik o kadar karmaşık değil, Port 0 yeterli. OK diyerek bu paneli kapatabiliriz.
KAYDA BAŞLAYALIM – ÖNCE ITM DATA KONSOLUNDA TEXT
Şimdi, konsolumuzu kayıt moduna geçireceğiz. Bunun için kırmızı yuvarlak “kayıt” butonuna tıklayacağız.
Butona basınca kayıt modu başlar, butonun görünümü de soldaki gibi değişir.
Şimdi, HAL_INIT() satırında beklemekte olan kodumuzu devam komutu ile çalıştırabiliriz. main.c içindeki while çevrimine girilince ITM_SendChar() fonksiyonları ile gönderilen A ve B karakterleri ITM Data Konsolunu dolduracaktır.
Evet, ITM port 0 a verilerimizi gönderebildik, ST Link de bunları algılayıp STM32 cube IDE ye aktardı, konsolumuzda görüntüledik. Ama bu, iletişimimizin sağlanabildiğini ve programımızın çalışmakta olduğunu göstermekten öte bir fayda sağlamıyor.
SWV TRACE LOG KONSOLUNDA ZAMAN BİLGİLERİNİN LİSTELENMESİ
Bizim amacımız A ile B arasındaki zaman aralığını ölçmek idi. Bunun için SWV Trace Log konsolunu kullanacağız.
Programımızı durdurup başa alalım, yine HAL_INIT() de bekler durumda olsun. Bu konsolun seçilip açılması da aynen ITM Data Console’da olduğu gibi, tekrar anlatmayacağım. ITM Port 0 seçimini bir önceki adımda yapmıştık, o nedenle burada tekrar yapmaya gerek yok. Sadece “kayıt” tuşuna basarak kaydı başlatalım ve programımızı koşturalım.
Konsolumuzun içi aşağıdaki gibi dolacaktır. Bir saniye çalıştıktan sonra programı durdurarak görüntülenen verilere bakalım.
Görüldüğü gibi ARM Cortex M çekirdeği bizim için epey bir şey kaydediyor. Port a gelen verinin değerini, kaçıncı saat periyodunda geldiğini, kaçıncı mikro saniyede geldiğini… Her seferinde tek karakter gönderdiğimiz sürece sorun yok. “ABCDE” gibi bir karakter dizisi gönderirsek zaman bilgilerini alamıyoruz.
Burada ‘A’ yani 65 ile ‘B’ yani 66 satırlarının zaman damgaları arasındaki farkı hesaplarsak, içerideki for() çevriminin süresinin 97,917 µs (7050 saat çevrimi) olduğunu bulabiliriz. Gayet güzel değil mi? Bu işi CPU ya hiç yük getirmeden, sürecimizin doğal süresini etkilemeden yapıyoruz. Yani, hemen hemen etkilemeden – ITM_SendChar() CPU dan sadece 1 saat çevrimi, 14ns alıyor.
Not: Yukarıdaki trace kaydı ve hesaplama, test programımızdaki HAL_Delay(1) satırları kapalı iken yapılmıştır.
SWV Trace Log paneli ve ITM SWV Data Consolun her ikisi de yukarıdaki gibi bir sefer açıldıktan sonra, aynı görüntüleme oturumu esnasında sekmeler tıklanarak birinden diğerine geçilerek iki panel de görüntülenebilir.
Sırada değişkenlerin SWV/ITM uzerinden izlenmesi var ama onu yayının ikinci bölümünde anlatayım.
HIZ KISITLAMASI
Görüldüğü gibi bu mikradenetleyicilerin işlem hızı çok yüksek. Eğer, porta gönderdiğimiz veriler çok yoğun olur ve üst üste gelirse iletişim kapasitesini ve tampon bellek kapasitelerini kolaylıkla aşabiliyor. Bu durumda veri paketi kayıpları oluyor, ve yapılacak ölçümlerin güvenilirliği bozuluyor.
Neyse ki SWV/ITM sistemi bize böyle bir durum olduğunu bir “overflow” uyarısı ile haber veriyor.
Overflow mesajları yani veri kayıpları seyrek aralıklarla geldiğinde, ekran görünümü yukarıdaki kadar kötü olmayabilir. Ama sol alt köşedeki “Overflow packets: …” mesajı her durumda belirecektir.
Böyle bir durumda verilerin güvenilir olmayacağını dikkate alarak, veri gönderim periyodunu uzatacak ve veri boyutlarını küçültecek önlemler almak gerekir. Test programımızdaki HAL_Delay(1) bekletmelerinin amacı da bu işte. Sadece ‘A’ ve ‘B’ gönderildiğinde bu bekletmelere gerek yok ama değişkenleri de izlemeye alınca overflow lar başlıyor.
merhaba elimde STM32F411 discovery kart var , STM32cube ide ortamında onlne baglantı saglıyorum debug modunda çalıştırıyorum , fakat hızlı çalışmassından dolayı registerlarının içeriklerini göremiyorum , ancak durdurdugumda görüyorum , hız ayarını bir türlü bulamadım şöyle yaklaşık 500 ms lik bir hızda çalıştıgını görsem online registerların içeriklerini takip edebilirim nereden ayar yapılması gerekir yardımcı olurmusunuz
Cem Bey merhaba,
Sorunu tam olarak anlayamadım. Debug modunda çalıştırıyorum diyorsunuz. İstediğiniz noktalara breakpoint’ler koyup programı adım adım ilerlettiğinizde istediğiniz registerlerin içeriklerindeki değişiklikleri sağ taraftaki izleme pencerelerinde göremiyor musunuz?
Break point koydugumda o noktaya geldiginde duruyor bu anda registerlarin içeriklerini görüyorum , çalişırken mesala , 500 ms araliklarla GPIO portunda ledin yanip sönmesini görmek istiyorum , göremiyorum , durdurdugumda görüyorum
STM32cubeide ayarlari ile ilgili türkçe kaynakta pek yok , sorunun ayarlardan olabilecegini tahmin ediyorum
STM32cubeide ortaminda stm32f103 assembly program yazabilecek bir uzman önerebilirmisiniz , genelde programcilar c dilini tercih ederler , assembly olan merakım var , birçok kişi program yazmayı bırakın main.s projeyi bile oluşturamadı , bunu mplab microchip te yaptım , STM32F10xc işlemcisinde yapamadım
Maalesef yardımcı olamayacağım Cem Bey. 45 yıl önce bırakın assembly’i, direkt makina dilinde de kod yazıyorduk, ama artık ilgimi çekmiyor. Mecbur kalmadığımı sürece elime assembly’i alacağımı sanmıyorum.
Selamlarımla,
Cem Bey, mikrodenetleyicinin çalışma hızını düşürmenin tek yolu saat ayarları ilsaat frekansını düşürmek. Bu durumda dahi 15625 Hz in, yani 64µs nin altına inemezsiniz. Programınızın akışı içinde GPIO portun içeriği izleyemeyeceğiniz kadar hızlı değişiyorsa bunu görmenin üç yolu var.
1) Değişiklik olan noktalara breakpoint koyarak içeriğine bakmak,
2) Değişiklik olan noktalarda içeriğini bir diziye kaydedip programı duraksattığınızda kaydedilmiş verilere bakmak
3) En iyisi de, yorum yazmış olduğunuz yayınımda anlattığım gibi SWV ile izleyip ekranda listelenen çıktılara bakmak.
Bunların dışında “biryerlerden hız ayarlayarak yavaşlatmak” diye bir seçenek yok maalesef.
Selamlarımla,