ARM Uygulamaları – IAR ile STM32F103 Blue Pill’de Register kullanarak LED Yakıp Söndürme #1

Resim-1 : Blue Pill

Merhabalar, bu yazıda STM32F103 Blue Pill olarak geçen ST firmasının Arduino Nano benzeri daha gelişmiş kartı üzerinde hiç kütüphane kullanmadan nasıl LED yakıp söndürme yapabiliriz onu ele alacağım.

Ben kullanım kolaylığı olsun diye geliştirme kartı üzerinden uygulamalar yapacağım ancak buradaki tüm çalışmalar çıplak mikrodenetleyici için de geçerli olacaktır.

Amacımız da bu kart üzerindeki C portunda 13 numaralı pine bağlı LED’i yakıp söndürmek olacaktır.

Bu arada bu kartı Arduino IDE’si üzerinden de kullanılabiliyorsunuz ancak ben doğrudan çıplak bir şekilde STM firmasının datasheetlerini okuyarak ve sonra da Standard Peripheral kütüphaneleri yardımıyla kullanacağım.

Bu kartın üzerinde STM32F103C8T6 mikrokontrolcüsü yer almakta olup ARM Cortex-M3 çekirdeği içermektedir. Maksimum saat (clock) frekans hızı ise 72 MHz‘dir.

Bu kartın incelemesini ayrıca bu linkteki yazımdan uzun uzuna okuyabilirsiniz.

Kartın üzerinde USB girişi bulunsa da ilk etapta iletişim kuracak herhangi bir bootloader yada arabirim için mikrodenetleyici bulunmadığı için direk PC’ye takıldığında programlayayoruz. 

Peki nasıl yapabiliriz?

Blue Pill (STM32F103) Kartının Programlama Yöntemleri

Bu mavi kartı programlamanın denediğim ve çalıştığını test ettiğim 4 farklı yolu bulunmakta olup bunlar;

1- STM mikrodenetleyicilerini programlamaya yarayan ST-Link adındaki programlayıcı ile programlamak,

2- Üzerinde programlayıcısı olan  farklı geliştirme kartları üzerinden programlamak (STM32F407-11 Discovery Kit gibi),

3- USB-TTL dönüştürücü gibi UART üzerinden PC ile haberleşen arabirim üzerinden programlamak,

4– USB desteği sayesinde içerisinde bootloader yazılım yükleyerek kartın USB arabirim üzerinden programlanmasıdır. 

Şuanlık dikkatimi çeken yöntemler bunlardır. Farklı deneysel yöntemleri yorum olarak yazıp birlikte deneyip çoğaltabiliriz. 

 

Geliştirme Ortamının Hazır Hale Getirilmesi

Geliştirme ortamı olarak IAR Embedded Workbench 8.32 kullanıyorum. Olabildiğince temiz ortam olduğu için siz farklı geliştirme ortamlarına kolaylıkla bu çalışmayı aktarabilirsiniz. Sıkıntınız olursa da yorum yazarak çözüm bulmaya çalışırız.

IAR Embedded Wordbench üzerinden boş temiz bir proje açarak başlayalım. Project > Create New Project… diyerek bu işlemi yapabilirsiniz.

Açılan pencereden C projesi olduğu C > main yoluyla devam edelim.

Proje açılırken sizden bunu kaydetmesini isteyecektir. Çalışmalarınızı düzgün arşivlemek için bir klasör içinde klasör adresinde Türkçe karakter içermeyen bir konumda saklamanızı öneririm.

Kod yazmaya başlayacağımız editörümüz açıldı ancak bir kaç ayardan sonra kodumuzu yükleyebileceğiz.

Öncelikle proje ayarlarından kullanacağımız mikrodenetleyiciyi, yükleme şeklini hangi cihaz üzerinden ve nasıl yapacağını seçmemiz lazım.

Proje ayalarını soldaki dosya yöneticisindeki projenize sağ tuş yapıp açılan menüden Options seçeneğine tıklayarak açabildiğiniz gibi üst menüden Project > Options seçeneceğiyle de erişim yapabilirsiniz.

Bu menü kullandığınız IAR Embedded Workbench sürümüne göre farklılılık gösterebilir. Benim kullandığım sürüm 8.32.1’dir.

Açılan menüde öncelikle General Options sekmesinin Target alt sekmesindeki Processor variant ayar grubundan Device seçeneğini aktifleştirerek ST > STM32F1 > STM32F103 > STM32F103C8 mikrodenetleyicisini seçelim. Sizdeki kart ufak tefek farklılıklar gösterse dahi doğru mikrodenetleyici seçildiğinden emin olmalısınız aksi takdirde kodunuzu aktaramayacaksınız.

Tabi oldukça fazla ayarlamalar yapmak mümkün bu bölümde oldukça kısa elzem ayarlamarı gösteriyor olacağım. Bu ayarlamalar içinde bir diğer önemli ayar ise programlayıcı ve debugger seçimi.

Debugger > Setup > Driver kısmından ST-LINK seçimini yapın. Bu seçimi yaptıktan sonra ise Download sekmesinden Verify Download seçeneğinin aktif edin.

Kabaca derleyici ayarlarımız bu kadar. Derleme tuşuna basıp herhangi bir sıkıntı olup olmadığından emin olduktan sonra kaldığımız yerden devam edebiliriz.

Eğer herhangi bir sorun yok ise şu şekilde çıktınız olacaktır.

Register Bilgilerine Ulaşmak

Öncelikle ilk yapılması gereken ST firmasının sitesinden gerekli mikrodenetleyici için hazırlanmış Reference Manual’leri temin etmek olacaktır.

Ben sizin STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm®-based 32-bit MCUs için hazırlanmış Reference Manual PDF’i şuradaki linkten bulup getirdim. Bu STM32F1 ailesini kapsar içinde STM32F103 ile ilgili bilgiler bizim için önemlidir. Mutlaka indirip projelerinizle arşivlemeyi öneririm.

ST’nin sitesinde bu mikrodenetletleyici ait daha bir çok yardımcı döküman paylaşılmıştır. Şu adresten kontrol edebilirsiniz.

Reference Manual’da sayfa 50‘ye baktığımızda Memory Map tablosunu göreceksiniz. Bu tablo mikrodenetleyicideki tüm register’ların hangi adresten başlayıp hangi adreste bittiğini gösteren tablodur.

Bizim için önemli olan Reset and Clock Control (RCC) memory adres aralığının 0x4002 1000 – 0x4002 13FF olduğu görüyoruz. Bu bilgi bizim için çok önemli bu bir yere not ediyoruz.

Amacımız LED olduğu için C portuna ait GPIO adreslerini de bulmamız bizim için önemli olacaktır. Reference Manual’da sayfa 51‘de GPIO’lardan C Portuna baktığımızda adresinin 0x4001 1000 – 0x4001 13FF aralığında olduğunu görüyoruz.

Bu adresler bizim için base (taban) adreslerimiz olacaktır. Diğer adresler verilirken spesifik olarak nerede olduğu değil base adreslere olan uzaklıkları verilecektir.

GPIOC için ilk kalp atışlarını vermek istediğimizde mikrodenetletleyici mimarisinde bazı yönlendirici bus’lar (hatlar) olacaktır. Bunu Reference Manual’da sayfa 47‘de görebiliriz.

GPIOC pinlerinin açılıp kapanmasını sağlayan clock pulselarını APB2 üzerinden gönderiyor. Yapacağımız ilk adım bunu aktifleştirmek olacaktır.

Reference Manual’da sayfa 112 bulunan APB2 peripheral clock enable register (RCC_APB2ENR) adındaki register’ı düzenlememiz gerekmektedir.

Görüldüğü gibi Address yazan bölüm aslında RCC adresine olan offset‘i (uzaklığı) tanımlamaktadır. RCC adresimiz 0x40021000 ile başladığı bilgisine edinmiştik. Şimdi bu adrese 0x18 eklediğimiz ise RCC_APB2ENR register adresinin 0x40021018 olduğunu bulabiliriz. Sırada bu adrese GPIOC aktifleştirme bilgisi yazacağız.

Görüldüğü gibi 32 bitten oluşan bir kayıt tutucudur kendisi. GPIOC ise 4. bite denk geliyor. Eğer clock’u açmak istersek 1 (high), kapatmak istersek ise 0 (low) bilgisi yazıyoruz.

4. biti 1 (high) yapıp geri kalanları 0 (low) yaptığımızda bu bilginin hexadecimal (onaltılık) karşılığı 0x0000 0010 olacaktır.

Note: Bu register sadece GPIOC portunu aktifleştirmekle kalmadığı için reset adreslerini (reset value yazan kısım) gözden kaçırmamak önemli olacaktır.

GPIOC portuna yaldır yaldır kalp atışlarını göndermeye başladık geriye GPIOC için pin mode tanımlamaları yapmak kaldı.

Bu nokta ilk bakışta biraz karışık gelebilir ancak dikkatli dinlerseniz oldukça basit bir mantık çerçevesinde inşa edildiğini göreceksiniz.

Herhangi bir portun pinlerini ya input (giriş) ya da output (çıkış) olarak kullanabiliriz. Ancak girişin digital veya analog, çıkış modununda çıkışın maksimum hızı da ayarlanabildiği için aslında iki farklı bilgi türünden daha fazla bilgi sayısı bulunuyor. Bunu da tek bir bitte belirtemeyeceğimiz için 2 bit ayarlamalar kullanılacaktır.

00: Input Mode (Giriş Modu)
01: Output Mode, Max Speed 10 MHz (Çıkış ama hız 10 MHz)
10: Output Mode, Max Speed 2 MHz (Çıkış ama hız 2 MHz)
11: Output Mode, Max Speed 50 MHz (Çıkış ama hız 50 Mhz)

MODE – Port mode bits

Görüldüğü gibi 2 bitlik bir kayıt tutucuya 4 farklı bilgi saklanabilmektedir. Bunun dışında Eğer çıkış ise veya değil ise şeklinde bir kaç daha ayarlama bulunmaktadır;

Eğer giriş ise (Mode = 0);
00 : Analog Mode
01: Floating Input (reset state)
10: Input with pull-up / pull-down
11: Reserved

Eğer çıkış ise (Mode > 0);
00: General purpose output push-pull
01:General purpose output open-drain
10: Alternate function output push-pull
11: Alternate function output open-drain

CNF – Port configuration bits

Şimdi asıl sıkıntı şurada bir portta toplam 16 tane pin var (giriş veya çıkış farketmeksizin) bunlar 0’dan başlayıp 15’e kadar gidiyor. Her bir pin için 16 farklı kombinasyon seçeneği bulunuyor. Toplamda 16 pin için bunu 32 bitlik bir reigstar’a sığdırılmadığı için iki tane register’a bölünmüş.

0’dan 7’ye kadar olan pinler için Port configuration register low (GPIOx_CRL) ve 8’den 15’e kadar olan pinler için ise Port configuration register high (GPIOx_CRH) register’ları bulunuyor.

Reference Manual’de sayfa 172‘ye bakıldığında Port configuration register high (GPIOx_CRH) reigster’ının GPIOC portu 13 numaralı pini kapsadığını anlayabiliriz.

Address offset: 0x04 olarak verilmiş GPIOC base adresine uzaklığı eklendiğinde GPIOC_CRH adresinin 0x4001 1004 olduğunu buluruz. Buradaki bir ufak ayrıntı RCC adresine değil GPIOC base adresine ekleme yaptığımızdır.

LED yakıp söndüreceğimiz için çıkış modunda kullanacağız, şuanlık çıkış hızımız bizim çok önemli ama 2Mhz hızı seçelim, output mode’unu ise push-pull olarak seçelim. Mode = 10, CNF ise 00 olacaktır. Hesap makinesi kullanarak baktığımızda değerin 21 ve 20. bitlere 1 ve 0 yazıp 23 ve 22. bitlere 0 yazdığımızda hexadecimal karşılığının 0x20 0000 olduğunu görebiliriz.

Reference Manual’da sayfa 173‘e bakıldığında Port output data register (GPIOx_ODR) ile çıkış tanımlası yapan register’ı göreceksiniz.

GPIOC base adresine bu adresin 0x0C offset’i eklenildiğinde GPIOC_ODR register’ının adresi 0x4001 100C olduğunu bulabiliriz.

13 numaralı pini aktif etmek için 0x0000 2000 bilgisi, pasif etmek için 0x0000 0000 bilgisi yazmamız dahilinde açıp kapama işleme yapabileceğiz.

Gerekli tüm bilgilerden sonra C portunun 13 numaralı pinine bağlı LED’i açıp söndürme kodunu yazdığımızda;

#define RCC_Base     (*(unsigned int *)0x40021000U)
#define GPIOC_Base   (*(unsigned int *)0x40011000U)
#define RCC_APB2ENR  (*(unsigned int *)0x40021018U)
#define GPIOC_CRH    (*(unsigned int *)0x40011004U)
#define GPIOC_ODR    (*(unsigned int *)0x4001100CU)

void delay(unsigned volatile int t) {
    for (unsigned volatile int i = 0; i < t; i++);
}

int main (void) {
    RCC_APB2ENR = 0x00000010;    
    GPIOC_CRH   = 0x00200000;
    
    while (1) {
      GPIOC_ODR = 0x00002000;
      delay(1000000U);
      GPIOC_ODR = 0x00000000;
      delay(1000000U);
    }
}

Bu çalışmanın STM32F4 ailesi için olanını incelemek isterseniz buraya tıklayabilirsiniz.

Hakan Kaya
Yarı zamanlı mühendis. Yarı zamanlı eğitmen. Biraz da film sever.
error: 5846 sayılı Fikir ve Sanat Eserleri Kanunu tarafında içeriklerin izinsiz kopyalanması, paylaşılması ve çoğaltılması yasaktır.