STM32F4 Discovery Maceraları – 4

Daha önceki yazımızda örnek bir led yakıp söndürme uygulamasına ait kodları vermiştik. Ve kabaca kodlar hakkında bir kaç kelam etmiştik. Hemen bir özet geçelim. Yazdığımız yazılımı yüklediğimiz kartımıza elektrik verildiği anda dahili bir clk kaynağı ile başlangıç komutları işletilir. Bunu bir nevi bilgisayarın açılış rutinine benzetebilirsiniz. Çünkü mikrodenetleyicimiz ilk açılış anında hangi hızla çalışması gerektiği nelerin etkin nelerin devre dışı olduğunu bilmiyor ve açılış bilgilerinin yüklenmesi gerekiyor. Haliyle bu ilk çalıştırma anı için gerekli clk kaynağını dahili bir üreteçten sağlıyor. Daha sonra bizim başlangıç rutinlerimiz işlendiğinde yaptığımız pll ayarlarımız işleme alınıyor ve çalışması gereken hıza ulaşıyor. Bu noktada farklı hızlarda çalışma yeteneğine sahip olan AHB ve APB adlı veri yollarından bahsetmemiz gerekir. Her biri iki adet olan bu veri yollarından AHB1 ve AHB2 168 MHz hızına kadar çıkabiliyor ve yüksek veri trafiğine sahip ethernet, usb, kamera arayüzü v.b. bileşenlerin sorunsuzca haberleşmesini sağlıyor. APB2 veri yolu ise azami 84 MHz hızına ulaşabiliyor. Ve son olarak APB1 ise 42 MHz çalışma frekansına sahip. Bu veri yollarının tam yapısına DM00037051.pdf dosyasının 18. sayfasından ulaşabilirsiniz. Kısaca bu yapıya da değindikten sonra bir önceki yazımızda verdiğimiz led yakıp söndürme uygulaması hakkında konuşmaya devam edelim. Bu kod parçası üzerinde bu kadar durmamın sebebi ise, içerisinde hem STM32F4 kütüphanesine ait fonksiyonları bulundurması hem de “register” seviyesinde atamaların yapılıyor olması. Yani karma bir yapıya sahip olması. Dilerseniz satırları incelemeye başlayalım.

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

Satırı ile GPIOD  için clk işaretimizi etkinleştiriyoruz. Buradan da anlayacağınız üzere diğer giriş-çıkış birimleri içinde aynı ayarlamayı yapmak mümkün. Bu sayede kullanmadığımız arabirimlerin clk kaynağını devre dışı bırakabiliyoruz. Peki bu komutun bu olduğunu nereden biliyoruz? İlk paragrafta DM00037051.pdf dosyasını incelemeniz gerektiğini belirmiştim. Kullandığımız dahili bileşenlerin çalışması için öncelikle o bileşene ait veri yolunu besleyen saat kaynağının etkinleştirilmesi gerekiyor. GPIOD birimi AHB1 veri yoluna bağlı. Bu veri yoluna ait saat kaynağını yöneten register ise RCC_AHB1 içindeki 3.bit (Bknz: DM00037051 Sayfa:110). Bu bit 1 olduğunda ilgili kaynak etkin, 0 olduğunda ise ilgili kaynak devre dışı oluyor. Bu kaynağı etkinleştirmek için doğrudan olarak bu registere değer atayabiliriz. Ya da kütüphanemizin bize sağladığı yukarıda verilen fonksiyonu kullanabiliriz. Bu noktada bir diğer önemli başvuru kaynağımızdan sözetmemiz gerekiyor. STM32F4 için sağlanan kütüphaneye ait kullanım klavuzu stm32f4xx_dsp_stdperiph_lib_um.chm adlı dosya. Kullandığımız donanım için sağlanan tüm fonksiyonlar ve kullanımları bu dosyada anlatılıyor. Bu kütüphaneyi kullanarak kod yazmak bize daha kolay taşınabilen bir kod olarak fayda sağlayacaktır.

  1. GPIO_InitTypeDef GPIO_InitStructure;
  2. ...
  3. ...
  4. ...
  5. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  6. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  7. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  8. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  9. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  10. GPIO_Init(GPIOD, &GPIO_InitStructure);

Clk kaynağımızı etkinleştirdikten sonra sıra geldi kullandığımız giriş-çıkış biriminin ayarlarını yapmaya. İlk olarak 1 numaralı satırda bir “structure” tanımlaması yapıyoruz. Tip olarak ise stm32f4xx_dsp_stdperiph_lib_um.chm dosyasından ayrıntılarına ulaşabileceğimiz “GPIO_InitTypeDef” biçimini kullanıyoruz. 5. satırda kullanacağımız bacakları belirtiyoruz. 6. satırda ise belirttiğimiz bacakların giriş ya da çıkış olacağını tanımlıyoruz. 7. satırda bu bacakların çıkış tipini belirliyoruz. 8. satırı açıklamak biraz zor olacak. Kullandığımız bacakların çalışma frekansına göre uygun tepkiyi verebilmesini sağlamak için hız ayarını yaptığımız yer burası. Kısaca açıklamak gerekirse daha düşük hıza ayarlanmış bir bacağı belirtilen hızın üzerinde bir şekilde çalıştırmaya kalkarsak sinyal geçişlerinde bir takım tutarsızlıkların oluşacağını söyleyebiliriz. 9. satırda ise kullandığımız bacağın “pull-up” ve “pull-down” ayarlarını yaptığımız yer. Son olarak 10. satırda yaptığımız tanımlamları GPIO_Init fonksiyonuna girdi olarak verip GPIOD bileşeninin ayarlarını tamamlamış oluyoruz. Kısa kısa açıkladıktan sonra bu ayarları nasıl olup da yapıyoruz kısmına gelelim. İlk olarak DM00037051.pdf dosyasının 148. sayfasından itibaren başlayan GPIO birimlerine ait register bilgilerini içeren dökümanı inceliyoruz. Daha sonra ise stm32f4xx_dsp_stdperiph_lib_um.chm dosyasında bulunan “Modules–>STM32F4xx_StdPeriph_Driver–>GPIO–>Functions” başlığını inceliyoruz.

Aslında yukarıda verdiğimiz kodların yaptığı aşağı yukarı şuna benziyor :

GPIOD->MODER  = 0x55000000; //12,13,14,15 Nu. pinler çıkış 
GPIOD->OTYPER = 0x00000000; //Çıkış bacakları push-pull 
GPIOD->OSPEEDR= 0xFFFFFFFF; //Çıkış bacak hız bilgisi 100MHz 
GPIOD->PUPDR	= 0x00000000; //No pull-up,pull-down

Bir önceki kodlarda kütüphane yardımıyla yaptığımız ayarları burda doğrudan register değerlerini atayarak yaptık. İlk yazılan kod kütüphane tarafından sağlanan fonksiyonları kullanıyor, ikinci yazdığımız kod ise yine aynı işi yapıyor fakat doğrudan register temelinde atama yaptığımız için taşınabilirlik adına sıkıntılı bir seçim olabilir.

Şimdi de ledleri yakıp söndürdüğümüz kısmı inceleyelim. Aşağıda verilen kod parçasından da göreceğiniz üzere register seviyesinde bir atamadan söz edebiliriz. GPIOD’nin çıkış bilgisini saklayan register içeriklerine doğrudan müdahale ile işlem yapıldığı görülüyor.

/* Set PD12 Green */
GPIOD->BSRRL = GPIO_Pin_12;
/* Reset PD13 Orange, PD14 Red, PD15 Blue */
GPIOD->BSRRH = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

Pekala aynı işi bir de kütüphanenin bize sağladığı fonksiyonlar ile yapalım. Burda da karşımıza birden fazla seçenek çıkıyor. İlk olarak bit işlemleri kullanarak yazalım.

  1. /* Set PD12 Green */
  2. GPIO_SetBits(GPIOD,GPIO_Pin_12);
  3. /* Reset PD13 Orange, PD14 Red, PD15 Blue */
  4. GPIO_ResetBits(GPIOD,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);

Görüldüğü gibi doğrudan register içeriklerini değiştirmek yerine okunabilirliği daha fazla olan ve ne iş yaptığı açık olan “set” ve “reset” fonksiyonlarını kullandık. Peki bu işlemleri bir kerede yapmak istersek?

  1. GPIO_Write(GPIOD,0x1000);
  2. Delay(10000000L);
  3.  
  4. GPIO_Write(GPIOD,0x2000);
  5. Delay(10000000L);
  6.  
  7. GPIO_Write(GPIOD,0x4000);
  8. Delay(10000000L);
  9.  
  10. GPIO_Write(GPIOD,0x8000);
  11. Delay(10000000L);

Görüldüğü gibi set-reset işlemleri yerine doğrudan GPIOD çıkışına gerekli değerleri yazdırarak da işlemizi tamamlayabiliyoruz. Geçen yazıda verdiğim led yak söndür uygulamasının son hali ise şöyle:

#include "stm32f4xx.h"
 
GPIO_InitTypeDef  GPIO_InitStructure;
 
void Delay(__IO uint32_t nCount) {
  while(nCount--) {
  }
}
 
int main(void) {
  /* GPIOD Periph clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
 
  /* Configure PD12, 13, 14 and PD15 in output pushpull mode */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
 
  while (1) {
 
    GPIO_Write(GPIOD,0x1000);
    Delay(10000000L);
 
    GPIO_Write(GPIOD,0x2000);
    Delay(10000000L);
 
    GPIO_Write(GPIOD,0x4000);
    Delay(10000000L);
 
    GPIO_Write(GPIOD,0x8000);
    Delay(10000000L);
  }
}

DEVAM EDECEK…

2 thoughts on “STM32F4 Discovery Maceraları – 4

  1. hakan dedi ki:

    Merhabalar. GPIOx_ODR bu register ile GPIOx_BSRRL bu register arasındaki fark nedir? Yani eğer ben herhangi bir portun herhangini bir biti 1 yada sıfır yapmak için hangi registeri kullanmam gerek?

  2. muuzoo dedi ki:

    ODR registeri ile porta bir kerede tüm değer ataması yapıyoruz.BSRRL ve BSRRH ile bit bazında kontrol edebiliyoruz.

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir