Bagaimana cara menangani I / O yang dipetakan pada memori?
Saya mencoba memahami sampel yang disediakan I2S: Adakah yang menjalankannya? .
Mengkonfigurasi Jam:
#define BCM2708_PERI_BASE 0x20000000
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
Pertama-tama memetakan kode seperti ...
clk_map = (unsigned char *)mmap(
(caddr_t)clk_mem,
MAP_BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
CLOCK_BASE
);
Maka ia melakukan sesuatu ...
// Always use volatile pointer!
clk = (volatile unsigned *)clk_map;
Dan ketika direferensikan ada tambahan aneh 0x26 & 0x27, tentang apa itu?
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;
Melihat lembar data, saya bisa melihat dari mana mereka mendapatkan beberapa nilai ini, seperti alamat dasar, tapi saya berjuang untuk memahami yang lain. Di mana itu CLOCK_BASE
ditentukan dan apa yang terjadi?
Jawaban:
Di komputer Anda menulis ke 'alamat memori' yang ditentukan. Alamat ini diakui oleh sistem sebagai alamat perangkat keras, dan perangkat keras yang sesuai menerima atau mengirim nilai yang sesuai.
Sebagian besar sistem perangkat keras memiliki banyak register berbeda yang dapat diatur atau dibaca. Beberapa mungkin memiliki beberapa, beberapa mungkin memiliki banyak. Register ini akan dikelompokkan ke dalam rentang berkelanjutan. Pointer basis menunjuk ke yang pertama dalam rentang, dan Anda menulis ke, misalnya, port kedua dengan base_pointer +1. Anda tidak harus, Anda bisa menulis langsung ke sebuah pointer, tetapi menggunakan offset membuat segalanya lebih mudah untuk dikerjakan.
Raspberry Pi mengenali sejumlah besar register perangkat keras di alamat 0x20000000. Berbagai register yang mengontrol sistem jam diakses dari BCM2708_PERI_BASE + 0x101000. Register yang mengontrol jam I2S adalah register 38 dan 39 di blok itu, ditulis untuk menggunakan BCM2708_PERI_BASE + 0x101000 + 0x26 dan 0x27
Anda tidak bisa hanya mengubah nilai jam, Anda harus menonaktifkan jam, mengubah nilai, dan memulai kembali.
Jika jawaban ini terlalu mendasar, saya minta maaf. Dalam hal ini pertanyaan Anda benar-benar hardcore, semoga berhasil. Anda mungkin menemukan tautan ini bermanfaat
Pembaruan: Mengapa menggunakan mmap dan tidak menulis langsung ke memori?
Ketika sebuah program menjalankan alamat memori yang dianggapnya bukan alamat asli, mereka dipetakan ke alamat asli oleh manajer memori. Ini menghentikan satu program untuk dapat mempengaruhi yang lain. Dua proses dapat membaca dan menulis ke alamat mereka sendiri dengan sangat gembira, dan manajer memori akan memisahkan kedua lokasi.
Port perangkat keras, bagaimanapun, berada pada alamat fisik absolut. Tetapi Anda tidak dapat menulis kepada mereka secara langsung karena manajer memori akan mengambil alamat Anda dan memetakannya ke area memori pribadi Anda.
Di Linux / dev / mem adalah ' file perangkat karakter yang merupakan gambar dari memori utama komputer '
Jika Anda membuka ini seperti file maka Anda dapat membaca dan menulis seperti file. Dalam sampel yang disediakan, mem_fd adalah file handle yang dihasilkan dari opening / dev / mem
Sistem lain yang dapat membuat hidup lebih mudah adalah kemampuan untuk memetakan file ke memori dan menulis seperti memori. Jadi jika Anda memiliki file di mana Anda ingin membaca atau menulis bit spesifik yang berbeda daripada memindahkan pointer file ke belakang dan ke depan, Anda dapat memetakannya ke lokasi di memori, dan kemudian menulis ke sana secara langsung seolah-olah itu adalah memori.
Jadi dalam sampel ini kode membuat pegangan ke memori fisik, seolah-olah itu file pada disk, dan kemudian meminta sistem untuk memperlakukannya seolah-olah itu adalah memori. Agak berbelit-belit, tetapi perlu untuk berkeliling manajer memori virtual dan menulis ke alamat fisik yang sebenarnya. Nilai 0x20000000, tampaknya, agak merah. Kode ini mengusulkan alamat ini sebagai petunjuk, sistem tidak harus memetakan / dev / mem di sini, meskipun mungkin. Biasanya nilai nol akan diteruskan, dan sistem akan memetakan pegangan file ke alamat apa pun yang dianggapnya terbaik.
Sekarang memori fisik dipetakan ke proses memori virtual, dan membaca dan menulis pergi ke tempat yang Anda harapkan.
Referensi:
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
sumber
@AlexChamberlain ini karena struktur OS. Anda dapat pergi tanpa
mmap
tetapi halaman dinyatakan, karenanya tidak ada akses langsung. Dalam mode kernel Anda dapat pergi tanpammap
, dengan, misalnya memasukkan driver Anda sebagai modul kernel tanpa perlummap
. Juga, dalam kasus OS paling sederhana, di mana tidak ada memori tabel halaman digunakan, Anda dapat mengakses tanpammap
salah satunya, yaitu akses alamat fisik langsung.sumber