AVR ile Arduino’dan 10 Kat Daha Performanslı Port Kütüphanesi

Bu uygulamada bir önceki uygulamada yaptığımızın üzerine ilave ederek Arduino uyumlu bir port kütüphanesi yazacağız.

Bu yazdığımız port kütüphanesine benzer olarak daha öncesinde bazı makroları önceki yazılarda size göstermiştim. Bunlar fonksiyon yazılır gibi yazılmakta ve port adı ile bit adını belirtmeyi gerektirmektedir.

#define bitset(byte,nbit)   ((byte) |=  (1<<(nbit))) 
#define bitclear(byte,nbit) ((byte) &= ~(1<<(nbit)))
#define bitflip(byte,nbit) ((byte) ^= (1<<(nbit)))
#define bitcheck(byte,nbit) ((byte) & (1<<(nbit)))

Bunlar performans yönüyle hiçbir kayıp yaşatmayacaktır. Ama işin aslına baktığımızda bizi donanımdan çok da koparmayacaktır. Yine port yazmaçları ve yine bit pozisyonları üzerine işlem yapıyoruz. Ama Arduino’da bu durum D0, D1, D2… ya da A0, A1, A2… diye isimlendirilen ayaklar üzerinde yapılmakta. Bu yüzden bu makrolar yeterli olmayıp biraz daha soyutlama gereklidir.

Arduino’da ise bir ayak üzerinde port işlemi yapacağımız zaman ayağın adını belirledikten sonra ilgili port fonksiyonlarını kullanırız. Bunlar şu şekildedir.

pinMode(1, INPUT);
digitalWrite(1, HIGH);
digitalRead(1);

Bu fonksiyonlar gayet iyi görünse de performans yönünden oldukça kötü bir durumdadır. 16MHz’lik bir işlemcide aç/kapa işlemi sonucu 147,5kHz’lik bir sinyal alınmaktadır. 16/0,147'den bir aç/kapa işlemi için 108 saykıl gerektiğini görebiliriz. Üstelik burada bitler üzerinde fonksiyon tabanlı bir işlem yapılmaktadır. Değişken tabanlı bir işlem daha çok mantığa oturur niteliktedir. Bizim yaptığımız ise şu şekilde olacaktır.

D2_dir = OUTPUT;
D2_out = HIGH;
okuma = D2_in;

Görüldüğü gibi yaptığımız işlem Arduino’nun bir kopyası değil tamamen farklı bir yöntem kullandığı için Arduino’ya rakip olarak değerlendirilebilir. Üstelik bu rekabette açık ara kazanan taraf bizim yaptığımız kütüphanedir.

Performans yönüyle değerlendirdiğimizde bizim yaptığımız aç kapa işleminin Assembly kodu şu şekildedir.

kirmizi = 1;92: 8b b1       b in r24, 0x0b ; 1194: 84 60        ori r24, 0x04 ; 496: 8b b9        out 0x0b, r24 ; 11kirmizi = 0;98: 8b b1        in r24, 0x0b ; 119a: 8b 7f        andi r24, 0xFB ; 2519c: 8b b9        out 0x0, r24 ; 119e: f9 cf        rjmp .-14      ; 0x92 <main+0x12>

Burada IN, ORI, OUT komutları birer saykıl tutmakla beraber RJMP komutu iki saykıl tutmaktadır. Yani aynı işlemi toplamda 8 saykılda yapmaktayız bu da bize 2MHz’lik bir sinyal vermekte. Arduino 108 saykılda aynı işi yaparken biz 8 saykılda yapmaktayız. Yani 108/8'den 13,5 kat daha performanslı olduğunu söyleyebiliriz.

Şimdi yazdığımız kütüphane kodlarını inceleyerek devam edelim.

Bu kütüphane sadece .h dosyasından ibaret olup tanımları içermektedir. Herhangi bir fonksiyon yoktur. Bu sebepten dolayı performans yönünden fonksiyonlu kütüphanelere göre daha iyi bir noktadadır. Fonksiyonlar her çalıştırıldığında fazlaca saykıl tüketen JUMP komutları işletilmektedir.

Ben bu kütüphaneyi yazarken Arduino kullanıcılarını da düşünerek bazı sabitleri ve bit adlarını Arduino’ya benzettim. Yalnız Arduino adlarından hoşnut olmayanlar içinse son kısımda alternatif ad tanımlamalarında bulundum. İsteyen D0_digitalRead, D0_pinMode, D0_digitalWrite şeklinde ifade ederken başka biri de D0_dir, D0_out, D0_in diye ifade edebilir. Bana kalırsa ikinci kullanım daha kısa ve pratik olacaktır.

Burada Arduino’nun ayak haritasına bakarak her bir ada karşılık gelen port adını ve bit numarasını tek tek elle belirledim. Örneğin şu kısmı inceleyip rahatça görebiliriz.

Burada D0_pinMode biti DDRD yazmacının 0 numaralı bitine atanmakta. Bu sayede buna atadığımız değer bu yazmacın ilgili bitine atanacak ve giriş veya çıkış olarak ayarlanacaktır. Bunu 1 veya 0 diye atabileceğiniz gibi daha anlaşılır(sözel) olması adına şu tanımları da kullanabilirsiniz.

#define HIGH 1
#define LOW 0
#define OUTPUT 1
#define INPUT 0
#define PULL_UP 1
#define NO_PULLUP 0

Şimdi örnek kullanımları size gösterelim.

Ben D portunun 5 numaralı bitini giriş, 6 numaralı bitini çıkış, 7 numaralı bitini ise hem dahili pull-up direnci ile giriş modunda kullanmak istiyorsam şöyle bir kod yazmam gerekir.

D5_pinMode = INPUT;
D6_pinMode = OUTPUT;
D7_pinMode = INPUT;
D7_pullUP = PULL_UP;

Ben C portunun 0 numaralı ayağından 1 çıkışı, 1 numaralı ayağından 0 çıkışı almak istiyorum ve 2 numaralı ayak ise aç/kapa (toggle) fonksiyonunda çalışacak.

A0_digitalWrite = HIGH;
A1_digitalWrite = LOW;
A2_dir = HIGH; // TOGGLE

Mikrodenetleyicide donanımsal olarak bile olmasına karşın Arduino’da toggle işleminin olmadığına dikkat ediniz! Burada _dir ya da pinMode değerine 1 yazarak toggle işlemi yapabilirsiniz.

En son olarak giriş olarak ayarladığım D2 ayağından okuma yapmak için şöyle bir kod yazmam gerekir.

okuma = D2_digitalRead;

Okuma değeri 1 veya 0 olarak geri dönecektir.

Şimdi Arduino üzerinden performans testi yapalım ve aradaki performans farklarını görelim. Öncelikle Arduino’nun yerleşik fonksiyonlarını kullanarak bir test yapacağız. Bu testte 10000 kere çalıştırılan iki digitalWrite() fonksiyonunun kaç mikrosaniye tuttuğunu göreceğiz.

Programı çalıştırdığımızda seri port ekranında şöyle bir çıktı alırız.

10000 kere çalıştırılan digitalWrite() fonksiyonu 67944 mikrosaniyede bu işi yerine getirmekte. Şimdi aynı işi yazdığımız kütüphane ile yapalım.

Programı çalıştırıp ne kadar süre geçtiğine bir bakalım.

Sadece 5064 mikrosaniye geçmiş. Bu zaman değerlerinde bazen artışların olduğunu görebilirsiniz. Bu Arduino’nun arka planda T0 zamanlayıcısını çalıştırması, kesmeye gitmesi ve orada işlem yapmasından dolayı gerçekleşmektedir. Arka planda çalışan bu program bazı kritik işlerde aksaklığa sebep olabilir. Aynı şekilde eğer bunu çalıştırmazsak millis() ve micros() fonksiyonlarını kullanma imkanımız olmaz. Şimdi kaç kat daha hızlı çalıştığını ölçelim.

67944 / 5064 = 13.4170

Burada da yine yaklaşık 13.5 kat daha hızlı olduğunu görmekteyiz. O halde bu kütüphane yerine Arduino’yu kullanmanın ne avantajı olabilir? Ben hiçbir sebep göremiyorum. Daha öncesinde yazdığım veya kullandığım AVR kütüphanelerini de bir araya getirirsek Arduino’dan çok daha hızlı ve özellikli bir kütüphane kolleksiyonu elde etmiş oluruz. Üstelik bunu Arduino IDE üzerinde de kullanma imkanımız vardır. İşin aslında Arduino bir mühendislik harikası, yüzyılın icadı değil basit bir öğrenci işi frameworktür.

--

--