Bellek eşlemeli G / Ç adreslemesi nasıl çalışır?


29

Bellek eşlemeli G / Ç adreslemesi nasıl çalışır?

Sağlanan bir örneği anlamaya çalışıyorum I2S: Biri onu çalıştırdı mı? .

Saatleri Yapılandırma:

#define BCM2708_PERI_BASE        0x20000000
#define CLOCK_BASE               (BCM2708_PERI_BASE + 0x101000) /* Clocks */

İlk önce kodu şöyle eşler ...

clk_map = (unsigned char *)mmap(
      (caddr_t)clk_mem,
      MAP_BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      CLOCK_BASE
   );

O zaman bir şey yapar ...

 // Always use volatile pointer!
   clk = (volatile unsigned *)clk_map;

Referans verildiğinde, 0x26 ve 0x27 garip eklentileri var, bunun nesi var?

 printf("Disabling I2S clock\n");
 *(clk+0x26) = 0x5A000000;
 *(clk+0x27) = 0x5A000000;

 usleep(10);

 printf("Confiure I2S clock\n");
 *(clk+0x26) = 0x5A000001;
 *(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001

 usleep(10);
 printf("Enabling I2S clock\n");
 *(clk+0x26) = 0x5A000011;

Veri sayfasına bakarak, temel adres gibi bu değerlerin bazılarını nereden aldıklarını görebilirim, ancak diğerlerini anlamak için mücadele ediyorum. Bu nerede CLOCK_BASEbelirlenir ve neler oluyor?


1
Bu muhtemelen StackOverflow için en uygun yöntemdir. RPI ile ilgili olmasına rağmen, orada programlama sorularına cevap alma ihtimaliniz daha yüksek olacak.
Jivings,

4
Belki, ama veri sayfasının ve Pi donanımının yorumunu birleştiren Pi programlama ile ilgili daha genel bir soru olduğunu düşünüyorum. biraz iyi bilgi alırsa bakalım.
Köpek Kulakları

Tamam. Nasıl gittiğini görelim :)
Jivings

1
Stack Overflow'ta bunun çok iyi olacağını düşünmüyorum - oldukça uzman ve burada daha fazla uzman ilgisi olabilir.
Flexo

Yanıtlar:


18

Bir bilgisayarda belirtilen 'hafıza adresine' yazıyorsunuz. Bu adres sistem tarafından bir donanım adresi olarak tanınır ve uygun donanım uygun değeri alır veya gönderir.

Çoğu donanım sisteminde ayarlanabilen veya okunabilen birçok farklı kayıt vardır. Bazılarında birkaç, bazılarında birçok olabilir. Bu kayıtlar sürekli bir aralıkta gruplandırılacaktır. Bir temel işaretçi aralıktaki birinciyi gösterir ve örneğin base_pointer + 1 ile ikinci bağlantı noktasına yazarsın. Zorunda değilsiniz, doğrudan işaretçiye yazabilirsiniz, ancak ofset kullanmak işlerin daha kolay yapılmasını sağlar.

Ahududu Pi, 0x20000000 adresinde çok çeşitli donanım kayıtlarını tanımaktadır. Saat sistemlerini kontrol eden çeşitli kayıtlara BCM2708_PERI_BASE + 0x101000 adresinden erişilebilir. I2S saatini kontrol eden kayıtlar BCM2708_PERI_BASE + 0x101000 + 0x26 ve 0x27 kullanılarak yazılmış olan bu bloktaki 38 ve 39. kayıtlardır.

Ancak saat değerlerini değiştiremezsiniz, saati devre dışı bırakmanız, değerleri değiştirmeniz ve yeniden başlatmanız gerekir.

Bu cevap çok basitse, özür dilerim. Bu durumda sorunuz gerçekten sert, iyi şanslar. Bu bağlantıyı yararlı bulabilirsiniz

Güncelleme: Neden mmap kullanıyor ve doğrudan belleğe yazmıyorsunuz?

Bir program hafıza adreslerini çalıştırırken, gerçek adres olmadığını düşünüyor, hafıza yöneticisi tarafından gerçek adreslerle eşleştiriliyor. Bu, bir programın diğerini etkilemesini önler. İki işlem kendi başlarına (1234) mükemmel bir şekilde okuyabilir ve yazabilir ve bellek yöneticisi iki yeri tamamen ayrı tutacaktır.

Ancak donanım portları mutlak fiziksel adreslerdedir. Ancak doğrudan onlara yazamazsınız, çünkü hafıza yöneticisi adresinizi alacak ve kişisel hafıza alanınızla eşleyecektir.

Linux'ta / dev / mem ' bilgisayarın ana belleğinin bir görüntüsü olan bir karakter cihazı dosyasıdır '

Bunu bir dosya gibi açarsanız, o zaman bir dosya gibi okuyabilir ve yazabilirsiniz. Verilen örnekte mem_fd, / dev / mem açılışından kaynaklanan bir dosya tanıtıcısıdır.

Hayatı daha kolaylaştırabilen diğer bir sistem, bir dosyayı hafızaya eşleme ve ona hafıza gibi yazma yeteneğidir. Bu nedenle, farklı belirli bitleri okumak veya yazmak istediğiniz bir dosyanız varsa, dosya işaretçisini ileri ve geri hareket ettirmek yerine, bellekteki bir konuma eşleyebilir ve ardından doğrudan hafızadaymış gibi yazabilirsiniz.

Bu nedenle, bu örnekte kod, fiziksel bellekte bir disk oluşturuyormuş gibi bir tutamaç oluşturuyor ve sistemden onu bellekteki gibi işlemesini istiyor. Biraz sarsılmış, ancak sanal bellek yöneticisini dolaşmak ve gerçek bir fiziksel adrese yazmak için gerekli. Görünüşe göre, 0x20000000 değeri biraz kırmızı ringa balığı. Kod, bu adresi bir ipucu olarak öneriyor, sistemin burada / dev / mem ile eşleşmesine gerek yok, muhtemelen. Normalde null değeri iletilir ve sistem dosya tanıtıcısını en iyi düşündüğü adresle eşleştirir.

Şimdi fiziksel bellek, süreçlerin sanal belleğiyle eşleştirilir ve okuduğunuz ve yazdığınız yere gittiğinizi yazar.

Referanslar:

http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html

http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359

https://superuser.com/questions/71389/what-is-dev-mem


Hala birkaç sorum var: Neden eşleşiyorlar? Neden sadece doğrudan belleğe erişmiyorsunuz?
Alex Chamberlain

@AlexChamberlain Kod linux üzerinde çalıştığından, her işlem kendi sanal bellek alanını aldığından doğrudan belleğe erişemezsiniz. Bununla birlikte, bir kişi fiziksel belleğe doğrudan erişmek için açabilir ve mmap / dev / mem
nos

1

@AlexChamberlain bu işletim sistemi yapısından kaynaklanmaktadır. Onsuz gidebilirsiniz, mmapancak çağrı bildirilir, bu nedenle doğrudan erişim yok. Çekirdek modunda mmap, örneğin sürücünüzü gerek kalmadan çekirdeği modülü olarak yerleştirmeksizin gidebilirsiniz mmap. Ayrıca, en basit işletim sistemi durumunda, sayfa tablosu belleğinin kullanılmadığı durumlarda, mmapikisine de erişebilirsiniz . doğrudan fiziksel adres erişimi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.