Як працює адресація, нанесена на пам'ять, вводу / виводу?


29

Як працює адресація, нанесена на пам'ять, вводу / виводу?

Я намагаюся зрозуміти зразок I2S, який постачається : хтось його запустив? .

Налаштування годинника:

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

Він спочатку відображає код так ...

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

Потім щось робить ...

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

А коли на нього посилаються, ці дивні доповнення 0x26 та 0x27, про що це?

 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;

Дивлячись на таблицю даних, я бачу, де вони мають деякі з цих значень, як-от базову адресу, але я намагаюся зрозуміти інші. Де це CLOCK_BASEвизначено і що відбувається?


1
Це, мабуть, найкраще підходить для StackOverflow. Хоча це стосується RPi, ви будете частіше отримувати відповіді на питання програмування там.
Відхилення

4
Можливо, але я вважаю, що це більш загальне питання, пов'язане з програмуванням Pi, що поєднує інтерпретацію аркуша даних та апаратного забезпечення Pi. давайте подивіться, чи отримує вона хорошу інформацію.
Вушні собаки

Гаразд. Подивимось, як це йде :)
Jivings

1
Я не думаю, що це буде занадто добре для Stack Overflow - це досить фахівець і, швидше за все, тут привернеться більше уваги фахівців.
Flexo

Відповіді:


18

На комп'ютері ви пишете на вказану "адресу пам'яті". Ця адреса розпізнається системою як апаратна адреса, і відповідне обладнання отримує або надсилає відповідне значення.

Більшість апаратних систем мають багато різних регістрів, які можна встановити або прочитати. Деякі можуть мати декілька, а деякі - багато. Ці регістри будуть згруповані в безперервний діапазон. Базовий вказівник вказує на перший у діапазоні, і ви записуєте, наприклад, на другий порт з base_pointer + 1. Не потрібно, ви можете записати прямо вказівник, але використання зміщення полегшує роботу.

Raspberry Pi розпізнає широкий спектр апаратних регістрів за адресою 0x20000000. До діапазону регістрів, які керують тактовими системами, доступ до BCM2708_PERI_BASE + 0x101000. Регістри, які керують тактовою частотою I2S, - це 38-й і 39-й регістри в цьому блоці, записані на використання BCM2708_PERI_BASE + 0x101000 + 0x26 та 0x27

Однак ви не можете просто змінити значення тактових значень, ви повинні відключити годинник, змінити значення та перезапустити його.

Якщо ця відповідь занадто елементарна, мої вибачення. У такому випадку ваше запитання справді жорстке, удачі. Це посилання може бути корисним

Оновлення: навіщо використовувати mmap, а не записувати безпосередньо в пам'ять?

Коли програма працює з адресами пам’яті, за якими вона вважає, що це не справжні адреси, вони керуються пам'яттю на реальні адреси. Це зупиняє можливість однієї програми впливати на іншу. Два процеси можуть читати та записувати на власну адресу 1234 цілком щасливо, а менеджер пам’яті збереже ці два місця повністю розділеними.

Однак порти апаратних засобів знаходяться за абсолютними фізичними адресами. Але ви не можете писати їм безпосередньо, тому що менеджер пам'яті візьме вашу адресу та відобразить її у вашій особистій області пам’яті.

У Linux / dev / mem - це файл пристрою символів, який є зображенням основної пам'яті комп'ютера .

Якщо ви відкриєте це як файл, тоді ви можете читати і записувати до нього, як файл. У наданому зразку mem_fd - це файлова ручка, що виникла внаслідок відкриття / dev / mem

Ще одна система, яка може значно полегшити життя - це можливість відображення файлу в пам'ять і записування в нього, як пам'ять. Отже, якщо у вас є файл, у якому ви хочете читати чи записувати різні конкретні біти, то замість того, щоб переміщувати покажчик файлу назад і вперед, ви можете зіставити його на місце в пам'яті, а потім записати в нього безпосередньо так, ніби це пам'ять.

Отже, у цьому прикладі код створює ручку фізичної пам'яті, як би це файл на диску, а потім просить систему обробляти його так, ніби це пам'ять. Трохи розгублений, але необхідний для того, щоб обійти віртуальний менеджер пам’яті та записати на фактичну фізичну адресу. Значення 0x20000000, здається, трохи червона оселедець. Код пропонує цю адресу як підказку, системі тут не потрібно карта / dev / mem, хоча, мабуть, так і є. Зазвичай значення null було б передано, і система відобразить обробку файлу на ту адресу, яку він вважав найкращим.

Тепер фізична пам'ять відображається у віртуальній пам'яті процесів, і читає і записує туди, куди ви очікуєте.

Список літератури:

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


У мене ще є кілька запитань: Чому вони роблять карту? Чому б просто не отримати доступ до пам'яті безпосередньо?
Алекс Чемберлен

@AlexChamberlain Оскільки код працює на Linux, ви не можете отримати доступ до пам'яті безпосередньо, оскільки кожен процес отримує власний простір віртуальної пам'яті. Однак можна відкрити і mmap / dev / mem, щоб отримати прямий доступ до фізичної пам'яті
нос

1

@AlexChamberlain це пов'язано зі структурою ОС. Ви можете пройти без, mmapале підказка оголошена, тому немає прямого доступу. У режимі ядра ви можете перейти mmap, наприклад, вставивши свій драйвер як модуль ядра без необхідності mmap. Крім того, у найпростішому випадку ОС, де не використовується жодна пам'ять таблиці сторінок, ви можете отримати доступ без mmapжодного, тобто. прямий доступ до фізичної адреси.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.