Skip to content

Raspberry Pi’ye İşletim Sistemi Yazmak Ders 4

Yeni Bir Araç

Yakın zamanda sadece Rpi’deki donanımın GPIO kontrolcüsü olarak isimlendirilen bir kısmına baktık. Basitçe ne istediğimizi söyledik ve oldu. Şimdi zamanlayıcıya bakacağız ve nasıl çalıştığını anlama konusunda yardımcı olacağız.

GPIO kontrolcüsünde olduğu gibi zamanlayıcı(timer) da bir adrese sahiptir. Zamanlayıcı adres olarak 0x20003000 değerini kullanır. Raspberry Pi’nin klavuzunu okuduğunuzda aşağıdaki tabloyu bulursunuz.

Tablo 1.1 GPIO Controller Registers
Address Size / Bytes Name Tanım Read or Write
20003000 4 Control / Status Register used to control and clear timer channel comparator matches. RW
20003004 8 Counter A counter that increments at 1MHz. R
2000300C 4 Compare 0 0th Comparison register. RW
20003010 4 Compare 1 1st Comparison register. RW
20003014 4 Compare 2 2nd Comparison register. RW
20003018 4 Compare 3 3rd Comparison register. RW


Bu tablo bize çok şey söyler ama değişik alanların klavuzundaki tanımlamalar bize daha fazla şey söyler. Klavuz, temel olarak, 1 mikro saniyede sayıcıdaki değer sadece 1 artar der. Her zaman bu böyledir, sayıcının değerinin en düşük 32 bitiyle 4 karşılaştırma yapılır ve bunların eşleşmesi halinde eşleşenlere aksettirmek için  control/status  güncellenir.

Hedefimiz bekletmek istediğimiz kadar miktar girip sonuçta o kadar bekleten bir fonksiyon yazmak olacaktır. Bize verilenlerle bunu nasıl yapabileceğimizi bir düşünelim.

Önümüzde iki seçenek var:
1. Sayaçtaki değeri okuyun ve daha sonra sayaç, bekleme için gereken zamanın miktarı olduğundan daha fazla olana kadar aynı koda geri dallanmayı sürdürün

2. Sayaçtaki değeri okuyun, beklemeye gerekli olan zamanın miktarını ekleyin, bunu karşılaştırma registerlarının birinde tutun, daha sonra Control/Status register’ı güncellenene kadar aynı koda geri dallanmayı sürdürün.

İki strateji de iyi çalışabilir. Fakat bu eğitimde sadece birini uygulayacağız. Karşılaştırma registerları hata çıkarmaya daha çok müsaittir. Bekleme yaptırmak için gereken zamanı ekletirken ve karşılaştırma registerında bunu saklama esnasında counter(sayaç) artabilir. Bu yüzden eşleşme olmaz. Bu istenilen zamandan daha fazla gecikmeye neden olabilir.

Gerçekleştirme

Yazılacak kodları systemTimer.s adlı bir dosya oluşturup yazmanızı tavsiye ederim. Bu metodun en karışık kısmı, sayaç 8 byte değerindedir. Ama her register sadece 4 byte’lık değer tutabilir. Buna göre sayaç değeri 2 register’ı kapsar.

ldrd r0,r1,[r2,#4]

Yukarıdaki ldrd size yardımcı olabilir. 2 registerın üstüne hafızanın sekiz byte’ını yükler. ldrd regLow,regHigh,[src,#val] src ile verilen değeri toplar ve regLow kısmına düşük değerlikli ve regHigh yüksek değerlikli olacak şekilde yükler. Başka bir deyişle onluk tabanda 999,999,999,999 = 1110100011010100101001010000111111111111 sayısının düşük kısmını r2(11010100101001010000111111111111) tutacak yüksek kısmını ise r1(11101000) tutacaktır.

Şimdi bekletme metodunu yazalım. Öncelikle sistem zamanlayıcısının adresini kaydetmemiz gerekmektedir. Aşağıdaki kod bu işlemi yapacaktır.

.globl GetSystemTimerBase
GetSystemTimerBase:
ldr r0,=0x20003000
mov pc,lr

Bir diğer fonksiyon daha önce bahsettiğimiz ldrd’yi kullanarak şimdiki sayıcı değerini bize verecek.

.globl GetTimeStamp
GetTimeStamp:
push {lr}
bl GetSystemTimerBase
ldrd r0,r1,[r0,#4]
pop {pc}

Şimdi bekleme metodumuzu yazmak istiyoruz. İlk olarak, metod başladığındaki counter değerine ihtiyacımız var.

delay .req r2
mov delay,r0
push {lr}
bl GetTimeStamp
start .req r3
mov start,r0

Bu kod metod’un girişini, gecikme zamanının miktarını r2’ye kopyalar ve r0 ve r1’de bulunan şimdiki counter değerini çağırdığını bildiğimiz GetTimeStamp’ı çağırır. Daha sonra r3’e counter’ın değerinin 4 byte’ını kopyalar.
Bundan sonra şimdiki counter değeri ile baktığımız değer arasındaki farkı hesaplamamız gerekiyor ve daha sonra aradaki açıklık gecikme zamanına en yakın olana kadar bunu yapmayı sürdürmemiz gerekiyor

loop$:
bl GetTimeStamp
elapsed .req r1
sub elapsed,r0,start
cmp elapsed,delay
.unreq elapsed
bls loop$

Bu kod istenilen miktar kadar zaman geçene kadar beklememizi sağlar. Counter’dan değeri alır, ilk değerle istenilen gecikmenin oluşturacağı değeri kıyaslar. Eğer geçen zaman miktarı istenilen gecikmeden az ise tekrar loop etiketine dallanır.

.unreq delay
.unreq start
pop {pc}

Son olarak geri dönüş komutununu da vermiş oluyoruz.

Işığın Başka Şekilde Yanıp Sönmesi

Artık main.s fonksiyonu içerisindeki bekletme yapılan yerleri bu fonksiyonu kullanarak değiştirebilirsiniz. Fakat r0’ın mikrosaniye cinsinden olduğunu unutmayın.

Bu bölümün çözümü için tıklayınız.

Be First to Comment

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir