STM32 – HAL KÜTÜPHANELERİ İLE UART INTERRUPT

Blog sitesini açtığımdan bu yana STM32 ile USART üzerinden veri alışverişini anlatmaya değer bir konu olarak düşünmemiştim. Ancak, internet üzerinde problemlerini paylaşan kişilerin yazdıklarına bakınca yaygın bir sorun olduğunu gördüm. Buna karşılık oluşturduğum çözümü paylaşmaya karar verdim.

Sorun şu : UART üzerinden ne zaman veri geleceğini bilmiyoruz. Herhangi bir anda gelebilir, ama biz o zamana kadar USART portu gözleyip beklemek istemiyoruz. Gelecek karakter dizisinin uzunluğunu da bilmiyoruz. Yani herhangi bir zamanda bir miktar karakter gelecek, son karakter hangisi onu da bilmiyoruz. Bu koşullar altında HAL kütüphaneleri ile işimizi halledeceğiz.

Bu yayında HAL kütüphaneleri kullanarak ürettiğim çözümü sunacağım. Yeni bir icat değil, HAL öncesinde alt seviye kodlama ile yaptığımız işin adaptasyonundan ibaret.

UART Üzerinden veri almak için iki yöntem olduğunu hatırlatmakta yarar var. 
Bunlardan birincisi portu sürekli olarak gözleyip, gelen veri olduğunda almak. Buna İngilizce olarak "polling" Türkçe karşılığımda da "yoklama" yöntemi diyoruz. CPU nun beklerken başka işlerle meşgul olmasına izin verilmediğinden bu, sistemin çalışmasını bloke eden bir yöntem.
Diğer yöntem ise "kesme"leri, İngilizce karşılığı ile Interrupt'ları kullanmak. Bu durumda Uart girişini gözlemek için CPU yu meşgul etmiyoruz. O başka işlerle meşgul olmaya devam ediyor. Veri geldiğinde "kesme" sinyali üreterek haber veriyor, bir nevi kapının zilini çalıyor. Bu yayında bu yöntemi anlatıyorum.

HAL Kütüphaneleri bize sadece uzunluğu önceden bilinen sayıda karakter almaya yarayan fonksiyonlar sunuyor. Sıkıntı bundan kaynaklanıyor.

Verinin ne zaman geleceğini bilmediğimiz için kesme (interrupt) kullanmamız gerektiği açık. Gelecek olan verinin uzunluğunu da bilmiyoruz, o halde her seferinde bir karakter alarak devam edeceğiz. Bu durumda da, gelen dizinin sona erdiğini anlamak için satırbaşı ya da başka bir özel sonlandırma karakterine ihtiyaç var. Ama çoğu uygulamamızda böyle bir işaret de tanımlanmış değil, herhangi bir karakterden sonra akış kesilebilir.

O halde geriye tek seçenek kalıyor; veri akışı belirli bir süre kesilirse alışın sonlandığına karar verip o ana kadar gelen karakter dizisi üzerinden işlem yapmak.

Bu benim GSM tabanlı cihazlar geliştirirken karşıma çıkan bir durumdu. Şebekeden ne zaman ne veri geleceğini, uzunluğunu, sonlandırma karakterinin ne olduğunu bilemezsiniz. Ama gelen şeyi de mutlaka yakalamanız gerekir.

KARAKTERLERİ TEK TEK ALGILAYARAK ÇALIŞMAK

Çözüm şu; USART kesmeyi aktive edip interrupt handler(IRQ) ile her seferinde tek karakter algılıyorum. IRQ handler her gelen karakteri bir alış bufferine yerleştiriyor, ta ki veri akışı belirli bir süre kesilene kadar. Bu süreyi de bir timer ile kontrol ediyorum. Her gelen yeni karakter ile timer’i yeniden başlatıyorum. Eğer bir sonraki karakter gecikir, timer sıfırlanırsa geliş de sonlanmış oluyor.

Her gelen karakter ile “uartReady” bayrağı dikiliyor, böylece timeri sıfırlanmış gördüğümüzde, bir şeyler geldikten sonra mı, yoksa hiç bir şey gelmeden mi sıfırlanmış anlayabiliyoruz. Birşey gelmemiş ise timer’i yeniden başlatıyoruz.

Gerisini kodlar üzerinden görelim.

PROJENİN YAPILANDIRILMASI – USART2 IT

Projede USART2 nin etkinleştirilir kesmelerinin de açılması gerekiyor. USART1’i başka amaçlarla kullandığımdan böyle bir seçim yaptım. Ayrıca verileri görüntülemek için TFT kullanıyorum. Böyle bir projenin cube IDE ile kurulmasını -biraz fazlasıyla- burayı tıklayarak görebilirsiniz.

Burada sadece USART tanımlamalarını anlatacağım. Geliştirme ortamı olarak STM32 CubeIDE kullanıyorum.

PROJENİN KURULUMU

Benim güncel uygulamam şöyle bir ihtiyaca yönelik:

Genelde tüm uygulamalarımda kullanıcı girişlerinin yapılabilmesi için bir tuş takımına ihtiyaç oluyor. Bu 4×4 mekanik bir klavye olabildiği gibi, TFT üzerinde 20-30 hatta daha fazla butondan oluşan dokunmatik bir klavye de olabiliyor.

Birbirine UART TX/RX üzerinden bağlı iki STM32F103 kiti. Tuş takımlı olan gönderen taraf (HMI), diğeri alıcı istasyon. İkisi arasındaki bağlantı sadece GND ve bir Tx/Rx telinden ibaret.

Birkaç butonlu olsun, onlarca tuşu olan karmaşık dokunmatik grafik bir panel olsun, epeyi bir CPU kapasitesi ve GPIO ayağını alıp götürüyorlar. Bu nedenle artık kullanıcı giriş ve görüntüleme işlerini ana işlemciden ayırıp, ayrı bir HMI birimine aktarmaya karar verdim.

Bu durumda HMI birimi, alıcı birime bir mouse ya da bilgisayar klavyesi gibi ASCII kodlar gönderiyor. Aksi yönde de ekranda görüntülenmesi istenen verileri alıyor.

İşte bu yayının konusu alıcı tarafı. Ne zaman ne uzunlukta veri geleceğini bilmiyorsunuz. Sadece 3-5 karakterden sonra bir süre ara verildiğinde gelen diziyi açıp bakmanız yeterli oluyor. Onun dışında alıcı birimin işlemcisi kendi süreçleriyle meşgul olmaya devam ediyor.

Proje geliştirme kurulumumda UART üzerinden birbirine bağlı iki STM32F103C8 kitim var. Bunlardan HMI görevini yürütende bir 4X4 membran klavye var. Basılan tuşun ASCII karşılığını USART üzerinden diğerine gönderiyor. Diğer modül, alıcı tarafında olan da bir STM32F103C8 kiti. USART2 üzerinden diğer modülden gelen karakterleri algılayarak TFT ekranında görüntülüyor.

İki kit arasındaki UART Bağlantısı. Kırmızı tel Rx/Tx sinyal bağlantısı, kahverengi olan ise GND. Alttaki Mapple Leaf kiti tuş takımının bağlı olduğu HMI, üstteki Pico Kiti ise alıcı birim.

İki kit birbirlerine sadece bir GND ve bir de UART sinyal teli ile bağlılar. UART bağlantısı HMI biriminin Tx pini ile alıcı ünitenin Rx pini arasında. Bu uygulamada tek yönlü haberleşme var. Başka projelerde ana üniteden HMI yönüne ekranda görüntülenmek üzere verileri de göndereceğim.

ALIŞ TARAFI STM32F103 PROJE YAPILANDIRMALARI

Burada USART2 yapılandırmasını göstereceğim. TFT ye ait SPI yapılandırmalarını önceki yayında(tıklayınız) anlatmıştım.

USART2 yi aktif duruma getirip baud rate i de 9600 a ayarlıyorum. Diğer parametrelerde değişiklik yok, varsayılanlar uygun.

USART2 yi Interrupt ile çalıştıracağımız için NVIC ayarlarını açarak interruptlarını aktif hale getirmemiz gerekiyor.

Burada önemli bir nokta var : USART interrupt kullanarak çalışıyoruz. Ama aynı zamanda Systick() kesmelerini kullanan timer’lara işimiz düşecek, onların önceliği bu UART IRQ dan yüksek olmalı ki çalışabilsinler. Aksi halde bu IRQ içinde iken Systick çalışmaz, burada çakılıp kalırız. Bununla ilgili bir yayınım vardı, görmek için tıklayınız. IRQ içinde bulunduğumuz süre kısa da olsa Timer’in durmasını istemiyorum.

Bunun için CubeMX System Core ayarları altındaki NVIC penceresini açalım:

Burada USART2 global interrupt önceliğini “0” iken “1” e çeviriyoruz, yani düşürüyoruz. Böylece Usart_IRQ artık Systick kesmelerinin çalışmasını engellemeyecek.

Bundan sonra Project/Generate Code seçeceği tıklanarak proje dosyalarımızın hazırlanmasını sağlıyoruz.

STM32 UART IT ALIŞ FONKSİYONLARI

Fonksiyon kodlarının içine açıklamaları zaten yazdığımdan daha fazlasını anlatmadan listeleri veriyorum. Aşağıdakiler main.c de USER CODE 4 bölgesi içinde yer alıyor.

USART IRQ Handler fonksiyonu. Başlıktaki notları gözardı edelim, eskiden kalma onlar.

Bu IRQ handler her gelen yeni karakteri rxBuffer’e kaydederek, timer’i yeniden başlatıyor. Bir sonraki karakteri almak üzere de HAL_Usart kesme fonksiyonunu yeniden çağırıyor. Sadece buffer dolduğunda kesme’yi yeniden açmayıp duruyor.

Bu durumda alışın yeniden başlaması için readKey() fonksiyonunun çağrılması gerekiyor.

readKey() Fonksiyonu.

ReadKey fonksiyonu, HMI biriminden UART üzerinden gelen birşey var mı diye sorgulama yapıyor. Önce kesme’nin aktif olup olmadığına bakıp, eğer değil ise aktifleştiriyor.

Bundan sonra timeOut olup olmadığına ve gelmiş karakter olup olmadığına bakarak gereken işlemleri yapıyor. Kod üzerindeki notlar yeterince açıklayıcı sanırım.

Aşağıdaki bölüm de kodların çalışmasını test etmek üzere main.c USER CODE 2 içinden çağırdığım test programı. Buradaki notlarda da yeterince açıklama var.

Bunlar da main.c başlığındaki değişken bildirim ve tanımları.

SONUÇ

Böylece, projelerimde kullanıcı girişleri için esnek bir çözüm geliştirmiş oldum. Giriş aracımın mekanik bir tuş takımı ya da dokunmatik panel olması artık ana işlemci açışından birşey değiştirmeyecek. Hem ileride görüntüleme işlerini de bu birim üzerinden yapabileceğim. Bunun bedeli de fazladan 2-3 dolarlık bir MCU daha kullanıyor olmam. Buna da değer doğrusu.

Bu yayının sonu – Selçuk Özbayraktar Temmuz 2020

Leave a Reply

Your email address will not be published. Required fields are marked *