STM32F4 Discovery ve Ubuntu Bölüm-3

İlk iki yazımızda temel olarak geliştirme ortamının nasıl kurulacağını ve örnek proje ayarlarını anlattık. Şimdi ise basit bir örnek yapalım ve ısınma turlarına başlayalım. Nasıl ki program yazmaya başlayanların ilk uygulaması “Merhaba Dünya!” ise elektronik ile uğraşanların ilk uygulaması da Led yakıp söndürmektir. Kartımızda ivme algılayıcısının etrafına yerleştirilmiş olan 4 ledi sırasıyla yakıp söndüren bir uygulamaya ait kodu deneyelim. Bu çalışmaya ait orijinal kaynak için BURAYA bakabilirsiniz.

main.c   
#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) {
    /* 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;
    Delay(10000000L);
 
    /* Set PD13 Orange */
    GPIOD->BSRRL = GPIO_Pin_13;
    /* Reset PD12 Green, PD14 Red, PD15 Blue */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15;
    Delay(10000000L);
 
    /* Set PD14 Red */
    GPIOD->BSRRL = GPIO_Pin_14;
    /* Reset PD12 Green, PD13 Orange, PD15 Blue */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
    Delay(10000000L);
 
    /* Set PD15 Blue */
    GPIOD->BSRRL = GPIO_Pin_15;
    /* Reset PD12 Green, PD13 Orange, PD14 Red */
    GPIOD->BSRRH = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;
    Delay(10000000L);
  }
}

Bu koda ek olarak gereken kütüphane dosyası

#ifndef __STM32F4xx_CONF_H
#define __STM32F4xx_CONF_H
 
/* Includes ------------------------------------------------------------------*/
/* Uncomment the line below to enable peripheral header file inclusion */
// #include "stm32f4xx_adc.h"
// #include "stm32f4xx_can.h"
// #include "stm32f4xx_crc.h"
// #include "stm32f4xx_cryp.h"
// #include "stm32f4xx_dac.h"
// #include "stm32f4xx_dbgmcu.h"
// #include "stm32f4xx_dcmi.h"
// #include "stm32f4xx_dma.h"
// #include "stm32f4xx_exti.h"
// #include "stm32f4xx_flash.h"
// #include "stm32f4xx_fsmc.h"
// #include "stm32f4xx_hash.h"
#include "stm32f4xx_gpio.h"
// #include "stm32f4xx_i2c.h"
// #include "stm32f4xx_iwdg.h"
// #include "stm32f4xx_pwr.h"
#include "stm32f4xx_rcc.h"
// #include "stm32f4xx_rng.h"
// #include "stm32f4xx_rtc.h"
// #include "stm32f4xx_sdio.h"
// #include "stm32f4xx_spi.h"
// #include "stm32f4xx_syscfg.h"
// #include "stm32f4xx_tim.h"
// #include "stm32f4xx_usart.h"
// #include "stm32f4xx_wwdg.h"
// #include "misc.h"
 
#ifdef  USE_FULL_ASSERT
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
  void assert_failed(uint8_t* file, uint32_t line);
#else
  #define assert_param(expr) ((void)0)
#endif
 
#endif

Verilen kodları projenize ekleyip derlediğinizde kısa yoldan bir led yakıp söndürme uygulamasına sahip olacaksınız.Eclipse altında projenize bu kodları eklemek için yapmanız gerekenler şunlar. Ana program doysası için:

  1. Sol taraftaki Project Explorer penceresinden proje dizinine sağ tuş ile tıklayın
  2. New->Source File Seçeneğini seçin
  3. Açılan pencerede “main.c” adını vererek işlemi tamamlayın.

Oluşturduğunuz boş dosyaya verdiğim ilk kodu kopyalayıp yapıştırabilirsiniz. Sıra geldi ikinci koda. Bir “header” dosyası olduğu için onun için de benzer bir şekilde boş bir “header” dosyası oluşturuyoruz.

  1. Sol taraftaki Project Explorer pencerisinden proje dizinine sağ tuş ile tıklayın
  2. New->Header File seçeneğini seçin
  3. Açılan pencerede “stm32f4xx_conf.h” adını vererek işlemi tamamlayın.

Oluşan boş dosyaya verdiğim ikinci kodu kopyalayıp yapıştırabilirsiniz. Şimdi gelelim kodu yükleyip çalıştırmaya. Kodları kaydettikten sonra sırası ile şu adımları takip ediyoruz.

  1. Run->External Tool->ST-Link diyerek ST-Link’in çalışmasını sağlıyoruz. Ya da kısa yoldan böcük simgesinin sağ tarafındaki ikinci simgenin yanındaki ok işaretine basarak açılan pencereden ST-Link uygulamasını seçebiliriz.
  2. Run->Debug Configuration seçeneğinden ayarlarınızı kaydedip debug işlemini başlatıyoruz. Size debug penceresinin açılacağına dair bir uyarı verir.
  3. Kodlar ST-Link üzerinden yüklenmeye başlayacaktır. Sağ alt köşede blunan bildirimden durumu takip edebilirsiniz. Kodlarınız yüklendikten sonra sisteminiz “reset” durumunda sizin emrinizi beklemektedir.F8 tuşuna basarak ya da “play” simgesine tıklayarak kodunuzu çalıştırabilirsiniz. Aşağıda debug penceresine ait bir ekran görüntüsü ekliyorum.

Şimdi Biz Ne Yaptık?

Üniversitedeki hocalarımdan birinin de dediği gibi “kopyala yapıştır-yükle çalıştır” yöntemiyle bir çalışma yaptık. Yaptık yapmasına da adama demezler mi, arkada neler oluyor. Biz neyi neden yazdık? Nerede ne oluyor? Şimdi bu konuyu inceleyelim. Hatırlarsanız önceki yazı dizilerimizde örnek proje ayarlarını yaparken proje dizinimize bir kaç dosya kopyalamıştık. Bu dosyalardan “startup_stm32f4xx.S” ve “system_stm32f4xx.c” adlı dosyalar bu konu için anahtar bilgiler içeriyor.

İlk Çalışma Anında Olanlar

Devremize verdik gücü ya da yeniden başlattık diyelim. İçeride neler oluyor peki? İlk olarak dahili osilatör kaynağı ile sistem başlatılır ve başlangıç kodlarımızı içeren “startup_stm32f4xx.S” dosyası çalıştırılır. Bu dosya içinde sistemimiz için gerekli vektör tabloları hazır olarak oluşturulmuştur. Bu dosya içinden bir diğer dosyamız olan “system_stm32f4xx.c” dosyamızda bulunan “SystemInit” fonksiyonu çağrılır ve olaylar olaylar… 🙂 SystemInit safhası tamalandıktan sonra ise ana programımız işletilir. Eğer derseniz ki bu olaylar hangi satırlarda gerçekleşyor, “startup_stm32f4xx.S” dosyası içindeki şu satırlar bunu sağlıyor. SystemInit safhasına kadar dahili saat kaynağımızla çalışıyoruz.

/* Call the clock system intitialization function.*/
  bl  SystemInit
/* Call static constructors */
//    bl __libc_init_array
/* Call the application's entry point.*/
  bl  main

 

SystemInit fonksiyonumuz çağrıldı. İşte zuranın zırt dediği yere geldik. Mikrodenetleyicimizin başlangıç ayarlarını yaptığımız yer burası. Foksiyon içeriğimiz aşağıdaki gibi.

void SystemInit(void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */
  #endif
 
  /* Reset the RCC clock configuration to the default reset state ------------*/
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;
 
  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;
 
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;
 
  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x24003010;
 
  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;
 
  /* Disable all interrupts */
  RCC->CIR = 0x00000000;
 
#ifdef DATA_IN_ExtSRAM
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM */
 
  /* Configure the System clock source, PLL Multiplier and Divider factors, 
     AHB/APBx prescalers and Flash settings ----------------------------------*/
  SetSysClock();
 
  /* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}

 

Gönül isterki yukarıdaki tüm işlemleri açıklayayım fakat sıkıcı olacaktır. Eğer yapılanları merak ediyorsanız DM00031020.pdf dosyasını inceleyebilirsiniz. İlgili başlık RCC (Reset and Clock Control). Şimdilik bu ön tanımlı ayarlarla gidebiliriz. Kodu incelediğinizde bir yerde SetSysClock() fonksiyonun çağrıldığını göreceksiniz. Frekans ayarlarımızın yapıldığı yer ise burası. Peki bu ayarlar neyi baz alarak işlem yapıyor? Frekans ayarlamasına ilişkin bilgi DM00031020.pdf dosyasına bulunmasına karşın özetlemek gerekirse şu değişkenlerin durumuna göre hesap edilip bulunuyor:

  • HSE_VALUE (Hatırlarsanız kurulum sırasında 8000000 değerini vermiştik.)
  • PLL_M, PLL_N
  • PLL_p, PLL_Q

Aslında olay oldukça basit. “system_stm32f4xx.c” dosyasını iyice incelerseniz yapılan işlemleri kolaylıkla anlayabilirsiniz. Hemen ilgili satırları inceleyelim:

/************************* PLL Parameters *************************************/
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      25
#define PLL_N      336
 
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2
 
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7
 
/******************************************************************************/

 

Örnek çalışmamıza göre hsaplarsak PLL_VCO = (8.000.000/25)*336 sonucunda 107.520.000 değerini buluyoruz. Bu durumda çalışma frekansımız olan SYSCLK = 107520000 / 2 sonucunda 53.760.000 (53,76 Mhz) gibi saçma bir değere eşit oluyor. USB hattını besleyen clk kaynağının frekansı ise daha da saçma olan 107.520.000 / 7 sonucunda 15.360.000 (15,36 MHz) oluyor. Fakat bu hat mutlaka 48 MHz ile beslenmeli. Demek ki neymiş hazır dosyalara balıklama atlamıyoruz ve iyice inceliyormuşuz. Bizim led yakma örneğimiz sorunsuz çalışmış olabilir fakat bu diğer kritik uygulamaların sorunsuz çalışacağı anlamına gelmiyor. O yüzden hemen kendimiz hesap ediyoruz. İsteklerimiz şunlar azami hız olan 168 MHz hızında çalışalım ve USB donanımı için gereken 48 MHz hızı elde edelim. Hemen formüllerden yola çıkıyoruz.

  • 168.000.000 = PLL_VCO / 2 işlemine göre PLL_VCO=336.000.000 olmalı
  • 336.000.000 = (8.000.000/ PLL_M)*PLL_N işleminde PLL_N değerini 336 olarak kabul edip PLL_M değerini hesaplarsak PLL_M=8 olduğunu buluruz.
  • Bu durumda PLL_Q değeri 7 olarak kalır ve 48MHz’e eşit olur. (336.000.000/7)

Örnek çalışmamızda sadece “system_stm32f4xx.c” dosyası içindeki tanımlamalardan PLL_M değerini 8 yaparak tekrar derlediğimizde ledlerin daha hızlı yanıp söndüğünü göreceksiniz.

UYARI: Sakın ama sakın bu değerleri kafanıza göre değiştirmeyin. Önce kullanım klavuzunu inceleyin. Çünkü bu değerlerin belirli alt ve üst limitleri var. Bunların dışına çıkarsanız kartınıza zarar verebilirsiniz. !!!

Şimdilik arka tarafta olanları kısaca anlattık. Yazı biraz uzayacağı için verdiğimiz programda yaptıklarımızı da bir sonraki yazıda anlatacağız.

DEVAM EDECEK…

7 thoughts on “STM32F4 Discovery ve Ubuntu Bölüm-3

  1. gokhan dedi ki:

    Hocam çok güzel anlatmışsınız, stm32f4 discovery kit sipariş ettim bende başlayacağım artık. Anlaşılan bir led yakmak için bile uzun uzun kodlar gerekiyor.

  2. muuzoo dedi ki:

    İşinize yaradıysa ne mutlu. Aslında çok kod kalabalığı yok, bir kere templete proje oluşturdunuz mu gerisi kolay.

  3. Lokman dedi ki:

    Merhaba gerçekten güzel bir derleme olmuş ellerinize sağlık.Ben uygulamayı yapmaya çalıştım aynen anlattığınız gibi dereleme hatası olarak şöyle bir hata alıyorum

    **** Build of configuration Debug for project deneme ****

    make all
    Building file: /opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c
    Invoking: ARM Sourcery Linux GCC C Compiler
    arm-none-eabi-gcc -DUSE_STDPERIPH_DRIVER -DUSE_STM32_DISCOVERY -D”HSE_VALUE= 8000000″ -I/opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/CMSIS/Include -I/opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include -I/opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/STM32F4xx_StdPeriph_Driver/inc -I”//home/lokman/workspace/deneme” -O0 -Wall -Wa,-adhlns=”src/misc.o.lst” -c -fmessage-length=0 -MMD -MP -MF”src/misc.d” -MT”src/misc.d” -mcpu=cortex-m4 -mthumb -g3 -gdwarf-2 -o “src/misc.o” “/opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c”
    In file included from /opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/STM32F4xx_StdPeriph_Driver/inc/misc.h:38:0,
    from /opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/STM32F4xx_StdPeriph_Driver/src/misc.c:76:
    /opt/STM32F4xx_DSP_StdPeriph_Lib_V1.1.0/Libraries/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h:79:3: error: #error “Please select first the target STM32F4xx device used in your application (in stm32f4xx.h file)”
    make: *** [src/misc.o] Error 1

    **** Build Finished ****

    Biraz araştırdım root hakları ile alakalı bi sorun olduğu söyleniyor benim dosya hiyerarşiğim
    /opt/CodeSourcery
    /opt/stlink
    /opt/STm….Perıph_Dri…
    /opt/eclipse/eclipse

    Dosya izinleri de şu şekilde

    root@lokman:/opt# ls -l
    total 16
    drwxrwxrwx 9 root root 4096 Sep 13 15:48 CodeSourcery
    drwxrwxr-x 9 root root 4096 Sep 13 17:42 eclipse
    drwxrwxrwx 2 root root 4096 Sep 13 16:05 stlink
    drwxrwxrwx 6 root root 4096 Sep 13 17:05 STM32F4xx_DSP_StdPeriph_Lib_V1.1.0

    Yardımlarınız ve güzel yazılarınız için teşekkür ederim.

  4. muuzoo dedi ki:

    Yanlış anlamadıysam uygun header dosyası projeye dahil edilmemiş gibi. O yüzden derleyici hangi st32f4xx serisine göre derleme yaptığını anlamamış sanki. Projenizde “stm32f4xx.h” dosyası ekli mi acaba bir de “stm32f4xx_conf.h” dosyası da ekli mi?

  5. lokman dedi ki:

    Evet herşeyi anlattığınız gibi yaptım

  6. lokman dedi ki:

    Eğer teamwiwerdan yardımcı olursanız çok sevinirim

  7. muuzoo dedi ki:

    Merhaba, email adresim üzerinden haberleşerek size yardımcı olmaya çalışırım. Uygun olduğunuz vakitleri bana bildirirseniz sevinirim.

Bir Cevap Yazın

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