İndir

Transkript

İndir
ARM Programlama
ARM Programlama
2
ARM Programlama
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]
ARM Programlama
3
ARM Programlama
İÇİ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
10. Modüller, Özyineleme ve AAPCS………………………………………………………………………………169
ARM Programlama
4
ARM Programlama
ARM Programlama
5
ARM Programlama
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
ARM Programlama
6
ARM Programlama
Bu Kursta Arm Cortex-M4F adındaki işlemciyi kullanacağız.
Ama bu öğrendiklerimizi bütün Cortex-M işlemci ailesine CortexM0'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.
ARM Programlama
7
ARM Programlama
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.
ARM Programlama
8
ARM Programlama
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.
ARM Programlama
9
ARM Programlama
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
ARM Programlama
10
ARM Programlama
"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
ARM Programlama
11
ARM Programlama
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.
ARM Programlama
12
ARM Programlama
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.
ARM Programlama
13
ARM Programlama
Gördüğünüz üzere, birazdan açıklayacağım proje oluşturulmuş bir main
dosyası içeriyor.
ARM Programlama
14
ARM Programlama
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.
ARM Programlama
15
ARM Programlama
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.
ARM Programlama
16
ARM Programlama
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.
ARM Programlama
17
ARM Programlama
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.
ARM Programlama
18
ARM Programlama
Kodların daha düzenli ve okunabilir olması için biraz düzenleme
yapalım.
ARM Programlama
19
ARM Programlama
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.
ARM Programlama
20
ARM Programlama
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).
ARM Programlama
21
ARM Programlama
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.
ARM Programlama
22
ARM Programlama
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.
ARM Programlama
23
ARM Programlama
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.
ARM Programlama
24
ARM Programlama
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
ARM Programlama
25
ARM Programlama
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.
ARM Programlama
26
ARM Programlama
Ö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ş.
ARM Programlama
27
ARM Programlama
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.
ARM Programlama
28
ARM Programlama
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ış.
ARM Programlama
29
ARM Programlama
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.
ARM Programlama
30
ARM Programlama
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.
ARM Programlama
31
ARM Programlama
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.
ARM Programlama
32
ARM Programlama
Görüldüğü üzere mevcut komut bir ilerledi ve sayac değişkeninin
değeri 0 olarak değişti.
ARM Programlama
33
ARM Programlama
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
ARM Programlama
34
ARM Programlama
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).
ARM Programlama
35
ARM Programlama
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.
ARM Programlama
36
ARM Programlama
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.
ARM Programlama
37
ARM Programlama
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.
ARM Programlama
38
ARM Programlama
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.
ARM Programlama
39
ARM Programlama
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.
ARM Programlama
40
ARM Programlama
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.
ARM Programlama
41
ARM Programlama
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.
ARM Programlama
42
ARM Programlama
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.
ARM Programlama
43
ARM Programlama
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.
ARM Programlama
44
ARM Programlama
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.
ARM Programlama
45
ARM Programlama
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.
ARM Programlama
46
ARM Programlama
İş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.
ARM Programlama
47
ARM Programlama
Bir seferde bir makine kodu atlatın ve PC kaydedicisinin her adımda
nasıl değiştiğini gözlemleyin.
ARM Programlama
48
ARM Programlama
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.
ARM Programlama
49
ARM Programlama
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.
ARM Programlama
50
ARM Programlama
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.
ARM Programlama
51
ARM Programlama
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ş.
ARM Programlama
52
ARM Programlama
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.
ARM Programlama
53
ARM Programlama
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.
ARM Programlama
54
ARM Programlama
İ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
ARM Programlama
55
ARM Programlama
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.
ARM Programlama
56
ARM Programlama
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.
ARM Programlama
57
ARM Programlama
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.
ARM Programlama
58
ARM Programlama
İ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.
ARM Programlama
59
ARM Programlama
Watch görünüm menüsü açıldığı zaman ilk satıra tıklayın ve
değişkenin adını yazın.
ARM Programlama
60
ARM Programlama
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
penceresinde (Memory) görünür olmalı.
doğrudan
bellek
görünüm
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.
ARM Programlama
61
ARM Programlama
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.
ARM Programlama
62
ARM Programlama
Aslına bakarsak bu
kaydırabilirsiniz.
etikete ne
Hey,
yüklediğini görmek
bu
benzer
R0'a yüklenen değer sayaç değişkeninin adresidir.
LDR.N komutunu çalıştıralım ve R0'ı izleyelim.
ARM Programlama
63
için aşağıya
gözüküyor.
ARM Programlama
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.
ARM Programlama
64
ARM Programlama
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.
ARM Programlama
65
ARM Programlama
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.
ARM Programlama
66
ARM Programlama
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.
ARM Programlama
67
ARM Programlama
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
değiştirebilirsiniz ve program eskisi gibi aynı çalışır.
yer
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.
ARM Programlama
68
ARM Programlama
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.
ARM Programlama
69
ARM Programlama
Dersin son
istiyorum.
adımında,
işaretçilerin
inanılmaz
gücünü
göstermek
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.
ARM Programlama
70
ARM Programlama
Bir sonraki denememizde, sayının sonuna U ekleyerek bir işaretsiz
sayı kullanmayı deneyebilirsiniz fakat derleyici bu ikisinden de
hoşlanmıyor.
ARM Programlama
71
ARM Programlama
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.
ARM Programlama
72
ARM Programlama
İş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
ARM Programlama
73
ARM Programlama
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.
ARM Programlama
74
ARM Programlama
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.
ARM Programlama
75
ARM Programlama
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ı.
ARM Programlama
76
ARM Programlama
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
Manual) indirmeniz gerekiyor.
Kullanım
kılavuzunu
(User
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
üzerinden kartın nasıl bilgisayara bağlanacağını açıklıyor.
ARM Programlama
77
kablosu
ARM Programlama
Bu sayfa ise kart üzerindeki bileşenlerin mikro denetleyiciye nasıl
bağlandığını açıklıyor.
ARM Programlama
78
ARM Programlama
Farklı birimlerin, Genel Amaçlı Giriş/Çıkış anlamına gelen GPIO'lar
ile birbirine bağlı olduğunu görebilirsiniz.
ARM Programlama
79
ARM Programlama
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.
ARM Programlama
80
ARM Programlama
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.
ARM Programlama
81
ARM Programlama
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.
ARM Programlama
82
ARM Programlama
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.
ARM Programlama
83
ARM Programlama
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
ARM Programlama
84
ARM Programlama
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ı.
ARM Programlama
85
ARM Programlama
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.
ARM Programlama
86
ARM Programlama
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
ARM Programlama
87
ARM Programlama
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
ARM Programlama
88
ARM Programlama
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.
ARM Programlama
89
ARM Programlama
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ş.
ARM Programlama
90
ARM Programlama
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.
ARM Programlama
91
ARM Programlama
Kaydedicinin taban (base) adresini kopyalayın ve ilaveten 0x608
adresini kaydedici adresine, tamamlamak için eklemeniz gerektiğini
fark edin.
ARM Programlama
92
ARM Programlama
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.
ARM Programlama
93
ARM Programlama
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.
ARM Programlama
94
ARM Programlama
Hey! GPIO-F‟in donanım engellemesi ortadan kalkıyor.
Led yakıp söndürme
aşamaya gelmedik.
becerisine
oldukça
yakınsınız
fakat
daha
o
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.
ARM Programlama
95
ARM Programlama
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
etmelisiniz.
yaradı,
kırmızı
led
0 yazarak led‟i söndürmeyi deneyin.
ARM Programlama
96
parlıyor.
Kendinizi
takdir
ARM Programlama
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 PointerHack‟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.
ARM Programlama
97
ARM Programlama
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.
ARM Programlama
98
ARM Programlama
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.
ARM Programlama
99
ARM Programlama
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.
ARM Programlama
10
0
ARM Programlama
Launcpad üzerinde bu kodu test edelim.
Sayaç
geçitleme
kaydedicisi
ayarlamasının
uyandırdığını not edin, beklendiği gibi.
Kırmızı ledin parladığını görüyorsunuz.
Ve tekrar karanlık oluyor.
ARM Programlama
10
1
GPIO-F
bloğunu
ARM Programlama
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!
ARM Programlama
10
2
ARM Programlama
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.
ARM Programlama
10
3
ARM Programlama
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.
ARM Programlama
10
4
ARM Programlama
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.
ARM Programlama
100
100
100
ARM Programlama
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.
ARM Programlama
101
101
101
ARM Programlama
Ö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.
ARM Programlama
102
102
102
ARM Programlama
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).
ARM Programlama
103
103
103
ARM Programlama
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.
ARM Programlama
104
104
104
ARM Programlama
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,
ARM Programlama
105
105
105
ARM Programlama
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.
ARM Programlama
106
106
106
ARM Programlama
Ü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
ARM Programlama
107
107
107
ARM Programlama
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.
ARM Programlama
108
108
108
ARM Programlama
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.
ARM Programlama
109
109
109
ARM Programlama
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.
ARM Programlama
110
110
110
ARM Programlama
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.
ARM Programlama
111
111
111
ARM Programlama
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.
ARM Programlama
112
112
112
ARM Programlama
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.
ARM Programlama
113
113
113
ARM Programlama
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)
ARM Programlama
114
114
114
ARM Programlama
Bu sağa kaydırma biti.
Ve son olarak sola kaydırma biti.
Kodu derleyip çalıştırmadan
olarak ayarlayalım.
ARM Programlama
önce,
115
115
115
optimizasyon
seviyesini
none
ARM Programlama
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
butonu ile Debugger’de kodu adım adım yürütelim.
and
Debug
Buradaki adımda a, b ve c değişkenlerinin temel değerlerinin Locals
Windows penceresinde ikilik (binary) olarak göstermemiz gerekiyor.
ARM Programlama
116
116
116
ARM Programlama
Bu
adımda
bitsel
inceliyoruz.
OR
ifadesinin
c
değişkenindeki
sonucunu
Gördüğünüz gibi, bitsel OR ifadesi a ve b değişkenleri arasında
mantıksal OR gibi davranıyor.
ARM Programlama
117
117
117
ARM Programlama
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.
ARM Programlama
118
118
118
ARM Programlama
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.
ARM Programlama
119
119
119
ARM Programlama
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.
ARM Programlama
120
120
120
ARM Programlama
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ğlandığını görüyoruz.
ARM Programlama
sağa
kaydırma
121
121
121
işinin
LSLS
komutu
ile
ARM Programlama
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
çalışır. Bir örnek ile inceleyelim.
operatörü
tamamiyle
farklı
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
görüntülüyerlim.
menüsünde
değişkenleri
binary
formatında
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ı.
ARM Programlama
122
122
122
ARM Programlama
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.
ARM Programlama
123
123
123
ARM Programlama
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.
ARM Programlama
124
124
124
ARM Programlama
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.
ARM Programlama
125
125
125
ARM Programlama
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
olması durumunda sonuç 1 olacaktır.
0
ise,
değişiklik
olmaz,
1
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.
ARM Programlama
126
126
126
ARM Programlama
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ış
çalışmaktadır.
olan
bu
iki
kod
tam
olarak
aynı
şekilde
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.
ARM Programlama
127
127
127
ARM Programlama
Derlemeden önce, Project > Options sekmesinden, Optimization kısmını
High seviyesine ve Debugger kısmını TI Stellaris’e ayarlıyoruz.
ARM Programlama
128
128
128
ARM Programlama
Şimdi programı Launchpad board’a yükleyip, çalıştıralım.
ARM Programlama
129
129
129
ARM Programlama
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.
ARM Programlama
130
130
130
ARM Programlama
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.
ARM Programlama
131
131
131
ARM Programlama
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.
ARM Programlama
132
132
132
ARM Programlama
Bu proje ders6’da yaptıklarımızdır.
ayıklamaya (Debug) geçelim.
ARM Programlama
133
133
133
Biraz
düzenleyelim
ve
hata
ARM Programlama
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.
ARM Programlama
134
134
134
ARM Programlama
İ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.
ARM Programlama
135
135
135
ARM Programlama
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.
ARM Programlama
136
136
136
ARM Programlama
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ı.
ARM Programlama
137
137
137
ARM Programlama
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ı
kullanabilirsiniz.
normal
birer
değişken
olarak
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.
ARM Programlama
138
138
138
ARM Programlama
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.
ARM Programlama
139
139
139
ARM Programlama
İşaretçi aritmetiği kullanımı ile aynı kapıya çıkıyor.
ARM Programlama
140
140
140
ARM Programlama
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.
ARM Programlama
141
141
141
ARM Programlama
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.
İkinci
olarak,
işaretçi
aritmetiği
kullanırız
çünkü
GPIO_PORTF_DATA_BITS_R uzun – işaretsiz işaretçidir. İşaretçi
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.
ARM Programlama
142
142
142
ARM Programlama
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.
ARM Programlama
143
143
143
ARM Programlama
Sonunda MAVİ_LED bit ayarı için tutarlı bir şekilde dizi indislemeyi
kullanıyoruz.
ARM Programlama
144
144
144
ARM Programlama
Bu, GPIO bitlerini değiştirmek için,
tekniğini kullandığımız son programdı.
Fast
–
Interrupt
Çalışma kitimizde test edelim.
İlk olarak, tam hızda çalışalım ve ledleri gözlemleyelim.
ARM Programlama
145
145
145
–
Safe
ARM Programlama
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,
mikrodenetleyicisi daha iyisini yapabilir.
ARM Programlama
146
146
146
ancak
Stellaris
LM4F
ARM Programlama
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.
ARM Programlama
147
147
147
ARM Programlama
Şekilde görüldüğü
edilmektedir.
üzere,
PORTF
(GPIOHBCTL)5.
Bit
ile
kontrol
Ş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.
ARM Programlama
148
148
148
ARM Programlama
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.
ARM Programlama
149
149
149
ARM Programlama
Bu ön eki, programınızda tüm GPIO_PORTF kayıtçılarına ekleyin.
ARM Programlama
150
150
150
ARM Programlama
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!
ARM Programlama
151
151
151
ARM Programlama
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.
ARM Programlama
152
152
152
ARM Programlama
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.
ARM Programlama
153
153
153
ARM Programlama
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.
ARM Programlama
154
154
154
ARM Programlama
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.
ARM Programlama
155
155
155
ARM Programlama
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.
ARM Programlama
156
156
156
ARM Programlama
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.
ARM Programlama
157
157
157
ARM Programlama
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.
ARM Programlama
158
158
158
ARM Programlama
Ö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.
ARM Programlama
159
159
159
ARM Programlama
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.
ARM Programlama
160
160
160
ARM Programlama
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.
ARM Programlama
161
161
161
ARM Programlama
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
ARM Programlama
162
162
162
ARM Programlama
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.
Gerçekten de 0xA8 adresine gidiyoruz, ki bu adres beklet()
fonksiyonumuzdan bir sonraki komutun adresidir. Son olarak ne
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
çekirdeğinde destekli değildir.
ARM Programlama
163
163
163
dönecektir,
ama
ARM,
Cortex-M
ARM Programlama
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.
ARM Programlama
164
164
164
ARM Programlama
Ö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.
ARM Programlama
165
165
165
ARM Programlama
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.
ARM Programlama
166
166
166
ARM Programlama
Gerçekten de göreceksinizki
kalmakta.
Sonra, parametrelerin nasıl
fonksiyonuna
yapılan
kırmızı renk, iki
iletildiğini
çağrılara
kat süreyle yanık
görmek için
breakpoint
beklet()
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.
ARM Programlama
167
167
167
ARM Programlama
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.
ARM Programlama
168
168
168
ARM Programlama
Modüller, Özyineleme ve AAPCS
Gömülü sistemler programlama derslerine hoş geldiniz. Bu derste C’de
fonksiyon konusuna devam edeceğim. Bugün fonksiyonların programınızı
nasıl ayrı dosyalara böldüğünü öğreneceksiniz. İlk özyineleme
fonksiyonunuzu yazacaksınız ve ARM uygulama prosedürü çağırma
standardı (AAPCS) hakkında bilgi edineceksiniz.
Yine her zamanki gibi önceki ders8 projesini kopyalayarak başlayalım
ve ismini ders9 olarak değişelim. Eğer eğitime yeni katılıyorsanız
önceki proje için bir önceki yazıyı okuyabilirsiniz. Ders9 dizinine
girin ve workspace (.eww uzantılı dosya) dosyasına çift tıklayarak
IAR Tool Set’i açın. Eğer IAR Tool Set’iniz ilk eğitime
gidebilirsiniz.
Şimdiye kadar ne yaptığımızı hızlıca anlatayım. Son derste
belirtilen sayıda döngü yinelemesi için beklet fonksiyonumuzu
oluşturmuştuk. Aşağıda beklet fonksiyonumuzun ifadesi var.
Bu ayrıca prototip olarak bilinir. Bu resimde
ise beklet fonksiyonumuzun kendisi var.
Beklet fonksiyonu programda iki yerde çağırılmış.
ARM Programlama
169
169
169
ARM Programlama
Tek fonksiyonun defalarca çağırılabilir olması, tekrarlanan kodların
yerine ilk etapta fonksiyonların kullanımı için iyi bir örnek oldu.
Fonksiyonlar programda daha çok uyum sağlamaya imkân sağlar.
Fonksiyonlar programı parçalara bölmenizi sağlar,
böylece beklet gibi rutinlerin, dosyaların hepsini main
fonksiyonunda tutmak zorunda kalmazsınız.
Bugün yapmak istediğim ilk şey beklet fonksiyonunu kendi dosyasına
taşımak. İlk olarak yeni belge araç butonuna tıklayarak yeni bir
dosya oluşturalım.
Sonra beklet fonksiyonunu kesip bu dosyaya yapıştıralım.
ARM Programlama
170
170
170
ARM Programlama
Son olarak bu dosyayı proje dosyanıza “beklet.c” olarak kaydedin. Bu
noktada dosya proje dizininizdedir ama henüz projenin parçası
değildir. Projeye bu dosyayı eklemeniz gerekecek.
Projeye sağ tıklayın ve ekleyi (Add) ve açılan menüden beklet.c’i
seçin.
ARM Programlama
171
171
171
ARM Programlama
Bu aşamada F7’ye basarak projeyi derlediğinizde bir hata alırsınız.
ARM Programlama
172
172
172
ARM Programlama
Bu, beklet fonksiyonu bir prototip olmadan tanımlanmış demektir.
Kolayca bu hatayı giderebilirsiniz. Prototipi main.c’den beklet.c’e
kopyalayın.
ARM Programlama
173
173
173
ARM Programlama
Fakat bu çok berbat bir düzeltmedir. Çünkü Eğer birini değiştirip
diğerini unutursanız, tekrarlanan prototipler çok kolay farklı hale
gelebilir. Bu KENDİNİ TEKRARLAMA! prensibi (DRY) için bir örnektir.
Tek prototip tanımlayıp bunu tüm dosyalarınızda içerebilirsiniz.
Bu beklet fonksiyonunun prototipi olabilir.
Daha önce olduğu gibi yeni bir belge oluşturun
ve beklet fonksiyonunun prototipini kesip bu dosyaya yapıştırın.
ARM Programlama
174
174
174
ARM Programlama
Dosyayı “beklet.h” olarak kaydedin. Şimdi tekrarlanan fonksiyon
prototipi yerine, beklet.h dosyasını main.c ve beklet.c ’ye include
(içermek) edebilirsiniz.
ARM Programlama
175
175
175
ARM Programlama
ARM Programlama
176
176
176
ARM Programlama
Son dokunuş olarak birden fazla dahil edilmesine karşı koruma için
beklet.h dosyasına bir şeyler ekleyebilirsiniz. Otomatik koruma
yararlıdır çünkü bir başlık dosyası altında başka başlık dosyası
içerebilir. Başlık dosyasının birden fazla dahil edilmesi kolayca
böyle bir duruma yol açabilir. Aslında böyle çoğu başlık dosyası
çeşitli kütüphanelerde sağlanır. Lm4f.h başlık dosyası da birden çok
içermeye karşı bir tür koruma bulundurur. Bu C önişlemcisi ile
aşağıdaki gibi sağlanır.
ARM Programlama
177
177
177
ARM Programlama
Dosyanın üst kısmında #ifndef önişlemci yönergesi, takiben dosyanın
süslenmiş ismi (mangling name) ve isim süslemenin belirli kuralları.
Burada örnek olarak iki alttan çizgi, ön genişletme (boşluk), son
genişletme büyük harfle dosya ismi görüyorsunuz. Burada düşünce bu
makronun önceden tanımlanmış olmasıdır. Böylece işlemci ilk
seferinde #ifndef’in sonrasına gidecektir. Ancak sonraki
satırda #define önişlemcisi ile makro tanımlanır, böylece bu
tanımlama artık açıktır. Bu nedenle başlık dosyası tekrar
içerilemez. Önişlemci geçilen #ifndef talimatına gitmeyecektir ve
dosyanın sonuna yani #endif satırına atlayacaktır.
Şimdi beklet.h başlık dosyasında bu tekniği uygulayalım. Lm4f.h
dosyasındaki ilk 2 satırı kopyalayıp beklet.h dosyasına kopyalayıp
ismini değiştirelim.
ARM Programlama
178
178
178
ARM Programlama
Dosya sonuna #endif önişlemcisini eklemeyi unutmayın.
Hızlıca bir özetle siz C programlama dilinin en güçlü
özelliklerinden biri hakkında kullanabileceğiniz bilgiler edindiniz;
Ayrı ayrı derlenmiş kaynak dosyalarından programlar oluşturma
yeteneği. Kullanıcı fonksiyonlarıyla etkinleştirilen bu yetenek
kritik önem taşır çünkü sadece bir dosyayla tamamlanan programlama,
hem elverişsiz hem de rahatsız edicidir. Bir yoldan bir program
dosyaları düzenlemesi size genel olarak yapısını anlamanıza yardımcı
olabilir ve bu yapıyı uygulamak için derleyebilmenizi sağlar. Bu
şekilde modüle etme, derleme işlemini hızlandırmak için faydalıdır.
Çünkü sadece değişen dosyaların derlenmesi gerekir.
Şimdi diğer bazı özelliklerini keşfetmek için hareket edelim. Bir
değer döndürme yeteneği gibi. Örnek olarak tam sayı argümanın
faktöriyelini hesaplamak için bir fonksiyon düşünün ve bu fonksiyonu
yukarıdan aşağı tasarlayalım.
Bu tasarım prototip ve kullanma durumu ile başlıyor. Fonksiyon
ismi fakt ve unsigned tipinde n adında bir argümanı var.
ARM Programlama
179
179
179
ARM Programlama
Faktöriyel fonksiyonu unsigned (işaretsiz) değerini döndürür bir
kez, iki kez, üç kez, .. her seferinde n kadar.
ARM Programlama
180
180
180
ARM Programlama
Sonra fonksiyonu yazmadan önce main fonksiyonuna gelelim ve
fonksiyon için değerleri atayalım.
Faktöriyel fonksiyonu tarafından Bir unsigned volatile değişkeni
olan x, döndürülen değerleri saklamak için kullanılacaktır.
ARM Programlama
181
181
181
ARM Programlama
Derleyici geçici değişkeni korumak için onun uzağında optimize eder.
Birazdan burada nasıl bir değer döndüren fonksiyon çağrıldığını
göreceksiniz. Fonksiyondan dönen değeri sadece bir değişkene
atayabilirsiniz.
ARM Programlama
182
182
182
ARM Programlama
Bu noktada siz ayrıca fonksiyon argümanlarının izin verilen
aralığını düşünmelisiniz. Matematiksel olarak her faktöriyel için
düşük değer sıfır tanımlanır. Aslına daha açıkçası bizim fonksiyona
göndereceğimiz argüman tipi unsigned olmalıdır çünkü bu fonksiyon
unsigned değer döndürür.
Ayrıca hemen bir değişkene atanmış olmak yerine, bir ifadede
kullanılabilir.
ARM Programlama
183
183
183
ARM Programlama
Son olarak siz ayrıca bir şey yapmadan sadece dönüş değeri ile
fonksiyonu çağırabilirsiniz. Fonksiyonunuz yan etkilere sahipse bu
mantıklı olacaktır. Temizleme yaparsanız bu dönen değere dikkat
etmeniz gerekmez. Bu satırda dönen değeri boş olarak ayarlayalım.
ARM Programlama
184
184
184
ARM Programlama
Bu kısımda programınızı derlemeye çalıştığınızda bir hata alırsınız.
Fakat bu bir derleyici hatası değil, linker (bağlayıcı) hatasıdır.
Bir program oluşturmanın sonraki adımı tüm derleme birimlerinin
hepsinin birbirine bağlandığı yerdir. Hata penceresini yukarı
kaydırdığımızda bağlantı aşamasında başarısız olduğunu
görebilirsiniz, nedeni fakt fonksiyonunun bulunamayışıdır.
ARM Programlama
185
185
185
ARM Programlama
Çünkü fonksiyonumuzu henüz tanımlamadık. Bunun nedeni açıktır. Fakat
ben dikkat çekmek istedim. Bu hata tipi derleyici tarafından
saptanamaz. Çünkü derleyici hangi dosya içinde bu işlevin tanımının
bulunduğunu bilemez.
Şimdi fakt fonksiyonunu tanımlayalım. Prototipi kopyalayalım ve
sayfanın en altına yapıştıralım. Fonksiyon kodlarımızı yazmadan önce
matematiğinizi tazelemek isteyebilirsiniz. Fonksiyon için aslında
iki tanımlama var, yinelemeli (iteratif) ve özyinelemeli (recusif).
Bu uygulama için siz özyinelemeli tanımlamayı kullanacaksınız.
Burada faktöriyel 0, 1’dir (0! = 1). Ve N sıfırdan büyük olmak şartı
ile n faktöriyel, n kere n-1 faktöriyeldir (n > 0
n! = n*(n1)!).
Bu dönüşümü C içine alın.
Eğer n işaretsiz değişkeni 0’a eşitse..
ARM Programlama
186
186
186
ARM Programlama
İşaretsiz 1 değerini döndür.
ARM Programlama
187
187
187
ARM Programlama
Aksi halde, geriye n*fakt(n-1U) döndür.
ARM Programlama
188
188
188
ARM Programlama
Gördüğünüz gibi bir fonksiyon dönüş ifadeleri vasıtasıyla sonuç
üretir. Şimdi F7’ye bastığınız zaman derleme ve bağlamanın ikiside
başarılı olacaktır. Tebrikler! İlk özyinelemeli fonksiyonunuzu
yazdınız. Bu fonksiyon kendisini çağırıyor.
Tamam, şimdi nihayet gerçekten nasıl çalıştığını görme zamanı. Kodun
gerçek donanımda nasıl çalıştığını görmek için, bunu TI boardında
çalıştıracağım. Ama eğer TI kitiniz yoksa simülatörü de
kullanabilirsiniz. Ctrl+D’ye basarak kodu kite yüklüyoruz.
Kod içinde adımlamadan (satır satır çalıştırma) önce yığının üstünü
görmek için bir bellek görüntü menüsünü ayarlayacağım.
Son dersten hatırlayacağınız gibi bu, yığın işaretçisindedir. SP
kayıtçısında.
Hafıza görüntüsünde yığın içeriğini izlemenize yardımcı olması
amacıyla geçerli yığının üstünü işaretlemek için görüntülerde bir ok
kullanacağım.
ARM Programlama
189
189
189
ARM Programlama
Kod içerisinde adımladığınızda göreceksiniz ki faktöriyel
fonksiyonunuzun çağrılması iki talimattan oluşur. Birincisi argüman
değeri R0’a hareket eder ve sonra şube kullanımı ve BL talimatı ile
fonksiyon çağrılır.
ARM Programlama
190
190
190
ARM Programlama
Faktöriyel fonksiyonu içinde kodun yaptığı ilk şey register itmek
(PUSH); R4 ve LR link registerlarını yığına iter. Neden olduğunu
anlamalısınız. Neden LR kaydedilmiştir? Bunun nedeni faktöriyel
önceden var olan bir fonksiyon değildir. Bu yüzden LR registerı BL
talimatı tarafından kendisini tekrar çağırmak için korunur.
ARM Programlama
191
191
191
ARM Programlama
Bir sonraki talimat LR register kaydının neden gerekli olduğuna dair
size bir ipucu vermelidir. Belki son dersten fonksiyonun ilk
argümanının R0 registerına geçtiğini hatırlıyorsunuzdur. Ama biz
faktöriyeli R0 içine değer dönmesini sağlamak için kullanmaktayız ve
ayrıca argüman olarak iç içe faktöriyel çağrısını kullanıyoruz.
Böylece derleyici R4’den R0’a hareket eder. Burada R0 registerı
içine dönüş değeri olarak 1 hareket değerinin ettirildiğini
görebilirsiniz.
ARM Programlama
192
192
192
ARM Programlama
Fonksiyonun son komutu çok ilginçtir. Çünkü bu komut bir taşla iki
kuş öldürür. Bildiğiniz gibi fonksiyon başlangıcında herhangi bir
yığın işlemi yürütülürken fonksiyon tam olarak Main’e dönmeden her
şeyin başa döndürülmesi gerekir.
Burada fonksiyon başlangıçta itilmiş olan 2 registerı atar. Ama LR
orijinal içeriği doğudan geri dönüşe yol gösteren program sayıcı
(PC) içine yükler.
ARM Programlama
193
193
193
ARM Programlama
Lütfen dikkat edin, yığındaki değer PC içine atanır. Aslında hex 49
tek sayısı eklenir. PC geri dönüş adresini bir çift sayı olan hex 48
olarak getirir.
ARM Programlama
194
194
194
ARM Programlama
Ben adresin en küçük anlamlı bitinin BX komutunda neden özel olarak
ele alındığını açıkladım; var olan bir fonksiyondan geri döndürmede
kullanıldığı için (beklet gibi).
Burada gördüğünüz gibi PC’ye atama talimatı da özel bölgededir ve BX
talimatı gibi davranır.
Son olarak burada gördüğünüz üzere tekrar fonksiyon R0 değeri
döndürür. Yığının üstünde hafızaya alınan; x değişkeninin bulunduğu
yerdeki.
ARM Programlama
195
195
195
ARM Programlama
Faktöriyeli sonraki çağırmanızda siz bu faktöriyelin kendisini
çağırdığını görebilirsiniz.
ARM Programlama
196
196
196
ARM Programlama
Burada en önemli gözlem faktöriyelin sonraki çağırımı önceki çağrı
dönmeden ve registerlar yığından çıkmadan önce olmasıdır. Bu yüzden
bunlar yığının üst kısmında, birinci çağrı tarafında
bulundurulmaktadır.
Burada gördüğünüz gibi özyineleme çağrısı dönüşünden sonra
döndürülen R0 değeri R4’de saklanan n argümanının orijinal değeri
ile çarpılır. Sonuç fonksiyondan döndürülmek için tekrar R0’da
saklanır.
ARM Programlama
197
197
197
ARM Programlama
Main fonksiyonuna dönerseniz, ifadenin nasıl gerçekleştirildiğini;
faktöriyel değerini R0’dan aldığı yerde ki gibi görebilirsiniz. 5
faktöriyelinin son çağrısı özyineleme çağrısının 6. Düzeyini
gösterir. Lütfen kodları hızlıca adımlarken açıkça fark
edilebilen n argümanının eksilmesini ve dönüş adreslerini yığın
oluşumu ile izleyin.
ARM Programlama
198
198
198
ARM Programlama
Bu noktada özyinelemeli çağırma durdurulduğunda bütün iç içe
çağrılar bir zaman ekleyerek dönecektir.
Tekrar dönüş dizisine adımlıyorum. Lütfen yığının nasıl açıldığını
gözlemleyin.
ARM Programlama
199
199
199
ARM Programlama
Faktöriyel fonksiyonu nihayet tüm yapılanlarla Main’e döndükten
sonra sonuç olarak 5 faktöriyelinin gerçek değeri, R0’da hex 78 ve
120 decimal’i ürettiğini görebilirsiniz (ondalık sistem).
ARM Programlama
200
200
200
ARM Programlama
Bu derste değinmek istediğim son konu fonksiyon çağırma
kurallarıdır. Önceden beri tartışılan bir şeyi fark ettiğinizi
umuyorum. Fonksiyon çağırıcı ile çağırılan fonksiyon arasında bazı
uzlaşmalar olmalıdır. Örnek olarak her iki tarafında fonksiyona
sağlanacak dönüş adresinin LR registerda olduğunu anlaşılmalıdır.
Ayrıca her iki tarafta ilk argümanın R0’a geçileceğini kabul
etmelidir ve dönüş değeri de R0’a dönecektir. Elbette birçok böyle
küçük anlaşmalar vardır. Bunların hepsi bir resmi sözleşme olan ARM
Uygulama Prosedürü Çağırma Standardı (AAPCS)’de bulunur. Tüm resmi
doküman oldukça karmaşıktır ve online arama yaparak AAPCS’yi
bulabilirsiniz. Burada ben sadece AAPCS’nin ARM registerlar için
yükümlülükleri nasıl atadığından bahsetmek istiyorum. Çünkü ARM
işlemcilerde kesme işlemeyi öğrendiğiniz zaman bu sizin için çok
faydalı olacak. Saklayıcı R0’dan R3’e ve R12’ye parametre geçirmek
ve değer döndürmek için kullanılır ve bir fonksiyon dönüşü olabilir.
ARM Programlama
201
201
201
ARM Programlama
Diğer taraftan fonksiyon R4’den R11’e 8 registerı rezerv etmelidir.
Bu, fonksiyon R4’den R11 arasını kullanamaz anlamına gelmez. Fakat
bunu yaparsa, fonksiyon kodu onları yığına kaydetmelidir ve dönüş
yapmadan önce onları geri yüklemelidir. Örnek olarak faktöriyel
fonksiyonunuzu R4 kullanarak tekrar çağırın ama onu yığına kaydedin.
Bu kural fonksiyon çağırıcının ön rezerv edilmiş registerları
kullanmasına izin verir, fonksiyon çağırıldığında değerler sağlam
kalır. Yine n parametresi değerini çağırın; faktöriyel özyinelemeli
çağrısının sağlam kalması için R4’de saklanmıştır. Çünkü bu son
çarpımda gereklidir. Faktöriyel hesaplamasını konuşurken, bu derste
kullandığım özyineleme uygulaması derin çağırma sırasında gösterim
için uygun olur. Yığın büyüme ve küçülmesini izleyebilirsiniz. Ama
normalde bir derin çağrı sırasında gömülü programlamadan tam olarak
kaçınılmalıdır çünkü bu yığın için çok fazla RAM kullanır.
Faktöriyelden çok daha iyi bir uygulama olacaktır; iteratif tip veya
daha da iyisinin kullanımı.
Modüller, değer döndüren fonksiyonlar, özyineleme fonksiyonları ve
ARM uygulama prosedürü çağırma standardı ile tamamladık. Ancak
fonksiyonlarla olan işimizi bitirmedik.
Sonraki derste siz fonksiyon parametreleriyle ilgili daha fazla
bilgi edineceksiniz. İşaret parametreleri içeriği ile kapsamlı ve
yerel yığın tabanlı değişkenler hakkında bilgi edineceksiniz. Son
olarak yığın taşmasında neler olabileceğini göreceksiniz. Herkese
iyi çalışmalar.
ARM Programlama
202
202
202

Benzer belgeler