Professional Documents
Culture Documents
net -1-
Not: Bu dosya web sitemde 4 parça halinde yayınladığım STM32 Discovery ile ilgili yazımın tek parça
haline getirilmi eklidir. Diğer yazılarım için web siteme bakabilirsiniz.
Co kun TA DEMĐR
http://www.coskuntasdemir.net
Burada Genel IDE kullanımı, mikrodenetleyici birimleri gibi konulara girmeyeceğim. O yüzden bu temel konuları
bildiğinizi farz ederek devam edeceğim.
Kartı programlamak için Keil firmasının MicroVision IDE yazılımını tercih ettim. Keil’in sitesinden bu yazılımın
deneme versiyonu bir form doldurulacak ücretsiz indirilebiliyor. Kurulumu yaptıktan sonra
“C:\Keil\ARM\Boards\ST\STM32 Discovery\Blinky” klasöründeki Blinky projesini açıp kodları incelemeye
ba layabilirsiniz.
Kartın üzeride ST Link Debugger ile beraber geliyor. Yani USB üzerinden karta yazılım atıp, hata ayıklama
i lemleri yapabilmek mümkün. Đlk denemelerimde debugger’ı çalı tıramadım. Google’dan yaptığım aramalarda
Keil forumlarında ST Link için yeni bir sürücü dosyasının indirilmesi gerektiğinin söylendiğini gördüm.
http://www.keil.com/support/docs/3549.htm
Linkteki dosyayı indirip C:\Keil\ klasörüne atmanız gerekiyor (ARM klasörünün üzerine yazmanız gerekiyor).
https://www.keil.com/support/attachment/3549.htm
http://www.st.com/internet/evalboard/product/219866.jsp
Bu yazılımla i lemcinin flash belleğini silme ve programlama gibi i lemleri yapabiliyoruz. “Target” menüsünden
“Connect” seçeneğini seçtiğinizde eğer bir problem yoksa ST Link aracı kartı tanıyacaktır. Sağ üstte
i lemcimizin ismini göreceğiz.
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -2-
imdi Keil’deki projeyi incelemeye devam edelim. Sol taraftaki “project” bölümünde projedeki dosyalar
görünüyor.
“Startup” klasörünün altında bulunan dosyalarda i lemci reset anından itibaren ilk çalı maya ba ladığında
i leteceği komutlar bulunuyor. “startup_stm32f10x_ld_vl.s” adlı dosyada assembly komutlarıyla kesme
vektörlerinin ayarlanması ve yığın bellek(stack) boyutları ataması vs… yapılıyor. Ardından
“system_stm32f10x.c” dosyasındaki SystemInit fonksiyonu çağırılıyor. Bu fonksiyonla da sistem saat frekansı
ayarlanılıyor. Bu dosyayla imdilik bir i imiz olmayacak. Bütün bu i lemler tamamlandığında main() fonksiyonu
çağırılıyor. Bildiğiniz gibi C programlarında bütün her ey “main” fonksiyonu içerisinde gerçekle mektedir.
Buradan sonra i lemciyi ve main içerisinde çağırılan fonksiyonları tanımaya devam edeceğiz…
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -3-
Önceki bölümde STM32 Discovery kartı için Keil geli tirme ortamında “Blinky” projesini incelemeye ba lamı tık.
imdi de kartın üzerindeki STM32F100RB i lemcisini tanımaya ba layalım:
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0337e/DDI0337E_cortex_m3_r1p1_trm.pdf
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -4-
STM32F100RB:
Đ lemcimizin veri dökümanında i lemcimizin çevre birimleri ve çekirdeğinin blok diyagramı bulunmaktadır:
Đ lemcinin dökümanları oldukça uzun ve karma ık gibi görünebilir. Ama ba ta da söylediğim gibi en basitten
ba layıp adım adım gitmekte fayda var. Elimizde hazır bir donanım olduğundan direk olarak birçok ayrıntıyı
imdilik atlayabiliriz.
CMSIS:
Projenin kodlarını incelemeye ba lamadan önce CMSIS (Cortex Microcontroller Interface Standard) nedir bunu
inceleyelim. CMSIS, ARM firması tarafından farklı firmalar tarafından üretilen bütün Cortex serisi çekirdeğe
sahip i lemciler için ortak bir yazılım kütüphanesinin adıdır. CMSIS donanım birimleri ile uygulama yazılımı
arasındaki ara soyutlama katmanını (hardware abstraction layer) olu turuyor. Böylelikle üreticilere ve
geli tirme araçlarına bağlı kalmadan genel olarak Cortex çekirdeğe sahip i lemciler için yazılım bile enleri
olu turmak mümkün oluyor ve yazılım ta ınabilirliği, yeniden kullanım sağlanıyor. CMSIS ile ilgili daha ayrıntılı
bilgiyi ARM ve Keil firmalarının sitelerinde bulabilirsiniz.
http://www.keil.com/support/man/docs/gsac/GSAC_CMSISoverview.htm
Projede butonlar ve LED çıkı ları kullanıldığından önce ilgili kaydedicilerle IO portları ayarlarının yapılması
gerekiyor. Đ lemcimizde her bir çevre biriminin saat frekansı kontrol edilebiliyor. Böylelikle kullanılmayan çevre
birimleri kapatılarak güç tasarrufu sağlanıyor.
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -5-
Bir LED yakıp söndüren yazılım bile ne kadar karma ık diye dü ünüyor olabilirsiniz. Ama unutmayın “her ey bir
LED’i yakmakla ba lar”.
Bu üniteyle ilgili çok fazla ayrıntı var. imdilik sadece IO birimlerinin ayarlarını inceleyeceğiz.
Đ lemcimiz üzerinde her bir çevrebiriminin saat kaynağı ayrı ayrı kontrol edilebiliyor. Böylelikle
kullanılmayan çevrebirimleri kapalı tutarak güç tüketimi minimum seviyede tutabiliyoruz.
Aynı zamanda her bir çevrebirimi ayrı ayrı ba langıç durumuna(reset) getirilebiliyor.
Đ lemcimizin IO hatlarını kullanabilmek için öncelikle IO modüllerinin saat giri lerini aktif hale getirmemiz
lazım. Onun ardından IO yönlerini (giri çıkı ) ayarlamalıyız.
RCC->APB2ENR |= 1 << 4
satırıyla APB2ENR kaydedicisinin 4.bitini 1 yapıyoruz. Ardından IO portunun giri çıkı yön ayarlarını yapacağız.
Önce IO portlarını tanıyalım:
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -6-
IO Portları:
Đ lemcinin IO portları PA ,PB, PC, PD, PE olarak sıralanıyor. Discovery kartında A,B,C,D portları bulunuyor. Her
bir portta 16 pin var. Portlarla ilgili i lemler 32 bitlik kaydedicilerle yapılıyor. Portlar Analog veya dijital giri
çıkı olarak ayarlanabiliyor. Aynı zamanda Open drain, push pull çıkı tipleri de mevcut.
Port Konfigurasyon Kaydedicisi (dü ük): GPIOx_CRL (x burada A,B,C,D,E portlarından birisini temsil ediyor)
Port Konfigurasyon Kaydedicisi (yüksek): GPIOx_CRH (x burada A,B,C,D,E portlarından birisini temsil ediyor)
Dü ük kaydedici ile porta ait 1 8 arası pinlerin, yüksek kaydedici ile porta ait 9 16 nolu pinlerin ayarlamaları
yapılıyor.
Bu kaydediciler ile ilgili portlara ait pinlerinin yön ayarları yapılıyor. Her bir pine ait 2 bit CNF, 2 bit Mode
olmak üzere 4 bitlik değer bulunuyor. CNF grubu pinin giri – çıkı tipini belirlerken, Mode grubu çıkı olarak
ayarlanan pinlerin IO çıkı hızı seçimini yapmaya yarıyor.
GPIOx_CRL Kaydedicisi:
CNFy[1:0] (y = 0…7)
GPIOx_CRH Kaydedicisi:
CNFy[1:0] (y = 8…15)
Bu kaydedici ile portun giri değeri okunabilir. 0 15 arası bitlerin her biri ilgili pine ait giri değerini veriyor. Bu
porta yazma i lemi yapılmıyor.
Bu kaydedici ile ilgili porta çıkı değeri atanabilmektedir. Bu kaydediciye bit eri imi yapılamıyor. Yani çıkı
değerini 16 bit birden yazmak gerekiyor. Tek tek bitlere eri im GPIOx_BSRR kaydedicisiyle yapılıyor.
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -8-
Bu kaydedicinin ilk 16 biti ile ilgili portun 16 pin bitleri ayrı ayrı 1(set) yapılabiliyor. 17 32 bitleri ile de ilgili
portun pinleri sıfırlanıyor. Eğer ilgili pine ait hem set hem reset biti 1 yapılırsa set durumunun önceliği var. Bu
durumda ilgili pin 1 oluyor.
Bu kaydedicinin ilk 16 biti ile ilgili portun 16 pin bitleri ayrı ayrı 0 (reset) yapılabiliyor.
Bu kaydedici, giri çıkı portlarının ayarları bir kere yapıldıktan sonra bir daha yanlı lıkla deği tirilmesini
önlemek için kilitlemeye yarıyor. Kilitleme mekanizması u ekilde çalı ıyor:
Bu i lemler sonunda IO pinleri konfigurasyonu kilitlenmi olur ve ancak bir sonraki resetten sonra
deği tirilebilir.
Buraya kadar STM32F100RB i lemcimizin IO portlarına ait kaydedicileri tanıdık. Bundan sonra Blinky projesinde
bu kaydedicilerin nasıl kullanıldığını göreceğiz
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net -9-
Bu projede BUTON1, LED3, LED4 kaynakları kullanıldığından bunlara ait giri çıkı birimlerinin ayarlarının
yapılması gerekiyor.
LED3 PORTC 9
LED4 PORTC 8
BUTON1 – PORTA 0
1 /*----------------------------------------------------------------------------
2 MAIN function
3 *----------------------------------------------------------------------------*/
4 int main (void) {
5
6 LED_Config();
7 BTN_Config();
8
9 SysTick_Config(SystemCoreClock / 100); /* Setup SysTick Timer (10ms) */
10
11 while(1) {
12
13 if (BTN_Pressed()) {
14 ledVal += 1;
15 if (ledVal > 3) ledVal = 1;
16 }
17
18 if (ledBlink == 1) {
19 ledBlink = 0;
20 ledOn^= 1;
21 if (ledOn == 1)
22 LED_Out (ledVal); /* switch the LEDs on */
23 else
24 LED_Out (0); /* switch the LEDs off */
25
26 }
27 }
28
29 }
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net - 10 -
main() fonksiyonu:
ledBlink deği keni her 1 olduğunda (System Handler fonksiyonu içerisinde yapılıyor) LED çıkı larına dönü ümlü
olarak 1 veya 0 değeri veriliyor. ledval deği keninin değerine göre LED’lerin hangilerinin yanacağına LED_out
fonksiyonunda karar veriliyor.
1 /*----------------------------------------------------------------------------
2 Switch on LEDs
3 *----------------------------------------------------------------------------*/
4 __INLINE static void LED_On (uint32_t num) {
5
6 GPIOC->BSRR = led_mask[num]; /* Turn On LED */
7 }
1 /*----------------------------------------------------------------------------
2 Switch off LEDs
3 *----------------------------------------------------------------------------*/
4 __INLINE static void LED_Off (uint32_t num) {
5
6 GPIOC->BRR = led_mask[num]; /* Turn Off LED */
7 }
Daha önceki yazımda portlara ait BRR (bit reset register) kaydedicisi ile o porta ait pinlerin durumlarını
deği tirebileceğimizi görmü tük. Burada LED_off fonksiyonuna verilen parametre ile ilgili pine ait çıkı değeri
sıfırlanıyor. num değerinin aldığı 0 veya 1 değerine göre LED3 veya LED4 söndürülüyor.
1 /*----------------------------------------------------------------------------
2 Function that outputs value to LEDs
3 *----------------------------------------------------------------------------*/
4 void LED_Out(uint32_t value) {
5 int i;
6
7 for (i = 0; i < LED_NUM; i++) {
8 if (value & (1<<i)) {
9 LED_On (i);
10 } else {
11 LED_Off(i);
12 }
13 }
14 }
Bu fonksiyonla LED’lerin yakılıp söndürülme durumları kontrol ediliyor. Fonksiyona parametre olarak verilen
“value” değerine göre 3 durumdan biri gerçekle iyor:
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net - 11 -
Aslında programda yapılmak istenen i e göre çok karma ık bir yapı kurulduğunu söylemek mümkün. Aynı i i
ba ka ekilde çok daha az kod yazarak da gerçekle tirebilirsiniz.
1 /*----------------------------------------------------------------------------
2 configure Button pins
3 *----------------------------------------------------------------------------*/
4 __INLINE static void BTN_Config(void) {
5
6 RCC->APB2ENR |= 1<<2; /* Enable GPIOA clock */
7 GPIOA->CRL &= 0xFFFFFFF0; /* Configure the GPIO for BTNs */
8 GPIOA->CRL |= 0x00000008; /* Configure the GPIO for BTNs */
9 }
Burada BUTON1 pinine ait ayarlar yapılıyor. Yine pinin bulunduğu GPIOA portunun saat sinyali etkinle tirilip
porta ait CRL kaydedisine butonu giri olarak ayarlayacak değer atanıyor.
1 /*----------------------------------------------------------------------------
2 Read Button pins
3 *----------------------------------------------------------------------------*/
4 __INLINE static uint32_t BTN_Get(void) {
5
6 return (GPIOA->IDR & 0x0001);
7
8 }
Bu fonksiyon sadece GPIOA portunun 1. pininin durumunu döndürüyor. Böylelikle butonun basılıp basılmadığını
anlıyoruz.
1 /*----------------------------------------------------------------------------
2 USER1Pressed
3 check if USER1 is pressed (unbounced).
4 *----------------------------------------------------------------------------*/
5 uint32_t BTN_Pressed (void) {
6 static uint32_t USER1KeyCount = 0, USER1KeyPressed = 0;
7
8 if (USER1KeyPressed) {
9 if ((BTN_Get() == 0 )) { /* Check if USER1 not pressed */
10 if (USER1KeyCount < UNBOUNCE_CNT) USER1KeyCount++;
11 else {
12 USER1KeyPressed = 0;
13 USER1KeyCount = 0;
14 }
15 }
16 }
17 else {
18 if (!(BTN_Get() == 0 )) { /* Check if USER1 pressed */
19 if (USER1KeyCount < UNBOUNCE_CNT) USER1KeyCount++;
20 else {
21 USER1KeyPressed = 1;
22 USER1KeyCount = 0;
STM32 Discovery Kartı ile ilk adımlar – Co kun TA DEMĐR http://www.coskuntasdemir.net - 12 -
23 return (1);
24 }
25 }
26 }
27 return (0);
28 }
STM32 Discovery üzerinde bulunan mekanik butonlarda “bouncing” denilen bir durum gerçekle mektedir.
Butona basıldığında çok kısa bir süre içerisinde mekanik kontaklar 1 ve 0 değeri arasında gidip gelmektedir. Bu
durumda butona tam basıldığını anlamak için kısa bir bekleme süresi konulması gerekiyor. Bu i leme de
“debouncing”* deniliyor. BTN_Pressed fonksiyonunda yapılan da i te tam olarak bu. Fonksiyon ba ında
tanımlanan USER1KeyCount ve USER1KeyPressed deği kenleri fonksiyonun iç durumunun fonksiyondan
çıkıldığında da saklanmasını sağlıyor. Eğer fonksiyon ilk çağırıldığında henüz butona ilk defa basılmı sa
(USER1KeyPressed = 0 ise) butonun durumu tekrar okunuyor ( if ((BTN_Get() == 0 )) ). Bu arada butona
basıldığında giri e 0, basılmadığında ise 1 uygulandığını belirteyim. Eğer butona giri inden sıfır değeri
okunuyorsa USER1KeyCount değeri bir artırılıyor. Her fonksiyon giri inde aynı i lem tekrarlanarak
USER1KeyCount değerinin belirli bir e ik değerine gelmesi sağlanarak (UNBOUNCE_CNT) gecikme olu turuluyor.
Bu süre içerisinde buton mekanik olarak sönümlenmi oluyor ve kesin olarak butona basılıp basılmadığı
anla ılıyor. “Debouncing” i lemi yapılmadığı takdirde durumlar arası geçi ler çok hızlı olacaktır. Fonksiyon
sonuç olarak BUTONA BASILDI (1) veya BUTONA BASILMADI (0) değerini döndürüyor.
1 /*----------------------------------------------------------------------------
2 /*----------------------------------------------------------------------------
3 SysTick_Handler
4 *----------------------------------------------------------------------------*/
5 void SysTick_Handler (void) {
6 static uint32_t ticks;
7
8 if (ticks++ >= LED_BLINK_RATE) {
9 ticks = 0;
10 ledBlink = 1;
11 }
12
13 }
SysTick_Handler (System Tick Handler ) fonksiyonu aslında bir “kesme hizmet fonksiyonu”. Yani System Tick
kesmesi olu tuğunda bu fonksiyon çağırılıyor. imdilik STM32 Kesmelerine çok girmeden basitçe açıklayayım:
System Tick kesmesi ile belirli zaman aralıklarında çalı ması gereken eyler için kullanılabilen bir nevi “timer/
zamanlayıcı”. Daha sonra göreceğimiz main() fonksiyonunda System Tick için 10 ms’lik bir periyod belirleniyor.
Yani SysTick_Handler fonksiyonu her bir 10 ms’de çağırılıyor. Dolayısıyla bunu zamanla ilgili i lemlerde
kullanabiliyoruz.
Burada fonksiyon her çağırıldığında ticks deği keni 1 artırılıyor. Ticks deği keni LED_BLINK_RATE değerine
ula tığında (buradaki değeri 10) ticks değeri sıfırlanıp ledBlink deği kenine 1 değeri atanıyor. Bu değer de ana
fonksiyon içerisinde led yakıp söndürme i leminde kullanılıyor. LED’lerin yanıp sönme hızını LED_BLINK_RATE
sabitiyle kontrol edebiliyoruz.
Basit bir LED yakıp söndüren programın bile bu kadar karma ık olması gözünüzü korkutmasın. Burada yapılan
bütün i lemleri tam olarak anladığınızda C ile gömülü yazılım geli tirmenin temel konularını kavramı sınız
demektir. Unutmayın “HER EY BĐR LED’Đ YAKMAKLA BA LAR”
*Jack Ganssle’ın “Switch Debouncing” konusuyla ilgili makalesini okumanızı tavsiye ederim:
http://www.ganssle.com/debouncing.htm