STM32F4 Discovery Maceraları – 5 : CRC Donanımı

STM32F4 ile bir macerada daha birlikteyiz. Bu seferki hedefimiz CRC donanımını uygun bir şekilde kullanabilmek. Her zamanki gibi ilk önce güzel bir müzik açıp olaya girişiyoruz. Müziksiz olmaz :). İlk olarak STM32F4’ün olmazsa olmaz belgesi olan DM00031020.pdf dosyasını inceleyerek başlıyoruz. Göreceğiniz üzere CRC donanımı hakkında topu topu 3 sayfalık bir yer ayrılmış. Bu şu anlama geliyor; fazla teferruat yok demek. Dikkat edilecek hususlar ilk sayfada sıralanmış:

  • CRC-32 Ethernet polinomu kullanılıyor : 0x4C11DB7
  • 32 bitlik tek bir saklayıcı kullanılıyor (giriş/çıkış)
  • İşlem 4 AHB çevrim süresinde tamamlanıyor.
  • Genel maksatlı 8 bitlik bir saklayıcımız da var.
  • CRC birimi reset edilirse içeriği 0xFFFFFFFF değerini alır.

Evet bu anahtar bilgilerden sonra sıra geldi bu donanım için yazılmış olan kütüphane fonksiyonlarını incelemeye. Bunun için de stm32f4xx_dsp_stdperiph_lib_um.chm dosyasını inceliyoruz. İlgili donanım için gerekli fonksiyon tanımlamaları şunlar olarak verilmiş:

//Resets the CRC Data register (DR).
void CRC_ResetDR (void)
 
//Computes the 32-bit CRC of a given data word(32-bit). 
uint32_t CRC_CalcCRC (uint32_t Data)
 
//Computes the 32-bit CRC of a given buffer of data word(32-bit).
uint32_t CRC_CalcBlockCRC (uint32_t pBuffer[], uint32_t BufferLength)
 
//Returns the current CRC value.
uint32_t CRC_GetCRC (void)
 
//Stores a 8-bit data in the Independent Data(ID) register. 
void CRC_SetIDRegister (uint8_t IDValue)
 
//Returns the 8-bit data stored in the Independent Data(ID) register.
uint8_t CRC_GetIDRegister (void)

Bu fonksiyonlara ait ayrıntılı kullanım bilgisine bahsettiğim belgeden ulaşabilirsiniz. Burda sadece fikir vermesi açısından fonksiyon tanımlamalarını vermek istedim. Sıra geldi örnek bir çalışma yapmaya. Ayrıca bu kodu yazarken ufak bir asm kodu da kullanacağız ve c ile kod yazarken nasıl asm kodu eklenebileceğini de göreceğiz. İlk olarak crc kütüphanesini kodumuza ekliyoruz. Eğer başından beri bu sitede yazılan yazıya göre hareket ediyorsanız daha ilk çalışmamızda projemize dahil ettiğimiz “stm32f4xx_conf.h” dosyası içindeki tanımlamalardan #include “stm32f4xx_crc.h” tanımlamasını etkinleştiriyoruz. Ya da bu tanımlamayı kodumuza dahil ediyoruz, seçim size kalmış. Daha sonra da aşağıda verdiğim kodu test amaçlı kullanıyoruz.

/* CRC Donanımı Kullanımı.
 * main.c
 *
 *  Created on: 19 Temmuz 2012
 *      Author: m2k
 */
#include "stm32f4xx.h"
 
GPIO_InitTypeDef  GPIOD_InitStructure;
 
/*Bit sıralamasını tersleyen fonksiyon*/
uint32_t ReverseBit (uint32_t data) {
	asm("rbit r0,r0; bx lr");
	return data;
}
 
int main(void) {
  uint32_t sonuc = 0;
  /* GPIOD ve CRC Periph clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_CRC, ENABLE);
 
  /* Configure PD12, 13, 14 and PD15 in output pushpull mode */
  GPIOD_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIOD_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIOD_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIOD_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIOD_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
 
  CRC_ResetDR();
  GPIO_Init(GPIOD, &GPIOD_InitStructure);
 
  sonuc = ReverseBit(0x34333231);
  sonuc = CRC_CalcCRC(sonuc);
  sonuc = ReverseBit(sonuc);
  sonuc^= 0xFFFFFFFF;
 
  while (1) {
	  if(sonuc == 0x9BE3E0A3)
		GPIO_SetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
	  else
		GPIO_ResetBits(GPIOD,GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
 
  }
}

Şimdi yaptıklarımı açıklayayım. CRC donanımına sadece veri girişi yapıp daha sonra da sonucu okuyabilirdik fakat bu durumda elde ettiğimiz değerler, yazılımlarda (ethernet, winzip,winrar v.b.) kullanılan crc32 ile uyumlu değil. O yüzden bir kaç ufak numara çevirmemiz gerekti. İlk olarak bize lazım olan şey bit sıralamasını terslemek. Bunun için bir “c” fonksiyonu da yazabilirdik ama burada mikrodenetleyicimizin asm komut kümesinde bulunan “rbit” komutunu kullandık ve c içinde asm olarak çağırdık. İlgili satırlar şunlar:

/*Bit sıralamasını tersleyen fonksiyon*/
uint32_t ReverseBit (uint32_t data) {
	asm("rbit r0,r0; bx lr");
	return data;
}

Daha sonra sıralaması terslenmiş olan değerimizi ki burda kullandığım örnek değer ascii “1234” olan bilginin hex karşılığı olan “0x34333231” değerinin bit sırası terslenmiş halidir, CRC_CalcCRC fonksiyonuna giriyoruz. Burada şöyle bir bilgilendirme yapmalıyım. Şimdi kullandığımız veri olan “1234” bilgisinin yazıldığı sıraya dikkat ediniz. İlk girilen ascii “1” değerinin karşılığı olan “0x31” değeri en sağda yer almış durumda. Bu duruma dikkat ediyoruz.

CRC donanımından aldığımız değerin  bit sırasını tekrar tersliyoruz ve son larak 0xFFFFFF değeri ile xor işlemine tabi tutuyoruz. Bu işlemleri neden yapıyoruz derseniz eğer CRC32 standartının gerekliliği ile alakalı bir durum. Elde ettiğimiz değeri ise “0x9BE3E0A3” değeri ile kıyaslıyoruz. Bu değeri nasıl hesapladık derseniz BURADAKİ İnternet sitesinden kopya çektik :). Elde ettiğimiz değer doğru ise ledler yanarak bizim sonucumuz doğru olduğunu gösteriyor.

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…

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…

Hizmet Sağlayıcı Güncellemesi

Yaklaşık 4 saat süren bir çabadan sonra hizmet sağlayıcımı sunucuları Türkiye’de bulunan bir firma ile değiştirdim. Şu an yaklaşık 4 kat daha hızlı bir şekilde erişim sağlanması gerekiyor. Yaptığım ping testleri bu civarda bir oran gösteriyor. Eğer sitede gözümden kaçan bir hata varasa lütfen bildirin

STM32F4 Discovery ve Ubuntu Bölüm-2

Yazı dizimizin ilk kısmında gerekli programlardan ve kurulumlarından bahsetmiştik. Bu kısımda ise kurduğumuz programları nasıl bir araya getireceğimizi ve gerekli ayarların nasıl yapılacağını göstereceğiz. Dilerseniz sırasıyla gerekli işlemlere başlayalım.

ST-Link ve Eclipse İlişkilendirmesi

Eclipse programımızı açıyoruz ve sırasi ile bu adımları takip ediyoruz.

  1. Run > External Tools >External Tools Configurations.
  2. Program yazan yere sağ tuş ile tıklayıp New seçeneğini seçiyoruz.
  3. Name kısmına “ST-Link“, Location kısmına da “/opt/stlink/st-util yazıyoruz. Working Directory kısmına ${workspace_loc}${project_path} yazıyoruz.
  4. Build sekmesine geliyoruz. Burdaki “Build Before Launch” seçeneğindeki işareti kaldırıyoruz.
  5. Common sekmesine geçip “Display in Favorites menu” başlığı altındaki “External tools” seçeneğini işaretliyoruz.

Değişiklikleri Apply diyerek kaydediyoruz ve Close tuşu ile çıkıyoruz. Buraya kadar ayarlarımızı yaptık. Eclipse programımızı kapatıp çıkabiliriz. Yeni safhaya geçmeden önce kendinize bir bardak kahve ya da çay hazırlamanızı tavsiye ederim. Sıra geldi proje hazırlıklarına. Öncelikle path ayarlarımızdan emin olarak eclipse programımızı başlatıyoruz. İlk bölümdeki kurulumu yaptıktan sonra bilgisayarınızı yeniden başlattıysanız “path” ayarlarınız halihazırda yapılmış olmalıdır ama emin değilseniz “source /etc/environment” komutunu verdikten heen sonra eclipse komutunu vererek programı başlatın.

Örnek Proje Ayarları

Eclipse programımızı açtık. Tertemiz bir sayfa bizi karşıladı. Sıra proje ayarlarımızı yapmakta. Sırasıyla bu adımları takip ediyoruz.

  1. File > New > Project
  2. C/C++ > C Project > Next
  3. Arm Cross Target Application > Empty Project
  4. Yandaki pencereden Arm Linux GCC (Sourcery G++ Lite) seçiliyor
  5. Project kısmına bir proje adı verip devam ediyoruz.

Eğer her şey doğru yapıldıysa sol taraftaki “Project Explorer” penceresinde oluşturduğumuz projeye eklenmiş 3 dizin göreceğiz

/opt/CodeSourcery/arm-2011.09/arm-none-eabi/include

/opt/CodeSourcery/arm-2011.09/lib/gcc/arm-none-eabi/4.6.1/include

/opt/CodeSourcery/arm-2011.09/lib/gcc/arm-none-eabi/4.6.1/include-fixed

Şimdi diğer ayarları yapmaya geçelim. Bu aşamaya geçmeden önce indirmemiz gereken bir dosya daha var. STM32 için gerekli olan kütüphaneleri içeren paket. STM32F4 DSP Peripherals and Standart Library adlı yaklaşık 30 MB büyüklüünde bir dosya. İçinde elimizdeki donanım için gerekli tüm kütüphaneler mevcut. Biz de bu kütüphaneleri projemize ekleyeceğiz. Bunun için sırası ile

  1. Project > Properties
  2. C/C++ Generals > Paths and Symbols
  3. Configuration Ayarlarını “All configurations” olarak değiştiriyoruz.
  4. Include sekmesindeki Languages ayarını GNU C olarak seçiyoruz.

Bu ekranda iken Add tuşuna basarak indirdiğimiz STM32F4 kütüphanelerini ekliyoruz. Eklememiz gereken dizinler şunlar:

/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/CMSIS/Include

/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/CMSIS/Device/ST/STM32F4xx/Include

/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/STM32F4xx_StdPeriph_Driver/inc

/${ProjDirPath}

Bu dizinleri ekledikten sonra “Source Location” sekmesine geçiyoruz ve Link Folder seçeneğine tıklıyoruz:

  1. Folder Name kısmına StdPeriph yazıyoruz.
  2. Link to folder in the file system seçeneğini seçiyoruz.
  3. Browse tuşuna basıp /STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/STM32F4xx_StdPeriph_Driver/src dizinini gösteriyoruz. Onaylayıp işemi bitiriyoruz.

Daha sonra Symbol sekmesine geçiyoruz. Buraya bir kaç değer eklememiz gerekiyor. Sol taraftan GNU C seçili iken Add tuşuna basarak şu 3 değeri ekliyoruz.

  1. Name kısmına USE_STDPERIPH_DRIVER deyip OK diyoruz. Value değeri boş kalacak.

  2. Name kısmına USE_STM32_DISCOVERY deyip OK diyoruz. Value değeri boş kalacak.
  3. Name Kısmına HSE_VALUE diyoruz. Value kısmına 8000000 değerini giriyoruz. OK diyoruz.

Apply diyerek değişikliklerimizi kaydediyoruz. Aynı pencerede iken sol taraftaki C/C++ General başlığı altındaki Indexer ayarlarına giriyoruz. Burada resimde görülen ayarları işaretliyoruz ve Apply diyoruz.

Azimle yolumuza devam ediyoruz. Herşey ARM için 🙂 Sol taraftaki seçeneklerden C/C++ Build sekmesine geliyoruz. Environment seçeneğine tıklıyoruz. Sağ taraftaki “Select” tuşuna tıklayıp PATH değişkenini ekliyoruz.

Daha sonra soldan yine Settings seçeneğini seçiyoruz ARM Sourcery Linux GCC Linker başlığı altındaki General seçeneğini seçiyoruz ve Script File kutusuna /${ProjDirPath}/stm32_flash.ld

Aynı yerden ARM Sourcerry Linux GNU Flash Image ayarlarından Output seçeneğine gelip Output File Format seçeneğini “binary” olarak değiştiriyoruz.

Sabırlı okurlarım yüzdük yüzdük kuyruğuna geldik. Az daha sabredin. Projemizin sorunsuz derlenmesi için gereken bir kaç dosyayı proje dizinimize kopyalamamız gerek. İşte o dosyalar

/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Project/STM32F4xx_StdPeriph_Templates/TrueSTUDIO/STM324xG_EVAL/stm32_flash.ld
/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
/STM32F4xx_DSP_StdPeriph_Lib_V1.0.1/Libraries/CMSIS/Device/ST/STM32F4xx/Source/Templates/TrueSTUDIO/startup_stm32f4xx.s

ÖNEMLİ : Proje dizinimize kopyaladığımız “startup_stm32f4xx.s” dosyasının uzantsını büyük s ile “S” ile değiştiriyoruz. Yani dosya adımız “startup_stm32f4xx.S” olacak. Bir de netleştiremediğim bir durum olmakla birlikte bu dosyanın içinde bulunan bir satırı iptal etmemiz gerekiyor ya da gerekmiyor. Yaralandığım kaynaklardan biri almanca ve google translate ile tercüme ettiğimde ilgili yeri “uncomment” edin demiş fakat bu satır etkinken kod derlenmiyor. Kaldı ki bu satır zaten etkinleştirilmiş. Yani etkinleştirilmiş satırı tekrar nasıl etkinleştirebiliriz ki. Olmak ya da olmamak işte bütün mesele bu. Ya da bir ihtimal daha var ölmek mi dersin… (Yazar burda saçmalamaktadır ciddiye almayınız 🙂 Olması gereken durum şu:

/* Call static constructors */
//    bl __libc_init_array

Biraz mola verebiliriz. Bundan sonra fazla bir işimiz kalmadı. Sırada GDB ile Debug işlemi için gerekli ayarları yapacağımız yere geliyoruz.Şimdi bazı okurlar diyordur ki hep az kaldı diyoruz ama bir olayınızı göremedik. Bizi mi kandırıyon len! Ben de diyorum ki şunu da yaptık mı tamamdır bu iş.Sırasıyla

Run>Debug Configuration seçeneğine tıklıyoruz.

Açılan pencerede solda bulunan “GDB Hardware Debugging” kısmına sağ tuş ile tıklayıp New seçeneğini seçiyoruz. Açılan pencerede NEW kısmına “STM32F4-Discovery ST-Link” ismini veriyoruz. Debugger sekmesine geçip GDB Command kısmına “arm-none-eabi-gdb” yazıyoruz ve port numarasını 4242 olarak belirliyoruz. Aşağıdaki ekran görüntüsünde ayarları görebilirsiniz.

Son olarak Common sekmesine gelip Display in favorites menu başlığı altındaki Debug seçeneğini işaretleyin. Apply ve close diyerek pencereyi kapatıyoruz. Aşağıdaki örnekte deneme projesi için yaptıığım ayarları görebilirsiniz.

Şimdi bir kaç püf noktasına değinelim:

  1. Debug işleminden önce ST-Link çalışıyor olmalı. (Run > External Tools > ST-Link)
  2. Eğer ST-Link açılında “Variable References empty selection” hatası verirse Project Explorer penceresindeki proje klasörünüze bir kere tıklayıp tekrar deneyin.
  3. Run > Debug Configuration penceresinden proje ayarlarınızı yapın.
  4. Debug işlemini başlatın. Açılan pencere uyarısına yes diyerek debug ekranına ulaşabilirsiniz.
  5. F8 ile kodunuzu tekrar baştan başlatabilirsiniz.

GDB henüz %85 oranında faal olan bir uygulama olduğu için hatalarını olgunlukla karşılayacağını biliyorum :D. Bir sonraki yazımızda basit bir led yak söndür uygulaması kodu vereceğim.

BÖLÜM 2 SONU