Merhaba,

Bugünkü yazımızda ARM mikroişlemcilerde kesme yani interrupt rutinlerine değineneceğiz. Öncelikle gömülü sistemlere ARM programlamayla başlayanlar için interruptların ne olduğuna bir göz atalım. C programlama dilinde yazdığınız komutlar yukarıdan aşağıya işlenir. Standart bir C programında bu akışı bozacak herhangi bir durumla, eğer “goto” gibi bir etiketleme metodu kullanmıyorsanız, pek karşılaşmazsınız. Fakat komutların akışını denetleyerek, beklenen bir durumda programın akışını bir başka fonksiyona dallandırmak istediğinizde nasıl bir yol izlenmelidir? Aslında bu durumun temelde iki çözümü olduğunu söyleyebiliriz. Uygulamanızda beklenen durumları bir if-else yapısı ile kontrol etmek ilk aklınıza gelecek yol olacaktır. Şimdi bir buton durumunu kontrol ederek kitinizin üzerinde bulunan kullanıcı ledini yakmayı ele alalım ve birinci yolu kullandığımızı düşünelim. Main fonksiyonunuz aşağıdaki gibi olacaktır.

while(1) {
    if (button_pressed) {
       led_on();
    } else {
       led_off();
    }
}

Bu örnekte butonun basılıp basılmadığını sürekli sonsuz döngü içinde kontrol edip, eğer butona basıldıysa ledin bağlı olduğu çıkışa lojik 1 değerini yazıyoruz. Ancak tekrar vurgulamakta yarar var, buton durumunu “sürekli” kontrol ediyoruz. Dolayısıyla yukarıdaki sonsuz döngü içinde bir başka işlem daha yapmak istediğinizde butonun durumunu kontrol edip ledi yakma süreciniz, yapmak istediğiniz diğer süreç ile birbirilerini etkileyen iki öğe haline geleceklerdir. Bu şekilde bir durumun gerçekleşmesini sürekli kontrol ederek bir uygulama geliştirmeye “polling” metodu denir.

İkinci metot olarak tanımladığımız kesme fonksiyonları bu durum için daha faydalı bir çözüm olacaktır. Kesme metoduyla yukarıdaki problemimizi tekrar ele almadan önce ARM mikroişlemcilerde bulunan önemli kesme öğelerinden bahsetmemiz gerekiyor. Öncelikle kesme fonksiyonları external olabildiği gibi internal da olabilmektedir. Bu da ARM’ ın size sunmuş olduğu çevresel birimleri interrupt rutinleriyle birlikte kullanabileceğiniz ya da onları dışarıdan gelecek olan bir sinyal ile tetikleyebileceğiniz anlamına gelmektedir. Mikroişlemci içinde kullanabileceğiniz tüm kesmeler bir “id” ile birlikte (yani bir sayı ile) hafızada bulunan vektör tablosu içinde tanımlanmış durumdadır. Aynı zamanda kullandığınız kesme biriminin beklediğiniz gibi çalışması CPU ile koordinasyon kurmuş olan Nested Vectored Interrupt Controller (NVIC)’ ın sorumluluğu altındadır. Konfigüre etmiş olduğunuz kesmenin gerçekleşmesi için, tanımlanan kesme fonksiyonunun hafızadaki yerinin CPU’ya bildirilmesi işlemi NVIC tarafından gerçekleştirilir. Böylece kesme fonksiyonuna dallanmak gerektiğinde programın komutlarını adım adım tutan bir pointer geçici olarak kesme fonksiyonunun adresini alır ve kesme fonksiyonunu işler. Kesme fonksiyonunun görevinin bitmesiyle program tekrar kaldığı yerden devam eder.

Şekil 1: Kesme rutinine dallanma

HAL kütüphanesi sizlere diğer mikroişlemcilerde olduğu gibi ISR (Interrupt Service Request) ya da IRQ_Handler (Interrupt Request Handler) adı verilen fonksiyonları kesme fonksiyonları olarak sunmaktadır. Bu fonksiyonlar kesme rutinlerini gerçekleştirmek üzere özelleşmiş ve içini sizlerin kullanıcı komutlarıyla doldurabilmeniz adına boş bırakılmışlardır. Kesme fonksiyonları olarak kullanabileceğiniz bir diğer fonksiyon ise CallBack fonksiyonlarıdır. CallBack fonksiyonları da IRQ_Handler’ da olduğu gibi kesme bayrağı kalktığında tamamen otomatik olarak dallanılabilen bir rutindir. Kısa açıklamamızın ardından arayı soğutmamak adına tekrar problemimize geri dönecek olursak polling metodu yerine kesme rutinlerini kullandığımız takdirde programın nasıl çalıştığına göz atalım.

Şekil 2: Örnek kesme fonksiyonu

Şekil 2’ de görebileceğimiz uygulamada butonun sahip olduğu lojik durum mikroişlemci için external (dış) bir sinyal olup ana program içinde sürekli olarak kontrol edilmesi gerekmemektedir. Böylece butona basılmadığı durumlarda led sürekli kapalı durumda kalacaktır. Ancak siz butona bastığınız anda program CallBack fonksiyonuna dallanacak (ya da Request Handler) ve eliniz butona basılı olduğu sürece ledin bağlı olduğu çıkış pini lojik 1 durumunda kalacaktır. Butondan elinizi çektiğinizde ise program normal rutinine dönecek ve çıkış pinini lojik 0’ da tutmaya devam edecektir.

Şimdi uygulamamızı gerçeklemek ve neler olduğunu daha yakından görmek adına gerekli konfigürasyonlarımızı yapmaya başlayabiliriz. Öncelikle ilk adımımız eğer kullandığımız kitin üzerinde kullanıcı butonu varsa onun hangi pine bağlı olduğuna bakmak. İşleri uzatmamak adına bu konuda size güveniyorum. Kullandığım STM32F767ZI için kullanıcı butonu PC13 pinine bağlıdır. Peki bu noktada bu pini bir giriş olarak mı konfigüre etmemiz gerekiyor? Sorumuzun yanıtı hayır!

Şekil 3: PC13 pininin kesme pini olarak ayarlanması

Şekil 3’te PC13 pininin üzerine tıkladığınızda, PC13 pininin GPIO_EXTI13 interruptına bağlı olduğunu görebilirsiniz. Bu etapta söz konusu pin için yapacağımız tek konfigürsayon bu olacaktır. Bununla birlikte herhangi bir kullanıcı ledinin bağlı olduğu pini GPIO_OutPut olarak konfigüre etmeyi unutmayın?. Ardından PC13 pininin bağlı olduğu interruptların aktivasyonunu gerçekleştirmelisiniz.

Şekil 4: NVIC kesme aktivasyonu

Şekil 4 üzerinden anlaşılacağı üzere NVIC sekmesi altından EXTI hattına bağlı interruptları aktif etmiş olduk. Şimdi gerekli proje ayarlarını “Project Manager” sekmesinden yapıp kod üretebiliriz. Keil tarafında açılan programımızda her zaman olduğu gibi “Functions” sekmesinden birkaç önemli ayrıntıyı kısaca inceleyelim.

Şekil 5: Kesme fonksiyonları

Stm32f7xx_hal_gpio.c dosyasına göz attığınız takdirde iki adet kesme rutini karşınıza çıkacaktır. Bunlar HAL_GPIO_EXTI_CallBack ve HAL_GPIO_EXTI_IRQHandler fonksiyonları olacaktır. Stm32f7xx_hal_gpio.c dosyasına giderek ileriki uygulamalarımızda daha sık karşımıza çıkacak olan CallBack fonksiyonunu inceleyelim.

Şekil 6: CallBack fonksiyonu

Farkedeceğiniz üzere “weak” olarak tanımlanmış boş bir CallBack fonksiyonu ile karşı karşıyayız. Birinci adımımız bu boş fonksiyonu kopyalayıp main dosyasının içine yapıştırmak olacaktır.

Şekil 7: CallBack fonksiyonunun main.c içine kopyalanması

Şekil 7’ de CallBack fonksiyonu bir pinin durumunu interrupt gerçekleştiğinde değiştirecek şekilde programlanmıştır. Burada dikkat edilmesi gereken husus bu fonksiyonu main fonksiyonunun herhangi bir yerinde çağırmanıza gerek olmayışıdır. Burada fonksiyonun ne yapması gerektiğini yazdıktan sonra bu şekilde bırakmalısınız. Çünkü program otomatik olarak bu fonksiyona dallanacaktır. Bu durumda main fonksiyonu içindeki sonsuz döngü ne yapacak diye merak edenler için yanıtımız tam anlamıyla “hiçbir şey”! (Bu bir şey yapamayacağınız anlamına gelmiyor tabi…)

Şekil 8: sonsuz döngü

Programı derleyip kitinize yükleme yapmanızın ardından butona her basışınızda ledin durumunun değiştiğini ve basmadığınız durumda ise en son hangi durumduysa onu koruduğunu gözlemleyeceksiniz. Eğer her şey yolundaysa bu uygulamayı da başarılı bir şekilde gerçekleştirmiş durumdasınız. Bu uygulamada diğer uygulamalarımızdan farklı olarak sizlerle proje dosyasını GitHub üzerinden paylaştığımızın bilgisini vermek isteriz. Yazının sonundaki linke tıklayarak “karamelektech_interrupt” adlı dosyayı indirebilir ve test edebilirsiniz. Ancak dip not olarak eğer STM32F767ZI kullanmıyorsanız kullandığınız kite göre yeni bir CubeMX projesi oluşturmalısınız.

Bir sonraki yazımızda görüşmek üzere, hoşça kalın!

Uygulama Linki: https://github.com/karamelekrobotics/karamelektech_interrupt

5 Comments

  1. Kardeşim selamun aleyküm. Bir sorum olacak sana. Ben bu bilgisayarı interupta sokuyorum ama hiçbir şekilde interuptan çıkamıyorum. Visual sutudio kod kurdum ama yine de bu arm işlemci çalışmıyor. Acaba bunları yapabilmek için rasperi pi mi alsam ne diyorsun? İnterupta sıkıştım, mavi hapı seçecektim seçemedim, sanırım pil oldum nolur beni kurtarın bu tarladan.

    • Aleykümselam kardeşim. Öncelikle interupta giren ,interuptta kalmalı. Rasperi pi değil “Banana” pi kullanmanı tavsiye ederim. Gördüğüm kadarıyla baya ilerlemişsin, kendini bu şekilde geliştirmeye devam et. 🙂

  2. merhaba benim sorum biraz farklı , birçok işlemciyle çalıştım , bu işlemcilerde donanımsal kesme uygulaması yaptıgımızda , kesmeleri aktif ettigimizde metal bir cisimle entegrenin pinlerine dokundugumuzda işlemciler hemen reset atıyor , bu durum programın çalışmasında bir düzensizlik oluşturuyor , egerki programlama low power ise durum dahada vahim , metal bir cismi bırakın aynı şebekeden farklı bir chaz devreye alındıgında veya lamba yakıldıgında reset atıyor , bir çok kişi temiz bir voltaj ve kapasite konulması gerektigini söylüyor buda çözüm degil , DSPIC işlemcilerinde böyle bir sorun yok bunun sebebi ne olabilir , port yapısı veya üretim teknolojisi olabilirmi

    • Low power konusunda deneyimlediğim bir problem olmadı açıkçası. Ancak donanımsal kesme konusunda tahminim işlemci bacağına örneğin bir tel değdirdiğinizde o telin direncinin işlemci bacağındakinden daha az olması sebebiyle bir karışıklık yaşanıyor olabilir.

Bir Cevap Yazın