174

ARM Programlama

Embed Size (px)

Citation preview

Page 1: ARM Programlama
Page 2: ARM Programlama

ARM Programlama

ARM Programlama 2

Page 3: ARM Programlama

ARM Programlama

ARM Programlama 3

ARM konusunda oluşturulan bu e-kitap size ARM Cortex-M4F tabanlı işlemcilerin çalışma yapısı, C programlama ve Assembler konusunda gerçekten hatırı sayılır bir kaynaktır. Eğitimler Texas Instruments

firmasının düşük güç tüketimi ile çalışan ve oldukça ucuz olan Stellaris Launchpad kiti kullanılarak anlatılmıştır. Yazılar Dr. Miro Samek'in yayınladığı ve Eren BAŞTÜRK'ün çevirdiği eğitimler temel alınarak

yazılmıştır. Bu yazıları hazırlarken desteğini gördüğüm Ahmet Alpat'a ve tüm Çizgi-TAGEM ailesine teşekkürlerimi sunuyorum. Faydalı bir yazı olması dileği ile, iyi çalışmalar.

Arif Ahmet Balık

Yazar Hakkında

ARİF Ahmet BALIK

Bir teknik lisede web programcılığı dalında okuyor. Gömülü sistemler ve FPGA meraklısı. birkodyaz.blogspot.com.tr adlı bloğun kurucusu ve yazarı. Şuan YTÜ Teknoparkta bir ARGE şirketi olan

KATIHAL Elektronik Yazılım ARGE AŞ'de part-time olarak çalışıyor. İstanbul HackerSpace üyesi. İletişim

[email protected]

Eren BAŞTÜRK

1990 Kayseri doğumlu. 2005 yılında ilkokul eğitimini tamamlayıp Antalya Adem Tolunay Anadolu Lisesinde eğitimine devam etti. 2009 yılında Süleyman Demirel Üniversitesi Elektronik ve Haberleşme Mühendisliği bölümünü kazandı. Halen aynı üniversitede 3.sınıf öğrencisi olarak eğitimine devam etmektedir. Gömülü Sistemler , Linux İşletim Sistemleri , Fpga ,

Yazılım Geliştirme ve Sayısal Elektronik üzerine çalışmalarını sürdürmektedir.

İletişim [email protected]

Page 4: ARM Programlama

ARM Programlama

ARM Programlama 4

İÇİNDEKİLER

1. Başlangıç .........................................................................................................................4

2. Sayım ..............................................................................................................................10

3. Kontrol Akışı ..................................................................................................................42

4. Değişkenler ve İşaretçiler ..............................................................................................56

5. Led Yakıp Söndürme.......................................................................................................75

6. Önişlemci ve Volatile.....................................................................................................101

7. C'de Bitsel Opreratörler ...............................................................................................114

8. Diziler ve İşaretçi Aritmetiği.........................................................................................135

9. Fonksiyonlar ve Stack...................................................................................................155

Page 5: ARM Programlama

ARM Programlama

ARM Programlama 5

Page 6: ARM Programlama

ARM Programlama

ARM Programlama 6

Herkese Merhabalar, İlk derste ücretsiz gömülü geliştirme araç setini (IAR Embedded

Workbench) yükleyeceğiz ve pahalı olmayan bir geliştirme kartı olan Stellaris

Launchpad'i nereden sipariş edeceğimizi göstereceğim. Bu kart sayesinde kodlarınızı

fiilen gerçek bir mikrodenetleyici üzerinde çalıştırabilirisiniz. Ancak geliştirme

kartı olmadan da bu eğitim serisini takip edebilirsiniz çünkü komut seti

simülatörünün nasıl kullanılacağını öğreneceğiz.

C Programlama Dili

Öğreneceğimiz yüksek seviyeli olarak adlandırılan programlama dili

C'dir. Fakat sıklıkla düşük seviyeli makine koduna ineceğiz ve size gömülü işlem sürecinde neler olacağını göstereceğim. Siz'de

işlemcinizin kodunuzu nasıl çalıştırdığını verileri nasıl işlediğini ve bir

bilgisayarın gerçek dünyada yapabildiği şeyleri göreceksiniz. Bir ledi yakıp söndürmek

gibi. Bu kavrama gücü sizin C dilini daha etkin şekilde ve daha fazla güven duygusu

ile kullanmanızı sağlayacak. Programlama anlayışını kazanacaksınız. Sadece

programınızın yapması gerekenleri değil,

bunun yanında bu durumların nasıl makine dolarına nasıl çevrildiğini anlayışını ve

işlemcinin kodları ne kadar hızlı çalıştırabildiği anlayışını kazanacaksınız.

ARM Cortex-M4F

Page 7: ARM Programlama

ARM Programlama

ARM Programlama 7

Bu Kursta Arm Cortex-M4F adındaki işlemciyi kullanacağız.

Ama bu öğrendiklerimizi bütün Cortex-M işlemci ailesine Cortex-

M0'dan M0+'a, Cortex-M3 ve M4'e uygulayabileceksiniz.

Bu kurs boyunca günümüzde ve uzun yıllar boyunca

bulabileceğiniz gömülü mikrodenetleyici işlemci çekirdeklerinden en

popüler, en modern ve en fazla enerji tasarruflu işlemci ailesini

seçtim.

IAR Embedded Workbench

Öncellikle bu kurs için ilk ihtiyacımız olan gömülü geliştirme

setini "Embedded Workbench for ARM" için desteklenen IAR'dan EWW

sistem olarak adlandırılan profesyonel araç setini seçtim. Bu araç

setinin ticari versiyonu piyasadaki en pahalı versiyonlardan

birisidir ancak IAR size kod limiti olan zaman limiti olmayan bir

yazılım geliştirme sürümünü soruyor, şimdi hangi sürüm nasıl

indirilecek ve nasıl yüklenecek göstereceğim. IAR EWARM'ın

yükleneceği websitesi www.iar.com. Siteye girdikten sonra şekildeki

gibi önce SERVICE CENTER sonra Downloads'a tıklayalım.

Page 8: ARM Programlama

ARM Programlama

ARM Programlama 8

Sonra şekildeki gibi ARM için Size-limited licence'n altında bulunan

bağlantıya tıklayalım.

Karşımıza çıkan sözleşmeyi aşağıya kaydırarak şekildeki gibi indirme

bağlantısına tıklayalım.

Page 9: ARM Programlama

ARM Programlama

ARM Programlama 9

Dosya boyutu biraz büyük olduğu için indirme biraz zaman alabilir.

Dosya indikten sonra çift tıklayıp açın ve yüklemenin tamamlanmasını

bekleyin.

Page 10: ARM Programlama

ARM Programlama

ARM Programlama 10

Yükleme bittikten sonra karşınıza çıkan ekrandan şekildeki gibi

"Install IAR Embedded Workbench" üzerine tıklayın.

Geriye kalan standart yükleme işlemini gerçekleştirin. Yükleme

bittikten sonra karşınıza bir uyarı çıkacaktır bu uyarı size

Page 11: ARM Programlama

ARM Programlama

ARM Programlama 11

"licence dongle yüklensinmi" diye soruyor. buna hayır deyip

geçiyoruz.

IAR ile ilk karşılaştığınızda size bir kayır işlem kutusu ibraz

edilecek. "Register"a tıklayın. Doldurmak zorunda olduğunuz kayıt

formu karşınıza çıkacak buradaki en önemli adım kod limiti lisans

türünü seçmek geri kalan şeyleri doldurup son olarak "submit

registration" butonuna tıklayın. Mail adresinize eglen linki açın ve

lisans numarasını IAR'ı açtığımızda karşımıza çıkan ekrandaki metin

kutusuna yazın.

Tebrikler! Artık gömülü yazılım geliştirmek için bir araç setine

sahipsiniz.

Stellaris LM4F120 Launchpad

Dersin son aşaması olarak pekte pahalı olmayan bir geliştirme

kartının nasıl alınacağını göstereceğiz.

Tekrar ediyorum bu aşama gerekli değildir IAR araç setinde bulunan

simulatör ile derslerin büyük bölümünü takip edebilirsiniz.

Şuan Çizgi-TAGEM'in internet sitesinde %29 indirimli olarak 39,83

TL'ye bu geliştirme kartını alabilirsiniz. ilgili web sitesi :

http://market.cizgi.com.tr/product/education/ti-stellaris

Page 12: ARM Programlama

ARM Programlama

ARM Programlama 12

SAYIM

Tekrar merhaba. Gömülü sistem programlama derslerinin 2. serisine

hoş geldiniz. Bu derste bilgisayarların nasıl sayım yaptığını

göreceğiz. Bu ve bundan sonraki derslerde, ilk derste anlatılan IAR

araç setinin ücretsiz sürümünü kullanacağız.

İlk projemizi oluşturalım, IAR EWARM'ı başlatın ve Project > Create

New Project menüsünü seçin.

Karşımıza çıkan ekranda C proje tipini genişletelim ve main'e

tıklatalım.

Page 13: ARM Programlama

ARM Programlama

ARM Programlama 13

Bir dosya gezgini açılacak, projeniz için kaydedilecek bir yer

seçmelisiniz. Ben bütün ders boyunca Gömülü Programlama adında bir

klasör oluşturup projeleri buraya kaydedeceğim, sizinde böyle

yapmanızı tavsiye ediyorum. Bu klasör altında ders 1 adında bir

klasör daha açıp proje isimini ise proje yapıyorum ve kaydet

diyoruz.

Page 14: ARM Programlama

ARM Programlama

ARM Programlama 14

Gördüğünüz üzere, birazdan açıklayacağım proje oluşturulmuş bir main

dosyası içeriyor.

Page 15: ARM Programlama

ARM Programlama

ARM Programlama 15

Projenin konfigürasyonunu bitirmek için birkaç parametreyi

ayarlamanız gerekiyor. Project > Options menüsüne tıklatalım.

Target sekmesi içinde, işlemci türünü belirtmemiz gerekiyor.

Device'i seçin ve seçim butonuna tıklayın, listeden "Texas

Insruments > LM4F Family ve LM4F120H5QR" donanımını seçin.

Page 16: ARM Programlama

ARM Programlama

ARM Programlama 16

Hemen sonra C/C++ Complier kategorisini seçin. Varsayılan dil olarak

C'yi ve varsayılan C diyalektini c99 olarak görüyorsunuz.

Bu eğitim boyunca size en yeni C diyalektini öğreteceğim. (Diyalekt

: Yazım Standardı) Son olarak Optimizations sekmesini açalım ve varsayılan optimizasyon

seviyesinin low olduğundan emin olalım.

Page 17: ARM Programlama

ARM Programlama

ARM Programlama 17

yüksek optimizasyonlu kodun nasıl yazıldığını öğretene kadar, böyle

kalması gerekiyor. OK deyip kapatıyoruz. Böylelikle, sonunda IAR araç seti aracılığıyla oluşturulmuş kodlara

erişiyoruz.

Nitekim ilk olarak geçerli olan C kodlarını doğrulamayı deneylim.

Bunu derleme işlemi ile yapabiliriz. Bu derleme derleyici denilen

(Complier) denilen bir program aracılığı ile çalışıyor. Project

menüsünden Make seçeneğini seçin ve F7 kısa yolunu bir yere not

edin, çoğunlukla bu kısayolu kullanacaksınız.

Page 18: ARM Programlama

ARM Programlama

ARM Programlama 18

Projenizi ilk derlediğinizde IAR bir dosya gezgini ile size çalışma

alanınızı sorar, genel bir isim verip kaydedelim (calisma_alani) Bu derleme 0 hata ve 0 uyarı ile tamamlanıyor. İlk legal programınız

için tebrikler.

Page 19: ARM Programlama

ARM Programlama

ARM Programlama 19

Kodların daha düzenli ve okunabilir olması için biraz düzenleme

yapalım.

Page 20: ARM Programlama

ARM Programlama

ARM Programlama 20

ilk küme parantezini bir üst satıra aldık ve return 0; ve bundan

sonra gelecek ifadeleri 4 boşluk girinti olacak şekilde ayarladık,

aslında bu derleyici için hiçbir önemi yoktur, derleyici bütün

kodları tek ve uzun bir satır olarak algılar, yaptığımız bu

düzenlemeler kodun okunabilirliğini arttırmak içindir.

Fakat C ile yaptığımız her işlem legal değildir. Örneğin illegal bir

şeyler yazıp F7'ye basıp tekrar derleyelim.

Bu sefer derleyici bize hataları bildiriyor. Hata raporunun üzerine

çift tıkladığınız zaman sizi hatanın olduğu satıra götürüyor.

Problemi giderdikten sonra kodun doğruluğunu kontrol etmek için

tekrar derleyiciye sormak iyi bir yol.

Page 21: ARM Programlama

ARM Programlama

ARM Programlama 21

Derleyicinin, sizi omzunuzun üzerinden izleyen en iyi dostunuz

olduğuna inanmanızı istiyorum, tüm ihtiyacınız sık sık F7'ye basarak

ona bir şans vermeniz.

Şimdi bilgisayarların nasıl sayım yaptığını göstermek için

kullanacağımız bir sayaç değişkeni tanımlayalım.

Bir değişken bir değeri bilgisayar belleğinde tutmak için bir

konumdur, bir sayı gibi. C'de bir değer kullanmadan önce bir

değişken tanımlamak zorundasınız. Bunu değişkenin türünü belirtip

(1) ardından bir isim belirtip (2) ve opsiyonel olarak bir başlangıç

değeri belirterek yapabilirsiniz (3).

Page 22: ARM Programlama

ARM Programlama

ARM Programlama 22

Hemen F7'ye basarak kodumuzun doğru çalışıp çalışmadığını

derleyiciye soralım.

Güzel. Hiçbir hata yok fakat sayac adlı değişkeninin tanımlandığı

ancak kullanılmadığını söyleyen bir uyarı var, bu doğru.

Şimdi sayaç değişkenini şu anki değerinden birer birer arttıralım.

C'de bu arttırma için ön arttırma (pre-increment) olarak

adlandırılan özel bir operatöre (++) sahip.

Page 23: ARM Programlama

ARM Programlama

ARM Programlama 23

Her zamanki gibi derleyiciyi kontrol edelim.

Bilgisayarın nasıl sayım yaptığını izlemek istediğimiz için sayac

adlı değişkeni birkaç kez daha arttıralım.

Page 24: ARM Programlama

ARM Programlama

ARM Programlama 24

F7'ye basıp son bir kez daha derleyelim ve düzgün çalıştığından emin

olalım.

Şimdi bu programın nasıl çalıştırılacağını göstereceğim. Öncelikle

projenin simulatör için yapılandırıldığından emin olun, aslında bunu

üstteki simulatör menüsünden anlayabilirsiniz fakat iki defa kontrol

edelim. Project > Options menüsüne tıklayın. Debugger kategorisinde

Simulator seçeneğini görmelisiniz.

Page 25: ARM Programlama

ARM Programlama

ARM Programlama 25

Programı çalıştırmak için 2 seçeneğe sahipsiniz. İlki Project >

Download and Debugmenüsü, diğeri ise araç çubuğu butonu. Ben bu

butonu kullanacağım.

Şimdi, IAR araç seti hata ayıklayıcısı (Debugger) moduna geçti.

Takip eden hata ayıklayıcı görünümlerinin görünür olduğundan emin

Page 26: ARM Programlama

ARM Programlama

ARM Programlama 26

olun (Disassembly, Memory, Register ve Locals), bunları açmak için

View menüsünden ilgili alanları seçelim.

Menüleri sürükleyip düzenleyelim. Böylece ARM Cortex-M4F

işlemcisinin içindeki en iyi görünüme sahibiz.

Page 27: ARM Programlama

ARM Programlama

ARM Programlama 27

Öncelikle Disassembly menüsüne göz atalım. Programımız için

derleyici tarafından üretilmiş olan kodları bu görünüm menüsü size

makine kodu olarak gösteriyor. Ana (main) fonksiyomuzun

başlangıcındaki vurgulanmış satırda işlemci durmuş.

Page 28: ARM Programlama

ARM Programlama

ARM Programlama 28

Makine Komutları, bilgisayarın içinde başka bir deyişle sadece

sayılardır.

Sembollerin sağındaki komutlar, komut anımsatıcı (instruction

mnemonics) olarak adlandırılır ve komut anımsatıcıları hata ayıklacı

tarafından okunurluğu arttırmak için ekleniyor.

Page 29: ARM Programlama

ARM Programlama

ARM Programlama 29

Sembollerin solunda kalan sayı sütunları komutların bellek

adresidir. Bellek adresleri basit olarak belleğe bayt olarak atanan

sayılardır. Unutulmamalıdır ki komutlar sadece bellekteki

sayılardır.

Bellek görünüm menüsüne bir göz atalım. Belleği büyük bir bayt

tablosu olarak düşünebilirsiniz. Sıfırdan başlayıp sıralı olarak

numaralandırılmış.

Page 30: ARM Programlama

ARM Programlama

ARM Programlama 30

Bunlar sıraları sayılar, adresler olarak adlandırılanlar, bellek

görünüm menüsünün solunda sayı sütunu boyunca gösteriliyor.

Bellekteki makine kodlarını daha iyi tanımak için görünümü 2xbirim

olarak değiştirelim çünkü ARM Cortex komutlarının büyük çoğunluğu

bellekte 2 bayt işgal eder.

Şimdi komutları rahatlıkla tanımalısınız. Örneğin 0x12c adresinde,

aynı sayıyı Disassembly menüsünde göreceksiniz.

Page 31: ARM Programlama

ARM Programlama

ARM Programlama 31

Bu 0x130 ile 0x14a bulunan komutlar içinde aynıdır.

0x12 ifadesinden sonra gelen c harfinin neyi temsil ettiğini kısaca

açıklamak istiyorum.

Page 32: ARM Programlama

ARM Programlama

ARM Programlama 32

Her bir komut bir sütunda saklanır ve sütunlar yukarıda görüldüğü

gibi adlandırılır, yani0x120 adresi 000d verisini tutarken 0x122

adresi eb00 verisini tutar.

Buraya kadar herşey anlaşıldıysa, C kodunun başından sonuna kadar

satır satır ilerleyelim. Bunu yapmak için aşşağıda gösterildiği

şekilde Step-Into butonuna tıklayın.

Page 33: ARM Programlama

ARM Programlama

ARM Programlama 33

Görüldüğü üzere mevcut komut bir ilerledi ve sayac değişkeninin

değeri 0 olarak değişti.

Page 34: ARM Programlama

ARM Programlama

ARM Programlama 34

Ayrıca Register görünümünü dikkatlice incelerseniz PC

saklayıcısı0x12e olarak değişti. PC program sayacını (Program Counter) simgeliyor çünkü program

sayacı komutların sayımını yapıyor ve her zaman mevcut komutun

adresini tutuyor.

Şimdi bir sonraki komutu çalıştırmak için Step-Into butonunun üstüne

bir kez daha tıklatalım.

Bu sefer sayıcı (sayac) değerinin değeri 1'e yükseldi.

Sayıcı (sayac) değişkenin R1 saklayıcısında yer aldığını locals

Page 35: ARM Programlama

ARM Programlama

ARM Programlama 35

menüsünde görebilirsiniz.

Kaydedici (Register) görünüm menüsünü gözden geçirdiğinizde deR1'in

değerinin 1 oldğunu görebilirsiniz.

Fakat nedir bu saklayıcılar ?

Eğer şimdiye kadar bir hesap makinesi kullandıysanız önceden bir

fikir sahibisiniz demektir çünkü mikrodenetleyicilerdeki

kaydedicilerle hesap makinesindeki kaydediciler birbirlerine çok

benzer. Genel anlamda bir hesap makinesinin bellek kaydedicisine

ekleme yapabilir (+), geri çağırabilir (M+) ve temizleyebilirsiniz

(MRC).

Page 36: ARM Programlama

ARM Programlama

ARM Programlama 36

ARM Cortex-M işlemcisi bunun gibi 16 kaydediciye sahip, bunlarR0'dan

R15'e sıralı olarak isimlendirilmiş.

Fakat burada 15 tane kaydedici görüyoruz. Peki nerede bu 16.

kaydedici. R15, PC kaydedicisinin diğer adıdır.

Tüm bu kaydediciler 32 bitlik sayıları tutabilir.

Page 37: ARM Programlama

ARM Programlama

ARM Programlama 37

Bu kaydedicilerin önem durumu gerçek şu ki makine kodları genel

olarak bir saat çevriminde (clock cycle) doğrudan kayedicileri

hünerli bir şekilde kullanabilirler.

Zaten komutların kaydedicileri kullanmasının 2 örneğini gördünüz

0'dan R1'e olan değişim ve R1'e ekleme yapma gibi.

Şimdi aynı düzende kod boyunca ilerleyelim (Step-Into) ve sayaç

(sayac) değişkeninin artışını izleyelim.

Page 38: ARM Programlama

ARM Programlama

ARM Programlama 38

Herşey beklenildiği gibi çalışıyor gibi görünüyor fakat sayaç

(sayac) 10'a ulaştığında ilginç birşey oluyor. Hatırladığımız

kadarıyla "sayac" R1 kaydedicisinde bulunuyor sayac'ın 10 değerinde

Locals ve Register görünüm menüsü senkronizasyonun dışına çıkmış

gibi görünüyor çünkü R1'in değerini 'A' olarak görüyoruz. Bu biraz

açıklama gerektiriyor.

Locals görünüm menüsü sayac değişkenini onluk sayı sisteminde

gösteriyor. İnsanlar bunu benimsemiş çünkü normal bir insan 10

parmağa sahip. Halbuki, C programcılarının bir süre sonra işlerinde

parmaklarının sayısı 16'ya çıkıyor. Örneğin alttaki resim yıllarca C

programlamadan sonra parmaklarımın hali.

Page 39: ARM Programlama

ARM Programlama

ARM Programlama 39

Programcılar 16'lık

sayı sistemini, çalışmak için 10'luk sayı sistemine göre daha uygun

buluyorlar çünkü 16'lık sayı sistemi ksusursuz bir şekilde tüm

bilgisayarın temelini oluşturan ikilik sayı sistemini haritalıyor.

Yanda gördüğünüz bu karşılaştırma 10'luk, 2'lik (BIN) ve 16'lık sayı

sistemleri arasında tek bir 16'lık hane 4 bitlik bir grubu temsil

ediyor. Karşılaştırmada, 10'luk (DEC) sistem 9 üzerindeki sayılar

için 2 haneye ihtiyaç duyuyor. Her 16'lık hanenin öneünde garip

görünümlü '0x' ön eki, C dilindeki hexadecimal (16'lık sayı sistemi)

sayıların kodlanmasının bir düzenidir.

Alttaki resim bir 32 bitlik sayının 16'lık sistemdeki karşılığının

bir örneğinin uygulamasını tablonun üzerinden görebilirsiniz. Bitler

8 li dörlük paketler halinde gruplanmış. Her 8 bit bir Bayt olarak

adlandırılıyor, her bayt iki adet 4 bit (yarım bayt - nibble)

içeriyor. Biraz önce açıkladığım üzere, yarım bayt'lar direkt olarak

16'lık sistemin hanelerini haritalıyor. Örneğin '1010' yarım bayt'ı

hex hanesi olarak A'yı haritalıyor. '0101' yarım bayt'ı 5'i

haritalıyor ve benzeri şeyler. Sonunda tüm 32 bit'lik ikilik sayı

sistemindeki dizi '0x260F3E5A' değerine denk geliyor.

Page 40: ARM Programlama

ARM Programlama

ARM Programlama 40

Ayrıca ben, hata ayıklama (Debug) menüsünün konuyu daha iyi

anlamanıza yardımcı olacağını düşünüyorum çünkü bunların çoğu 16'lık

bir sistemi gösteriyor '0x' ön ekini anladığınız üzere.

Şimdi, programımızla 'sayac' değişkeninin değerini arttırmayı

bırakmadan önce sayılar büyük değer aldığında ne olacağını test

etmek için bir bit ile aldatma yapalım. Bunu yapmak hata

ayıklayıcısı (Debug) görünüm menüsünde oldukça kolay çünkü manuel

olarak herhangi bir değeri değiştirebilirsiniz, sadece üstüne

tıklayın ve yeni bir değer girin.

Test için

'0x7FFFFFFF' değerini yanmamız gerekiyor, bu sayı onluk sistemdeki

en büyük sayıdır. Bu sayıyı yazıp Enter tuşuna basınca karşımıza

onluk sistemdeki sayı çıkıyor.

Şimdi Step-Into butonuna tıklayarak sayac değişkenini bir

arttıralım.

Çok garip birşey oluyor. R1 kaydedicisi '0x80000000' iken, sizin

sayac değişkeninizin değeriniz onluk sistemdeki büyük bir negatif

sayıyı gösteriyor. Tekrar, bu biraz açıklama gerektiriyor.

Page 41: ARM Programlama

ARM Programlama

ARM Programlama 41

Sayac adlı değişkenimiz bir tamsayı (integer - int) olarak

bildirildi, bu C dilinde işaretli bir sayıdır. Bu Pozitif/Negatif

bütün sayıları depolayabilir anlamına geliyor. Sonunda anlaşıldı ki

bilgisayar oldukça garip bir yöntemle negatif sayıları ifade ediyor.

Yukardaki şekildeki dairesel grafik nasıl çalıştığını açıklıyor.

Grafikteki her ok bir artışı simgeliyor. Küçük pozitif sayılar için,

herşey tüm bitler dolana kadar beklenildiği gibi çalışıyor ama en

önemli bir bit... Bu sayı 32 bitlik pozitif işaretli sayı, en büyük

değeri temsil edebilir (0x7FFFFFFF). bu numarayı bir arttırırsanız

en önemli bit'i taşımış olursunuz. sayı bu noktada negatif değerli

bir sayı olur. Aslına bakarsak, bu 32 bit ile temsil edilen en küçük

negatif oluyor (0x80000000). Oradan arttırmaya devam ettiğinizde

değer tüm bitleri doldurmanıza kadar daha küçük bir negatif sayı

oluyor (0x80000001... 0xFFFFFFF). Bu noktada -1'e ulaşıyoruz

(0xFFFFFFF). -1'i arttırdığımız zaman 0 değerine ulaşıyorsunuz ve bu

çevrim tekrarlanır.

Hata ayıklayıcı (Debug) menüsüne geri dönelim, sayacın değerini -1

olarak değiştirip R1 kaydedicinin içeriğini izleyelim.

Bunun için Step-Into butonuna tıklayarak sayac adlı değişkenimizi

bir arttırıyoruz ve sayacı tekrar 0 yapıyoruz.

Hata ayıklayıcı menüsünü 'X' butonuna basarak kapatın.

Sevimsiz hocalar gibi davranıp size bir ödev veriyorum. Sizden

işaretsiz tamsayıların (unsigned int) sayımını istiyorum. Bunu

yapın. Sayac değişkeninin türünü unsigned int olarak değiştirmeniz

gerekiyor.

Page 42: ARM Programlama

ARM Programlama

ARM Programlama 42

Yeniden derleyin ve hata ayıklayıcı menüsünü başlatın. Bu derste

biraz önce yaptığımız gibi.

Son olarak, size Launchpad Board üzerinde bir kodun nasıl

çalıştırılacağını gösterme sözü vermiştim. Bunu yapalım, proje

seçeneklerini değiştirmeniz gerekiyor Project > Optionsmenüsünün

üzerine tıklayın. Debugger kategorisini seçin aşşağı açılan listeden

TI-Stellaris seçeneğini seçin.

Page 43: ARM Programlama

ARM Programlama

ARM Programlama 43

Daha sonra, Download sekmesinin üzerine tıklayın ve Use flash

loader(s) ve Verify download seçeneğini seçtikten sonra OK deyip

kapatıyoruz.

Page 44: ARM Programlama

ARM Programlama

ARM Programlama 44

Bu noktadan sonra bilgisayar ile Launchpad arasında USB kablo ile

bağlantı kurabilirsiniz. Eğer kartı ilk defa takıyorsanız gerekli

sürücülerin yüklenmesi için 2 dakika kadar bekleyin. Ledlerin

yanmasını sağlayan kart içine üretilirken yüklenmiş bir programdır.

Şimdi her zamanki gibi F7 kısayolunu kullanarak Launchpad'in flash

hafızasının içine yazdığımız kodları yükleyebiliriz. Programınızın

kartın içine kalıcı olarak yüklendiğini söylemek isterim, yani led

sönecek. Ama umutsuzluğa kapılmayın, bunu ve bundan fazlasını ilerde

yapacağız.

Page 45: ARM Programlama

ARM Programlama

ARM Programlama 45

KONTROL AKIŞI

Gömülü sistemler programlama derslerine hoş geldiniz, bu ders

kodlarımızda tümüyle kontrol akışının nasıl değiştirileceğini

göstereceğim.

Önceki ders1 projesinin bir kopyasını alarak başlayalım ve sonra

ders1’i ders2 olarak isimlendirelim. Eğer ders1 dosyasına sahip

değilseniz bu yazıyı okuyabilirsiniz.

Page 46: ARM Programlama

ARM Programlama

ARM Programlama 46

Yazılım geliştirmenin altın kuralı sadece küçük değişiklikler

yaparak çalışan kodları her zaman saklamaktır. Dolayısıyla eğer

çalışan bir şeye sahipseniz onu kaydedin. Bir aşamayı

karıştırdığınız zaman yaptığınız bu işten çok memnun olacaksınız.

Çalışan son sürümün yedeğini almak, hatalı kodu düzeltmeye

çalışmaktan daha kolaydır.

Ders2 klasörünün içine girin ve IAR araç setini açmak için çalışma

alanı dosyasının üstüne çift tıklayın (.eww uzantılı dosya). Eğer

IAR araç setine sahip değilseniz bu yazıyı okuyabilirsiniz.

IAR araç seti açılınca geçen karşımıza ilk derste oluşturduğumuz C

programı çıkıyor. Her C programı aşağıdaki gibi bir main

fonksiyonunun yürütülmesiyle başlar. Main içinde, kontrolün

yukarıdan aşağıya doğru aktığı çok basit doğrusal bir koda

sahipsiniz.

Page 47: ARM Programlama

ARM Programlama

ARM Programlama 47

İşlemcinizin bu kolay kontrol akışını nasıl ele alacağını görmek

için hata ayıklayıcıya hızlıca bir göz atalım. Hata ayıklayıcının

simülatör olarak ayarlandığından emin olun veDownload and Debug

butonunun üzerine tıklayın. Hata ayıklama modunda ne gördüğümüzü

hızlı bir şekilde hatırlayalım.

Disassembly görünüm menüsü makine komutlarını gösteriyor.

Register görünüm menüsü ARM Cortex-M kaydedicilerinin durumunu

gösteriyor.

Halihazırdaki komutların adreslerini içeren disassembly görünüm

menüsünde sizin için vurgulanmış olan, bu dersin sizin için en ilgi

çekici şeyi program sayaç (PC) kaydedicisidir.

Page 48: ARM Programlama

ARM Programlama

ARM Programlama 48

Bir seferde bir makine kodu atlatın ve PC kaydedicisinin her adımda

nasıl değiştiğini gözlemleyin.

Page 49: ARM Programlama

ARM Programlama

ARM Programlama 49

Sadece R1 kaydedicisini arttırmak için komutları çalıştırdığımıza

dikkat edin çünkü PCkaydedicisini arttırmak için herhangi özel bir

komut bulunmuyor aksine her komut yan etki olarak PC kaydedicisini

arttırıyor. Böylece buradan anlıyorsunuz ki bu basit komutlar kendi

içlerinde tümüyle düzgün akış denetimindeki kodlar boyunca donanımla

bütünleşiktir. Bu derste, bu donanımla bütünleşik kontrol akışının

nasıl değiştirileceğini öğreneceksiniz, böylelikle program döngü

yada şarta bağlı olarak kod parçacıklarının üzerinden atlayabilir.

Kontrol akışındaki bu gibi değişiklikler yinelemeleri önlemeyi ve

çalışma anında karar vermeye olanak sağlayacak. Şimdi bu nedenle

hata ayıklayıcıdan çıkalım ve kodu bir döngüyle beraber kullanmak

için kodun üzerinde değişiklik yapalım.

Page 50: ARM Programlama

ARM Programlama

ARM Programlama 50

C dilindeki en basit döngü while döngüsüdür. Bunu "while" anahtar

kelimesini ekleyerek yapabiliriz (1), bunu takiben parantez içinde

bir şart kodlayalım (2), son olarak döngünün gövde kısmını

kodlayalım (3).

int main(){

int sayac = 0;

while(sayac < 5){

sayac++;

}

return 0; }

Bu kod şartı kontrol ederek başlıyor ve eğer bu şart doğruysa, bu

döngünün gövde kısmındaki kodları çalıştırıyor ve şartı tekrar

kontrol etmek için geri dönüyor. Bu döngüden sadece şart

sağlanmadığında çıkış yapılıyor.

Page 51: ARM Programlama

ARM Programlama

ARM Programlama 51

Bu durumda, sayaç değişkeni 21 artışa sahip oluyor böylelikle

"(counter < 21)" şartı ile artışın aynı sayıda olması için

çalıştıralım. Derleyelim ve bu kodu simülatörde çalıştıralım.

İlk komut (int sayac = 0) sayaç değişkenini tutmak için şuan

kullanılmakta olan R0kaydedicisine 0 değerini taşıyor.

Bir sonraki B komutu çok ilginç bir dallanma komutudur çünkü bu

komut PC üzerinde değişiklik yapıyor.

Page 52: ARM Programlama

ARM Programlama

ARM Programlama 52

Bundan dolayı bu birkaç komutun üzerinden atlıyor. Komutun

kendisinde hexadecimal sistemde 15 olarak kodlanmış fiilen

gördüğümüz CMP komutu R0 kaydedicisini 21 sayısıyla karşılaştırıyor. Application Program Status Register (APSR) için bulunan CMP komutu

APSR kaydedicisinin değiştirilmesinde ilginç bir yan etkiye sahip.

Özellikle CMP komutu APSR de N (negatif) bitini belirliyor, çünkü

negatif sonuçlandırılan karşılaştırma R0-5 bir fark olarak

gerçekleştirilmiş.

Page 53: ARM Programlama

ARM Programlama

ARM Programlama 53

BLT komutu dallanma komutunun bir çeşididir. Siz zaten önceden bunu

gördünüz fakat bu şarta bağlı bir dallanmadır. Özellikle sadece N

biti APSR'ye atandığı zaman BLT komutu PC üzerinde değişiklik

yapıyor. Aksi takdirde BLT komutu basit olarak bir sonraki komut

için başarısızlığa uğruyor ve program sonlanıyor.

Bu noktada şu güzel bir soru : "Dallanma komutu nereye dallanacağını

nasıl biliyor ?". Güzel, bu bilgi komutta kodlanmış olan bilgiden

dışarı çıkıyor. Aşağıda tüm B komut türlerinin kodlanmasını

açıklayan ARM mimarisi kullanma kılavuzundan bir sayfa.

Komutumuz "0xD" ile başlıyor bu demek oluyorki bu T1 kodlaması

kullanıyor.

Page 54: ARM Programlama

ARM Programlama

ARM Programlama 54

Komuttaki sonraki yarım bayt koşul anlamına geliyor ve "0xB" LT

(Less Than) koşulu anlamına geliyor. Sonunda, offset olarak

adlandırılan fc baytı PC kaydedicisinin ne kadar değişmesi

gerektiğini kodluyor. Şuan offset işaretli bir tamsayıdır ve ilk

dersten, işaretli sayıların ikinin tümleyen gösterimini kullandığını

hatırlamalısınız. Buna binayen fc baytı -4’ü temsil ediyor.

Böylelikle şimdi, PC kaydedicisinin yeni değerini hesaplayabiliriz.

0x7E olarak verilen değerini şuanki PC’nin değeri 0x82 değerinden 4

eksilterek anlıyorsunuz. Hesap makinesini programcı modunda açıp 82

değerinden 4 çıkarırsak 7E değerini buluyoruz.

Bu dallanmanın nereye gideceğini beklediğiniz yerdir. Bunu BLT

komutunu çalıştırarak doğrulayalım.

Hey! Şaşırtıcı!, siz haklısınız. PC geriye dallanıyor, böylelikle

kod boyunca giderek doğrulayabileceğiniz bir döngüye sahipsiniz.

Endişelenmeyin, komutların iç ytapısını irdeleme üzerine daha fazla

zaman harcamayacağım fakat BLT komut açıklamasının öğretici olduğunu

düşünüyorum çünkü bu ARM Cortex-M işlemcisinin iç işleyişine anlık

bir bakış verdi.

Şimdi kontrol akışına geri dönelim. Disassembly kodları while

döngüsü için açıkladığım kodların farklı bir kontrol akışı

gerçekleştiğini anladığınızı umuyorum.

Asıl kodun ilk koşulu kontrol etmesi gerekiyor ve eğer koşul doğru

değilse döngü gövdesinin üzerinden dallanır, yani arttırma işlemi

gerçekleşmez.

Derlenmiş kod koşulsuz bir bölüm ile başlıyor ve döngü gövdesinin

yolunu geri döndürüyor ve koşulu test ediyor. Bunun hakkında

düşündüğünüz zaman gerçi, bu iki kontrol akışı eşit, üretilen kodun

daha hızlı olması bekleniyor çünkü bu sadece döngünün altında bir

koşula sahip. Bu örnek iki önemli noktayı gösteriyor. İlk olarak,

tek bir C ifadesi “while” gibi, birlikte gruplanmış olması

gerekmeyen birden çok makine kodu üretebiliyor.

Page 55: ARM Programlama

ARM Programlama

ARM Programlama 55

İkincisi : derleyici oldukça akıllı ve işlemcinin size göre daha iyi

olduğunu biliyor ayrıca düzgün olmayan kontrol akışı işlemcinin

sizin kodlarınızı ne kadar hızlı çalıştıracağı üzerine önemli bir

etkiye sahip ve bir gömülü sistemler programcısı olarak bunun

farkında olmanız gerekiyor. İlk olarak burada bir döngü ek yükü var

çünkü sadece döngüyü işlemek için şuan ilaveten test ve dallanma

yapıyorsunuz.

Fakat bir dakika! burada daha kötü bir şey var. Dallanmalar ek

olarak iletişim hattı (Pipeline) gecikmelerinden dolayı işletim

gecikmesi ekliyor.

Açıklayalım ;

Bütün modern işlemciler, ARM Cortex-M'de dahil olmak üzere

verimliliği arttırmak için bir iletişim hattı (Pipeline) kullanıyor.

İşlemci işlemenin çeşitli aşamalarında çoklu komutlar üzerinde

çalışan iletişim hattı bir assembly hattı gibidir.

Bu verilen bir zamanda işlenebilen komutların sayısını arttırıyor.

Her komut, bağımsız aşamalar dizisi haline bölünür, bellek

kullanımı(1), kod çözme(2) ve çalıştırma(3) gibi.

Halbuki bu adımların her birinin tamamlanması bir saat çevrimi

(clock cycle) alıyor. Komutlar sırayla yürütüldüğü zaman iletişim

hattı tam kapasite çalışıyor. Fakat sıralama bir dallanma komutu

tarafından bozulduğu zaman iletişim hattı kısmen işleme tabi tutulan

komutları atması gerekiyor ve tekrar komutu başlatması gerekiyor. Bu

iletişim hattı gecikmelerinin birkaç çevrim için olduğu anlamına

geliyor. Az önce gerçekten önemli sadece kritik zamanlı koddan söz

ettim, kesme işlemi gibi ve diğer durumların çoğu için önemsiz

olması gibi. Ne var ki, bazı şeyleri hızlandırmanız gerektiğinde ne

Page 56: ARM Programlama

ARM Programlama

ARM Programlama 56

yapmanız gerektiğini biliyorsunuz. Bazı döngüleri ya tamamen yada

ihtiyacınız olduğu kadarıyla açabilirsiniz. Örneğin while döngüsünü

uygun olarak değiştirebilirsiniz : sayaç artış miktarını döngü

boyunca tek bir geçiş başına arttırabilirsiniz ve döngüyü

ayarlayabilirsiniz.

Şimdi. Kodu çalıştırdığımız zaman, test etme ve dallanmanın daha az

sıklıkla gerçekleştiğini görebilirsiniz. Oysa, 5 artışla aynı sayıda

çalıştırıyorsunuz.

Sonunda bu ders için, programın çalışma anında karar vermek için

kontrol akışının nasıl kullanılacağını göstermek istiyorum. Farz edelim, örneğin siz sayaç değişkeninin tek sayı olduğu her

zaman özel bir şey yapmak istiyorsunuz. Kodumuzu 20 artış haline

getirelim ve “if” ifadesini yazarak kodlamaya başlayalım.

İf anahtar kelimesini takiben parantez için şartla başlayın, bunu

takiben şart doğru olduğunda kodu çalıştırın. Sayacın çift olup

olmadığını test etmek için kullanılan koşul ifadesi biraz açıklama

gerektiriyor.

Page 57: ARM Programlama

ARM Programlama

ARM Programlama 57

Sayacın her biti arasındaki ve işlemi gerçekleştiren ampresan(&)

işareti bitsel AND operatörü için ve ikinci terim içindir.

Aşşağıdaki örnekte gördüğünüz gibi, bir testin ikinci terimi sayaç

çift olduğu zaman sıfır ve sayaç tek olduğu zaman bir.

Ünlem eşit operatörü (!=) eşit değil anlamına geliyor.

Sadece şart yanlış olduğunda çalıştırılan bir kodu ayrıca isteğe

bağlı olarak if’e ekliyebilirsiniz.

C’de iç içe yerleştirilebilen kontrol akış ifadelerinin farkına

vardığınızı umuyorum böylelikle while içinde if olan bir döngüye

sahipsiniz.

Page 58: ARM Programlama

ARM Programlama

ARM Programlama 58

DEĞİŞKENLER ve İŞARETÇİLER Merhaba. Gömülü sistemler programlama derslerine hoşgeldiniz. Bu

derste değişkenler ve işaretçiler hakkında konuşacağız.

Önceki ders2 projesinin bir kopyasını alalım ve bunu ders3 olarak

isimlendirelim. Eğer ders2 dosyasına sahip değilseniz bu yazıyı

okuyabilirsiniz.

ders3 klasörünün içine girin ve IAR araç setini açmak için çalışma

dosyasının üzerine çift tıklayın (.eww uzantılı dosya). Eğer IAR

araç setine sahip değilseniz bu yazıyı okuyabilirsiniz.

Ve burada ders2'de oluşturduğumuz C dosyası var. Bunu birazcık

temizleyelim ve sayaç değişkeninin nerede bulunduğuna ve nasıl

erişildiğine hata ayıklayıcıda hızlıca bir göz atalım.

Kod boyunca gittiğiniz ve Locals görünüm menüsünü izlediğiniz üzere,

sayaç değişkeninin R0 kaydedicisi içinde bulunduğu ve doğrudan

makine kodlarıyla erişildiğini görüyorsunuz.

Şimdi, değişken tanımlamasını (int counter = 0;) main fonksiyonunun

dışına taşıyalım, yeniden derleyelim ve hata ayıklayıcıya geri

dönelim.

Page 59: ARM Programlama

ARM Programlama

ARM Programlama 59

İlginç şekilde, sayaç değişkeni artık Locals görünüm menüsünde

değil, Çünkü artık local (yerel değişken) değil. Şimdi sayaç değişkenini görmek için farklı bir görünüm menüsüne

ihtiyacımız var. Viewmenüsüne gelin ve Watch > Watch1 görünüm

menüsünün üzerine tıklayın.

Page 60: ARM Programlama

ARM Programlama

ARM Programlama 60

Watch görünüm menüsü açıldığı zaman ilk satıra tıklayın ve

değişkenin adını yazın.

Page 61: ARM Programlama

ARM Programlama

ARM Programlama 61

Artık sayaç yorumlanabilecek bir durumda.

Göründüğü üzere, şimdi 0x2 ile sayaç değişkeninin konumu büyük bir

sayıyla başlıyor.

Bu adres ARM Cortex-M mikro denetleyicilerindeki Ram Accesed

Memory'nin başlangıcıdır. Bu nedenle sayaç değişkeni RAM' de

bulunuyor.

Eğer gerçekten bu böyle ise değişken doğrudan bellek görünüm

penceresinde (Memory) görünür olmalı.

Bunu kontrol edelim, bellek görünüm menüsüne 0x2000000 sayısını

atayın (1) ve bellek ayarlama görünüm menüsünü 4 byte'lık tamsayılar

olarak göstermek için 4x birim şeklinde değiştirin (2).

Şimdi, kod boyunca tek aşama gidelim ve hata ayıklayıcı görünüm

menüsünü takip edelim.

STR komutunun Watch1 görünüm menüsünde sıfırdan bire değişime neden

olduğunu fark edin.

Page 62: ARM Programlama

ARM Programlama

ARM Programlama 62

Kod boyunca ilerleyin ve artışı gözlemleyin. Bellekte derleyicinin sayaç değişkenine erişmek için ürettiği makine

kodlarını anlamaya çalışalım. Bellekten kaydediciye yükleme yapmak

için bulunan ilk ilginç komut LDR'dir.

LDR.N komutu, ??main2 etiketinden R0 kaydedicisine bir şeyler

yüklüyor.

Page 63: ARM Programlama

ARM Programlama

ARM Programlama 63

Aslına bakarsak

bu

etikete

ne

yüklediğini görmek

için aşağıya

kaydırabilirsiniz. Hey, bu benzer gözüküyor.

R0'a yüklenen değer sayaç değişkeninin adresidir.

LDR.N komutunu çalıştıralım ve R0'ı izleyelim.

Page 64: ARM Programlama

ARM Programlama

ARM Programlama 64

Bir sonraki LDR komutu R0'ı tekrar yüklüyor, fakat bu sefer sayaç

değişkeninin adresi için olan değer R0'ın şu anki tutulan adresinden

geliyor. Bir adım gidelim ve R0'ın şuan 3 değerine sahip olduğunu

doğrulayalım.

Page 65: ARM Programlama

ARM Programlama

ARM Programlama 65

ADDS komutu R0'ı bir arttırmada asıl işi yapıyor böylelikle R0 4

oluyor.

Bir sonraki LDR.N komutu R1'e sayaç değişkeninin adresini yüklüyor.

Ve sonunda, STR komutu R1 kaydedicisi tarafından gösterilen belleğe

R0 kaydedicisinin değerini yüklüyor. Lütfen bu komutu çalıştırdıktan

sonra Watch1 ve bellek görünüm menüsünün nasıl değiştiğini fark

edin.

Page 66: ARM Programlama

ARM Programlama

ARM Programlama 66

Bu noktada, ARM işlemcide belleğe erişmenin genel olarak modelini

görmeye başladığınızı umuyorum.

Sadece özel yükleme komutları ile okunabilen ARM, komut kümesi

azaltılmış bilgisayar (RISC) olarak adlandırılan mimarinin bir

örneğidir. Bu, tüm veri, manipülasyonlar, kaydedicileri içinde

bulundurur ve sonunda değiştirilmiş kaydedici değerleri özel

depolama komutu ile belleğe geri depolanabilir.

Bu karşılaştırmada karışık komut kümeli bilgisayar (CISC) yapısı

kompleks komutların kullanıldığı, bilgilerin bazılarının

kaydediciler içinde olmasına gerek olmayan ve yine bellek içinde

olabilen. Kişisel bilgisayarların içindeki saygı değer x86 işlemci

gibi.

Fakat işlemci mimarisi ne olursa olsun, sizin bellek adreslerinin

görevlerini beğenerek başladığınızı umuyorum, çünkü bir yerden veri

yüklemek yada veriyi tutmak için belleğe her erişim ister istemez

bellek adreslerinin bilgisini gerektirir.

Page 67: ARM Programlama

ARM Programlama

ARM Programlama 67

Tüm bunlar ilginç bir soruya yol açıyor. Eğer CPU için bunların

bellek adresleri oldukça belirginse, bunlar C dilinde temsil

edilebilir mi?

Bunun cevabı "Evet"'tir. C programlama dilinde adresler

değişkenlerin içinde işaretçiler(pointers) olarak adlandırılan

yapıyla tutulabilir.

Burada C'de bir işaretçi değişkeninin örneği var.

Çoğu C bildirimi gibi, açıklamanın en iyi yolu bir tanesini geriye

doğru okumaktır. Böylelikle, tamsayı belirtecinden (int) sonra

yazılan yıldız işareti, p_int adlı değişkenin bir işaretçi olduğu

anlamına geliyor. Başka bir deyişle tamsayı değişkenlerinin adresini

tutabilen p_int, bir değişkendir.

Eğer öyle ise, bu durumda p_int'in değerleri arasında tamsayı olarak

tanımlanan sayaç değişkeninin adresini tutması gerekir.

Doğrusunu söylemek gerekirse, C'de bu kolaylıkla sağlanabilir.

Ampresand (&) operatörü sayaç değişkeninin adresini veriyor ve bu

adres legal olarak p_int'e atanabilir.

Page 68: ARM Programlama

ARM Programlama

ARM Programlama 68

Sonunda, referanstan ayırma (De - Referencing) işaretçisi olarak

adlandırılan bu işaretçiden verilen bir adreste saklanan değeri

almak oldukça kullanışlıdır.

*p_int bu durumda sayaç değişkeninin değeri olan p_int işaretçisi

içinde güncel olarak saklanan adresteki değer anlamına geliyor.

Bu eşitlik sayesinde, sayaç değişkeni ile *p_int'i yer

değiştirebilirsiniz ve program eskisi gibi aynı çalışır.

Bakalım derleyici bu program ile memnun mu?

İşler yolunda, böylelikle şimdi hata ayıklayıcıya gidelim ve görünüm

menülerini hazırlayalım. Bu sefer sayaç değişkenini görmek için

Watch1 görünüm menüsüne ve p_int işaretçisini görmek için Locals

görünüm menüsüne ihtiyacımız var.

Kod boyunca ilerlemeden önce, Disassembly görünüm menüsüne bir göz

atalım ve p_int işaretçisini tanıtmadan önce şimdiki makine kodu ile

öncekini karşılaştıralım.

Page 69: ARM Programlama

ARM Programlama

ARM Programlama 69

Gördüğümüz üzere, sayaç değerinin adresini yükleyen LDR komutu en

üst bölüme taşındı ve aynı komutun bir kopyası birlikte kaldırıldı. Başka bir deyişle, p_int işaretçi komutu makine kodunun işini

kolaylaştırdı ve verimliliği arttırdı. Bu kod ayrıca p_int

işaretçisinin R0'da bulunduğunu gösteriyor.

Şuan kod boyunca adım adım ilerleyebilir ve sayaç değişkeninin

artışını hem Watch1 görünüm menüsünde hem de bellek görünüm

menüsünde izleyebilirsiniz, tamamen öncekiyle aynı.

Bu sayaç değişkeninin bir adı olduğunu tamamen doğruluyor. Sonunda, eğer döngünün sonuna kadar çalıştırmak isterseniz fakat kod

boyunca tek tek ilerlemekten sıkılıyorsanız bir kırılma noktası

(Breakpoint) atayabilir ve programı tam hızında çalıştırmak için

"Go" butonuna basabilirsiniz.

Kırılma noktasını atadıktan sonra final değerinin 20 olduğunu

doğrulayabilirsiniz, beklendiği gibi.

Page 70: ARM Programlama

ARM Programlama

ARM Programlama 70

Dersin son adımında, işaretçilerin inanılmaz gücünü göstermek

istiyorum.

Bu noktada, bu müthiş bir hack olacak (hacklemek teriminin yanlış

anlaşılması üzerine bir makalemi yakında yayınlayacağım). Bu size

gömülü sistemler programlamasında fiilen kullanılan bir teknik

gösterecek.

Daha önce söylediğim üzere, bir işaretçi değişkeni, p_int gibi, bir

tamsayının adresini tutuyor fakat bu neredeyse hemen hemen her adres

olabilir, sadece sayaç değişkeninin adresi değil. Öyleyse, p_int'e

uydurma bir adres atamayı deneyelim.

Hata ayıklayıcıda gördüğünüz üzere ilk girişimizde sadece bir hex

sayısı olarak ifade edilen bir adres kullanmayı deneyebilirsiniz.

Fakat F7'ye basıp derlediğimiz zaman derleyici kodu kabul

etmeyecektir.

Page 71: ARM Programlama

ARM Programlama

ARM Programlama 71

Bir sonraki denememizde, sayının sonuna U ekleyerek bir işaretsiz

sayı kullanmayı deneyebilirsiniz fakat derleyici bu ikisinden de

hoşlanmıyor.

Page 72: ARM Programlama

ARM Programlama

ARM Programlama 72

Bu noktada derleyici ile olan görüşmeniz bozuldu. Fakat C dili bir

tür kalıplama kullanımı uygulamak için bir mekanizmaya sahiptir. Siz

ifadenin önüne türünün adını yerleştirerek bunu

gerçekleştirebilirsiniz.

Şimdi derleyicinin herhangi bir seçeneği yok, bunu kabul edecektir.

Page 73: ARM Programlama

ARM Programlama

ARM Programlama 73

İşaretçiyi inceleyelim ve kolayca anlaşılabilir tamsayı değerini.

Gömülü programcılar bu gaye için ölü sığır (DEAD BEEF (Ölü Sığır).

İngilizcede kullanılan bir metafordur. Bu metaforun başarısızlığa

uğramış, bellek temizlenmesi gibi anlamları vardır.) gibi gözüküyor.

Açıkçası, bu hack'in test edilmesi gerekiyor. Fakat kusurları

önceden görmek için bir şeyler alabilir ki ben Stellaris geliştirme

kartı üzerinde bu kodu çalıştırmak istiyorum. Böylelikle eğer bu

karta sahipseniz bunu bilgisayarınızın USB konektörüne takın. Sonra,

Projectmenüsünden Options'u açın ve hata ayıklayıcıyı TI Stellaris

ara yüzü olarak ayarlayın. AyrıcaDownload sekmesinin altındaki "Use

Page 74: ARM Programlama

ARM Programlama

ARM Programlama 74

flash loader" seçeneğini seçmeyi unutmayın. Eğer karta sahip

değilseniz, bu adımları geçin ve simülatör ile birlikte takip edin.

Her iki durumda da, hata ayıklayıcıya erişmek için "Download and

Debug" butonuna tıklayın.

Page 75: ARM Programlama

ARM Programlama

ARM Programlama 75

p_int işaretçisinin yeniden atanmasında bir kırılma noktasına sahip

olduğunuza emin olun ve ayrıca sayaç değişkenini izleyebilmek için

Watch görünüm menüsünü görülür yaptığınızdan emin olun.

Kırılma noktasını çalıştırmak için "Go"'ya basın. Disassembly

penceresinde bir sefer bir makine komutu gitmek için tıklayın. R0 kaydedicisine uydurma bir adres yükleyen LDR komutunu uygulayın

ayrıca bu adres p_intdeğişkeninin Locals görünüm menüsünde ayrıca R0

görünüm menüsünde de göründüğünü doğrulayın.

Page 76: ARM Programlama

ARM Programlama

ARM Programlama 76

R1'e 0xDEADBEEF değerini yükleyen LDR komutunu çalıştırın. Ve

sonunda, bellekte p_intadresine 0xDEADBEEF'i depolayan STR komutunu

çalıştırın.

Bunun etkisi korkutucu türdür. Uydurma adresin bilinçli yanlış

ayarlanmasından dolayı, 0xDEADBEEF değeri kısmen sayaç değişkeni

üzerinden ve kısmen bellekte sonraki sözcüğün üzerine yazılmış olur.

Cortex-M4 bu yanlış ayarlamayı kabul etti fakat Cortex-M0 bununla

bir sorun yaşardı.

Page 77: ARM Programlama

ARM Programlama

ARM Programlama 77

Böylelikle, siz şimdi işaretçileri bir etkili mekanizma olarak

görüyorsunuz ayrıca eğer bunu dikkatsizce kullansaydım, bu çok

tehlikeli olabilirdi.

LED YAKIP SÖNDÜRME

Merhaba. Gömülü sistemler programlama derslerinin 5. serisine hoş

geldiniz. Bu derste Stellaris Launcpad'in üzerindeki bir ledin nasıl

yanıp söneceğini test edeceğiz.

Bu ders için, Stellaris Launcpad'in Kullanım kılavuzunu (User

Manual) indirmeniz gerekiyor.

Stellaris Launcpad'ine sahip değilseniz, bu dersi hala takip

edebilirsiniz, fakat hata ayıklayıcınızın görünüm menüsü

Launcpad'den biraz farklı olacak ve tabii ki ledin yandığını

göremeyeceksiniz. Kılavuzun bu sayfası size Launcpad ile sağlanan USB kablosu

üzerinden kartın nasıl bilgisayara bağlanacağını açıklıyor.

Page 78: ARM Programlama

ARM Programlama

ARM Programlama 78

Bu sayfa ise kart üzerindeki bileşenlerin mikro denetleyiciye nasıl

bağlandığını açıklıyor.

Page 79: ARM Programlama

ARM Programlama

ARM Programlama 79

Farklı birimlerin, Genel Amaçlı Giriş/Çıkış anlamına gelen GPIO'lar

ile birbirine bağlı olduğunu görebilirsiniz.

Page 80: ARM Programlama

ARM Programlama

ARM Programlama 80

Kılavuzun sonunda ise kartın şematiğini bulabilirsiniz.

Şematiğin ilk sayfasında, LED_R, LED_G, LED_B çıkışları ile ayrı

ayrı kontrol edilen transistorlar tarafından güçlendirilen kullanıcı

led'inin R, G ve B komponentlerini görebilirsiniz.

Page 81: ARM Programlama

ARM Programlama

ARM Programlama 81

Pin F1, pin F2 ve pin F3 olarak etiketlenmiş mikro denetleyici

pinlerine bağlı olan çıkışları tekrar üst düzey olarak

görebilirsiniz. F harfi, bu durumda GPIO-F için bulunuyor.

Böylelikle şimdi, Led'in nasıl bağlı olduğu hakkında bir fikre

sahipsiniz, bu ders için IAR projesini hazırlayalım. Alışıldığı

gibi, önceli ders3 dosyasının bir kopyasını alıp ve ders 4 olarak

isimlendirip başlayalım. Eğer ders3 dosyasına sahip değilseniz bu

yazıyı okuyabilirsiniz.

Page 82: ARM Programlama

ARM Programlama

ARM Programlama 82

ders4 klasörünün içine girin ve IAR araç setini açmak için çalışma

dosyasının üstüne çift tıklayın (.eww uzantılı dosya). Eğer IAR araç

setine sahip değilseniz bu yazıyı okuyabilirsiniz.

Eğer Launcpad kartına sahipseniz, şimdi bilgisayarınıza

bağlamalısınız ve hata ayıklayıcı (Debugger) menüsünde TI Stellaris

ara yüzünü konfigüre etmelisiniz ve ayrıca Download sekmesinin "Use

flash loader" seçeneğinin işaretli olduğuna emin olmalısınız.

Page 83: ARM Programlama

ARM Programlama

ARM Programlama 83

Eğer karta sahip değilseniz, hata ayıklayıcınızı simülatör olarak

konfigüre edin ve yazıyı aynen takip edin.

Ayrıca kart kullanıyorsanız, lütfen TI Stellaris menüsünün üzerine

tıklayın ve "Reset will do system reset" seçeneğini işaretleyin,

böylelikle kart her zaman temiz bir reset ile başlayacaktır.

Page 84: ARM Programlama

ARM Programlama

ARM Programlama 84

Sonunda, main.c dosyasını önceki ders3 projesinden çekmeyi önlemek

için lütfen projeyi tamamen derleyin. Şimdi, hata ayıklayıcıya gidelim ve işlemcinin çeşitli adresleri

nasıl kullandığına hızlıca bir göz atalım.

İlk olarak, en düşük adres 0 ile başlıyor, bunu makine kodlarından

görebilirsiniz.

Bunların hepsi mikro denetleyici içinde depolanmış sizin program

kodlarınızın derlenmiş halidir.

Bu en düşük adresler 0‟dan başlayıp flash hafızada haritalanıyor

anlamına geliyor. Ayrıca siz 0x2 den başlayan adreslerin zaten

değişkenler için kullandığını biliyorsunuz, sayaç değişkeni gibi.

0x2 adresi, rastgele erişimli belleğin (RAM) başlangıcının bir çok

sıfır ile takip edildiği anlamına geliyor. Doğrusu, hata

ayıklayıcının bu adreslerden herhangi bir şey okuyamadığı anlamına

gelen RAM‟in başlangıcının hemen önünde tüm adreslerin içinde

görebilirsiniz, büyük bir olasılıkla çünkü onlar kullanılmadı. Daha

Page 85: ARM Programlama

ARM Programlama

ARM Programlama 85

iyi incelediğimiz zaman, 0x2000,8000 adresinde RAM‟in sonlandığını

görebilirsiniz böylelikle onluk sistemde 32KB olan bir “island”

0x8000 adresi için bir uzatmadır. Bu mikro denetleyicinin 32KB‟lik

RAM‟e sahip olduğu anlamına geliyor. Bu noktada adresler hakkında bu kadar biliyorsunuz. Fakat bu dersin

hedefi olan led yakıp söndürmek için daha fazla öğrenmeniz

gerekiyor. En iyi şekilde, tüm çeşitli “contient” ve “island”‟ların

“map”‟ini bilmeniz gerekiyor, RAM island gibi.

Sizin mikro denetleyicinizin hafıza haritasını “data sheet” olarak

adlandırılan çok daha detaylı doküman açıklıyor. Bu url adresinden

sizin Launchpad kartınızın üzerinde olan LM4F mikrodenetleyicisinin

spesifik data sheet‟ini indirmenizi son derece tavsiye ediyorum.

Fakat data sheet‟lerin çok geniş olma eğiliminde olduğunu hemen size

söylemeliyim. Yinede bu nispeten kısa, 1200 küsür sayfalık bir data

sheet. Şansımıza bu dökümanlar baştan sona okumaya yönelik

tasarlanmış. Doğrusu bir gömülü sistemler mühendisi olmanın büyük

bir kısmı datasheetler‟de nasıl yolunuzun bulunacağından oluşuyor

böylelikle siz ihtiyacınız olan bilgiyi hızlı bir şekilde

bulabilirsiniz. Bu eğitim serisinde bu beceriyi aşama aşama elde

edeceğimizi umuyorum. Böylelikle örneğin, mikro denetleyicinizin

hafıza haritasını (Memory Map) bulmak için, “memory map” dizesini

basitçe datasheet içinde aratın.

Evet, bulduk. Tipik bir ARM Cortex-M mikro denetleyicisinin hafıza

haritasının bir kısmı.

Page 86: ARM Programlama

ARM Programlama

ARM Programlama 86

Bu çok hoş ve herhangi bir bölüm ya da bellek öbeği olmadan ve basit

bir bellek alanı. Eğer diğer mikro denetleyicilerle çalıştıysanız,

özellikle eski 8 bitlik olanlarla, umuyorum bir liner 32 bitlik

adres boşluğunun sadeliğini çok beğeneceksiniz.

Umuyorum 256KB flash belleğe klarşılık gelen 0‟dan 3‟e adreslenen

“On-chip Flash” olarak adlandırılan bu hafıza üzerinde ilk

“island‟ı” tanıdığınızı umuyorum.

Page 87: ARM Programlama

ARM Programlama

ARM Programlama 87

Statik Ram için bulunan SRAM, burada “Bit-banded on-chip SRAM”

olarak adlandırılmış. 0x2 ile başlayıp 0‟la devam eden bilinen RAM

island‟ı tanımalısınız.

Çevre birimi bölümünde, GPIO portlarını not etmelisiniz. Bu “island”

lar ilginç çünkü Led‟inizin kontrolü için “GPIO Port F”i arıyoruz.

Aradğımız Port burada

Page 88: ARM Programlama

ARM Programlama

ARM Programlama 88

Başlangıç adresini bir yere kaydedin ve IAR hata ayıklayıcısına geri

dönün. Bellek görüntü menüsüne GPIO-F‟in adresini yazın ve ortaya ne

çıkacağını izleyin.

Oops! Datasheet‟te belirtilen GPIO-F‟in adres aralığı boş görünüyor

(Karta sahip olmayanlar için bu geçerli değildir). Eğer bu size de

oluyorsa ümitsizliğe kapılmayın. Donanım engellemesi, varsayılan güç

koruması tarafından kapatılmasının genel nedenidir. Çip‟in belirli

parçalarının clock sinyalinin bloklanması tekniği Clock-Gating

Page 89: ARM Programlama

ARM Programlama

ARM Programlama 89

olarak adlandırılır ve modern modern mikro denetleyicilerde oldukça

yaygındır.

Böylelikle, datasheet‟e geri dönmeye ihtiyaç duyacağınız anlamına

gelen GPIO-F bloğunun nasıl tersine çevrilmesi gerektiğini

keşfetmeniz gerekiyor.

Dökümanın başına gidin ve “clock gating” dizesini aratın.

Evet, burada birşeyler var, Sayfaya gidelim.

Evet, GPIO clock geçitleme kontrol kaydedicisi (GPIO Clock control

register) burada.

Page 90: ARM Programlama

ARM Programlama

ARM Programlama 90

Kaydedici açıklamasına daha yakından bir göz atalım, çünkü bu

datasheet‟lerde yaygın olarak kullanılan çok genel bir format.

Bitlerin bir bloğu olarak gösterilen kaydedici her zaman 0‟dan

numaralanmış. Gösterilen bitlerin çeşitleri ise şöyle;

RO (Read-Only) : Salt okunabilir R/W (Read / Write) : Okunabilir, yazılabilir

WO (Write-Only) : Salt yazılabilir anlamına gelir. Bitlerin mantıksal olarak ilişkili olduğu gruplar kaydedici blok

resminin altında dökümante edilmiş.

Page 91: ARM Programlama

ARM Programlama

ARM Programlama 91

En önemli bitten başlıyor. Sizin için, en ilgi çekici 5. Bitin

açıklaması çünkü bu bit GPIO Port-F için clock‟a olanak sağlıyor. Bu

kaydedici tamamen ne aradığınızı doğruluyor.

Page 92: ARM Programlama

ARM Programlama

ARM Programlama 92

Kaydedicinin taban (base) adresini kopyalayın ve ilaveten 0x608

adresini kaydedici adresine, tamamlamak için eklemeniz gerektiğini

fark edin.

Page 93: ARM Programlama

ARM Programlama

ARM Programlama 93

Hata ayıklayıcıya geri dönün ve orijinal bellek görünüm menüsünde

GPIO Port-F başlangıç adresini eş zamanlı olarak izlerken saat

geçitleme kaydedicisinde (clock-gating) bit 5‟i ayarlamak için

sembolik bellek (Symbolic Memory) olarak adlandırılan ilave görünüm

menüsünü açın.

Page 94: ARM Programlama

ARM Programlama

ARM Programlama 94

Sembolik görünüm menüsüne datasheet‟ten aldığımız saat geçitleme

kaydedicisinin temel adresini yapıştırın ve 0x608 offset‟i eklemeyi

unutmayın.

Şimdi, belirtilen saat geçitleme kaydedicisine gidin ve birinci

dersten hatırladığınız 20 hex (ikilik sistemde 5. Bit‟i 1 yapar)

sayısnı şekildeki gibi bit 5‟e atayın ve enter‟a basın.

Page 95: ARM Programlama

ARM Programlama

ARM Programlama 95

Hey! GPIO-F‟in donanım engellemesi ortadan kalkıyor.

Led yakıp söndürme becerisine oldukça yakınsınız fakat daha o

aşamaya gelmedik.

Datasheet‟in GPIO bölümünde bazı şeyler daha okumamız gerekiyor

çünkü dijital bir çıkış sinyali olarak sırayla süreceğimiz kırmızı,

mavi ve yeşil renklerin GPIO-F 1,2 ve 3 bitlerini konfigüre etmeniz

gerekiyor.

Konfigüre İşlemi

0x40025400 adresi için GPIO-F adres bloğu içinde aşağı kaydırın veya

adresi yazıp aratın.

İkilik sistemde „1110‟a ve 16‟lık sistemde E değerine denk gelen 1,2

ve 3 bitlerine 1‟i atayın.

Çıkış Sinyali Ek olarak , pinler için fonksiyonu dijital çıkış olarak ayarlayın

0x4002551C adresi için GPIO-F bloğu içinde daha aşağıya inin ya da

aratın ve tekrar 1,2 ve 3 bitlerine 1‟i atayın.

Page 96: ARM Programlama

ARM Programlama

ARM Programlama 96

Böylelikle, sonunda led‟i kontrol edebiliriz. 0x400253FC konumunda

GPIO-F data kaydedicisine gelin ve ilk olarak sadece en düşük yarım

bayt‟a hex 2 değerini yazarak 1‟i atayın, tekrar bitlerin her zaman

0‟dan sayıldığını hatırlayın.

Heyy! Bu işe yaradı, kırmızı led parlıyor. Kendinizi takdir

etmelisiniz.

0 yazarak led‟i söndürmeyi deneyin.

Page 97: ARM Programlama

ARM Programlama

ARM Programlama 97

Harika.

Hex 4 yazarak bit 2‟yi ayarlamaya ne dersiniz.

Evet, led bu sefer maviye döndü. Gerçekten harika!

Şimdi ise hex 8 yazarak bit 3‟ü bir yapalım. Bu sefer led yeşil olarak yandı. 0 yapıp söndürüyoruz.

Bu uzun uzun ve ağır işlemler bitiyor çünkü C‟deki tüm kodlama çok

kolay olacak. Led‟i özel bellek adreslerine indirgeyerek kontrol etmek için herşey

burada ve siz zaten bunun işaretçiler ile nasıl yapıldığını

biliyorsunuz. Özellikle size 3. Dersin sonunda gösterdiğim Pointer-

Hack‟i kullancaksınız çünkü bu teknik herhangi bir bellek adresine

istediğiniz sayıyı yazmanıza izin veriyor.

Üstteki kodu silin sadece işaretçi kısmını bırakın.

Aslında, sizin işaretçi değişkenlerini ayırmaya hiç ihtiyacınız yok

çünkü birazdan göreceğiniz üzere Pointer-Cast diye adlandırılan

yöntemi kullanacağız.

3. derste int için işaretçileri kullandınız fakat ARM kaydedicileri

unsigned yani işaretsizdir, bu yüzden işaretçi tipini unsigned int

olarak değiştirmeniz gerekiyor.

Page 98: ARM Programlama

ARM Programlama

ARM Programlama 98

GPIO-F bloğunu tersine çevirmek için kullandığınız saat geçitleme

sistemi kaydedicisinin adresiyle 3. Dersten üretilmiş olan adresi

değiştirin.

Parantez içinde tüm Pointer-Cast‟i çevreleyin ve tüm bu şeyin bir

işaretçiyi unsigned int yapmak için olduğunu fark edin. Eğer böyle

ise, yıldız operatörü ile bu işaretçiyi referanstan ayırabileceğiniz

anlamına geliyor, aşağıdaki satırda gördüğünüz gibi.

Şimdi, işaretçiye yazabilirsiniz. Hata ayıklayıcıdaki deneyimden

hatırladığınız üzere bit 5‟i ayarlamanız gerekiyor bu kaydedici

içinde hex 20 anlamına geliyor. “U” son ekiyle belirteceğiniz değer

unsgined olmalı.

Artık kullandığınız p_int işaretçisinden kurtulun ve F7‟ye basarak

derleyicinin kodlarınızı sevip sevmediğini kontrol edin.

Page 99: ARM Programlama

ARM Programlama

ARM Programlama 99

Tamam, hex E yazarak 1,2 ve 3 bitlerini atamaya ihtiyaç duyduğunuz

GPIO-F Pin-Direction kaydedicisi olan bir sonraki kaydedici ile

devam edebilirsiniz.

Sonunda, GPIO-E konfigürasyon gerektiriyor ayrıca dijital fonksiyon

kaydedicisinde 1,2 ve 3 bitlerini atamak gerekiyor.

Buda tamam, GPIO-F Data kaydedicisi kırmızı renkli Led‟i bit 1‟i

temizleyerek yada atama yaparak yakıp söndürebilirsiniz.

Page 100: ARM Programlama

ARM Programlama

ARM Programlama 100

Aslında, eğer gerçekten led‟i yakıp söndürmek istiyorsanız, bunu bir

defaya mahsus yakıp söndüremezsiniz. Bunu sonsuza kadar yapmanız

gerekiyor. Yapalım, led yakıp ve söndürme için kodu bir while

döngüsü içine alabilirsiniz. Şartın her zaman doğru olduğu anlamına

gelen şartın yerine sabit 1 yazarsanız, sonsuz döngüyü kurmuş

olursunuz.

Bu kodu derlediğiniz zaman, sonsuz while döngüsünün akış yönüne

ulaşamayacağını gönderen bir uyarı alacaksınız.

Page 101: ARM Programlama

ARM Programlama

ARM Programlama 101

Launcpad üzerinde bu kodu test edelim. Sayaç geçitleme kaydedicisi ayarlamasının GPIO-F bloğunu

uyandırdığını not edin, beklendiği gibi.

Kırmızı ledin parladığını görüyorsunuz.

Ve tekrar karanlık oluyor.

Page 102: ARM Programlama

ARM Programlama

ARM Programlama 102

Sonsuz döngü güzel bir şekilde çalışıyor gibi görünüyor. Eğer herşey

doğru çalışıyorsa, "Go" butonuna basarak kodu gerçek hızında

çalıştıralım.

O da ne! Led sürekli çalışır durumda kalıyor. Break butonuna basarak

kodu durduralım ve tekrar tek tek ilerleyelim.

Bu sefer herşey iyi, yinede gerçek hızında çalıştırdığımız zaman

yanıp sönme duruyor. Problemin nerede olduğunu biliyor musunuz ?

Evet, program insan gözünün Led'in hızlı yanıp sönmesini görmek için

yetersiz. Program sadece çok çok hızlı çalışıyor. Programı

yavaşlatmanız gerekiyor.

Bunun için 2. derste öğrendiğiniz sayım while loop döngüsünü

kullanabilirsiniz. Bir döngü CPU çevriminin çoğunu boşa harcamaya

benzer fakat while döngüsünün şartında bir üst limit atlamasıyla

gecikme kontrol edilebilir.

Led'i yaktıktan ve söndürdükten sonra her ikisinde de tekrar bir

gecikmeye ihtiyaç duyduğunuzu not edin.

Tamam, tekrar bir deneme yapalım.

Evet, Çalışıyor!

Page 103: ARM Programlama

ARM Programlama

ARM Programlama 103

Bu led yakıp söndürme ile ilgi dersi sonlandıralım. Bunun çok fazla

önemli olarak görünmemesine rağmen, bu sizin gömülü programlama

kariyerinizde çok önemli bir dönüm noktası.

Tebrikler!

ÖN İŞLEMCİ ve VOLATİLE

Gömülü sistemler programlama derslerine hoş geldiniz. Bu derste

sizlere C preprocessor (Önişlemci) ve Volatile (Uçucu) anahtar

kelimeleri ile “Led yak söndür”ü nasıl geliştireceğinizi

göstereceğim.

Her zamanki gibi, önceki ders4 projesini kopyalayıp, ders5 olarak

yeniden adlandırarak başlayalım. Eğer ders4 dosyasına sahip

değilseniz bu yazıyı okuyabilirsiniz.

Yeni oluşturulan ders5 dizinine girin ve çalışmaalanı (.eww uzantılı

dosya) dosyasına çift tıklayarak IAR’ı başlatalım. Eğer IAR araç

setine sahip değilseniz bu yazıyı okuyabilirsiniz.

Aşağıda ders4’te oluşturduğumuz programı görüyoruz.

Page 104: ARM Programlama

ARM Programlama

ARM Programlama 104

Stellaris Launcpad kartındaki kırmızı led’i yakıp söndürme işini

görse de, pek okunabilir durumda değil. Çünkü gizemli numaralar ile

dolu olmasının yanında, ne olduğunu anlatan yorumlar da yok.

Kodun okunabilirliğini arttırmak amacıyla, Registerlar (Yazmaç) için

bu numaralar yerine isimler kullanabilmek çok iyi olurdu. Bunu

başarmamızın bir yolu, herhangi bir C kod parçasını makro olarak

kullanmanızı sağlayan C preprocessor (Önişlemci) kullanmaktır.

Örneğin, yazım yaptığınız ilk Register için bir makro tanımlayalım.

“#” karakteri, “define” kelimesi ve ardından makronun adı ile

başlayan yeni bir satır oluşturun.

Page 105: ARM Programlama

ARM Programlama

ARM Programlama 100100100

Entegre kılavuzu (Datasheet), GPIO için Run-Mode Clock Gating

Control Register’ını çağırmış, bizde makromuzu bu registerin baş

harflerinden yola çıkarak RCGCGPIO olarak adlandırdık. Makro adından

sonra, makronun yerine geçeceği kodu yapıştırın.

Makro tanımlandıktan sonra, bu makroyu orijinal kod parçası yerine

kullanabilirsiniz.

Derleyici buraya kadarki kodunuzu kabul edip etmediğini anlamak için

F7’ye basın.

Page 106: ARM Programlama

ARM Programlama

ARM Programlama 101101101

C preprocessor denmesinin nedeni, asıl derleme öncesindeki metin

düzenleme işleminin ayrı bir ilk basamağı oluşudur. Preprocessor,

“#” işareti ile başlayan tüm satırları kaldırır, böylece derleyici

bunları görmez. Örneğin; Herhangi bir makro tanımı yapın ama kod

içerisinde kullanılmasın. Hiçbir etkisi olmaz ve kod yine derlenir.

Ayrıca, Preprocessor sadece kod içerisinde kullanılan makroları

değiştirir. Böylece; derleyici sadece karakter karşılıklarını görür,

makro isimlerini görmez. Bu demek olurki; makro C diline tamamen

uymasa da olur.

Page 107: ARM Programlama

ARM Programlama

ARM Programlama 102102102

Örneğin, “FOO” makrosu, bir işaretçi ifadesinin sadece bir

parçasıdır. Ama makronun yerine geçtiği metin, içeriğe

uygunsa,derleyici bunu kabul eder, çünkü aslında derleyici aradaki

farkı anlamaz. Buradan çıkaracağımız sonuç ise, makrolarınızı nasıl

tanımladığınıza ve yerine geçtikleri bölümlerde anlamlarının

beklenmedik şekilde değişmesine dikkat etmeniz gerektiğidir.

Örneğin, sağlama almak amacıyla, RCGCGPIO gibi makroları parantez

içerisine alıp, referanstan ayırmak her zaman iyi bir fikirdir.

Başka makrolar kullanarak, makro tanımlamak da mümkündür. Örneğin;

entegre kılavuzunda belirtildiği gibi GPIOF_BASE makrosunu

tanımlarsınız, bunu diğer makroların tanımında da kullanabilirsiniz.

Mesela bacak yönü Register için GPIOF_DIR makrosunu, ana adresten

0x400 uzakta, dijital etkinleştirme için GPIOF_DEN makrosunu, ana

adresten 0x51C uzakta ve GPIOF_DATA makrosunu, 0x3FC uzakta

tanımlıyorum.

Page 108: ARM Programlama

ARM Programlama

ARM Programlama 103103103

Son olarak, kodunuzda yorumlar eklemeniz şiddetle tavsiye edilir.

Yorumlar sadece kodunuzu okuyan insanların yararınadır ve derleyici

tarafından tamamen görmezden gelinir. C99 standardı 2 yorum tipini

destekler;

“/*” ve “*/” karakterleri arasında sınırlanan geleneksel C yorum

tipi.

Ve de “//” ile başlayıp satır sonunda biten C++ yorum tipi.

Derleme öncesi bu yorumların hepsi birer boşluk ile değiştirilir

yani programa bir fayda sağlamazlar sadece diğer yazılımcılar

tarafından okunabilirliğini arttırır.

İki yorum tipide makro tanımında kullanılabilir.

Şimdi kodumuz hala led’i yakıp söndürebilecek mi,bunu görmek ilginç

olacak. Bunu gerçekten görmek için, Stellaris Launcpad kartını

kullanacağım. Ancak karta sahip değilseniz, Benzetimci için hata

ayıklayıcı ayarını yapın ve takip edin (Debugger for simulator).

Page 109: ARM Programlama

ARM Programlama

ARM Programlama 104104104

Harika, Led hala eskisi gibi yanıp sönüyor, tüm değişikliklerimiz

çalışıyor.

Şimdi GPIOF_DATA makrosunu, derleyicinin nasıl çevirdiğini ve bunun

ekstra bir yük katıp katmadığını detaylıca inceliyelim. Sonuçta,

kodumuz çalışırken CPU’nun adres öteleme işlemleriyle uğraşacağından

endişeleniyor olabilirsiniz. Ama kodunuzu adım adım çalıştırırsanız,

LDR.N komutunun, 0x400253FC adresini, toplama yapmadan, R0’a direkt

yüklediğini görürsünüz. Başka bir deyişle, kod eskisi kadar verimli,

çünkü derleyici mümkün olan her sabiti derleme sürecinde hesaplar ve

çalışma sürecinde oluşabilecek gereksiz hesaplamaları önler.

Page 110: ARM Programlama

ARM Programlama

ARM Programlama 105105105

Son olarak, led’i yakan asıl komutun hangisi olduğunu görmek çok

ilginçtir. Eğer kodu kartınıza yüklediyseniz bunun STR komutu

olduğunu görürsünüz. Yani, CPU’nun bakış açısıyla, dış dünya ile

konuşmak aslında çok kolaydır ve belli bir adrese belli bir değeri

yazmak şeklinde özetlenebilir.

Tamamdır, programınız hala çalışıyor ve eskisi kadar verimli. Ancak

tüm makroları kendiniz tanımlamak zorundaymışsınız gibi bir izlenim

vermek istemiyorum.

Aslına bakarsanız, zorunda değilsiniz. Çünkü mikro denetleyici

üreticileri, mesela Stellaris kartı örneğindeki Texas Instruments,

Page 111: ARM Programlama

ARM Programlama

ARM Programlama 106106106

bu makroları hali hazırda bir dosyada sunmaktadır. Hatta ders5

dizinine bu dosyayı kopyalamıştım. (buradan dosya içeriğini

bulabilirsiniz. Tek yapmanız gereken bu içeriği kopyalayıp bir text

dosyasına yapıştırmak ve dosya uzantısını '.h' olarak değiştirmek.

http://users.ece.utexas.edu/~valvano/Volume1/lm4f120h5qr.h) Bu

dosyayı, projenize sağ tıklayıp, Add > Add Files seçeneği ile

ekleyebilirsiniz. Dosyanın adı “lm4f120h5qr.h” şeklindedir ve

Stellaris Launchpad kartınızdaki işlemci türüne tekabül etmektedir.

“.h” dosya uzantısı, üstbilgi (Header) dosyasıdır ve “.c”

dosyalarına, örneğin main.c, eklenmesi için tasarlanmıştır.

Bu üstbilgi dosyasını açarsanız, demin tanımladığımıza benzeyen bir

sürü makro içerdiğini görürsünüz. Ancak, bu üstbilgi dosyasındaki

işaretçi (Pointer) tanımları oldukça farklıdır ve biraz açıklamaya

ihtiyaç duyuyorlar.

Page 112: ARM Programlama

ARM Programlama

ARM Programlama 107107107

Üstbilgi dosyasından bir makro alayım ve karşılaştırmak için main.c

dosyasına yapıştırayım.

İlk fark işaretçi tipidir. Main.c’deki makrolarımız işaretsiz int

(unsigned int) tipini kullanırken, üst bilgi dosyası işaretsiz long

kullanmakta. Veri tiplerini başka bir derste anlatacağım ama

şimdilik şöyle anlatayım; 32 bitlik bir cihazda, örneğin ARM

işlemci, int tipi de long tipi de 32 bit genişliğindedir. Yani

unsigned int ve unsigned long aynıdır.

Asıl fark Volatile niteleyicisindedir. Derleyiciye işaretçinin

işaret ettiği nesnenin aniden aniden aniden değişebileceğini

bildirir. Bir nesneyi volatile olarak tanımlarsanız, derleyiciye,

programda nesneyi değiştirecek bir ifade olmasada, bu nesnenin

değişebileceğini söylersiniz. Örneğin; Launchpad kartında, GPIOF

Page 113: ARM Programlama

ARM Programlama

ARM Programlama 108108108

Register’ının 2 bit’i, kullanıcı butonlarına bağlıdır. Kullanıcı bu

butonlara basarsa ya da bırakırsa, bu bitler değişir. Bu olay tabii

ki bir program komutu yüzünden meydana gelmez. Bu yüzden, GPIOF

Register’ı ve hatta çoğu diğer Giriş/Çıkış Registeri, Volatile’dır.

Bu önemlidir, çünkü derleyici volatile olmayan nesnelerin değerini

CPU Register’ına geçirip, bir süre bu Register ile işlem yapıp,

sonunda bu Registerdaki değeri nesneye geri yazacak şekilde bir

optimizasyon yapabilir. Volatile nesnelerde, derleyicinin bu tarz

bir optimizasyon yapma izni yoktur. Program, bir volatile nesneyle

yazma ya da okuma işlemi yapmak isterse, derleyici bunu yapmak

zorundadır. Açıkça görülüyorki, volatile niteleyicisi GPIOF gibi

Giriş/Çıkış Registerları için kullanışlıdır. Ayrıca normal

değişkenlerde de, derleyicinin yapabileceği optimizasyonları önlemek

için kullanışlı olabilir.

Örneğin counter değişkeni, sadece 2 gecikme döngüsünde

kullanılmıştır. Ancak bu döngülere, derleyicinin bakış açısından

bakarsanız, işleme herhangi bir katkıları yoktur. Çünkü counter

değişkeninin son değerinin ya üzerine yazılmaktadır ya da bu değer

atılmaktadır. Bu durumda, derleyicinin gecikme döngülerini yok etmek

için optimizasyon yapmaya izni vardır. Optimizasyon seviyesini

yükselterek bu durumu rahatlıkla görebilirsiniz. Project > Otions’a

tıklayın. C/C++ Complier ve ardından Optimizations sekmesine gelin.

“High” optimizasyon seviyesini seçin ve OK’e tıklayın.

Tekrar derleyin ve programınızı Launchpad kartında çalıştırın.

Page 114: ARM Programlama

ARM Programlama

ARM Programlama 109109109

Gördüğünüz gibi led yanar ve yanık kalır, sonsuza kadar. Kodunuzu adım adım çalıştırırsanız, led’i yakıp söndürme

komutlarının yerinde olduğunu görürsünüz. Ancak aradaki gecikme

döngüleri gitmiştir. Ancak artık volatile anahtar kelimesini

bildiğinize göre, derleyicinizin bu gecikme döngülerini

optimizsyonla yok etmesini önleyebilirsiniz. Counter değişkenini

volatile yapmalısınız.

Bu arada volatile kelimesi, veri tipinden önce, üstbilgi

dosyasındaki makro gibi, ya da sonra yazılabilir. Veri tipiden sonra

yazmanızı tavisye ederim.

Şimdi volatile tanımının sorunu çözüp çözmediğini test edin.

Evet, led yanıp sönüyor.

Adım adım çalıştırırsanız, gecikme döngüsünü de görebilirsiniz.

Şimdi .h header dosyasını ana programımıza dahil ederek kullanalım.

Tekrardan, bunun için Preprocessor kullanıyoruz. Bir dosya eklemek

için, yeni bir satıra “#include” yazıyorsunuz ve ardından tırnak

içinde dosya adınızı ekliyorsunuz.

Ve tanımladığımız makroları header dosyasındakilerle değiştirelim.

Mikro denetleyici üreticisinin yazdığı header dosyası,

Datasheet’teki Register isimlerini kullanmakta. Böylece aradığınız

registerler’ı bulmakta sıkıntı çekmezsiniz. Örneğin;

GPIO_PORTF_DATA, GPIO_PORTF_DIR ve GPIO_PORTF_DEN. Registerin doğru

adı konusunda şüpheniz olursa, adresini kontrol ederek istediğiniz

Register olduğunu doğrulayabilirsiniz. Tüm makroları değiştirdikten

sonra, kendi tanımlamalarınızı silip kodu tekrar derleyebilirsiniz.

Page 115: ARM Programlama

ARM Programlama

ARM Programlama 110110110

Kodumuzu son bir kez test edelim, bakalım led hala yanıp sönecek mi

?

Böylelikle C Preprocessor ve Volatile anahtar kelimesi üzerine

dersimiz sona eriyor.

Page 116: ARM Programlama

ARM Programlama

ARM Programlama 111111111

Artık herhangi bir optimizasyon seviyesinde, doğru olarak çalışan

programlar yazabileceksiniz. Tebrikler!

BİTSEL OPERATÖRLER

Merhaba, gömülü sistemler programlama derslerine hoş geldiniz. Bu

derste Launchpad board üzerindeli komposite LED’in tüm renklerinin

bitsel operatörler kullanılarak nasıl yakıldığını göstereceğim.

Her zaman kigibi bir önceki projeyi kopyalayıp ismini ders6 ile

isimlendirerek başlayalım. Eğer eğitimlere yeni başlıyorsanız,

önceki proje için bu yazıyı okuyabilirsiniz.

Ders6 klasörünün içine girip çalışma sayfamızı açıyoruz (.eww

uzantılı dosya). Eğer IAR araç setine sahip değilseniz bu

yazıyı okuyabilirsiniz.

Bu programı ders5’de oluşturmuştunuz. Program 3 renkli led’in bağlı

olduğu genel giriş/çıkış portlarının ayarlanması ile başlıyor. Daha

sonra bir sonsuz döngü başlıyor. Önce kırmızı led’i yakıyor, bir

süre bekleyip, kırmızı led sönüyor. Ve tekrar döngüye giriyor.

Sonuçta kırmızı led yanıp sönüyor.

Page 117: ARM Programlama

ARM Programlama

ARM Programlama 112112112

Bu derste, komposit led’in diğer renklerini de kullanmayı

öğreneceğiz. Mavi ve yeşil renkler. Sanıyorum, kırmızı led’i yakıp

söndürdüğünüz zaman boyunca mavi led’i yanık tutmak istiyeceksiniz.

Peki bunu nasıl yapacaksınız ?

İlk adım basit. Mavi led’e karşılık gelen GPIOF 2 bit’ini sonsuz

döngüden önceye alıp ayarlama yapmak gerekir.

Page 118: ARM Programlama

ARM Programlama

ARM Programlama 113113113

Daha sonra, döngünün içinde, kırmızı led yandığında bir sorun

olacaktır. Kırmızı led bitini 1 yaptığımız zaman, mavi led’e bağlı

bit 2 de dahil olmak üzere diğer bütün bitleri de 0 yapmış

olacaksınız. Çünkü bütün led bitleri tek bir register içerisinde

bulunur. Burada ihtiyacınız olan şey, bitleri yanlışlıkla diğerini

bozmadan teker teker set/reset yapabilmektedir. İşte tam burada C

dilinin bitsel operatörleri devreye giriyor. Şimdi C dilinde bitsel

operatörleri kod yazarak öğrenmeye çalışalım. Birkaç tane unsigned

integer değişken tanımlıyoruz, bunlara temel değerlerini atıyoruz.

Page 119: ARM Programlama

ARM Programlama

ARM Programlama 114114114

c adlı değişken, bitsel operatörün sonucunu ifade edecek. Bu bitsel OR.

Bu bitsel AND.

Bu bitsel XOR.

Bu bit tersleyici (1’e komplementini yani tümleyenini alır)

Page 120: ARM Programlama

ARM Programlama

ARM Programlama 115115115

Bu sağa kaydırma biti.

Ve son olarak sola kaydırma biti.

Kodu derleyip çalıştırmadan önce, optimizasyon seviyesini none

olarak ayarlayalım.

Page 121: ARM Programlama

ARM Programlama

ARM Programlama 116116116

Debugger kısmında Setup sekmesinde simulatör seçeneğini işaretleyin.

Böylece launchpad board kullanmanıza gerek kalmayacak.

Artık F7’ye basarak programı derleyebiliriz. Download and Debug

butonu ile Debugger’de kodu adım adım yürütelim.

Buradaki adımda a, b ve c değişkenlerinin temel değerlerinin Locals

Windows penceresinde ikilik (binary) olarak göstermemiz gerekiyor.

Page 122: ARM Programlama

ARM Programlama

ARM Programlama 117117117

Bu adımda bitsel OR ifadesinin c değişkenindeki sonucunu

inceliyoruz. Gördüğünüz gibi, bitsel OR ifadesi a ve b değişkenleri arasında

mantıksal OR gibi davranıyor.

Page 123: ARM Programlama

ARM Programlama

ARM Programlama 118118118

Eğer okuldan hatırlarsanız 0’ın false yani yanlış, 1’in true yani

doğru anlamına geldiğini görebilirsiniz.

Doğruluk tablosunu verecek olursak; 1 OR 0 = 1,

0 OR 1 = 1,

1 OR 1 = 1 ve 0 OR 0 = 0 dır.

Disassembly penceresinde, 32 bitlik OR işlemlerinin iki operand ile

tek bir makine çevriminde ORRS komutu ile, oldukça hızlı ve etkili

yürütüldüğünü görürsünüz.

Bitsel AND ifadesi a ve b değişkenleri arasında mantıksal AND gibi

davranıyor. Doğruluk tablosunu hatırlarsanız;

0 AND 1 = 0, 0 AND 0 = 0,

1 AND 0 = 0 ve 1 AND 1 = 1 olduğunu rahatlıkla kavrayabilirsiniz.

Page 124: ARM Programlama

ARM Programlama

ARM Programlama 119119119

Disassembly penceresinde, 32 bitlik AND işlemlerinin iki operand ile

tek bir makine çevriminde ANDS komutu ile işlendiğini görürsünüz.

Bitsel XOR ifadesi a ve b değişkenleri arasında mantıksal XOR gibi

davranıyor. Doğruluk tablosunu hatırlarsanız;

0 XOR 1 = 1,

0 XOR 0 = 0, 1 XOR 0 = 1 ve

1 XOR 1 = 0 olduğunu rahatlıkla kavrayabilirsiniz.

Disassembly penceresinde, 32 bitlik XOR işlemlerinin iki operand ile

tek bir makine çevriminde EORS komutu ile işlendiğini görürsünüz.

Page 125: ARM Programlama

ARM Programlama

ARM Programlama 120120120

Bitsel NOT ifadesi teklidir. Yani sadece tek bir operandı var. Her

1’i 0’a, her 0’ı 1’e çevirir.

Disassembly penceresinde MVNS komutu ile işlendiğini, Move Negative

ifadesi ile gösterildiğini görürüz.

Sağa kaydırma oparetörü her biti bir sağa kaydırır. Sağa kaydırma

işlemi bir nevi int türünde bir değişkeni 2 ile bölmektir. Bir hesap

makinesi ile kanıtlayalım (DEADBEEF / 2). Locals görünüm menüsündeki

değişkenleri onluk sistemde görünmesi için ayarlıyoruz.

Page 126: ARM Programlama

ARM Programlama

ARM Programlama 121121121

Disassembly pencerisinde sağa kaydırma işinin LSRS komutu ile

sağlandığını görüyoruz.

Not : LSRS komutu 0’ları en önemli bit konumuna doğru kaydırır. Sola kaydırma operatörü her biti bir sola kaydırır. Kaydırma işlemi,

2’nin 3. Kuvvetine yani 8 ile çarpılmasına karşılık gelir. Fakat

burada olduğu gibi ilk bitin 32 bit’e fazla gelme ihtimaline karşı

fazla gelen bit’e 32 bitlik yapı için yer kalmayacaktır.

Disassembly penceresinde sağa kaydırma işinin LSLS komutu ile

sağlandığını görüyoruz.

Page 127: ARM Programlama

ARM Programlama

ARM Programlama 122122122

NOT : LSLS komutu 0’ları en önemsiz bit konumuna doğru kaydırır. Böylece, bitsel operatörlerin unsigned sayılarda nasıl çalıştığını

öğrendiniz.

Signed sayılar için, sağa kaydırma operatörü tamamiyle farklı

çalışır. Bir örnek ile inceleyelim.

Signed int türünde, x adında bir değişken tanımlayıp, temel pozitif

değerlerini atayalım.

Başka bir signed int türünde, y adında bir değişken tanımlayıp,

temel negatif değerini atayalım.

Sonra, x’in sağa kaydırma işlemini başka bir değerde gösterelim. Son olarak y’nin sağa kaydırma işlemini de aynı değerde gösterelim.

Derleyip test edelim. Locals görünüm menüsünde değişkenleri binary formatında

görüntülüyerlim.

Gördüğünüz gibi, pozitif değer kaydırılma sırasında değerini korudu.

Sıfırlar en önemli bite doğru kaydırıldı.

Page 128: ARM Programlama

ARM Programlama

ARM Programlama 123123123

10’luk tabanda z ve x’ikarşılaştırırsanız, sağa kaydırmanın 2’nin 3

üssü yani 8’e karşılık geldiğini rahatlıkla görürsünüz. ( 128 * (23)

= 1024 )

Ancak negatifin sağa kaydırılması diğerinden tamamiyle farklıdır.

Çünkü şimdi 1’ler en önemli bit’e doğru kaydırıldı.

Böylece, signed int türünde sağa kaydırma işleminde, kaydırma

işleminden önce bit 0 ise 0’lar en önemli bite doğru kayar. Buna

işaret taşması denebilir. Negatif değerin 2’ye tümleyenine karşılık

gelir. (Ders 1’e öğrenildi) Bu işlem sağa kaydırma ve 2’nin

katlarına bölünürken gerekli bir hal alır.

Aslında, değeri decimal’e çevirdiğiniz zaman, z ve y’nin negatif

olduğunu ve z’nin hala y’nin 8 ile bölümüne eşit olduğunu

görebilirsiniz.

Page 129: ARM Programlama

ARM Programlama

ARM Programlama 124124124

Unsigned integer ve signed integer arasındaki bu farklılık,

disassembly penceresine baktığınızda çok açıktır.

Gördüğünüz gibi derleyici sağa kaydırma işleminde signed sayılar

için ASRS komutunu (Aritmetik Sağa Kaydırma), unsigned sayılar için

ise LSRS (Mantıksal Sağa Kaydırma) komutunu üretir.

Gömülü sistem programcısı olarak, C dilindeki bitsel operatörlerin

arasındaki farkları ve ince ayrıntıları çok iyi bilmeniz gerekiyor.

Mesela aritmetik kaydırma / mantıksal kaydırma. Bu tür sorular iş

görüşmelerinde sıklıkla sorulmaktadır.

Ayrıca bitsel operatörler oldukça yararlıdır. Sizin yazacağınız led

yanıp söndürme programında size avantajlar sağlayacaktır.

Başlangıç için, ledlerin bağlı olduğu GPIO bitlerini

tanımlayabiliriz. Kırmızı led bit 1, mavi led bit 2 ve yeşil led bit

3.

Page 130: ARM Programlama

ARM Programlama

ARM Programlama 125125125

NOT! : Bu bit kaydırma ifadeleri derleme zamanı sabitleridir,

avantajı, kaydırılan bit numarasını derhal görebilirsiniz. Alt

seviyeli bitler için bu avantaj pek etkileyici olamayabilir. Ama üst

seviyeli bitler için, 18 bitlik gibi, 1 sağa kaydırma ifadesi

sonucunda 0x4000 sayısının sonucunu görmek hiç de kolay bir iş

olmayacaktır. Bu sabitlerin tanımlanması bize çok zaman

kazandıracak. Ayrıca programda bir çok aptalca hatayı önleyecektir.

Yani kesinlikle tavsiye ediyorum bunu!

Led renkleri için sabitleri tanımladıktan sonra hex sayıları yerine

bunları yazabiliriz. Kodun okunurluğunu arttıracaktır.

Page 131: ARM Programlama

ARM Programlama

ARM Programlama 126126126

Aslında kodunuz kendini açıklar hale geliyor. Yorum satırı gereksiz

bir hal alacaktır. Yorum satırlarını silebilirsiniz.

Şimdi, mavi led’i söndürmeden kırmızı renkli led’in yanması

durumunda yapılacak GPIOF ayarlamalarını ele alalım. Bunun için data

registerındaki o anki değer ile kırmızı renk biti arasında bitsel OR

operatörünü kullanabilirsiniz.

Bu işe yarar, çünkü bitsel OR, GPIOF içindeki herhangi bir bit ve

KIRMIZI_LED orijinal GPIOF bitini saklar. KIRMIZI_LED üzerindeki bütün bitler 0 ise, değişiklik olmaz, 1

olması durumunda sonuç 1 olacaktır.

GPIO_PORTF_DATA_R xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

KIRMIZI_LED 00000000000000000000000000000010

---------------------------------------------------------

GPIO_P.. | KIRMIZI_LED xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1x

NOT! : Bu durum sadece GPIOF registerı üzerinden okuma ve yazma

işlemi yaptığınızda geçerli olur.

Yani böyle bir durumda okuma/yazma izni olup olmadığını veri

sayfalarından kontrol edeceksiniz.

C dili, yazım kolaylığı sağlamak amacıyla bazı kısaltmaların

yapılmasına izin vermektedir.

Page 132: ARM Programlama

ARM Programlama

ARM Programlama 127127127

Eşitliğin sağ veya sol tarafına OR işaretini taşımak mümkündür ve

aynı sonucu verir.

Aşağıda yazılmış olan bu iki kod tam olarak aynı şekilde

çalışmaktadır.

Böylece burada GPIOF registerındaki kırmızı led bitini ayarlamak

için en kısa kodu görmüş oluyorsunuz.

Lütfen bunu C dilinde bir tür kısayol olarak hatırlayın. GPIOF registerındaki kırmızı led bitini sıfırlamak için, kırmızı led

bitinin tersi ile bitsel AND operatörünü kullanmalısınız.

Bu durum işe yarar, çünkü bitsel AND operatörü ~KIRMIZI_LED’in 1

olduğu yerlerde orijinal durumunu korur. 0 olduğu zaman 0 durumuna

değişir.

GPIO_PORTF_DATA_R xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

~KIRMIZI_LED 00000000000000000000000000000010

---------------------------------------------------------

GPIO_P.. & ~KIRMIZI_LED xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0x

Ve tekrar, bu operatör eşitliğini daha kısa bir kod parçacığı ile

yazabilirsiniz.

Bunun C dilinde bit temizleme kısayolu olduğunu unutmayınız. Şimdi, bu kod kısayollarına biraz daha kritik bir göz atabilirsiniz.

Örneğin, mavi led’i yakmak, aynı anda GPIOF registerında bir biti

ayarlamaktır. Yani bu bit ayarlama kısayollarıyla kod yazmayı

gerektirecektir.

Aslında kodumuzdaki ilk üç satırın hepsi, bit registerlarının

değerlerini gösteriyor, yani onlarında bit ayarlama kısayolları ile

yazılması gerekecektir.

Ve son olarak, kodunuzun okunabilirliğini arttırmak için daha fazla

makro ekleyebilirsiniz.

Page 133: ARM Programlama

ARM Programlama

ARM Programlama 128128128

Derlemeden önce, Project > Options sekmesinden, Optimization kısmını

High seviyesine ve Debugger kısmını TI Stellaris’e ayarlıyoruz.

Page 134: ARM Programlama

ARM Programlama

ARM Programlama 129129129

Şimdi programı Launchpad board’a yükleyip, çalıştıralım.

Page 135: ARM Programlama

ARM Programlama

ARM Programlama 130130130

Gördüğünüz gibi mavi led hep açık, sönük olan kırmızı led, göz

kırpar gibi açılıp kapanıyor.

Kodlara, kırmızı led’in set/reset ayarı için bölme noktaları

koyarsak, görüldüğü gibi, kırmızı led’in set olması Load – Modify –

Store işlemlerinden oluşan bir döngüye gerçekleşiyor.

Burada bitsel ORR makine komutu veriyi modife etmek için

kullanılıyor.

Kırmızı led’i resetlemek için, bir diğer Load – Modify – Store

döngüsü devreye giriyor.

Page 136: ARM Programlama

ARM Programlama

ARM Programlama 131131131

Buradaki ilginçlik, derleyici biti temizlemek için güzel bir kod

olan BIC (Bit Clear) komutunu üretiyor. Bu oldukça dikkat çekici

çünkü derleyici kodlarınızın bitsel AND ve terleyici ile olan

işlemini harfi harfine takip etmeyecektir.

Derleyici tüm kodlarda clear işlemini nerede yapma niyetin olduğunu

anlamak yerine, daha kullanışlı bir kod üretiyor.

Bu örneği iyi öğrenmenizi istiyorum. Çünkü bu örnek, bir biti

temizleme gibi kodların kısa şekilde kullanışlarını, derleyicinin

sizin aslında ne yapmak istediğini anlamasını sağlamayı, gösteriyor.

Sonuç olarak, bu ders bitsel operatörler ile ilgi bilgi verdi.

Bitlerde nasıl SET – CLEAR – TOOGLE ve kaydırma işlemlerinin

yapılacağını gösterdi.

Page 137: ARM Programlama

ARM Programlama

ARM Programlama 132132132

DİZİLER ve İŞARETÇİ

ARİTMETİĞİ

Gömülü sistemler programlama derslerinin 8. Serisine hoş geldiniz.

Bu derste, C dilinde dizileri ve temel işaretçi aritmetiğini

tanıtacağım. Bu bilgilerin Stellaris bilgi kaydedicilerine nasıl

uygulandığını ve avantajlarını öğreneceksiniz.

İlk önce, genel olarak bir önceki derste yaptıklarımızı

hatırlayacağız. Eğer eğitim serisine yeni katıldıysanız buradan

önceki ders dosyalarına ulaşabilirsiniz. Her zamanki gibi ders6

dosyasını kopyalayıp ders7 olarak adlandırıyoruz. Ders7 dosyasına

girin ve workspace dosyasına tıklayarak IAR programını çalıştırın.

Eğer bilgisayarınızda IAR yüklü değilse, bu dersi okuyabilirsiniz.

Page 138: ARM Programlama

ARM Programlama

ARM Programlama 133133133

Bu proje ders6’da yaptıklarımızdır. Biraz düzenleyelim ve hata

ayıklamaya (Debug) geçelim.

Page 139: ARM Programlama

ARM Programlama

ARM Programlama 134134134

Bu program genel giriş/çıkış portlarını değiştirmek için “Read –

Modify – Write – Sequence” tekniğini kullanır. Böylelikle diğer

bitler değişiklikten etkilenmezler. Örneğin, bit 1 kırmızı ledi

kontrol eder. Program GPIOF DATA’nın o anki değerini LDR

talimatlarıyla okur. Daha sonra, bit 1’i ayarlamak için mantıksal OR

işlemi yapar. Son olarak, değişen değeri yazdırır.

Read – Modify – Write – Sequence gereklidir, çünkü GPIO bitleri tek

bir byte’ın içinde tek adreste kayıtlıdır. Her bitin kendine özgü

adreslerle donatıldığını hayal edin. Daha da iyisi, ihtimal

dahilindeki GPIO kombinasyonlarının kendine özgü adreslerinin

olduğunu düşünün.

Tek atomik yazma işlemi, diğer bitleri işe karıştırmadan GPIO

bitlerinin değiştirilmesini sağlar. Bu derste, Stellaris donanımında

az önceki anlattıklarımı nasıl yapacağınızı göstereceğim. Tipik Read

– Modify – Write – Sequence ile bir adet Atomic Write işlemini

değiştirebileceksiniz. Ancak, nasıl yaptığımızı göstermeden, neden

bu kadar zahmete girdiğimizi anlamak daha iyi olacaktır.

En nihayetinde, Read – Modify – Write – Sequence çoğu zaman

yeterince hızlıdır. Ancak ilgilendiğimiz konu hız değildir. GPIO

bitlerine, gerçekten bağımsız olarak müdahale etmenizi amaçlıyorum.

Tüm kodlarınızda, hatta kesmelerde bile. Kesmelere ilerleyen

bölümlerde değineceğiz. Kesmeler büyüleyici bir konudur, Özellikle

gömülü sistemlerde. Şimdilik kesmelerin donanım tabanlı olduğunu ve

program akışınızı beklenmedik bir şekilde değiştireceğini

söyleyeyim. Bir kesme aktif olduğunda, işlemcideki özel bir donanım

Program Sayacındaki (PC) değeri değiştirir ve işlemci aniden ISR

(Interrupt Service Routine) adı verilen kodları çalıştırmaya başlar.

ISR kısa kodlardan oluşur. Kesme rutini bittiği zaman işlemci

kaldığı yere (Orijinal kodlara) dönerek çalışmasına devam eder.

Page 140: ARM Programlama

ARM Programlama

ARM Programlama 135135135

İlginç kısım ise; kesme rutini, ana programın GPIO değerlerini

okuduktan sonra ve değiştirilmiş değeri yazmadan önce, Read – Modify

– Write işleminin ortasında çalışırsa (1), kesme rutininin GPIO’da

yaptığı değişiklikler kaybolur. Çünkü esas kodlarımız kullanımdadır

ve GPIO’un eski değerini kullanıyordur (2).

Bu, Read – Modify – Write sekansı için doğal bir problemdir.

Stellaris GPIO donanım tasarlayıcıları bu hatayı düzeltmek için,

Read – Modify – Write sekansı yerine Atomic – Write – Operation

kullanmanızı tavsiye ediyor.

Page 141: ARM Programlama

ARM Programlama

ARM Programlama 136136136

Nasıl çalıştığına bakalım. GPIO ile CPU (işlemci) arasında pek çok

bağlantı vardır. Bunlara bus denir. Her bir bit atanmış veri yoluna

ve adrese bağlıdır. Bit, adres yolu 1 olursa değişir. Diğer

durumlarda bit etkilenmez. Örneğin, 3 GPIO bitini izole edip led’e

bağlamak için adresimizin 0000111000 olması gerekir. En düşük iki

adres, A0 ve A1 kullanılmadı çünkü donanım, tüm adreslerin 4’ün katı

olması gerektirir. Yazdığınız veri, pinlerin durumuna karar verir.

Örneğin, kırmızı ledi yakabilirsiniz, mavi ledi söndürebilirsiniz

veya yeşil ledi yakabilirsiniz. Hepsini tek bir komutla yaparız.

Umarım her şey anlaşılıyordur. Donanım dizaynında pek çok kayıtçı

kendine özgü adres gerektirir. Sadece GPIO kendine özgü adrese sahip

değildir. GPIO için 8 kayıtçı gerekir. Her bir bit kombinasyonu için

ayrı adres şemada tanımlıdır. 8 adet GPIO bitleri için tüm mümkün

bit kombinasyonlarında Stellaris GPIO, 0x40025000 adresi ile

başlayan 256 adet 32 bit veri kayıtçısı barındırır. Şimdiye kadar,

1111111100 ikilik ve 0x3FC onaltılık GPIO_PORTF_DATA_R kayıtçılarını

kullandık. Bu kayıtçının bitleri izole edilmemiş görünüyor fakat 8

GPIO bitleri veri yollarıyla değiştirilebilir. Bu derste diğer

kayıtçıları da kullanacağız. Şimdi, diğer tüm GPIO kayıtçılarına

C’de nasıl ulaşacağız?

Birinci seçenek, 3. Eğitimde öğrendiğimiz Brute – Force yaklaşımıyla

direkt adresleme. Örneğin, led ’den sorumlu 1 biti izole etmek için,

manuel olarak adresi hesaplayabiliriz. Datasheet’te bulunan Base

adress’ten başlarız, 2 bit sola kaydırarak KIRMIZI_LED’e ekleriz ve

kullanılmayan 2 biti atlamış oluruz.

İşaretçiye (pointer) ve işaretçiyi kaldırmak için sentezlenmiş adres

dökümüne ihtiyacınız vardır. Unutmayın bu adres tek biti izole eder,

bu bit için yazdığınız önemlidir. Diğer bitler için yazdığınız

önemsizdir.

Page 142: ARM Programlama

ARM Programlama

ARM Programlama 137137137

Gösterim için, KIRMIZI_LED’e 1 diğer bitlere de 0 değerini atayalım.

F7’ye basalım ve derleyelim. Kit üzerinde bunu test etmek ilginçtir.

Gördüğünüz üzere Read – Modify – Write sekansı, STR komutunu R2

adresinde basitleştirir. GPIO base adresi 8 eklenerek offset edilir.

Kodlara baktığımızda, kırmızı ledi yanıyor, diğer ledleri değişmiyor

olarak görürüz. Kodlar tam istediğimiz gibi kite yansıyor. Kodlar

çalışıyor, fakat kodlarımız optimize şekilde değiller. Dizi

tanımlaması ile kodları daha optimize hale getirebiliriz. Dizi

(Array), aynı tipteki bir grup değişkenin ardışık hafıza bloklarına

yerleştirilmesidir. Örneğin 256 adet GPIO veri kayıtçıları.

Page 143: ARM Programlama

ARM Programlama

ARM Programlama 138138138

C dilinde, bir değişkene köşeli parantez içerisine bir sayı yazıp

ekleyerek dizi tanımı yapabilirsiniz.

Örneğin; bu dizi, her biri geçici tam sayı olan 2 sayıcıdan oluşur.

Hatta tüm diziyi tanımlamak için bu şekilde bir çözüm

uygulayabilirsiniz.

Şimdi dizi elemanlarını normal birer değişken olarak

kullanabilirsiniz.

C dilinde, parantez içerisindeki sayı dizi indisi (Array index)

olarak adlandırılır ve dizinin ilk elemanının indisi daima 0’dır.

İkincisi 1’dir ve artarak devam eder.

F7’ye basıp derleyelim.

C’deki diziler işaretçilerle bağlantılıdır. Derleyici dizinin

başladığı noktaya işaretçi gibi davranır. İ indisli işaretçiyi almak

için, dizi işaretçisine i eklersiniz.

Counter[1] yerine *(counter+1) yazılabilir. Bu işaretçi aritmetiğine

bir örnektir.

Page 144: ARM Programlama

ARM Programlama

ARM Programlama 139139139

Diziler ve işaretçiler arasındaki haberleşme çift yönlüdür çünkü her

bir işaretçi dizi olarak görüntülenebilir. Örneğin, standart LM4F

header dosyası, işaretçi GPIO_PORTF_DATA_BITS_R’yi tanımlar.

Bu işaretçi, 256 GPIO kayıtçılarının tümüne ulaşmak için

kullanılabilir. Sadece KIRMIZI_LED bitine ulaşmak için,

GPIO_PORTF_BITS_R’a bu şekilde indis atayabilirsiniz.

Page 145: ARM Programlama

ARM Programlama

ARM Programlama 140140140

İşaretçi aritmetiği kullanımı ile aynı kapıya çıkıyor.

Page 146: ARM Programlama

ARM Programlama

ARM Programlama 141141141

Hata ayıklamaya geçelim ve bu üç seçeneği karşılaştıralım.

Gördüğünüz gibi, üç uygulama, R4’e aynı adresi yazıyor.

Page 147: ARM Programlama

ARM Programlama

ARM Programlama 142142142

İkinci olarak, işaretçi aritmetiği kullanırız çünkü

GPIO_PORTF_DATA_BITS_R uzun – işaretsiz işaretçidir. İşaretçi

Bu küçük deneyimiz, 3 farklı alternatifin de eşdeğer olduğunu ve

aynı makine kodlarını ürettiğini gösteriyor.

Kaynak kodumuza dönelim. Size işaretçi aritmetiğinin farklarından

bahsedeyim. İlk olarak, adres aritmetiğini ve uzun – işaretsiz işaretçilerde raw

adres aritmetiğini göreceğiz.

KIRMIZI_LED’i, 4 byte boyutundaki GPIO kayıtçısına almak için, 2 bit

sola kaydırmanız gerekir.

aritmetiğinde elemanın büyüklüğünü küçültmek zorunda değilsiniz, bu

otomatik olarak yapılır. Dizi indislemesi ve işaretçi aritmetiği

denkliği nedeniyle böyle olmalıdır.

Üç seçenek arasında dizi indisleme en iyisi gibi görünüyor.

Bu seçeneği kullanıp diğerlerini ayrı tutuyorum.

Page 148: ARM Programlama

ARM Programlama

ARM Programlama 143143143

Kırmızı ledi söndürmek için dizi indisleme tekniğini kullanalım.

Bağlantı şemasından hatırlarsanız, bu teknikte KIRMIZI_LED bit

konumuna 0 yazmamız gerekiyor.

Page 149: ARM Programlama

ARM Programlama

ARM Programlama 144144144

Sonunda MAVİ_LED bit ayarı için tutarlı bir şekilde dizi indislemeyi

kullanıyoruz.

Page 150: ARM Programlama

ARM Programlama

ARM Programlama 145145145

Bu, GPIO bitlerini değiştirmek için, Fast – Interrupt – Safe

tekniğini kullandığımız son programdı.

Çalışma kitimizde test edelim.

İlk olarak, tam hızda çalışalım ve ledleri gözlemleyelim.

Page 151: ARM Programlama

ARM Programlama

ARM Programlama 146146146

Gördüğünüz gibi program önceden olduğu gibi çalışıyor. Kodları duraklattığımızda KIRMIZI_LED bitini temizlemek için, R0’da

bulunan sadece bir adet STR komutu kullandığımız görülüyor.

Programımız daha iyi hale geldi, ancak Stellaris LM4F

mikrodenetleyicisi daha iyisini yapabilir.

Page 152: ARM Programlama

ARM Programlama

ARM Programlama 147147147

Yukarıdaki görüntüye baktığımız zaman mikrodenetleyicinin bir değil

de, iki adet çevresel bus’a sahip olduğunu görürüz. Advanced

Peripheral Bus (APB) ve Advanced High – Performance Bus (AHB). GPIO

portları her ikisine de bağlıdır.

APB, ön tanımlı olarak seçilidir ve şimdiye kadar bunu kullandık.

Ama APB eskidir ve AHB’den daha yavaştır. Bunun nedeni geriye dönük

uyumluluk olması içindir. Dersin kalan kısmında AHB’nin nasıl aktive

edileceğini göstereceğim.

İlk olarak Datasheet’ten “GPIO High-Performance Bus Control” kısmını

bulun.

Page 153: ARM Programlama

ARM Programlama

ARM Programlama 148148148

Şekilde görüldüğü üzere, PORTF (GPIOHBCTL)5. Bit ile kontrol

edilmektedir. Şimdi LM4F header dosyasını açın ve GPIOHBCTL kayıtçısına bakın.

Kayıtçı ismini kopyalayın ve 5. Biti aktive edin.

Page 154: ARM Programlama

ARM Programlama

ARM Programlama 149149149

Datasheet’te “APB Apeture” adıyla geçen, APB adres aralığından GPIO

adreslerini değiştirmelisiniz. GPIO_PORTF için LM4F header dosyasına

göz atın, _AHB ön eki ile başlayan kayıtçılarını bulun.

Page 155: ARM Programlama

ARM Programlama

ARM Programlama 150150150

Bu ön eki, programınızda tüm GPIO_PORTF kayıtçılarına ekleyin.

Page 156: ARM Programlama

ARM Programlama

ARM Programlama 151151151

En son şekli ile kodları kitimizde test edelim.

Bu dersi, C dilinde diziler ve işaretçi aritmetiği ile bitiriyoruz.

Stellaris GPIO konusunda uzman oldunuz. Tebrikler!

Page 157: ARM Programlama

ARM Programlama

ARM Programlama 152152152

FONKSİYONLAR ve STACK

Gömülü sistemler programlama dersinin 9. serisine hoş geldiniz. Bu

derste C fonksiyonları ve Stack'i (Yığın) tanıtacağım.

Fonksiyonlarla çalışmanın tüm önemli yönlerini sadece bir derste

anlatmama imkan yok. Bu yüzden, genel olarak C'deki stack'lerin

başka fonksiyonlar çağıran fonksiyonları çağırmayı nasıl mümkün

kıldığına odaklanacağım.

C ya da C++'ın alt düzeyde nasıl çalışacağına dair sadece tek bir

şey öğrenmek istiyorsanız, C stack bu tek bir şey olmalıdır. Çünkü

fonksiyonları, kesmeleri, programdan programa geçiş ve RTOS'u (Real

Time Operating System – Gerçek Zamanlı İşletim Sistemi) anlamanın

temelinde stack vardır.

Her zamanki gibi, bir öndeki “ders7” projesini kopyalayıp, “ders8”

olarak adlandırarak başlayalım. Derse henüz başlıyorsanız önceki

proje için şu yazıyı okuyabilirsiniz. Yeni oluşturulan “ders8”

dizinine girin ve çalışma alanı (.eww uzantılı dosya) dosyasına çift

tıklayarak IAR ortamında açın. IAR programına sahip değilseniz

şuyazıyı okuyun.

Çabuk bir şekilde bu programın ne yaptığını hatırlayalım.

Page 158: ARM Programlama

ARM Programlama

ARM Programlama 153153153

GPIO hatlarına bağlı olan led'leri kontrol etmek için LM4F

mikrokontrolcüsündeki yazmaçları ayarlamakla başlıyor (1). Sonra,

mavi led'i yakıyor (2) ve devamında sonsuz bir döngüye giriyor (3).

Bu döngü içerisinde, kırmızı led'i yakıyor (4), gecikme döngüsünde

bekliyor (5), kırmızı led'i söndürüyor (6), başka bir gecikme

döngüsünde tekrar bekliyor (7) ve başa dönüyor. Şu aşamada, programa

baktığınızda, gecikme döngüsünün tekrar kullanımının çirkin

gözüktüğünü kabul edeceksinizdir. Hatta, DRY prensibine ters

düşmektedir. Do Not Repeat Yourself (Kendini tekrar etme). Diğer bir

deyişle; programlama yaparken tekrarlamaları yok etmek için

uğraşmalısınız. Böylece aynı olması gereken kodlarınız uyumsuz

çalışmaz.

Bugün, tekrarlardan kaçınmanın ana tekniklerinden birini

öğreneceksiniz. Bu teknik ise, aynı kodu harfi harfine tekrardan

yazmaktansa, bu kod parçasını fonksiyona çevirip, gerektiği kadar

çağırmaktır. C dilinde bir fonksiyon, namı diğer procedure,

subroutine, sub-program, bir program içerisinde farklı yerlerden

çalıştırılabilen, tekrar kullanılabilir bir kod parçasıdır. Bir kod

parçasını, fonksiyona çevirmek için; ona bir isim, argüman listesi

ve dönüş değeri tipi atamalısınız. Basit bir başlangıç yapalım:

Gecikme fonksiyonumuzun adı “beklet” olsun, değişkeni ve döndürdüğü

bir değer olmasın.

Page 159: ARM Programlama

ARM Programlama

ARM Programlama 154154154

Dönüş tipi, isim ve argüman listesi birlikte bir fonksiyonun

imzasını oluştururlar. İmzadan sonra, parantez içerisinde fonksiyon

kodu olur.

Fonksiyonunuz tanımlandıktan sonra, kolaylıkla istediğiniz kadar

çağırabilirsiniz. Bir fonksiyonu çağırmak için gereken sözdizimi;

fonksiyon adı ve parantez içerisindeki argümanlar şeklindedir.

Page 160: ARM Programlama

ARM Programlama

ARM Programlama 155155155

Fonksiyon argümansız da olsa, parantezler gereklidir. Bir fonksiyon

çağırmak, akışı değiştirerek fonksiyon kodunun başlangıcına atlamak,

kodu yürütmek ve çağrıdan bir sonraki komuta geri dönmek demektir.

F7'ye basarak bu kodun derlenip derlenmeyeceğine bakalım.

Page 161: ARM Programlama

ARM Programlama

ARM Programlama 156156156

Bu kodu kit üzerinde denemeden önce, proje seçeneklerini

değiştirelim. Optimizasyonu Low'a ayarlayın. Çünkü yüksek

optimizasyon seviyelerinde derleyici o kadar akıllıdır ki, şimdiye

kadar yaptıklarınızı tersine çevirip, fonksiyon ek yükünü yok

edecektir. Buna bir fonksiyonu “Inlining” (Satıriçileme) denir ve bu

durumda böyle Bir şey istemiyoruz. Ayrıca, fonksiyonlarla çalışırken

“REQUIRE PROTOTYPES” seçeneğini işaretlemenizi şiddetle tavsiye

ederim.

Bu sefer F7'ye basarak derlemeye çalıştığınızda, beklet()

fonksiyonunun bir prototipe sahip olmadğına dair bir hata alırsınız.

Bir fonksiyon prototipi, fonksiyon imzasından sonra, kod bölümü

yerine noktalı virgül koyarak oluşturulur.

Page 162: ARM Programlama

ARM Programlama

ARM Programlama 157157157

Derleyici, tanımlarından önce her fonksiyonun prototipini

görmelidir. Bu arada, beklet() fonksiyonunuz bir argüman listesi

istememektedir. Eski C dili standartlarında, bunu “void” yazmak

yerine sadece boş bırakrak tanımlayabilirdiniz.

Bunu bir deneyelim hemen.

Gördüğünüz gibi kod artık derlenmiyor. Bunun nedeni, geriye

uyumluluk için, boş argüman listesinin, argümanların tanımlanmadığı

ve her şey olabileceği anlamına gelmesidir. “REQUIRE PROTOTYPES”

seçeneği ile, derleyici daha katıdır ve böyle zayıf tanımlanmış bir

prototipi tanımaz. Fonksiyonun argüman listesini tekrar “void”

olarak tanımlayalım.

Artık kodu, Stellaris kartında çalıştırmak için hazırsınız. İlk iş,

programın led'i hala yakabildiğini test etmek.

Page 163: ARM Programlama

ARM Programlama

ARM Programlama 158158158

Ve yanıyor. Kodu durdurduğumuzda, programınızı beklet() fonksiyonu

içinde bulacaksınız. Bu olağandır, çünkü program zamanının

%99.999'unu gecikme döngüsünü yürütmekle geçiriyor. Test edilecek

diğer ilginç şey ise, işlemcinizin gecikme fonksiyonunu aslında

nasıl çağırdığı. Bir breakpoint (kesme noktası) koyalım ve programı

çalıştıralım.

Gördüğünüz gibi, gecikme fonksiyonunuza yapılan çağrı, BL isimli tek

bir komuttan ibarettir.

Page 164: ARM Programlama

ARM Programlama

ARM Programlama 159159159

Önceki kontrol akışı konulu 2. dersimizden hatırlarsanız, bir

dallanma komutu, sadece program sayacı (Program Counter – PC)

yazmacının değerini değiştirir. BL komutu ise, fazladan bir etkisi

vardır ve sıradaki komutun adresini R14 yazmacına, Link Register'a

(Bağlantı yazmacı) saklar.

Böylece, LR, fonksiyon tamamlandıktan sonra dönülecek yeri hatırlar.

BL'den sonraki komutun adresinin 0xA8'de olduğunu aklımızda tutalım.

Bu arada, BL komutunun 4 byte uzunluğunda olduğuna dikkat edin.

Diğer komutların çoğu sadece 2 bayt uzunluğundadır. ARM Cortex-M

işlemcisinin THUMB2 isimli komut seti, çoğunlukla 2 byte, nadiren de

4 byte komutlardan oluşur. BL komutundan bir adım ileri giderseniz,

program sayacının gerçekten de beklet fonksiyonunuzun başlangına

atladığını ve LR'nin 0xA8 olarak değiştiğini görürsünüz.

Bir dakika! Aslında 0xA9 oldu. Bu oldukça gariptir, çünkü THUMB2

komutları çift sayılı bir adres ile hizalanmalıdır ve 0xA9 tekdir.

Bu garipliği birazdan, fonksiyonumuzun nasıl geri döndüğünü

gözlemledikten sonra açıklayacağım. Ama bundan önce, fonksiyon

kodumuz hakkınada birkaç ilginç şey açıklayacağım.

Page 165: ARM Programlama

ARM Programlama

ARM Programlama 160160160

Fonksiyon, SP yazmacını ayarlamakla başlıyor.

SP'nin açılımı Stack Pointer (Yığın yazmacı)'dır ve R13 yazmacının

diğer adıdır. Sp, C çağrı yığını (call stack) mekanizmasının

donanımsal uyarlamasıdır ve bu dersteki öğrenilecek en önemli

yazmaçtır. C yığını, basitçe söylersek, RAM'deki tek bir taraftan

büyüyen ya da küçülen bir alandır. Bu tarafa yığın tepesi denir ve

SP yazmacı bu tepe adresi içerir.

Hafızadaki yığını, Memory View'i (Hafıza Görünümü) SP'de saklanan

adrese yönlendirerek. Kolayca görebilirsiniz. Yığını görmek için,

hafıza görünümünü tek sütuna ayarlamak en iyisidir.

Page 166: ARM Programlama

ARM Programlama

ARM Programlama 161161161

ARM işlemcilerde, yığın, en alt adreslere doğru (Hafıza görünümünde

yukarıda) büyür ve yüksek adreslere doğru (Hafıza görünümünde

aşağıda) küçülür. Diğer işlemcilerde, yığın ters yönde büyüyebilir.

C yığınları için iyi bir benzetme, bulaşık yığınlarıdır. Tabakları

sadece en tepeden alabilir ya da ekleyebilirsiniz. Yani artık

anlayacaksınız ki, SP'den 4 çıkarmak, yığını bu kadar büyütür ve

yığının tepesinde “counter” yerel değişkenine yer açar. Sonrasında

bu değişken sıfırlanır ve 1 milyon kere arttırılır.

Şimdi, fonksiyonun sonuna bir breakpoint koyalım ve nasıl geri

döndüğünü görelim.

Geri dönmeden önce derleyicinin yapması gereken ilk şey, fonksiyona

girilince yığında yapılan değişiklikleri geri almaktır.

Page 167: ARM Programlama

ARM Programlama

ARM Programlama 162162162

Bizim örneğimizde; counter değişkeni tarafından tutulan 4 baytlık

alanı boşaltmak için yığın küçülür. Yığının şimdiki tepesinde

görebileceğiniz gibi, counter'ın son değeri 0xf4240'tır ve ondalık

tabanda 1 milyona denk gelmektedir. Yani gecikme döngümüzdeki

tekrarlama sayısı. Sonraki komut ise, fonksiyondan geri dönme

komutudur.

Geri dönme; BX dallanma komutu ile gerçekleşir. BX, branch (dallan)

ve exchange (değiştir)'in kısaltmasıdır. Bu komut, Program Counter'ı

belirlenmiş bir yazmacın değerine ayarlar. Bu durumda LR. Ancak,

LR'deki bitlerin hepsi PC'ye aktarılmaz. Özellikle PC'deki en düşük

değerli bit 0'a ayarlanır. Bu mantıklıdır çünkü geri dönüş adresi

çift olmalıdır. LR'nin en düşük değerli bit'i adreleme yerine, komut

Page 168: ARM Programlama

ARM Programlama

ARM Programlama 163163163

Gerçekten de 0xA8 adresine gidiyoruz, ki bu adres beklet()

fonksiyonumuzdan bir sonraki komutun adresidir. Son olarak ne

seti değişim bit'i olarak kullanılır. Bu bit 1 ise, işlemci THUMB

komut setine, 0 ise ARM komut setine geçiş yapar. Ancak ARM Cortex-M

serisi, sadece THUMB2 komut setini destekler ve aslında ARM setine

geçemez. Yani, Cortex-M'de, BX komutunun bu davranışı sadece eskiden

kalan bir mirastır. Şimdi BX komutunu işletelim ve nereye

gideceğimizi görelim.

olacağını görmek için, beklet() fonksiyonunun sonuna gidelim ve

LR'nin en düşük değerli bitini 0 yapalım.

Böylece çekirdek durumu ARM'a dönecektir, ama ARM, Cortex-M

çekirdeğinde destekli değildir.

Page 169: ARM Programlama

ARM Programlama

ARM Programlama 164164164

Gördüğünüz gibi, BusFault (Veriyolu Hatası) istisnai durumu

oluşuyor. İstisnai durumları, kesmeler hakkındaki bir sonraki yazıda

anlatacağım. Şimdilik, bir işlemcinin olasılıksız bir durumu nasıl

idare ettiğini göstermek istedim. Makine istisnai durum işleyicisine

girer. Bu da projenize tanımlayacağınız bir fonksiyon gibidir.

İşleyiciden çıkmak için, makineyi yeniden ayarlamanız (Reset)

gerekir.

Reset, sizi main'in başına getirdiği için, başka bir fonksiyonu

çağıran bir fonksiyonu incelemeniz için iyi bir fırsattır. Artık

main()'in de aslında, beklet fonksiyonu gibi bir fonksiyon olduğunu

fark ettiğinizi umuyorum. beklet()'i çağırmadan önce, main bir

yaprak (Leaf), ağacının bir yaprağı gibi, fonksiyondu, çünkü başka

fonksiyonu çağırmamıştı. beklet()'e çağrıyı eklediğinizde, main

artık bir yaprak fonksiyon olmaktan çıkar ve kendi geri dönüş

adresini korumak için özel bir şey yapması gerekir. Hatırlarsanız,

geri dönüş adresi, LR yazmacında saklanır. Ama bu yazmaç, BL komutu

tarafından yeni bir geri dönme adresi ile doldurulur. BL komutunu

işleten her fonksiyon, bir şekilde LR'nin önceki değerini doğru yere

dönmek için saklamalıdır. Asıl soru, LR'yi saklamak için en iyi yer

neresidir? Koddaki gibi, bu yerin stack olduğunu umarım görürsünüz.

PUSH (itme) işlemi, belirli yazmaç listesini stack'e kaydeder ve

stack'i büyütmek için otomatikman ve hassasiyetle stack işaretçisini

azaltır. Bunu PUSH komutunu çalıştırarak doğrulayalım.

Page 170: ARM Programlama

ARM Programlama

ARM Programlama 165165165

Özetlersek, stack'in 2 amaç için kullanıldığını öğrendiniz. İlki;

çağrılan fonksiyonların yerel değişkenlerini tutmak ve ikincisi;

geri dönme adresini saklamak.

Son olarak, fonksiyon argümanlarının ne için olduğunu ve nasıl

kullanılacağını göstermek istiyorum.

Fonksiyon argümanları fonksiyon çağırıldığında yerel değişkenlerin

ilk değerlerini belirtmenizi sağlar. Böylece her çağrı, farklı

argüman değerleri ile yapılabilir. Örneğin, beklet() fonksiyonunuzun

her yürütmede farklı bir tekrarlama sayısını işletmesini

isteyebilirsiniz. Bunun için, fonksiyon içindeki tekrarlamayı

sınırlayan “iter” isimli bir integer argüman tanımlayabilirsiniz.

Bir fonksiyona argüman tanımladıktan sonra, her çağrılışında

başlangıç argüman değerleri verilmelidir. Programı şimdi derlemeyi

denerseniz, derleyici, beklet() fonksiyonuna yapılan 2 çağrı için

hata verecektir. Çünkü artık prototipe uymuyorlar.

Page 171: ARM Programlama

ARM Programlama

ARM Programlama 166166166

Bu da prototipleri kullanmanın güzelliğidir. Çünkü derleyici, her

fonksiyon çağrısında doğru sayıda ve tipte argümanı vermeyi

unutursanız, sizi uyarabilecektir.

Artık argümanları verelim. İlk çağrı için 1 milyon tekrarlama ve ikincisi için sadece 500 bin

kullanıyorum. Böylece kırmızı led, sönük olduğu sürenin iki katı

yanık kalacaktır.

Bu kodu LaunchPad kartından çalıştıralım. İlk olarak, tüm

breakpoint'leri kaldıralım ve led'i izlemek için engel olmadan

çalıştıralım.

Page 172: ARM Programlama

ARM Programlama

ARM Programlama 167167167

Gerçekten de göreceksinizki kırmızı renk, iki kat süreyle yanık

kalmakta.

Sonra, parametrelerin nasıl iletildiğini görmek için beklet()

fonksiyonuna yapılan çağrılara breakpoint koyun.

Gördüğünüz gibi, BL komutundan önce, R0'a sabit bir değer atanmış.

beklet()'e ikinci çağrıda bu sabit 0x7A120, yani ondalık tabanda 500

bin.

İlk çağrıda ise, R0'a yüklenen değer önceden de tanıdığımız 0xF4240,

yani ondalık tabanda 1 milyon değeri yükleniyor.

Page 173: ARM Programlama

ARM Programlama

ARM Programlama 168168168

Gördüğünüz gibi, iki durumda da, iter argümanı R0 yazmacına

taşınmıştır. Şimdi gecikme fonksiyonumuza geçelim ve iter

argümanını nasıl kullandığını görelim.

Gerçekten de, iter argümanı R0'da ve counter değişkeni stack'in

tepesinde bulunuyor, çünkü counter'ın adresi SP yazmacındaki değer

ile aynı.

Böylelikle fonksiyonlar ve çağrı stack'i üzerine ilk dersimiz

sona eriyor. Fonksiyonlar son derece önemlidir, çünkü onları

düzgün bir şekilde tasarlayabilirseniz, işin NASIL yapıldığını

göz ardı edebilir ve sadece NE yapıldığına odaklanabilirsiniz,

ki bu çok daha kolaydır.

Page 174: ARM Programlama

ARM Programlama

ARM Programlama 169169169