Gömülü Linux
  • Giriş
  • Linux Çekirdeği
    • Gömülü Sistemlerdeki Kullanımı
    • Geliştirme Süreci ve Versiyonlar
    • Kod Sözdizim Rehberi
    • Konfigürasyon Süreci ve Kbuild Sistemi
    • Derleme ve Çapraz Derleme
    • Initramfs İmajının Eklenmesi
    • U-boot İmajı Haline Getirilmesi
  • Gömülü Sistemlerde Boot Yükleyiciler
    • U-boot
    • RedBoot
    • ARM Mimarisinde Açılış Süreci
  • Linux Açılış Süreci
    • Kernel Açılış Süreci
    • Kullanıcı Kipine Geçiş - Init Süreci
  • Kök Dosya Sistemi Oluşturma
  • Initramfs İle Erken Kullanıcı Kipi
  • Devtmpfs Dosya Sistemi
  • NfsRoot Çalışma Yöntemi
  • Çapraz Derleme ve Gerekli Ekipmanlar
  • NOR, NAND, eMMC ve Flash Tabanlı Depolama
  • Memory Technology Device - MTD Katmanı
  • Unsorted Block Images - UBI Katmanı
  • Gömülü Sistemlerde Kullanılan Dosya Sistemleri
    • JFFS2 Dosya Sistemi
    • YAFFS2 Dosya Sistemi
    • UBIFS Dosya Sistemi
    • Cramfs Dosya Sistemi
    • Squashfs Dosya Sistemi
    • Minix Dosya Sistemi
    • FAT Dosya Sistemi
    • Ext2,3,4 Dosya Sistemi
  • Watchdog Kullanımı
  • CPU Frequency Scaling
  • Buildroot
  • Android Platformu
    • Geliştirme Ortamının Hazırlanması
    • İnşa Süreci
  • Sistem Çağrıları
  • I2C Protokolü
    • I2C Protokolünün Tanıtılması
    • Linux Altında I2C İşlemleri
    • Board Seçimi ve İlk İşlemler
    • Sıcaklık Sensörünün Seçilmesi
    • Sıcaklık Değerinin Yazılımsal Olarak Elde Edilmesi
  • Strace Kullanımı
  • GNU Build Sistemi Araçları
    • Make
    • Autoconf, Automake
  • Orange Pi Zero
    • Orange Pi Zero Teknik Özellikleri
    • Gerekli Araçların Elde Edilmesi
    • U-boot Derleme Süreci
    • Kernel Derleme Süreci
    • Wifi Desteği - Problemli Senaryo Örneği
    • Dosya Sisteminin Hazırlanması
    • SD Kartın Hazırlanması
    • Cihazın Açılması
  • Raspberry Pi
    • Raspberry Pi 2 Teknik Özellikleri
    • Açılış Süreci
    • Gerekli Araçların Elde Edilmesi
    • Kernel Derleme Süreci
    • U-boot Derleme Süreci
    • Dosya Sisteminin Hazırlanması
    • Cihazın Açılması
    • NFS Root Çalışma
    • Sistem Konfigürasyonu
    • Raspberry Pi 3
  • Board Spesifik Kılavuzlar
    • Hawkboard
    • Olimex A20
    • TI DM6446 EVM
    • BeagleBoard
    • BeagleBoneBlack
    • Savage Board
  • EKLER
    • Seri Konsol Kullanımı
    • TFTP Sunucu Kurulumu
    • NFS Sunucu Kurulumu
    • TI işlemcilerinde DSP kullanımı
      • C6Run
      • DSP Testi
    • Ubuntu Sanal Makine Performansı
Powered by GitBook
On this page
  • Yazma ve Okuma İşlemlerinde read, write Sistem Çağrılarının Kullanılması
  • Yazma ve Okuma İşlemlerinde ioctl Çağrılarının Kullanılması
  • Yazma ve Okuma İşlemlerinde i2c-dev.h Fonksiyonlarının Kullanılması

Was this helpful?

  1. I2C Protokolü

Sıcaklık Değerinin Yazılımsal Olarak Elde Edilmesi

Bu bölümde, daha önce Linux Altında I2C İşlemleri konusunda bahsettiğimiz yöntemlere ilişkin birer örnek vereceğiz.

Örnek kodları derlerken, i2c-tools içinden çıkan i2c-dev.h başlık dosyasına ihtiyacımız olacak, bu sebeple derleme işleminde bu başlık dosyasının bulunduğu dizini de derleyiciye göstermeliyiz.

Her 3 örnekte de MCP9808 adresi, sıcaklık değerini okuyacağımız yazmaç adresi ve sıcaklık çözünürlük değeri aşağıdaki sembolik sabitlerle gösterilmiştir.

#define MCP9808_ADDR    0x18    // MCP9808 I2C adresi
#define TEMP_REG_ADDR   0x05    // Ortam sıcaklık yazmaç adresi
#define RESOLUTION      0.0625  // Sıcaklık çözünürlüğü

3 örneğimizde yalnızca sıcaklık değerinin okunma kısımları farklıdır. Sıcaklık yazmacındaki değer elde edildikten sonraki yorumlama kısmı ise değişmemektedir. Daha önce i2cget ile elde ettiğimiz değeri inceleyerek sıcaklık değerine ulaşmıştık. Benzer işlemi burada C kodu ile yapacağız.

Her 3 uygulamada da temelde yapılan işlemler, MCP9808 ile iletişim kurmak, sonrasında sıcaklık yazmacının adresini göndermek ve periyodik olarak sıcaklık yazmacının değerini okuyarak yorumlamak şeklindedir.

İlk olarak sıcaklık yazmaç değerinin t isimli int bir değişkene çektiğimizi varsayalım. Bu aşamadan sonraki işlemler aşağıdaki gibi olacaktır.

int t = SICAKLIK_YAZMAÇ_DEĞERİ;
double temp;
temp = t & 0x0FFF;
temp *= RESOLUTION;
if (t & 0x1000) {
    temp -= 256;
}
printf("Sıcaklık: %.2f C\n", temp);

Bu kod üzerinden tekrar eski bilgilerimizi tekrarlayalım. Sıcaklık yazmacındaki yüksek anlamlı 4 bit'in sıcaklığın mutlak değeriyle alakalı olmadığını hatırlayın. 15., 14. ve 13. bitler alert bitleri, 12. bit ise işaret bitidir. Bu sebeple başlangıçta bu bitleri göz ardı edebiliriz. Aşağıdaki kod bu duruma ilişkindir.

temp = t & 0x0FFF;

Bu değer daha sonra sıcaklık ölçüm çözünürlüğüyle çarpılarak, mutlak sıcaklık değerine erişilir.

temp *= RESOLUTION;

Bu aşamadan sonra sıcaklığın polaritesi için işaret bitine (12. bit) bakılmalıdır. 0x1000 ile bitsel and işlemi sonucu 1 çıkıyorsa sayı negatif demektir. Sıcaklığın sayının ikiye tümleyeni şeklinde tutulduğunu daha önce söylemiştik. Bu sebeple bu durumda sayıdan 256 değeri çıkarılmaktadır.

256 sayısının nereden geldiğini daha iyi anlamak için aşağıdaki nota bakabilirsiniz.

Not: Bir sayının 2'ye tümleyeni alınırken, ilk önce 1'e tümleyenin alındığını daha sonra elde edilen sonucun 1 ile toplandığını hatırlayınız. 1'e tümleme işlemi için sayının 1 olan bitleri 0, 0 olanlar ise 1 yapılmalıdır.

Bir byte sınırlarındaki bir sayı için konuşacak olursak. Sayının bitlerinin ters çevrilmesi neticesinde elde edilen sayı, sayının kendisinin 255 sayısı ile arasındaki farkı vermektedir. Çünkü sayının kendisiyle bitlerinin ters çevrilmiş halinin toplamı 255 sayısını verecektir.

Sonrasındaki 1 ile toplama işlemi ise sayının 255 ile arasındaki farktan 1 fazlasının elde edilmesine neden olacaktır. Aynı işlem sayının 256 sayısı ile arasındaki fark ile de elde edilebilir.

if (t & 0x1000) {
    temp -= 256;
}

Bu aşamadan sonra temp değişkeni Celsius derece cinsinden sıcaklık değerini göstermektedir.

Örnek kodları sırasıyla i2c_1.c, i2c_2.c ve i2c_3.c adlarıyla saklayıp, çapraz derleyicinize i2c-dev.h dosyasının yerini göstererek derleyebilirsiniz. Bizim sistemimiz için geçerli derleme aşağıdaki gibidir.

$ arm-none-linux-gnueabi-gcc -o i2c_1 i2c_1.c -I i2c-tools-3.1.2/include

Her 3 örnekte de sıcaklık 1 saniye aralıklarla okunarak konsola basılmaktadır.

Yazma ve Okuma İşlemlerinde read, write Sistem Çağrılarının Kullanılması

Örnek kodda, I2C üzerinden okuma işlemleri read/write sistem çağrılarıyla yapılmaktadır.

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define MCP9808_ADDR    0x18    // MCP9808 I2C adresi
#define TEMP_REG_ADDR   0x05    // Ortam sıcaklık yazmaç adresi
#define RESOLUTION      0.0625  // Sıcaklık çözünürlüğü

void main()
{
    int i2c_fd;
    char *bus = "/dev/i2c-2";
    long funcs;
    int rc;

    if ((i2c_fd = open(bus, O_RDWR)) < 0)
    {
        printf("Failed to open the bus. \n");
        exit(1);
    }

    // İletişim kurulacak aygıtın adreslenmesi
    ioctl(i2c_fd, I2C_SLAVE, MCP9808_ADDR);

    // İçeriği okunacak yazmacın adreslenmesi
    char reg[1] = {TEMP_REG_ADDR};
    write(i2c_fd, reg, 1);
    char data[2] = {0};

    do {
        // Sıcaklık yazmaç değerinin okunması
        if(read(i2c_fd, data, 2) != 2) {
            printf("read error \n");
        }
        else {
            double temp;
            int t = (data[0] << 8) + data[1];
            temp = t & 0x0FFF;
            temp *= RESOLUTION;
            if (t & 0x1000) {
                temp -= 256;
            }
            printf("Sıcaklık: %.2f C\n", temp);
        }
        sleep(1);
    } while(1);
}

Yazma ve Okuma İşlemlerinde ioctl Çağrılarının Kullanılması

Örnek kodda, I2C üzerinden okuma işlemleri ioctl çağrısı ile yapılmıştır. Bu yöntemde okuma ve yazma işlemleri, hattın kullanımını bırakmaksızın, combined bir şekilde yapılabilmektedir.

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define MCP9808_ADDR    0x18
#define TEMP_REG_ADDR   0x05
#define RESOLUTION      0.0625

int i2c_fd;

int i2c_read16(int addr, int reg) {
    struct i2c_rdwr_ioctl_data msgset;
    struct i2c_msg iomsgs[2];
    char buf[1], rbuf[2];
    int rc;

    buf[0] = (char) reg;

    iomsgs[0].addr = iomsgs[1].addr = (unsigned) addr;
    iomsgs[0].flags = 0;        /* Yazma */
    iomsgs[0].buf = buf;
    iomsgs[0].len = 1;

    iomsgs[1].flags = I2C_M_RD; /* Okuma */
    iomsgs[1].buf = rbuf;
    iomsgs[1].len = 2;

    msgset.msgs = iomsgs;
    msgset.nmsgs = 2;

    if ( (rc = ioctl(i2c_fd, I2C_RDWR, &msgset)) < 0 )
        return -1;
    return (rbuf[0] << 8) | rbuf[1];
}

void main()
{
    char *bus = "/dev/i2c-2";
    double temp;
    int t;
    if ((i2c_fd = open(bus, O_RDWR)) < 0)
    {
        printf("Failed to open the bus. \n");
        exit(1);
    }
    do {
        t = i2c_read16(MCP9808_ADDR, TEMP_REG_ADDR);
        if (t < 0) {
            printf("read error \n");
             continue;
        }
        temp = t & 0x0FFF;
        temp *= RESOLUTION;
        if (t & 0x1000) {
            temp -= 256;
        }
        printf("Sıcaklık: %.2f C\n", temp);
        sleep(1);
    } while (1);
}

Yazma ve Okuma İşlemlerinde i2c-dev.h Fonksiyonlarının Kullanılması

Bu yöntemde, i2c-tools fonksiyonlarını kullandık. Gerekli fonksiyonlar i2c-dev.h başlık dosyasında inline olarak tanımlıdır.

Örnekteki bir noktaya dikkatinizi çekmek istiyoruz. i2c_smbus_read_word_data ile okunan değerin yüksek ve düşük anlamlı byte'ları swap edilmiştir.

rt = i2c_smbus_read_word_data(i2c_fd, TEMP_REG_ADDR);
t = rt << 8 | rt >> 8;

Daha önce benzer işlemi i2cget ile elde ettiğimiz değer için de yaptığımızı hatırlayınız. i2c_smbus_read_word_data, ilk okuduğu değeri düşük anlamlı olarak ifade etmektedir. Fakat MCP9808 üzerinden ilk olarak yüksek anlamlı byte gönderilmektedir. Bu sebeple, sıcaklık değeri yorunlanmadan önce, bir swap işlemi yapılmaktadır.

#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>

#define MCP9808_ADDR    0x18
#define TEMP_REG_ADDR   0x05
#define RESOLUTION      0.0625

void main()
{
    int i2c_fd;
    char *bus = "/dev/i2c-2";
    double temp;
    int t;
    int rt;

    if ((i2c_fd = open(bus, O_RDWR)) < 0)
    {
        printf("Failed to open the bus. \n");
        exit(1);
    }

    ioctl(i2c_fd, I2C_SLAVE, MCP9808_ADDR);

    do {
        rt = i2c_smbus_read_word_data(i2c_fd, TEMP_REG_ADDR);
        t = rt << 8 | rt >> 8;
        temp = t & 0x0FFF;
        temp *= RESOLUTION;
        if (t & 0x1000){
            temp -= 256;
        }
        printf("Sıcaklık: %.2f C\n", temp);
        sleep(1);
    } while(1);
}
PreviousSıcaklık Sensörünün SeçilmesiNextStrace Kullanımı

Last updated 5 years ago

Was this helpful?