STM32F4 Kesmeler ve Portlar
Programcının yazdığı program satır satır işletilir. Bir kısımdan diğer bir kısma atlayabilir. Fakat önceden programlanmış ve/veya değişkenlerin değerine göre programın akışı düzenlenir. Düzenli bir programda işlemcinin davranışı ve gereksinim duyduğu ve dikkat etmesi gerekenler çoğunlukla işlemcinin dışındaki olaylara dayanır. Düzenli programın işleyişinin önemli bir olay olduğunda askıya alınmasına ve başka bir kod parçasının çalıştırılmasına kesme (interrupt) denir. Bu durum kesme isteği (interrupt request) denilen bir elektriksel sinyal ile başlatılır. Kesme isteği işlemcinin iç donanımlarından gelebilir ya da port pinleri üzerinden dış dünyadan gelebilir. İnceleyeceğimiz uygulamada PortE portunun bit-3’ünde bağlı olan bir butona basıldığında işlemcinin kesme isteğine nasıl cevap verdiğini göreceğiz.
Karmaşık kesme isteklerinin işlemciye sürekli yük getirmemesi için işlemci içerisinde özel bir donanım bloğu oluşturulmuştur. Bu donanıma kesme kontrolörü (interrupt controller) adı verilir. Kesme kontrolörü haklı bir sebeple gelen kesme isteği neticesinde düzgün işleyen programı askıya alarak kesme fonksiyonu (interrupt function) olarak adlandırılan özel kod parçasını işlemeye başlar. Kesme fonksiyonunun işletilmesinin bitiminde program kaldığı yerden çalışmaya devam eder.
STM32F4 serisi mikroişlemcilerde kesme kontrolörü “Nested Vectored Interrupt Controller” olarak isimlendirilir. (NVIC, RM0090 Teknik dokümanı, sayfa 247, bölüm 10). NVIC kontrolör mikroişlemci içerisindeki önemli donanım kesmelerini (DMA istekleri, USART, CAN, I2C ve Timer gibi donanım kesmeleri) ve ayrıca External Interrupt/Event Controller (EXTI) adı verilen donanım vasıtasıyla portlardan gelen kesmeleri kontrol eder. Kesme isteklerinin işletilmesini basit bir şekilde gösteren blok diyagram aşağıda verilmiştir.
Figür 1. Kesme istekleri zinciri (Basitleştirilmiş)
Mikroişlemcinin kesme kapasitesinin kullanılması amacıyla yerine getirilmesi gerekenler;
1- Kesme Fonksiyonu hazırlanmalıdır. Programcı kesme isteği geldiğinde ne yapması gerektiğini bilmeli ve kesme anında çalıştırılacak olan (interrupt function) kesme fonksiyonunu yazmalıdır. Kesme fonksiyonu normal programın yürütülmesine zarar vermeyecek özel bir şekilde yazılmalıdır. Derleyiciye bunun belirli bir olay, belirli bir kesme isteği halinde yürütülecek bir fonksiyon olduğu belirtilmelidir. Kesme fonksiyonu her hangi bir argüman ile çağırılmamalıdır. Kesme fonksiyonunda argüman kullanılacak ise normal program başlangıcında değişken genel olarak tanımlanmalıdır.
2- Kesme kontrolör NVIC kurulumu yapılmalı ve aktif edilmelidir. Ayarlar değiştirildikten sonra kesme kontrolörü hassas bir iştir. Bu kontrolörün kurulumundaki register’lara sadece işlemcinin özel bir durumunda erişilebilir. NVIC kontrolörün değişmesi/kurulumu için kullanılan fonksiyonlar derleyici paketi içindeki kütüphanede mevcuttur. Ayarlanacak her fonksiyon aşağıda açıklanacaktır.
3- EXTI kontrolör kurulumu yapılmalı ve aktif edilmelidir. Port sinyallerini sıralamak için ve kesme isteklerini onaylamak için EXTI kontrolör kurulumu yapılmalı ve aktif edilmelidir. Prosedür register’ların normal bir şekilde yazılmasıyla tamamlanır.
NVIC kontrolör kesme isteği aldıktan sonra onu doğrular ve işlemciye bildirir. İşlemci daha sonra kesme kaynak kodunu ister ve kesme vektör tablosundan uyan kesme fonksiyonunu pointer’a alır. Tablo mikroişlemcinin hafızasında yer alır. Bu tablo vektörler için 80’den fazla girdiye sahiptir. Vektörler için tam liste RM0090 teknik dokümanının 248nci sayfasında Table 43’te verilmiştir. Varsayılan kesme özellikleri aynı tablonun 3ncü kolonunda verilmiştir. Fakat öncelikler yazılım ile değiştirilebilir. Tablodan portlardan gelen 7(yedi) vektörü görebilirsiniz. Bu vektörler EXTIx olarak isimlendirilirler, burada x bir sayıya karşılık gelir. Bu 7(yedi) vektör portlardan gelen 16 kesme isteğine hizmet edebilir; bazı vektörler birden fazla kesme isteği tarafından paylaşılabilir.
Derleyici tarafından kullanılan vektör tablosunun kendisi assembly dosya olarak “startup-stm32f4xx.s” dosyasının 57nci satırından itibaren bulunur. Bireysel vektörlerin işaret ettiği kesme fonksiyonları derleme sırasında bu tabloda yer alırlar ve bireysel kesme isteklerinin yürütüldüğü fonksiyonlar bu tabloda yer alan aynı isimde olmak zorundadırlar. Örneğini EXTI3 harici kesmesinin yürüteceği kesme fonksiyonu “EXTI3_IRQHandler” olmak zorundadır. Diğer kesme istekleri için kesme fonksiyonlarının isimleri bu vektör tablosundan elde edilebilir.
Daha önce belirtildiği gibi NVIC kontrolör sadece önceliklendirilmiş modda ele alınabilir ve kontrolörün register’larını değiştiren fonksiyonlar ile kolayca ayarlanabilir. Bu fonksiyonlar aşağıdaki gibidir;
NVIC_EnableIRQ(IRQ#)
IRQ# ile belirtilen kesme isteiğini aktif duruma getirir. RM0090 teknik dokümanında sayfa 252 Table 44’ün ilk kolonunda verilmiştir. IRQ# numaraları “stm32f4xx.h” dosyasında 157nci satırdan itibaren tanımlanmıştır.
NVIC_DisableIRQ(IRQ#)
Verilen kesme isteğini (IRQ#) pasif duruma getirir.
NVIC_SetPendingIRQ(IRQ#)
Verilen kesme isteğini bekleme durumuna alır.
NVIC_ClearPendingIRQ(IRQ#)
Bekleme durumunda olan kesme isteğinin bekleme durumundan çıkarır.
NVIC_GetPendingIRQ(IRQ#)
Verilen kesme isteğinin beklemede olup olmadığını sorgular. IRQ# beklemede ise sıfırdan farklı bir değer ile döner.
NVIC_GetPriority(IRQ#)
Verilen kesme isteğinin ayarlanmış olan öncelik seviyesini verir.
EXTI kontrolör portların tüm bitlerinden gelen kesme istek sinyallerini işler ve 16 hat üzerinden NVIC kontrolöre geçmesini sağlar. Port üzerinden gelen sinyaller için 16-bit’lik Multiplexer’lar kullanılmıştır.
Figür 2. EXTI kontrolör donanımı; mavi kutucuklar register’ları, kırmızı kutucuklar giriş pinlerini belirtir.
Kesme isteği sinyalleri Multiplexer’lar ile süzülerek kullanılmaktadır. Tüm portların bit-0’ları bir multiplexer’a girer ve bunlardan biri EXTI0 kesme isteği sinyali ile kullanılabilir. Bahsi geçen multiplexer SYSCFG_EXTICR[0] register’ının 4 düşük (LSB) bit’i ile kontrol edilir. “0010” kombinasyonu ile PC00 seçilir. Tüm portların bit-1’leri bir sonraki multiplexer’a girer ve bunlardan biri EXTI1 kesme isteği sinyali ile kullanılabilir. Multiplexer SYSCFG_EXTICR[0] register’ının sonraki 4(dört) bit’i ile kontrol edilir. Aynı patern diğer bit’lerde tekrarlanır.
Ortaya çıkan yol 23-bit genişliğindedir ve edge detection(kenar dedektörü) devresine girer. Bir kesme sinyali yükselen veya düşen kenarda oluşabilir ve 23(yirmi üç) sinyalin hangi kenarında gerçekleşeceği EXTI_RTSR ve EXTI_FTSR register’larının bit’leri ile aktif edilir.
Bir kesme isteği yazılım tarafından yönlendirilebilir. Kesme işlemi donanım tarafından başlatıldı ise EXTI_SWIER register’ının bir biti set edilerek kurulur. Ancak kesme isteği sinyallerinin tümü kesmeyi tetikleyemez.
Kendi kesme isteği sinyalini aktif etmek için EXTI_IMR register’ının belirli bit’leri maskelenir. Aktif edilen kesme istekleri figür 2’de üst taraftaki AND(ve) kapısından geçer ve NVIC kontrolörü girişinden önce sıraya atılır.
İşlemci yüksek öncelikli kesme fonksiyonlarını işletirken, düşük öncelikli isteklerin işletilmesini bekletmek zorundadır. Bu “pending request” (bekleyen kesme istekleri) olarak adlandırılır. Yazılım EXTI_PR register içeriğini inceleyerek bekleyen istekleri kontrol edebilr. Aynı register aynı zamanda kesme isteğini hatırlatır ve kesme fonksiyonu içerisinde yazılımla temizlenmelidir. Kesme isteği bit’e high yazılarak temizlenir.
Portlar, NVIC kontrolör ve EXTI örneğinde ilk kurulumlar yapılır ve sonsuz döngüye girilir. Burada “IRQcount” değişkeninin içeriği periyodik olarak LCD’ye yazılır. EXTI3_IRQHandler kesme fonksiyonu kullanılmaktadır. Bu fonksiyon yukarıda da bahsi geçmiş olan PortE üzerindeki butona basıldığında çağrılır ve “IRQcount” değişkeninin değeri artırılır. Demo program aşağıda verilmiştir.
#include "stm32f4xx.h"
#include "LCD2x16.c"
int IRQcounter = 0; // IRQcounter tanımlanır ve ilk değeri verilir
void main (void) {
RCC->AHB1ENR |= 0x10; // PortE clock aktif edilir.
RCC->APB2ENR |= 0x00004000; // Clock SYSCFG - system configuration controller
GPIOE->MODER |= 0x55550000; // PortE üst yarısındaki pinler çıkış olarak ayarlanır
LCD_init(); // LCD kurulumu yapılır
LCD_string("Number of IRQs:", 0x00); // LCD’ye verilen string basılır
NVIC_EnableIRQ(EXTI3_IRQn); // EXTI3_IRQn harici kesme sinyali aktif edilir
SYSCFG->EXTICR[0] = 0x4000; // select PE to make IRQ EXTI3
EXTI->RTSR |= 0x00000008; // EXTI3 için pozitif kenar kesmesine izin verilir.
EXTI->IMR |= 0x00000008; // EXTI3 kesmesi aktif edilir.
while (1) {
LCD_uInt16(IRQcounter,0x40,1); // IRQ count LCD’ye yazılır
LCD_uInt16(GPIOE->IDR & 0x3f,0x48,1);
for (int i = 0; i<100000; i++) {}; // zaman gecikmesi
};
}
// IRQ kesme fonksiyonu
void EXTI3_IRQHandler (void) {
IRQcounter++; // değişken değerini artır
EXTI->PR = 0x0008; // EXTI3 kesme bayrağını temizle
GPIOE->ODR |= 0x0100; // IRQ fonksiyonunun uygulanmasını göstermek için ilave
GPIOE->ODR &= ~0x0100; // yürütme sonu, yaklaşık 300ns
}
Şimdilik bu kadar arkadaşlar
Sorularınız ve önerileriniz için m.hakki.kaplan@gmail.com adresinden her zaman bana ulaşabilirsiniz.
Hakkı KAPLAN