Pages

7 Nisan 2015 Salı

Proje 3. Sistem Onay Zamanlayıcısı (SysTick Timer) Kullanarak Ledleri Yakıp Söndürmek.

Proje 3. Sistem Darbe Zamanlayıcısı (SysTick Timer) Kullanarak Ledleri Yakıp Söndürmek.

Amaç :

Bu uygulama ile sistem onay zamanlayıcısının(SysTick Timer)  nasıl kurulacağını ve 500ms'lik gecikme süresinin nasıl oluşturulup kullanılacağını öğreneceğiz.

İşlem Basamakları

  • SysTick Timer (Sistem Onay Zamanlayıcısı) nedir nasıl kullanılır öğreneceğiz,
  • STM32F429I Discovery kartının sistem saati 180Mhz olarak nasıl ayarlanır inceleyeceğiz,
  • SysTick Timer (Sistem Onay Zamanlayıcısı) Kesmesi nasıl kullanılır detaylıca öğreneceğiz,
  • SysTick Timer (Sistem Onay Zamanlayıcısı) /Counter (Sayıcı), serbest çalışma modunda periyodik kesmeler oluşturmak üzere başllatacağız
  • SysTick Timer (Sistem Onay Zamanlayıcısı) kemesi her 1ms'de bir tetiklenmesini sağlayacak ve Delay fonksiyonumuzu oluşturacağız.
  • Bir gecikme fonksiyonu, SysTick Timer (Sistem Onay Zamanlayıcısı) 'na bağlı olarak sayım sonu eylemini oluşturacak ve ledlerimizi her 500ms de bir yakıp söndüreceğiz.

SysTick Timer (Sistem Darbe Zamanlayıcısı) :

SysTick basit bir zamanlayıcıdır. Diğer zamanlayıcıların input capture / output compare gibi özellikleri olduğu için, bu zamanlayıcıları sıradan zamanlama için kullanmak, işlemci kaynaklaını boşa harcamakmak anlamına gelmektedir. Yani mümkünse bunun yerine SysTick zamanlayıcısını kullanmalıyız.

SysTick zamanlayıcısı ARM mimarisinde çekirdeğin temel zamanlayıcı fonksiyonu olduğundan cmsis altında core_cm4 kütüphanesinde bulunur.

Kütüphaneyi inceleyecek olursak ;


/* ################## SysTick function  ################## */
/** \ingroup  CMSIS_Core_FunctionInterface
    \defgroup CMSIS_Core_SysTickFunctions SysTick Functions
    \brief      Functions that configure the System.
  @{

*/

#if (__Vendor_SysTickConfig == 0)

/** \brief  System Tick Configuration

    The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
    Counter is in free running mode to generate periodic interrupts.

    \param [in]  ticks  Number of ticks between two interrupts.

    \return          0  Function succeeded.
    \return          1  Function failed.

    \note     When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
    function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
    must contain a vendor-specific implementation of this function.

 */

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);          /* Reload value impossible */

  SysTick->LOAD  = ticks - 1;                                                  /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                                 /* Enable SysTick IRQ and SysTick Timer */
  return (0);                                                                          /* Function successful */
}

#endif

/*@} end of CMSIS_Core_SysTickFunctions */


Yukarıdaki fonksiyonda kırmızı renkle yazılmış olan kısmı systick zamanlayıcısını kurmak için fonksiyonu çağırmak amaçlı kullanacağız.

SysTick_Config(uint32_t ticks)

Timer 'ın ne olduğunu hatırlayacak olursak ; Timer donanımın geçen süreyi ölçümlemek kullandığı bir yapı. Genellikle belirlenen sürenin sonuna gelindiğinde bir kesme oluşturarak sürenin sona erdiğini kullanıcıya bildirmek amaçlı kullanılır.

STM32F429 Discovery kitimizin sistem saati 180Mhz olduğuna göre systick ön tanımlı olarak saniyede 180.000.000 darbe üretmektedir,buna bağlı olarak fonksiyonumuzda uint32_t ticks değişkenine atayacağımız değer zamanlayıcının ölçümleyeceği değer olacağından 1ms lik zaman palsi üretmek için 1000 olarak atanmalıdır. 

Tabi sistem saatimizin ön tanımlı olarak 180Mhz olarak tanımlanmış olduğunu farzederek bu değeri veriyorum.

Ki kendi kartımda yaptığım ilk denemlerde maalesef SysTick_Config(SystemCoreClock/1000); olarak tanımlamamı yaptığımda ledlerin togle süresinin neredeyse 1sn yi geçtiğini gözlemleyince ciddi bir kafa karışıklığı yaşamıştım.

Şimdi size aksi bir durumla karşılaştığınızda sistem saatini nasıl 180Mhz olarak ayarlayacağınızı anlatacağım (eğer bu konuda bir sorun yaşamadıysanız bu bölümü okumanıza gerek yok yazının ilerleyen bölümlerinden devam edebilirisiniz.)

Pek çok forum alanında "stm32f4xx.h" kütüphanesinde bazı değişiklikler yapılması gerektiğinden bahsetmiş.

Yönerge aynen şöyle...

İlk olarak "stm32f4xx.h" kütüphanesini açıp aşağıda gördüğünüz satırı buluyoruz,


#if !defined  (HSE_VALUE)
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */


Bu kodda HSE_VALUE karşısında bulunan 25000000 değerinin yerine (ki bu harici osilatörün değeridir.), kendi bordumuzdaki kristal osilatörün değeri olan 8Mhz karşılığı olan "8000000" yazıp keydediyoruz. Yeni kod aşağıdaki gibi değiştirilmiş olmalı.

#if !defined  (HSE_VALUE)
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */


Bu işlemden sonra "system_stm32f4xx.c" kütüphanesini açalım ve aşağıdaki satırı bulalım.


#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
#define PLL_N      360 //Set this to 336 for 168MHz clock
 

/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2
#endif /* STM32F427_437x || STM32F429_439xx */


ve 

#if defined (STM32F427_437xx) || defined (STM32F429_439xx)
#define PLL_M      8
#define PLL_N      360 //Set this to 336 for 168MHz clock
 

/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2
#endif /* STM32F427_437x || STM32F429_439xx */


Şeklinde değiştirip kaydettiğimizde bu ayarlar STM32F429I Discovery kitimizin saat frekansını 180MHz e ayarlanmış olacak.

Son olarak aynı kütüphanede aşağıdaki satırı kontrol edeceğiz eğer görüldüğü gibi "168000000" tanımlanmış ise bunu :

uint32_t SystemCoreClock = 168000000;

yerine 

uint32_t SystemCoreClock = 180000000;

yazıp kaydediyoruz. Ve işlem tamam. Artık kitimiz 180Mhz olarak çalışmaya hazır.

Tabi bu tanımlamalardaki kontrol ve düzeltmeler yapıldıktan sonra kodumuza eklememiz gereken satırlar var :

int main(void) {  

Tanımlamasından hemen sonra uygun göreceğiniz bir yere aşağıdaki satırları yazalım.

        //HSE clock aktif ediliyor
        RCC_HSEConfig(RCC_HSE_ON);

        //Saatin stabil hale gelmesi bekleniyor.
        while (!RCC_WaitForHSEStartUp());

        //Sistem ayarlarını güncelliyoruz
        SystemInit();

Bu kodlar ile sistem saatimizi 180Mhz'e sabitliyor ve sistem saatini çalıştırıyoruz.

Şimdi dönelim kodumuza... 

systick artık 1ms lik darbeler üretebildiğine göre ledlerimizi 500ms lik periyodlar ile yakıp söndürebiliriz.


Tabi bunun için öncelikle Delay fonksiyonumuzu ve her 1ms sürenin sonunda oluşacak kesme (interrupt) yi kontrol edecek ve 500ms'lik süreyi denetleyecek fonksiyonlarımızı yazmamız gerekiyor.

İlk fonksiyonumuz 1ms de bir oluşacak kesme fonksiyonumuz ki bu fonksiyon Systick_Handler olarak anılmaktadır.

Systick_Handler fonksiyonumuzda  belirleyeceğimiz TimingDelay değişkenine atayacağımız 500ms lik süre tanımımızın her 1ms de bir bir azaltıp 500ms lik süreyi tutacağız.

kodumuz şöyle olacak ;

void SysTick_Handler(void)
{
if (TimingDelay != 0)
    {
    TimingDelay --;
    }
}

Burada TimingDelay Delay fonksiyonumuzla tanımladığımız geciktirme süresi olarak kullanılmaktadır. ifade de TimingDelay değişkeninin değeri sıfırdan farklı olduğu sürece if rutinimiz her 1ms de bir kesme oluştuğunda çalışacak ve TimingDelay değişkeninin değierini 1 azaltacak.

TimingDelay değişkenini ise Delay fonksiyonu ile belirliyoruz ki o kodumuzda şöyle olacak.

void Delay(__IO uint32_t time)
{
  TimingDelay = time;
  while(TimingDelay != 0);
}

Delay fonksiyonumuzu kodumuzun içinden Delay(500); kodu ile çağırıyoruz ve time değişkenimize 500 değerini atıyoruz. Fonksiyonumuzun içinde ise kesmemizde kullanmakta olduğumuzn TimingDelay değişkenimize time ile belirlediğimiz değeri atıyor ve TimingDelay'in değeri 0 olana kadar beklemeye başlıyoruz. Her 1ms de oluşan kesme ile TimingDelay değişkenimizin değeri bir azalıyor taki değeri 0'a eşit olana kadar.

Eşitlik 0 olduğunda Delay fonksiyonumuz sonlanıyor ve kodumuzda 500ms tanımını yaptığımız Delay(500); kodumuzun alt satırından itibaren main yürütülmeye devam ediliyor.

İşte bizde Delay fonksiyonumuzla belirlediğimiz bekleme süresini bu şekilde oluşturuyor ve sonraki satırda ledlerimizi togle ediyoruz.

  while (1)
          {
           Delay(500);
           GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14); //Ledlerimizin durumunu değiştirerek birinn yanmasını sağlarken diğerini söndürmüş oluyoruz
              }

        return 0;

Şimdi kodumuzun tamamını görelim.

/**
 *    Project template
 *
 *    @author     Zeynel Abidin Delikan
 *    @email        zdelikan@gmail.com
 *    @website    http://netmicrohouse.blogspot.com.tr/
 *    @version    v1.4
 *    @gcc        v4.9
 *    @ide        CooCox CoIDE v2.0.2
 */

#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "defines.h"
#include "core_cm4.h" // SysTick Registerlarının bulunduğu kütüphane
void Delay(__IO uint32_t time);
__IO uint32_t TimingDelay;

int main(void) {

        //HSE clock aktif ediliyor
        RCC_HSEConfig(RCC_HSE_ON);

        //Saatin stabil hale gelmesi bekleniyor.
        while (!RCC_WaitForHSEStartUp());

        //Sistem ayarlarını güncelliyoruz
        SystemInit();

        // Artık Systick zamanlayıcımız sistem saatimizin 180Mhz e kurulmasıyla
        // tam olarak 1ms'lik puls üretebilir.

        // Disco bordumuzun kırmızı ve yeşil ledlerimizi kullanmak için AHB1 i hazırlıyoruz

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);

        // GPIO port tiplerini kullanabilmek için GPIO_InitDef değişkenimizi tanımlıyoruz
        GPIO_InitTypeDef GPIO_InitDef;

        // İlk olarak GPIOG portunun pinlerini düzenliyoruz

        // Pinlerimizi Belirliyoruz

        GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
        // Pinlerimizi çıkış tipini Push Pull olarak belirliyoruz
        GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
        // Pinlerimizi çıkış olarak tanımlıyoruz.
        GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
        // Pinlerimizin çekme direncini ayarlıyoruz.
        GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
        // Pinlerimizin çalışma frekanslarını ayarlıyoruz
        GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;

        //Şimdi portlarımızı kuralım
        GPIO_Init(GPIOG, &GPIO_InitDef);

        // Şimdi ledlerimizin ilk değerlerini tanımlıyoruz.
        // Kırmızı Led "Düşük", yeşilled ise "Yüksek" durumda olacak

        GPIO_SetBits(GPIOG, GPIO_Pin_14);
        GPIO_ResetBits(GPIOG, GPIO_Pin_13);

        //Son Olarak Systick Timer'ı 1ms'ye ayarlayalım. (sistem saatimiz ön tanımlı olarak 180Mhz dir)
        SysTick_Config(SystemCoreClock/1000);

        while (1)
          {
           Delay(500); // Delay Fonksiyonumuzu çağırarak 500ms lik bekleme süresi oluşturuyoruz
           GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
              }

        return 0;
}

void SysTick_Handler(void) // Her 1ms'de bir oluşacak kesmeyi yakaladığımız fonksiyonumuz

{
if (TimingDelay != 0) // TimingDelay'in değeri sıfırdan farklı ise çalıştır.
    {
    TimingDelay --; //TimingDelay'in değeri bir azaltır.

    }
}


void Delay(__IO uint32_t time) // Delay Fonksiyonumuz
{
  TimingDelay = time; //Kesme fonksiyonunda kullanacağımız değişkenin değerini ayarlıyoruz
  while(TimingDelay != 0); //TimingDelay değişkeninin değeri sıfırdan farklı olduğu sürece döngüde kal.
}
 


Şimdi kodumuzu derleyip MCU muza yükleyip sonucu görelim.

Sonuç olarak STM32F429 Disco bordumuz üzerindeki kullanıcı ledlerimiz, gecikme fonksiyonumuzda tanımlanmış zamanlamaya bağlı olarak yanıp söner.





   

22 Mart 2015 Pazar

Proje 2 STM32F429I Disco Bordundaki Led ve Butonun Birlikte Kullanılması

KULLANICI BUTONU İLE LEDLERİMİZİN DURUMUNU DEĞİŞTİRİYORUZ !


İlk projemizde bordumuz üzerindeki kırmızı (PG14) ve Yeşil (PG13) ledlerimizi nasıl yakıp söndüreceğimizi öğrenmiştik.

Bu projemizde ise aynı projede yapacağımız değişiklikler ile yine 429I Dısco bordu üzerindeki kullanıcı uygulamaları için ayrılmış mavi renkli butona basıldığında yanmakta olan kırmızı ledimizi söndürüp, sönmüş durumdaki yeşil ledimizi yakan, tekrar buttona basıldığında ise budefa yeşil ledimizi söndürüp kırmızı ledimizi yakan ve sürekli bir döngü içinde çalışan bir uygulama geliştireceğiz.

Bir önceki yazımızda GPIO portlarını nasıl kullanacağımızı uzun uzun anlatmıştım. Bu nedenle tekrar üzerinden uzun uzadıya geçmeyeceğim.

Şimdi uygulamamızı yazmaya başlayalım.

yine aynı kütüphaneleri kullanarak başlıyoruz.
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
 int main(void)

{
429I Disco bordumuzun kırmızı ve yeşil ledlerini kullanabilmek için AHB1 i hazırlıyoruz
 

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);

GPIO port tiplerini kullanabilmek için GPIO_InitDef değişkenimizi GPIO_InitTypeDef tipinde olmak üzere tanımlıyoruz :


        GPIO_InitTypeDef GPIO_InitDef;

İlk olarak GPIOG portunun pinlerini düzenliyoruz :

        // Pinlerimizi Belirliyoruz
        GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
        // Pinlerimizi çıkış tipini Push Pull olarak belirliyoruz
        GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
        // Pinlerimizi çıkış olarak tanımlıyoruz.
        GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
        // Pinlerimizin çekme direncini ayarlıyoruz.
        GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
        // Pinlerimizin çalışma frekanslarını ayarlıyoruz
        GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;

        //Şimdi GPIOG portumuzu kuralım
        GPIO_Init(GPIOG, &GPIO_InitDef);

  
Şimdi sıra buton tanımlarının yapılmasında;Şimdide 429I Disco bordumuzda bulunan mavi butonu kullanabilmek için AHB1 i hazırlıyoruz

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);



GPIO port tiplerini kullanabilmek için GPIO_InitDef değişkenimizi GPIO_InitTypeDef tipinde olmak üzere daha önce tanımlamıştık burada da aynı tanımlamayı kullanabiliyoru, bu nedenle doğrudan GPIOA portunun pin ayarlarını tanımlamaya başlayabiliriz. 


       // Butonun bulunduğu PA0 pin'ini tanımlıyoruz
        GPIO_InitDef.GPIO_Pin = GPIO_Pin_0;
        // Pinimizi çıkış tipini Push Pull olarak set ediyoruz
        GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
        // Buton bir giriş aygıtı olduğu için pinimizi giriş olarak tanımlıyoruz
        GPIO_InitDef.GPIO_Mode = GPIO_Mode_IN;
        // Çekme direncimizi Pull Down olarak ayarlıyoruz
        GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_DOWN;
        // Son olarak buton pin hızımızı 2MHz e ayarlıyoruz
        GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;

        //Şimdi GPIOA portumuzu kuralım
        GPIO_Init(GPIOA, &GPIO_InitDef);


Bundan sonra butona basılana kadar bekleyerek, butona her basıldığında led'lerin durumunu değiştirecek olan kodumuzu yazalım.

İlk olarak ledlerimizi ilk çalışma zamanında default değerlerini tanımlıyoruz.

// Kırmızı Led "Düşük", yeşilled ise "Yüksek" durumda olacak
        GPIO_SetBits(GPIOG, GPIO_Pin_14);
        GPIO_ResetBits(GPIOG, GPIO_Pin_13);

        // Şimdi Butona basılmasını beklemek için sonsuz deönümüzü kuralım       
 
volatile int i;
        while (1)
          {

            // butona basılıp basılmadığını kontrol edelim
            if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
              {
                // Buton'a basıldığında bir parazit anı vardır. Bu parazite bouncing denir.
                // eğer bu durumu ortandan kadıracak zamanı vermezseniz led lerin kontrolsüzce
                // yanıp söndüğünü gözlemlersiniz. Bu sorunu ortadan kaldırmak için yapılan
                // işleme debouncing adı verilir butonun bu parazitten kurtulup düğmeye bastığınızı
                // algılaması için bir süre beklemeniz ve sonraki işleme bu sürenin sonunda geçmeniz gerekir
                // Şimdi Debouncing süresince beklememizi sağlayacak döngümüzü ekliyoruz.
                for(i=0;i<300000;i++){
                            }
                // Şimdi de ledlerimizin durumunu değiştirelim
                GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
              }

            }

    }


Ve uygulamamızı bitirdik. Şimdi CoIDE'ile derleyerek ST-Link ile bordumuza derlediğimiz kodumuzu atalım.

ve çalıştıralım işte sonuç !



İlk Uygulama; Bordumuz Üzerindeki Kırmızı ve Yeşil Ledi Yakıp Söndürelim !

Led Yakıp Söndürme Uygulaması

Standart uygulamamız sanırım sizinde tahmin ettiğiniz gibi bir led yak söndür uygulaması.

Bir önceki yazımızda CoIDE nin nasıl kurulup yapılandırılacağını anlatırken standart bir uygulama ekleyerek Bllink adlı bir uygulama oluşturmuş ve bu uygulamayı derleyerek CoIDE kurulumumuzun doğru biçimde yapılandırıldığını sınamıştık.

Bu bölümde işte bu standart uygulamanın nasıl oluştuğunu hangi standart kütüphanelerin kullanıldığını neden kullanıldığını ve kodlarımızı satır satır açıklayacağız.

Umarim kafalarda soru işaretleri bırakmayan bir anlatım gerçekleştirmiş olurum. (Lütfen eleştirmekten çekinmeyin ki bende hem uslubumu hem anlatımımı mükemmelleştirebileyim.)

Eveeet gelelim maydanozun fayladalarına...

İlk olarak kodumuzu genel anlamda bir görelim :

/**
 *    Project template
 *
 *    @author     Tilen Majerle
 *    @email        tilen@majerle.eu
 *    @website    http://majerle.eu
 *    @version    v1.0
 *    @gcc        v4.7 20013qr3
 *    @ide        CooCox CoIDE v1.7.6
 */
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"

int main(void) {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
        GPIO_InitTypeDef GPIO_InitDef;

        GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
        GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
        GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
        GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
        GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
        //Initialize pins
        GPIO_Init(GPIOG, &GPIO_InitDef);

        volatile int i;
    while (1) {
        // Toggle leds
        GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
        // Waste some tome
        for (i = 0; i < 500000; i++);
    }
}


Öncelikle bu çalışmaları tüm dünya ile paylaşma nezaketini gösteren Sayın Tilen Majerle bir defa daha bu vesile ile teşekkür etmek istiyorum. Ki kodun başlığındaki tanımlama satırlarını özellikle kaldırmadım ki kendisinin emeğine saygısızlık etmiş olmayalım...

Kodumuzu açıklamaya başlıyoruz.

İlk olarak kodumuzun başında "#include" komutu ile başlayan üç adet tanımlama görülmektedir.

#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"


Bu komutlar yazılım boyunca kullanacağımız ve kod yazarken kullanacağımız bir takım ön tanımlı foksiyonları ve mikrokontrolcü çekirdek tanımlamalarını içeren kütüphanelerdir.

Bunlara kısaca bir göz atacak olursak ;

#include "stm32F4xx.h" komutu temel mikrokontrolcü çekirdek tanımlamalarını içeren ve yazılımımızın tamamında kullanmamızı gerektiren çekirdek registerlarını tanımlayan bir kütüphanedir ki olmazsa olmazımızdır diyebiliriz. Bu kütüphane olmadan CoIDE bizim hangi kontrolcüyü kullandığımızı ve ne için kod yazdığımızı anlamasına imkan yok.

Bu kütüphane stm32F4xx serisi mikro kontrollerin datasheet'lerinde belirtilen tüm işlem basamaklarının temllerini sisteme tanıtır.

Bu kütüphane  aynı zamanda CoIDE kod alanının solunda yer alan ve project tabında gördüğümüz cmsis_boot ana kütüphanesinin de içeriğidir ki cmsis_boot eklenmediği taktirde kodumuz çalışmayacaktır. 
 

Aynı şekilde cmsis_core ARM mimarisinin çekirdek yapısını tanımlaması sebebiyle bulunması zorunlu olan, cmsis_lib ise GPIO, SPI, DAC, ADC, USART, SPI ve benzeri yapıların alt kütüphanelerini barındıran ve tanımlamalarımızda bizlere kolaylık sağlayan bir ana kütüphanedir.

Bu kısmı daha fazla uzatmadan kısaca geçiyorum, daha fazla ayrıntılı bilgi almak istemeniz halinde STM32F4xx datasheet lerini ve STM sitesindeki diğer dökümanları okumanızı tavsiye ederim.

gelelim kodlarımıza...

Kodları açıklamaya başlamadan önce biraz daha kafanızı şişirmek sorunda olduğum ve ciddi ciddi anlatılması gereken cmsis_lib kütüphanesinde bulunan GPIO'yu irdelememiz gerekmekte.

Öncelikle GPIO ne demek ?

Genel Amaçlı Giriş/Çıkış anlamına gelen (General Purpose Input/Output) kelimelerinin kısatmasıdır.

Mikrokontrolcülerin dış dünyaya açıldıkları ve bizlerin yazılımla hükmettikleri pinlere verilen genel bir addır aslında.

Biz programımızda bu GPIO pinlerinden 2 tanesini kullanarak iki adet ledi yakıp söndürmeyi amaçladık. Ama nasıl ? bu GPIO pinlerine nasıl hükmedeceğiz ?

İşte işin can alıcı kısmı şimdi başlıyor !

GPIO pinlerini giriş yada çıkış olarak tanımlayabilir, düşük "0" yada yüksek "1" olarak ayarlayabilir, pinlerin işlemci içerisinde Pull Up dirençlerini aktif yada deaktif edebilir (amaç portları "unstate" "belirsiz durum" da kalmaktan kurtarmaktır), çıkış tipini belirleyebilir yada çalışma hızını tanımlayabiliriz.

Peki bütün bu tanımlamalar nasıl yapılacak ? (Biraz sabır bombayı patlatıyoruz.)

I/O pinleri ile çalışabilmek için ilk işlem pin clock(saat) larını set etmektir (ayarlamaktır).

Pin saatlerini aktif edebilmek için RCC tanımlayıcısını (registeri'nı) kullanmamız gerekecek. RCC (Reset and Clock Control) Sıfırlama ve Saat Kontrol anlamına gelir.

Bütün GPIO'lar AHB1 veri yolu üzerinde konumlanmıştır. (Bkz stm32F429ZI datasheet) Biz bu veri yolu üzerindeki GPIO G port'unu kullanacağız çünkü STM32F429I Discovery kartındaki kırmızı ve yeşil ledler bu portun PG13 ve PG14 numaralı pinlerine bağlıdır.

İşte bu ledleri yakabilmek için ilk kod satırımızda pinlerin clock larını aktif hale getirmemiz gerekiyor.

Bunuda ;


RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOG, ENABLE); 

kodu ile yapacağız.

Yukarıdaki kod parçacığında RCC tanımlayıcısına AHB1 veriyolundaki çevrebiriminin saat tanımlama parçacığına GPIOG portunu kullanmak istediğimizi ve bu portun saat çevrimini aktif hale getirmesini söyledik.

Bir sonraki adımda artık pin seçeneklerinin üzerinde oynayabilmek için GPIO_InitTypeDef tipinde bir değişken tanımlamamız gerekmekte. 

Eğer projemize GPIO kütüphanesini tanımlamışsak ki #include "stm32f4xx_gpio.h" tanımıyla bunu yapmıştık bu tip değişkenini şu şekilde oluşturuyoruz ;

GPIO_InitTypeDef GPIO_InitDef; 

Burada GPIO_InitDef Değişkeni GPIO_InitTypeDef tipinde tanımlanmıştır. Bu sayede pinlerimize ait tipler bu değişken altında kullanılabilir hale geldi.

GPIO_InitTypeDef tipinin pinlerin kullanımına yönelik 5 adet tanımlama tipi mevcuttur.

Bunlar sırasıyla :


  • GPIO_Pin
Ayarlamak istediğimiz pin tanımını belirleyen tiptir.
  • GPIO_Mode 
Olay modlarını belirleyen tiptir.
  • GPIO_OType
Çıkış türünü belirleyen tiptir.
  • GPIO_PuPd
Pull Up dirençlerini belirleyen tiptir.
  • GPIO_Speed
Pin saat hızlarını belirleyen tiptir.

Buradaki her bir tip tanımının kendisine göre seçenekleri vardır. Ki tek tek ele alacak olursak :

  • GPIO_Pin Bu tip ile kullanacağını pinleri tanımlayabilirsiniz. Peki bunu nasıl yapabiliriz ? Kod örneklerini yazıp inceleyelim...
//Tek bir pin tanımlamak için örneğin GPIO_Pin_13
GPIO_InitDef.GPIO_Pin = GPIO_Pin_13;
// Eğer aynı ayarlarda daha fazla pin kullanmak isterseniz
// Komut aynı ayarlarda olan Pin 13 ve pin 14'ü tanımlar
GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
// Bu komut ise GPIO pinlerinin tamamını aynı ayarla tanımlar
GPIO_InitDef.GPIO_Pin = GPIO_Pin_All;

  • GPIO_Mode : Pin Olay Modlarını Tanımlar ve 4 Seçeneği Mevcuttur
GPIO_Mode_IN : Pin'i giriş olarak tanımlamakta kullanılır.
GPIO_Mode_OUT : Pin'i çıkış olarak tanımlamakta kullanılır.
GPIO_Mode_AF : Pin'i alternatif fonksiyonlar için tanımlamakta kullanılır (SPI,USART,I2C vb).
GPIO_Mode_AN : Pin'i Analog olaraktanımlamakta kullanılır (ADC veya DAC).

  • GPIO_OType : Pinlerin çıkış tiplerini belirlemek için kullanılır iki seçeneği mevcuttur.
GPIO_OType_PP : Çıkış tipini Push Pull yapar.
GPIO_OType_OD : Çıkış tipini Open Drain yapar.

  • GPIO_PuPd : Pull Up dirençlerini aktif yada deaktif yapmakta kullanılır.
GPIO_PuPd_UP : Pull Up direncini aktif yapmakta kullanılır.
GPIO_PuPd_DOWN : Pull Down direncini aktif etmekte kullanılır.
GPIO_PuPd_NOPULL : Pull UP yada Pull Down dirençlerini deaktif eder.

  • GPIO_Speed : Pinlerin çalışma hızlarını belirlemekte kullanılır ve dört seçeneği mevcuttur.
GPIO_Speed_100MHz : Pin çalışma hızını 100MHz'e tanımlar.
GPIO_Speed_50MHz : Pin çalışma hızını 50MHz'e tanımlar.
GPIO_Speed_25MHz : Pin çalışma hızını 25MHz'e tanımlar.
GPIO_Speed_2MHz : Pin çalışma hızını 2MHz'e tanımlar.
Şu ana kadar GPIOG portunu kullanabilmek için hangi tanımlayıcıları kullanmamız gerektiğini, bu tanımlamalar için hangi tiplerin bulunduğunu ve nasıl tanımlama yapacağımızı anlamaya çalıştık.

Şimdi ise bu bilgiler ışığında, PG13 ve PG14 pinlerini kullanarak  bordumuz üzerindeki kırmızı ve yeşil ledleri yakmaya çalışalım.

Öncelikle pin tanımlarımız nasıl olmalı ?

Biz pinleri kurarken ; çıkış olarak kullanmak üzere, Push Pull çıkış tipinde, Pull Up yada Down direnci kullanmadan 50MHz hızında bir port tanımı yapmak istiyoruz. 
O halde kodumuz bu bilgiler ışığında şu şekilde yazılmalı.


  1. //GPIOG portunu tanımlayıp saatini aktive edelim
  2. RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOG, ENABLE);
  3. // GPIO_InitDef değişkenimizi GPIO_InitTypeDef tipinde oluşturalım.
  4. GPIO_InitTypeDef GPIO_InitDef;
  5. // Şimdi Pin13 ve Pin14 ü kullanacağımızı belirtiyoruz.
  6. GPIO_InitDef.GPIO_Pin = GPIO_Pin_13|GPIO_Pin14;
  7. // Çıkış Modunu Tanımlıyoruz
  8. GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
  9. // Çıkış Tipimizi Push Pull yapıyoruz
  10. GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
  11. // Push Pull Kullanmayacağımız için hepsini deaktif hale getiriyoruz
  12. GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
  13. // Ve pin çalışma Hızımız 2MHz olacak şekilde tanımlanacak
  14. GPIO_InitDef.GPIO_Speed = GPIO_Speed_2MHz;
Sanırım buraya kadar ne yapmaya çalıştığımızı ve nasıl yaptığımızı anladık.

ama bu noktaya kadar yazdığımız kodda sisteme portları kur ve kullan demediğimizi farketmişsinizdir.

stm34F4xx'e bunu söylemek için GPIO_Init(); komutunu kullanmamız gerekiyor

Aşağıda ilk GPIO fonksiyonumuz olan GPIO_Init(); i çağıracağımız #include "stm32f4xx_gpio.h" kütüphanesindeki tanım görülmektedir.


/**
* @brief Initializes the GPIOx peripheral according to the specified parameters in the GPIO_InitStruct.
* @param GPIOx: where x can be (A..I) to select the GPIO peripheral.
* @param GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that contains
* the configuration information for the specified GPIO peripheral.
* @retval None
*/
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
Bu tanımlamanın kullanımı ise 
//Şimdi pinlerimizi kurma işlemini başlatalım ve yaptığımız tüm ayarları geçerli kılalım.
        GPIO_Init(GPIOG, &GPIO_InitDef);
 
Bu komutla STM32F4'e GPIOG portunu ve GPIO_InitDef tanımlarının tamamını kullanıma hazırla dedik.

Şu anda pinlerimiz ledlerimizi kontrol etmemiz için kullanımımıza hazır.

Fakat ledlerimiz hala kapalı konumda (yanmıyor). Onları açık konuma getirmeliyiz.

Bunu 3 şekilde yapabiliriz. Bunlar sırasıyla...


  1. // PG13 ve PG14 Pinlerinin durumlarını "Yüksek" (High) yada "1" yapalım
  2. GPIO_SetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
şeklinde olur.

Ya da eğer istersek Ledlerimizi tekrar "Düşük" (Low) yada "0" yapmak istersek ;


  1. // PG13 ve PG14 Pinlerinin durumlarını "Düşük" (Low) yada "0" yapalım
  2. GPIO_ResetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
 Şeklinde kullanabiliriz.

Veya Pinlerin durumları arasında geçiş yapmakta mümkün. Yani led durumu "Yüksek" (High) yada "1" ise "Düşük" (Low) yada "0" yapmak istersek yada yam tersini o zaman kod dizlimimiz şu şekilde olmalıdır :

  1. // PG13 ve PG14 pinlerinin durumlarını değiştirelim.
  2. // Eğer pinler "Yüksek" durumdaysa "Düşük" olacak
  3. // Eğer pinler "Düşük" durumdaysa "Yüksek" olacak
  4. GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
Şimdi geciktirme rutini olarak kullanacağımız bir For döngüzüne ihtiyacımız var ki ledlerin yanıp södüğünü gözlemleyelim. Aksi taktirde 2MHz lik bir çalışma hızında ledleri sürekli yanıyor olarak görürüz.

Bunun için öncelikli olarak bir "i" değişkeni tanımlayalım.

volatile int i;
programımızın sürekli çalışmasını istiyoruz ki ledler birkere yanıp södüğünde program durmasın ve sürekli yanıp sönme gözlemleyebilelim.

Ki bunun içinde while komutu ile bir sonsuz döngü oluşturacağız ve led durumunu bu döngü içinde değiştireceğiz. Bu durumda kodumuz : 


While (1) {
       GPIO_ToggleBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
       for (i=0; i<500000; i++);
}
 İşte uygulamamız sona erdi.

Şimdi kodumuzu CoIDE ile derleyip ST-Link Utility ile STM32F429I Discovery karımıza yükleyelim.

Ve Sonuç...



Umarım açıklamalarım sizler için çok sıkıcı ve uzun olamamıştır uygulamaya ilişkin soru ve önerilerinizi benimle paylaşırsanız çok minnettar kalırım.

Hepinize bol kod dolu günler dilerim.

 

21 Mart 2015 Cumartesi

STM32F429I Dıscovery Kartıyla İlk Uygulamamız İçin Hazırlanalım.

STM32F429ZI İle Maceramız Başlıyor


Bu gün üzerinde STM32F429ZI işlemcimizin bulunduğu STM32F429I DISCOVERY kartımızı keşfetmeye başlıyoruz.

İlk olarak STM32F429I Discovery kartını programlamak için gerekli toolları seçip kurulumunu yapalım.

Kartımızı programlamak için öncelikle kartın üzerindeki ST-Link programlayıcısının sürücüsünü kurmak gerekiyor...




ST- Link ile STM32 kartlarına program atabiliyoruz. ST-Link düzgün olarak kurulduğunda kartı taktığınızda Windows Aygıt Yöneticisinde ST-Link görülecek.


Sürücüyü kurduktan sonra ST-Link Utility’i de kurarak programlayıcının çalışıp çalışmadığından emin olabiliriz. Bunun için aşağıdaki linkten utility'i indirip kuralım...



ST-Link Utility STM32 serisi mikrokontrolcüleri programlamak için kullanılan bir arayüz.

STM32F4 Discovery kartını USB kablosuyla bilgisayara bağlayıp ST – Link Utility üzerindeki “Connect to the Target” butonuna bastığımızda aşağıdaki gibi mikrodenetleyici ile ilgili bilgilerin görünmesi gerekiyor.



Bu noktaya kadar herşeyin yolunda gittiğini düşünüyorum.

Bu arada benim bilgisayarım Windows 8.1 ve 64 Bit Intel işlemcili bir notebook.

Şimdi sıra derleyici kurulumlarında.

Derleyicinin Kurulumu


Öncelikle  aşağıdaki linkten ARM GCC derleyicisinin en son sürümünü indiriyoruz.



Kurulumu standart “next next” adımlarıyla geçiyoruz. Son adımda karşımıza çıkan checkbox’ların üçünü de işaretlememiz gerekiyor. 3. checkbox ile Windows Path değişkenlerine derleyicinin bulunduğu klasör adresi eklenmiş oluyor. Böylelikle derleyiciye komut satırından herhangi bir klasör altından erişmek mümkün hale geliyor.


GCCSetup

Böylelikle derleyiciyi de kurmuş olduk. Şimdi CooCox IDE kurulumuna geçebiliriz.

CooCox IDE Kurulumu !


Ben açık kaynaklı olması ve sürekli geliştirilmesi ve her hangi bir sınırı olmadan ücretsiz kullanıma açık olması nedeniyle Coocox IDE 'yi tercih ettim.

Bu konuda profesyonel çalışan pek çok uzman arkadaşımız, Keil yada IAR tool larını tercih etse de, bana bu ortamlar fazlasıyla karışık ve soğuk geldi açıkçası.

Neyse lafı fazla uzatmadan Coocox IDE' yi nerden indireceğimizi öğrenelim ve kuruluma başlayalım.

Coocox'un resmi web adresinden "Software Tools" tabından downlod butonuna tıklayarak siteye kayıt yaptırıp dosyayı indirelim.



Sonraki adımları takip edip kurulumu gerçekleştirelim.

Kurulumu tamamladıktan sonra masaüstünde oluşturulmuş olan CoIDE kısayolundan IDE’yi çalıştırabilirsiniz.


  
Bu arada çok sık karşılaşılan bir hata mesajını ve ne anlama geldiğini burada aktarmayı uygun görüyorum çünkü bu mesaj ilk bir hafta işi gücü bırakıp CooCox IDE de bir sorun olduğunu düşünüp defalarca kaldırıp kurmama sebep olmuştu.



"java.lang.NullPointerException" bu hata mesajının herhangi bir derleme sorununa sebep olduğunu görmedim ve forumlarda bahsedildiği üzere projenizi açık bırakıp CoIde den çıktıysanız açarken bu mesajla karşılaşıyormuşsunuz.

Ama tekrar ediyorum : Bu mesaja rağmen hiç bir şekilde beni engellediğini görmedim.

İlk Projemizi Oluşturalım

İşin bu kısmında blogumda paylaştığım ve şimdilik Tilen Majerle nin sitesini tercüme ederek aktarmakta olduğum projelere başlangıç mahiyetinde önemli bir detaydan bahsetmek istiyorum.

Arkadaşlar öncelikle Tilen Majerle in bana tavsiyesi üzerine STM32F429ZI çipi için gerekli tüm kütüphanelerin linkini paylaşıyorum. Rar formatındaki kütüphaneleri buradan indirebilirsiniz.

Burada bulunan Download Zip butonundan kütüphanenin tümünü indirebilirsiniz ki tavsiye ederim çünkü 429ZI ile çalışmak istiyorsanız bu kütüphanelere mutlaka ihtiyaç duyacaksınız.

Ayrıca standart bir başlangıç projesini de buradan indirebilirsiniz.

Coocox 'ta standart proje açılış yönergelerini izlediğimizde, Coocox'un başlangıç proje kütüphaneleri maalesef sorunlu ve projenizi derlediğinizde bir alay hata ile karşılaşıp bir türlü projelerinizi çalıştırmayı başaramıyorsunuz.

Bu nedenle sizinle başlangıç projesini özellikle paylaştım. Başlangıç projemiz bundan sonra kullanacağımız tüm kütüphaneleri barındırmakta. Bizde bu projeyi kullanarak projelerimizi gerçekleştireceğiz.

Bu durum baya dolambaçlı bir başlangıca sebep olacak ama ben daha kısa bir yolunu bulamadım açıkçası, eğer başlangıç projesini CoIDE ye tanımlamayı başaran olursa, lütfen benimle baylaşsın ki bu öğreticiyi düzeltip daha sonra faydalanmak isteyen arkadaşları uğraştırmayalım.

Peki bunu nasıl yapacağız ?

Anlatalım...

1. İlk olarak çalışma alanı için ana bir klasör belirleyerek başlangıç klasörümüzü rar dosya olarak buraya atıyoruz.


2. Sonraki adımda yeni gerçekleştireceğimiz projenin adına uygun bir klasör oluşturuyoruz...
 

3.Sonra başlangıç rar dosyamızı buraya açıyoruz.



 5. Masa üstünde bulunan kısayoldan Coocox IDE yi çalıştırıyoruz.



 6. Proje Klasörümüzdeki stm32f429_project isimli dosyanın adını projemizin adıyla değiştiriyoruz. Bunu daha sonra projeleri karıştırmamak adına yapacağız.










7. Menü çubuğundan Project Sekmesini seçip, tekrar Open Project sekmesini seçiyoruz...


8. Çalışma klasörümüzdeki projemizin adında tanımladığımız klasörün altından, proje dosyasını seçip açıyoruz.


Ve son olarak Project tabındaki proje ismini projemizin ismiyle değiştiriyoruz.

Böylece başlangıç projemizi oluşturmuş olduk hepimize hayırlı olsun.

Tabi daha işimiz bitmedi; şimdi GNU derleyicisini CoIDE ye tanıtmamız lazım.


Project menüsünden "Select Toolchain Path" sekmesini seçerek açılan alanda daha önce indirip kurmuş olduğumuz GNU Derleyicsinin konumunu tanımlıyoruz.


Yukardaki resim GNU'nun ön tanımlı kurulum noktasını görebilirsiniz muhtemelen GNU tools sizin bilgisayarınızda da aynı noktada olacaktır.

GNU Tools Path tanımlandıktan sonra artık projemizi derleyebiliriz.

Bunun için aşağıdaki resimdede görülebileceği gibi Project Build yada F7 tuşu ile projemizi derleyelim ve herşeyin yolunda olduğundan emin olalım.

Sorunsuz bir biçimde derlendiyse geçmiş olsun CoIDE başarılı bir şekilde kurulmuş demektir.

Sonraki yazımızda bu ilk başlangıç projemizin nasıl main.c dosyasını nasıl oluşturduğumuzu, hangi kütüphaneleri kullandığımızı ve ne şekilde kullandığımızı anlatacağım.

Umarım takip eden herkese  faydalı bir çalışma olmuştur.