sayfa başı

8 Mart 2015 Pazar

Adım Adım Linux Driver Yazıyoruz -2-

Adım Adım Linux Driver Yazıyoruz

    Adım Adım Linux Driver Yazıyoruz başlıklı yazıma devam ediyorum. Eğer bu yazının ilk kısmını okumadıysanız buradan ulaşabilirsiniz. Bu yazımda biraz daha teorik bilgiler ile açıklama yaptıktan sonra iştahla beklediğimiz kod örneklerine ulaşacağız. Biraz sabırla devam edelim ki konuyu tam anlamıyla öğrenelim.

Kernel Fonksiyonlarının Geri Dönüş Değerleri

    Kernel fonksiyonları kendini çağırana belli bir değer ile geri döner. Bu değerler belli bir kurala tabi tutulmuştur. Burada oluşturulan yöntem oldukça basittir, hatta kullanıcı katmanında da(user space) bu yöntemi uyguladığımızda oluyor. Bu yüzden bu konuya uzak değiliz.
  • Hata Durumu: Kernel fonksiyonları hata durumlarını iletmek için negatif değer döner. Fonksiyonun geri dönüş değerini sorguladığınızda eğer bir negatif değer ile karşılaşırsanız işler rast gitmiyor demektir. Tıpkı user space olduğu gibi Kernel seviyesinde de aldığınız hata mesajlarını açıklayan bir başlık dosyası bulunmaktadır. <linux/errno.h> İşte bu dosyada hata numaraları açıklanmaktadır. Ayrıca kendi yazdığınız fonksiyonların da geri dönüş değeri olacaktır. Kernel fonksiyonları gibi hata durumlarını iletmeniz gerekecektir. Bu yüzden fonksiyonun geri dönüş tipi int olmalıdır. Şunu da söylemek gerekir başlık dosyasını incelediğinizde tüm hata mesajlarının pozitif sayı olduğunu görürsünüz. Bu yüzden kendi fonksiyonlarınızda hata durumlarınızı dönerken bu başlık dosyasında tanımlı hata makrolarının önüne "-" işareti koyarak sayıyı negatif yapmalısınız.
  • Başarı durumu: Kernel fonksiyonları işlerini başarı ile yaptıklarını iletmek için sıfır değeri ile geri döner. Tabi bu durumun bazı istisnaları vardır. Örneğin read ve write fonksiyonları gibi. Bu fonksiyonlar başarı sağladıkları karakter sayısı ile geri dönerler. Ama sonuçta negatif değildir. 
    Not: Konuya devam etmeden önce bu başlık için bir referans kitabı belirtmek istiyorum. Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman tarafından yazılmış “Linux Device Drivers” kitabını okumanızı tavsiye ederim. Zaten pdf olarak bulmanız çok kolay. Hatta bu linkten hızlıca temin edebilirsiniz.

    Linux cihazları üç farklı türde farklılaştırmıştır ve modül yazımında bu farklılığa göre kodunuzu oluşturmalısınız. İlk olarak cihazın türünü belirlemek ve sonra o türe ait modül yazılımını yapmak gerekiyor. char module, block module, network module işte ayrıma sebep olan modül isimleri. Biz yazılacak olan modül için char device ele alacağız.


Char Devices

    Char Devices byte akışı ile erişim sağlanan cihazlardır. Bu cihazlara ait modül de bu davranışa göre oluşturulmalıdır. Byte akışı ile erişim olduğundan bu cihazların sürücüleri(driver) open, close, read, ve write sistem çağrıların içerirler. Konsol ekranı(dev/console), seri port(dev/ttyS0) ... karakter cihazlara örnektir.
    Karakter cihaz sürücüleri normal dosyalar gibi kullanıcı katmanında karşımıza çıkar. Karakter cihaz sürücüleri(Char Driver) üzerinde open, close, read, ve write işlemleri yapabilmemize rağmen normal dosyalardan ayıran fark ise onların normal dosyalar gibi kalıcı bilgiler taşımaması ve normal dosyaların kullanıcı iznine bağlı olarak silme, yer değiştirme ve isim verme gibi işlemlerinin yapılamamasıdır. Durumu daha iyi açıklamak için bir audio device dosyasını ele alalım. Bu dosyaya ne yazarsak direk cihaza doğru yönlendirilir ve bu yazılanların etkisiyle cihazdan çıktı alırız. Fakat normal dosya gibi okumak istediğimizde ise bir önceki yazdığımız verilere ulaşamayız. Durumun tam tersini düşünelim ve bir mikrofon ile kayıt yapıyor olalım bu sefer okuma fonksiyonu ile mikrofondan gelen verileri alıyor olacaktık.
  Bu konuda daha fazla bilgiye referans olarak belirttiğim “Linux Device Drivers” kitabının 42 sayfasında ulaşabilirsiniz. 

Kullanıcı Katmanından Cihaza Kadar Olan Bağlantının Sağlanması

Kullanıcı Katmanından başlayarak char device nasıl erişildiğini aşağıdaki resim açıklamaktadır.

Figure 7: Character driver overview
Char Driver Çalışması

    Görüldüğü gibi kullanıcı katmanında cihazı kontrol etmek için(ulaşmak için) cihaza ait dosya kullanılır.(char device file -CDF-) Uygulamalar sadece bu dosyalar üzerinde bildiğimiz dosya işlemlerini yaparak basitçe cihazı kontrol edebilirler. Bu durumun bir güzel yanı da tüm cihazlar için kullanıcı katmanında aynı fonksiyonların kullanılması. Cihazımız ne olursa olsun o cihazı okumak ya da yazmak için hep aynı fonksiyonları kullanırız.
    Peki bu nasıl oluyor? Yukarıdaki resmi incelersek her char device file -CDF- tek bir noktada birleşiyor. Virtual File System. Virtual file system uygulama seviyesindeki CDF gelen isteğin hangi cihaz için olduğunu çözümler ve isteği o cihazın sürücüsüne yönlendirir. Bu sayede istek doğru cihazı bulmuş olur. İsteğin çözümlenmesi ve yönlendirilip ilgili cihaz sürücüsüne ulaşma işlemleri Kernel seviyesinde olur. Son olarak artık isteğin cihaz üzerinde işlenmesi donanım seviyesinde(Hardware Space) olur.
    Uygulamalar  open fonksiyonu ile device file erişirler. Device file VFS ile Device Driver bağlanırlar. Device Driver cihaza özgü olan alt seviye özel işlemler ile cihaza ulaşır ve cihaz üzerinde yapılmak istenen işlem tamamlamış olur.


Major ve Minor Numaraları

     Major ve minor numaraları konusuna giriş için ilk olarak şu komutu koşalım; $ls -l /dev/ Bu komutu koştuğumuzda sistemimizdeki cihazlara ait dosyaları (device file) görürüz. Burada dosya isimlerinden başka konumuz olan major ve minor numaralarını da görürüz. Major ve minor cihazı tanımlayan özel bir sayı çiftidir.


    Resimde /dev/ altında cihazlara ait major ve minor numarı görülmektedir. Major numarası cihazları gruplandırmak için kullanılır. Resimde tüm cihazların major numarası dörttür. Çünkü bu cihazlar serial interface grubunda olup, o gruba ait major numarasını taşırlar. Minor numarası ise tekildir. Yani bir grup içinde her cihazın minor numarası ayrıdır. Kernel hangi cihaza erişim olacağını minor numarası ayrımı ile yapar.
  Kullanıcı katmanındaki uygulamalar sadece device file gördüklerinden onlara isimleri ile ulaşırlar. Her ne kadar kullanıcı katmanında dosya ismi kullanılsa da cihaz sürücüsüne (device driver) ulaşmak için artık numaralar kullanılır. Bu numaraları kullanma kullanıcı seviyesinde yapılan bir iş değildir. Bizim kullandığımız dosya ismi kernel seviyesinde cihaz sürücüsüne ait olan major ve minor numaralarına dönüşür.
  Not: Major ve Minor her ikisi Kernel 2.6 versiyonundan sonra desteklenmektedir.
    Kernel modülü yazılırken bu major ve minor numaralarının nasıl ele alındığına bakalım. İlk olarak <linux/types.h> dosyasını modül yazımında dahil edilmelidir. Çünkü cihaza yüklenecek olan major ve minor numaraları dev_t türündeki bir değişkenin içinde saklanacaktır. dev_t türü 32 bitlik bir değişken olup 12 bitinde major numarası, 20 bitinde de minor numarasını içerir.
Major ve minor numaralarını ayrı ayrı görmek için <linux/kdev_t.h> tanımlanan makroları kullanılır.

MAJOR(dev_t dev) // major numrasını verir
MINOR(dev_t dev) // minor numarasını verir
MKDEV(int major, int minor) // major ve minor numarası ile dev oluşturur.
Bu konuda daha fazla bilgiye “Linux Device Drivers” kitabının 43-44 sayfalarından ulaşabilirsiniz.


Cihaz Numaralarını Oluşturmak

    Modül yazılırken ilk olarak cihaz numaraları (major ve minor numaraları) oluşturulmalıdır. Cihaz numaraları oluşturulduktan sonra sitem cihazımızı bu numaralar ile tanıyacaktır.
int register_chrdev_region(dev_t first, unsigned int cnt, char *name);
int alloc_chrdev_region(dev_t *first, unsigned int firstminor, unsigned int cnt, char *name);
    İlk fonksiyonda first, almak istediğimiz device number başlangıcıdır. Bu değere genellikle 0 olarak değer geçilir.  cnt ise en yakın cihaz numarasına ulaşmak için kullanılır. Son olarak name cihaza verdiğimiz isimdir. Bu isim oluşturulan cihaz numarası ile ilişkilendirilir. İlk fonksiyon kullanımımıza sunulmuş olunsa da genellikle bu fonksiyon yerine ikinci fonksiyon kullanılır. Çünkü çoğunlukla cihazımızın hangi major numarasını kullanacağını bilemeyiz. Bu yüzden ikinci fonksiyonun kullanımı daha kolaydır.
    Eğer çağırdığımız fonksiyon başarı ile döner ise verdiğimiz isim major numarası ile /proc/device/ altında görülür.
    Bu fonksiyonlar modülümüzün init fonksiyonu içinde çağrılmalıdır ki modül dinamik olarak yüklendiğinde cihaza ait veriler oluşsun. Şimdi tüm bu anlatılanlara yönelik kodu yazalım.

#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>

static dev_t dev;

static int __init myModule_init(void) /* Constructor */
{
      int retVal;
    
      retVal = alloc_chrdev_region(&dev, 0, 1, "ZAFER");
      if (retVal < 0)
      {
          return retVal;
      }
      printk(KERN_INFO "<Major, Minor>: <%d, %d>\n", MAJOR(dev), MINOR(dev));
      return 0; // success
}

static void __exit myModule_exit(void) /* Destructor */
{
      unregister_chrdev_region(dev, 1);
      printk(KERN_INFO "myModule_exit\n");
}

module_init(myModule_init);
module_exit(myModule_exit);

MODULE_AUTHOR("Zafer Satilmis");
MODULE_DESCRIPTION("First Char Driver");
   Kodu yazdıktan sonra tabi ki derlenmesi gerekiyor. Bir sonraki yazımda derleme işlemini nasıl yapacağımızı (Makefile oluşturma), cihaza nasıl yükleyip modülü nasıl çalıştırılacağını aktaracağım. 

Faydalanacağını düşündüğünüz kişilere iletin, eksik ya da yanlış olduğunu düşündüğünüz yerleri belirtin.

Şimdi Yazmaya Devam ....

Kuşadası

6 Mart 2015 Cuma

Adım Adım Linux Driver Yazıyoruz -1-

Adım Adım Linux Driver Yazıyoruz
Giriş
Bu yazımda Linux driver eklemeyi ele alacağım. Kullanacağımız başlık dosyalarından(header file) yazacağımız koda, teorik bilgilerden uygulamalı anlatıma hatta konsol komutları ve çıktılarına kadar değinip anlaşılması ve öğrenilmesi kolay bir içerik oluşturmaya çalışacağım. Bu sayede daha öncesinde örümcek ağı gibi gelen konular ve sorular gittikçe açılacak. Hatta yazının sonunda bunlar o kadar da zor değilmiş diyeceksiniz ki bu da zor olduğu halde bilinen(becerilen) iş kolay iştir cümlesini size hatırlatacak.


   Her ne kadar basit bir anlatım oluşturmayı amaçlasam da bu dokümanda bulunanları tam olarak anlamak için işin bir kısmı da sizin üzerinizde. Size yüklediğim görev yazılan her kodu satır satır bakarak yazmak, ismi geçen başlık dosyasını bulup bahsi geçen fonksiyonlara göz atmak, koşulan konsol komutlarını koşmak ve buradaki çıktılar ile karşılaştırmak olacak. Her zaman söylendiği gibi “Yazılım” nasıl öğrenileceğini kendi içinde saklar. “YAZ ılım”. Bu yüzden yazın yazın yazın tekrar tekrar yazın.
Kernel Nedir?
Eğer bir sözlüğe bakarsanız kernel kelimesinin anlamının çekirdek, öz olduğunu görürsünüz. Fakat  Kernel bizim bildiğimiz gibi bir işletim sisteminin tüm çekirdeğidir. Kernel sistem yöneticisidir. Tüm sistem kaynaklarını yönetir. Sistem kaynakları nelerdir diyecek olursanız eğer: CPU, memory, input/output, network...

   Kernel' dan neden bu kadar az bahsettim derseniz ilk olarak uzun uzun yazıp konu dışına çıkmamak için bu özet bilgi ile yetindim diyebilirim. İkinci olarak ilerde anlatılacak konuların, özellikle yazılacak kodların bu katmana ait olduğunu belirtmek isterim. Burada aklınızda bir soru oluşmasını bekliyorum. “Başka katmanlar da mı var?” sorusu ya da en azından şu kelimenin aklınıza gelmesini umut ediyorum. User space(kullanıcı katmanı). Fark ettiyseniz iki katmanımız oluştu, kernel ve user space. User space çok yakın olduğumuz alan hatta sürekli kullandığımız alan. Hani şu printf ile “Hello World” uygulamasını koşup çıktısını konsolda gördüğümüz katman.
Kernel' dan bu kadar az bahsetmemin sebebinin anlaşıldığını umarak ana konunun derinliklerine doğru giriş yapıyorum.

Kernel C (Pure C)
  Kernel modül yazmadan önce Kernel katmanında kullanacağımız Kernel C tanımamız gerekir. Bu sayede yazılan kodları daha kolay ve hızlı kavrayabiliriz. Kernel C dedim, bu sizi yanıltmasın. Hemen telaş edip "Kernel modüle yazmak için yeni bir dil mi öğreneceğim?" sorusunu aklınıza getirmeyin. Kernel C normal kullandığımız C dilidir. Sadece Kernel seviyesinde GNU uzantıları ile kullanılır. Biraz daha açıklayıp sizi rahatlatmak için şöyle söyleyeyim: Kernel C, kullanıcı katmanında kullandığımız kütüphaneleri içermez. Yani C dilini elimizde glibc kütüphaneleri olmadan kullanacağız. (glibc için busiteye ve bu siteye gözatabilirsiniz. glibc bahsetmişken şu sayfaya da göz atın derim.) Peki elimizde o çok sevdiğimiz başlık dosyaları olmadan(stdio.h, stdlib.h, string.h) nasıl kod yazacağız derseniz eğer imdadımıza Kernel seviyesine ait başlık dosyaları yetişir. <kernel_source>/kernel/lib. Ufak bir örnek #include <linux/module.h> İşte Kernel C ile kullandığımız C arasındaki fark bu, başlık dosyaları.
   
    Kernel seviyesinde çalışırken bile en sevdiğimiz dil C kullanmamız işin en güzel yanlarından. Fakat burada nesne dayalı programlama mantığı kullanılmıştır. Biraz C++ bilenler için şu iki kelime constructor ve destructor tanıdık gelecektir. C++ bilmeyenler bu durumu dert etmesine gerek yok. Çünkü bu işleri yine basit bir fonksiyonla yapacağız. Bu kadar yazıdan sonra basit bir modül kodu örneğine bakalım.

Şekil 1 Basit Bir Kernel Modul Kodu

   Gördüğünüz gibi modül constructor ve destructor fonksiyonlarını içerir. mymodule_init modülün constructor fonksiyonu, mymodule_exit modülün destructor fonksiyonudur. C++ bilenler constructor fonksiyonunun obje yaratılırken çağrıldığını bilirler. Fakat burada constructor (kurucu fonksiyon) fonksiyonu -mymodule_init- modül dinamik olarak Kernel yüklenirken çağrılır. Peki destructor fonksiyonu -mymodule_exit- ne zaman  ne zaman çağrılır. Tabi ki de modül Kernel' dan çıkartılırken yani modül sistemden geri alınırken.

Kernel' ın Mesaj Kayıtcısı printk()

   Basit Bir Kernel Modul Kodunda kullanılan constructor ve destructor fonksiyonlarının dışında biraz bu basit modülde ismi geçen printk() fonksiyonundan bahsedelim.  printk(), çok yakından bildiğimiz printf() in Kernel seviyesinde çalışan eşdeğeridir. Tabi kullanımı ve görevi printf()' den biraz farklıdır.

   printk, printf gibi çıktılarını standart output basmaz. Peki printk nereye yazar? Kullanıcı katmanında(user space) çalışan syslog daemon bu mesajları toplar ve son işlem olarak çeşitli cihazlara yönlendirir. Yani kısaca bazı mesajları konsol komutuna yolladığı gibi bazılarını da sadece dosya da saklar. Tüm printk çıktılarını
default olarak /var/log/messages dosyasına basılır. Ayrıca ayarlanarak bazı printk mesajları seri port üzerinden
 konsola(/dev/ttyS0) basılabilir. Örneğin KERN_ERR mesajları konsolda gözlenebilir.



NOT 1: /var/log/messages dosyası normal kullanıcılar için okunabilir biri dosya değildir. Fakat $dmesg komutu ile bu verilere ulaşabilirsiniz

NOT 2: kernel seviyesinde çağrılan tüm printk mesajlarını konsol ekranına basmak için şu komutu koşmanız yeterli:    $dmesg  

NOT 3:dmesg kullanıma yönelik pratik bilgi: $dmesg koştuktan
sonra ekranda bir sürü kernel seviyesinden gelen mesaj göreceksiniz. Bunların içinde kaybolmamak için bir anahtar kelime ile arama yapabilirsiniz. $dmesg | grep my_key_word















printk teknik özelliğinin yanında birazda kullanım biçiminden bahsedelim. Basit Bir Kernel Modul Kodunda kullanımına tekrar bakalım. printk(KERN_INFO "BYE BYE My Module"); İlk göze çarpan KERN_INFO makrosu oluyor. Aslında bu makro sabit bir stringden başka bir şey değil. KERN_INFO kullanımından sonra virgül kullanılmadığına dikkat ediniz. (Arada bir şey kullanılmamış.) Bu durum bize C nin kurallarından biri olan string birleştirmeyi hatırlatması gerekir. 
printf("first text" " second text\n");   [çıktısı: first text second text] 
kodu her ne kadar geçerli ise prink çağrımı da o kadar geçerli ve aynı. Bu açıklamadan sonra printk gizemi gittikçe azalıyor olması lazım. Artık printk ya da bizim printf gibi bir yakınlık duymamız lazım.

Printk sadece KERN_INFO makrosu kullanılmaz. #include<linux/kernel.h> başlık dosyasında printk mesaj durumunu anlatan sekiz adet makro bulunmaktadır.



Yazının devamı olan Adım Adım Linux Driver Yazıyoruz -2- de bu uyku getirici teorik bilgilerden biraz daha uzaklaşıp daha fazla kod göreceğiz. Hatta ilk modülümüzü derleyeceğiz ve cihaza yükleyip çalıştıracağız. Böyle zevkli işler olacak pek yakında. Yazının devamında görüşmek üzere.

Faydalanacağını düşündüğünüz kişilere iletin, eksik ya da yanlış olduğunu düşündüğünüz yerleri belirtin.

Şimdi Yazmaya Devam ....

3 Mart 2015 Salı

Linux GPIO Kontrolü Uygulaması

    İlk olarak bloguma uğrayarak bu yazıyı okuyan herkese merhaba. Konumuz geçen yazımda belirttiğim üzere uygulama seviyesinde GPIO kontrolünü bir C uygulaması ile yapmak olacak. Gerekli malzemeler üzerinde çalıştığınız bir linux bord ve bu borda bulunan işlemciye ait compiler. (Eğer bu yazıyı okumaya devam edecekseniz zaten daha öncesinde cross compiler kurup çalışır hale getirmişsinizdir demektir) Kod geliştirme ortamını da unutmamak gerek, Eclipse vazgeçilmezler arasında.
   Gpio kontrol eden kodları yazmaya başlamadan önce eğer okumadıysanız bu yazımı okuyun derim. Çünkü yazacağımız kod bunların C ile run time (çalışma zamanı) yapılması. Kısaca kodumuzda yapacaklarımızı özetler isek;
  1. GPIO dosyasını açmak ve kapamak.
  2. GPIO rezerve eden fonksiyonu yazmak
  3. GPIO geri veren fonksiyonu yazmak
  4. GPIO giriş ya da çıkış olarak yönlendiren fonksiyonu yazmak
  5. GPIO değer yazan fonksiyonu yazmak
  6. GPIO o anki değerini okuyan fonksiyonu yazmak
    Yazacağımız kod topu topu bu kadar işlem yapacak. Birde bu fonksiyonları test etmek için main için de bunları çağırarak nasıl kullanılacağına bakacağız. Linux yeni başlayanlar için gayet kolay ve zevkli bir çalışma olacağını düşünüyorum. Zaten kodu başarılı bir şekilde derleyip bord yükledikten sonra ilgili GPIO bir led bağlayıp GPIO gerçekten de kontrol edilip edilmediğini görebilirsiniz. 

    İlk olarak başlık dosyasını(.h dosyası) oluşturalım. Hem bu sayede kaynak dosyasında (.c dosyası) ne yapacağımızın özetini görmüş oluruz. Başlık dosyası için driver.h

     Başlık dosyasını oluşturduktan sonra gelelim kaynak dosyasına. Kodları inceleyerek hatta baka baka tekrar kendiniz yazarak çalışmanızı tavsiye ederim. Zaten yazılım çalışmanın en iyi yolu kod yazmak kod yazmak kod yazmak tekrar yazmak yazmak yazmak. driver.c


drvGpio test uygulaması
#include <stdio.h>
#include <unistd.h>

#include "drvGpio.h"

int main(int argc, char *argv[])
{
 int retVal;

 retVal = drvGpioInit(11);
 if (SUCCESS == retVal)
 {
  retVal = drvGpioSetDirection(11, EN_GPIO_DIR_OUTPUT);

  if (SUCCESS == retVal)
  {
   drvGpioSetHigh(11);
   sleep(1);
   drvGpioSetLow(11);
   sleep(1);
   drvGpioSetHigh(11);
   sleep(1);
   drvGpioSetLow(11);
   sleep(1);
   drvGpioSetHigh(11);

   printf("---- %d \n", drvGpioGetValue(11));
   drvGpioUninit(11);
  }
 }

 return 0;
} 
drvGpio test uygulaması ile kodlar test edilmiştir. Umarım faydalı bir yazı olmuştur..
Herkese iyi çalışmalar

1 Mart 2015 Pazar

LINUX GPIO Kontrolü

Bilindiği üzere işlemcilerin dış çevre birimleri kontrol etmesi yada onlar ile haberleşmesi için GPIO (General Purpose Input/Output) kullanılır. GPIO giriş (input) ya da çıkış (output) olarak ayarlanabilir. Çıkış(output) olarak ayarladığımız GPIO üzerinden dışarıya 1(HIGH) ya da 0(LOW) verisini verir iken giriş(input) olarak ayarladığımız GPIO üzerinden dışarıdan 1(HIGH) ya da 0(LOW) verisini alırız. Genellikle GPIO gömülü Linux sistemlerinde kernel modülünde yönetilir fakat kullanıcı seviyesinden (user space) kontrolü de mümkündür. Yazılacak ufak bir kod ile boşta olan GPIO ele alıp istediğimiz gibi kullanabiliriz. Kullanıcı seviyesinden (user space) yazılacak kod yardımı ile belirlediğimiz GPIO aşağıdaki resimde bulunan örnek kullanımlar ile devremizde kullanabiliriz.

Örnek GPIO bağlantıları
Standart Linux kernel GPIO erişimine izin vermek için özel bir interface içerir. Kernel özelliklerinize(kernel menuconfig) bakarak bu özelliğin aktif olup olmadığını anlayabilirsiniz.
Eğer bu özellik sisteminizde kapalı ise  Device Drivers  > GPIO Support yapıp kernel yeniden derlemeniz gerekmektedir.
Yok hayır benim sistemimde bu özellik açık diyorsanız eğer sisteminizde aşağıdaki dizini görebilirsiniz.
/syst/class/gpio..
Kullanıcı seviysinde ele aldığımız GPIO lar hepsi bu dizinde bulunacaktır. 
$ls /sys/class/gpio/ komutu ile bu dizin altında dosyası açılmış (ele alınmış) GPIO görebilirsiniz.

Konsoldan GPIO Yönetimi
İlk olarak linux konsolunu kullanarak bir GPIO ele alma, yönlendirme, yazma ve okuma işlemlerini yapacağız. Bu yapacağımız işlemleri yazacağınız bir script ile de yapabilirsiniz. Zaten neyi ne amaçla yaptığımızı gördükten sonra nasıl kullanılacağı çok da sorun olmaz. İster bir script yazar hatta bu script sistem açılışında otomatik olarak da çağırarak sisteminizde açılışta yapmak istediğiniz işi yapmış olursunuz.

Komut satırından GPIO yönetmek için ilk olarak yapmamız gereken kullanacağımız GPIO ele almaktır.(Ben ele almak diyorum ama rezerve etmek de denilebilir.) GPIO ele almadan önce $ls /sys/class/gpio/ çıktısına bir bakalım. (Adım adım ilerleyip detayları kaçırmayalım). Benim sistemimde bu komut çağırdığımda aldığım çıktı şu şekilde:
export  gpiochip0@ unexport
export ve unexport bu konu için önemli dosyalarımız. Bu dosyalara kısaca bakalım. Bir GPIO ele almak için export dosyası kullanılır. Bu dosyaya yazacağımız GPIO numarası sonucunda sistem o GPIO bizim kullanımımıza ayırır. unexport ise bu işlemin tam tersini yaparak kullanım için ayırdığımız GPIO sisteme geri verir. Kısacası özgür bırakır. Bir örnek ile devam etmek için 11 nolu GPIO kullanım için ele alalım.(rezerve edelim)
  1. $cd /sys/class/gpio/              ilk olarak o dizine gidelim
  2. $echo 11 >> export              11 nolu GPIO ele alalım
Bu komutlardan sonra $ls /sys/class/gpio/ tekrar koştuğumuzda şu şekilde bir çıktı almamız gerekir.
export  gpio11@ gpiochip0@ unexport

Şimdi oluşturduğumuz yeni GPIO dizinine giderek GPIO özelliklerini yükleyelim.

$cd gpio11/ ile GPIO dizinine gittikten sonra bu dizinde $ls komutunu koşalım. Burada kullanacağımız dosyaları görürüz. 

ilk olarak GPIO kullanım yönünü belirtelim. Çıkış(output) ya da gişir(input) olarak GPIO yönlendirelim.

Çıkış olarak yönlendirmek için:
 echo "out" > /sys/class/gpio/gpio11/direction

Giriş olarak yönlendirmek için:
echo "in" > /sys/class/gpio/gpio11/direction

Var olan yönlendirmeyi okumak için
 cat /sys/class/gpio/gpio11/direction

Çıkış olarak yönlendirdiğimiz GPIO HIGH(1) ya da LOW(0) konumuna almak için value dosyası kullanılır. Bu dosyaya yazacağımız 1 yada 0 değerine göre ilgili GPIO çıkışı değişir.

GPIO HIGH(1):
echo 1 >>  /sys/class/gpio/gpio11/value 

GPIO LOW(0)
echo 0 >>  /sys/class/gpio/gpio11/value

Giriş olarak yönlendirdiğimiz GPIO dan veri okumak için:
cat /sys/class/gpio/gpio11/value

Ayrıca çıkış olarak yönlendirdiğimiz GPIO o anki çıkış durumunu öğrenmek için de bu komut kullanılabilir.

Yukarıda açıklanan komutlar ile bir GPIO konsol komutları ile istenildiği gibi kontrol edilebilir. Bu yazının sonuna gelmeden ufak bir bilgiyi daha aktarayım. Hem bizim hem de sistemin ele aldığı tüm GPIO görmek gerekebilir. Hem bu sayede ele almak istediğimiz bir GPIO daha önceden rezerve edilip edilmediğini görebiliriz. Bunun için ilk olarak kernel ayarlarımızın bunu destekliyor olması lazım.


 Kernel configuration > Kernel hacking > Debug FS

Kernel ayarlarına bakıp, eğer bu özellik açık değil ise açıp kernel yeniden derlemeniz gerekmektedir.Bu adımdan sonra diğer adımlara geçebilirsiniz. İlk yapmamız gereken debugfs mount etmemiz olacak. (mount işlemini hangi dizin altına yaptığınıza dikkat edin)
mount -t debugfs none /sys/kernel/debug

Kullanılan tüm GPIO özellikleri ile birlikte görmek için koşmamız gereken son komut:
cat /sys/kernel/debug/gpio


Peki buraya kadar her şey iyi hoş da ben bu işlemleri C ile yazdığım bir uygulama ile kendi projemde nasıl yaparım diyenler için bir sonraki yazımda bunu ele alacağım.

Herkese iyi çalışmalar

25 Şubat 2015 Çarşamba

printf("Hello My Blog");

#include <stdio.h>

int main(void)
{
    printf("Hello My Blog\n");
    return 0;
}

Bu şekilde blog dünyasına girmiş bulunuyorum. 

Genelde blogların ilk yayınlarında kişiler kendilerinden ya da bloglarının amaçlarından bahsediyor. Şu an mini bir kartvizit yazısı yazmayı düşünmüyorum. Kısaca blogumda, yaptığım çalışmaların ya da edindiğim bilgilerin uçmaması adına kod ve bilgi paylaşımında bulunmayı düşünüyorum. Söz uçar yazı kalır nede olsa.
Burada paylaştığım kodlar eğer birilerinin işine yarar ya da yol gösterirse istenildiği gibi kullanılabilir. Zaten kullanıma kapalı olacaksa neden paylaşılsın ki :) 
Paylaştığım kodlar denenmiş olsa da eğer bir yanlış veya eksiklik görürseniz lütfen bildirin. 

ilk yazımı içine saygı da katarak şu resimle sonlandırıyorum.

Goodbye World