3 min read

[TR] STM32 Register-based: LED On/Off with User Button Interrupt

Ben bu yazıda STM32 Nucleo-L053R8 kullanacağım. Öncelikle yapmamız gereken aşamaları sıralamakta fayda var.

  1. Kullanıcı butonunun GPIO pini giriş soketi olarak ayarlanmalı ve Pull-Up/Pull-Down seçimi yapılmalı.
  2. Kullanıcı LED'inin pini için çıktı modu seçilmeli.
  3. İki GPIO pinine de clock sinyali verilmeli.
  4. Butonun pinini, ilgili EXT yolununun çoklayıcısında seçmeliyiz.
  5. Interrupt Mask Register'ın ilgili EXT yolunun biti 1'e çevrilmeli ki ilgili yol maskelenmesin.
  6. Buton basışından sonra oluşacak elektrik sinyalinde "rising" kenarın mı "falling" kenarın mı yoksa her ikisinin de tespit edilmesini mi istiyoruz, bunu belirtilmeli.
  7. Kullanıcı LED'inin pini için çıktı modu seçilmeli.
  8. Bir Interrupt Handler Fonksiyonu yazılmalı.
  9. Kesme fonksiyonumuz gerçekleştirildikten sonra EXTI Pending Register'da ilgili biti 1 olarak ayarlanmalı.

Benim kullandığım kartta kullanıcı için ayrılmış olan buton PC13 girişine bağlı. Bunu mikrodeneteyleyicinin şematiğinden bulduk. GPIO işlemlerinde yapmamız gereken C portunun (buton orada olduğu için) clock'unu aktif etmek. Clocku aktive etmek için gerekli olan registerın adresini Reference Manual'deki "Reset and Clock Control" başlığından bulabilirsiniz. İlgili registerın adı benim kartımda GPIO clock enable register olarak verilmiş ve port C'yi açmam için 2. biti 1 yapmam gerektiği söylenmiş.

Daha sonra butonun girişinin hangi EXT yoluna bağlı olduğunu anlayabilmek için ise mikrodenetleyicinin "Reference Manuel"indeki "EXTI interrupt/event line mapping" adlı başlığına bakabilirsiniz. Burada bir şema olacak, bu şemada ise birçok çoklayıcı görüyor olacaksınız. PC13'ün bağlı olduğu çoklayıcının çıktı kanalına bakarsanız ilgili EXT'i göreceksiniz. Benim durumumda bu EXT13'tür. Buna ek olarak ilgili EXT çoklayıcısının girdi kanalı seçicisine de bakmanız gerekiyor, bunu da kullanacağız.

Bir çoklayıcı, çok sayıda olan girdiler arasındaki belirli bir girdiyi direk çıktıya aktaran sistemdir. Bu belirleme işlemi farklı bir girdi yolu ile yapılır. Örneğin 4 girdi sinyalli sistemde, 2 bitlik farklı bir girdi daha oluştururuz. Bu 2 bitlik son girdi kanalımıza verdiğimiz bitler bizim hangi sinyal kanalını seçeceğimizi belirtir. Çıktıya da seçtiğimiz sinyal yönlendirilir.

Benim kartım için EXT13 yolunu kontrol eden çoklayıcının seçimci bitlerinin, SYSCFG_EXTICR4 yazmacının (register) [4:7] bitleri olduğunu görüyorum. "Reference Manuel"deki "System Configuration Controller" başlığının altında yazmaç listesinde istediğim yazmaca bakıtığımda bize hangi giriş/çıkış portu için bitleri nasıl ayarlamamız gerektiğini söylüyor.

0000: PA[x] pin
0001: PB[x] pin
0010: PC[x] pin
0011: PD[x] pin
0100: PE[x] pin

Öyleyse benim SYSCFG_EXTICR[4:7] bitlerini 0010 olarak ayarlamam gerekiyor.

Şimdi ise sıra Interrupt Mask Register'da 13. yolun bitini, yol maskelenmesin diye için 1 yapmakta. Bunun için ben EXTI_IMR[13] bitini 1 olarak ayarlıyorum. Bu bitin numarasını ve yazmacının detaylarını yine Referans Manual'den "External Interrupt and Event Controllers" kısmından bulabilirsiniz.

Butonun sinyalinin yüksekten düşüğe düşmesi ile kesmenin tetiklenmesini istediğim için ben "falling" kenar bitini etkinleştireceğim. Bunu yapabilmek için aynı doküman üzerinden EXTI_FTSR yazmacının detaylarına bakıyorum. Dokümanın bana söylediğine göre 13. yol için 13. biti 1 yapmam gerekiyormuş.

İnterrupt sinyali alındıktan sonra ilk olarak EXT çoklayıcısından geçen sinyal en son adımda Pending devresine gelir. Bu devrede bekler. Devre ona izin verdiğinde NVIC'e geçerek ilgili işlemi gerçekleştirir. Pending devresinin izini vermesi otomatik gerçekleşse de, izini durdurması otomatik olmaz. İzin verildikten sonra NVIC'e varan sinyal bitse dahi izin bitmez. Girişleri Pending devresi ve interruptın geldiği EXT yolu olan bir OR kapısı olarak hayal ediniz, izin verilme durumunda da Pending devresinin verdiği sinyali 1 olarak hayal edin. Gördüğünüz gibi bir sorunla karşılaşmış oluyoruz. Artık interrupt sinyalimiz yok olsa dahi (yani 0), Pending devremiz 1 vermeye devam ediyor OR kapımıza. Bu kapı da çıktıda 1 veriyor ve NVIC'a bir sinyal varmış gibi gösteriyor durumu. NVIC da interrupt varmışcasına handler fonksiyonunu çağırıyor.

Bu sorunu düzeltebilmek için buton için kurduğumuz Interrupt Handler fonksiyonumuzun ardından el ile EXTI Pending Registerımızda ilgili biti 1 olarak güncellemeliyiz. Burada önemli olan "güncelleme" kelimesi çünkü dokümanda ilgili yeri okursanız, "İzini deaktif etmek için biti 1 olarak yazmanız gerekiyor." kısmını göreceksiniz. Bu size saçma gelebilir çünkü interrupt geldiğinde belleğe bakarsanız zaten o bitin 1 olduğunu göreceksiniz, önemsemeyin. Donanımsal olarak bu biti tekrardan 1 olarak güncellediğiniz zaman izni engellemiş olduğunuzu bilmeliyiz yalnızca.

/*	Pseudo Kod Hali		*/
SYSCFG_EXTICR[4:7] = 0010;	// Çoklayıcı seçimi
EXTI_IMR[13] = 1;		// Masking kapatma
EXTI_FTSR[13] = 1;		// Falling-edge ayarı

Sanırım devamı gelecekti bu yazının ancak bir türlü bitiremedim. Umarım bu kadarı dahi faydalı olmuştur!