Как работает адресация ввода-вывода с отображением в памяти?

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, вы с большей вероятностью получите ответы на вопросы по программированию.
Jivings
4
Может быть, но я чувствую, что это более общий вопрос, связанный с программированием на Пи, сочетающий интерпретацию таблицы данных и аппаратного обеспечения Пи. давайте посмотрим, получит ли он хорошую информацию.
Уши собаки
Хорошо. Давайте посмотрим, как это будет :)
Jivings
1
Я не думаю, что это будет слишком хорошо для переполнения стека - это довольно специалист и, скорее всего, здесь будет больше внимания экспертов.
Флекс

Ответы:

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

Дэвид Сайкс
источник
У меня все еще есть пара вопросов: почему они mmap? Почему бы просто не получить доступ к памяти напрямую?
Алекс Чемберлен
@AlexChamberlain Поскольку код работает в linux, вы не можете напрямую обращаться к памяти, поскольку каждый процесс получает свое собственное пространство виртуальной памяти. Однако можно открыть и mmap / dev / mem, чтобы получить прямой доступ к физической памяти
nos
1

@AlexChamberlain это связано со структурой ОС. Вы можете обойтись без, mmapно объявление объявлено, следовательно, нет прямого доступа. В режиме ядра вы можете обойтись без mmap, например, вставив драйвер как модуль ядра без необходимости mmap. Кроме того, в простейшем случае ОС, где не используется память таблицы страниц, вы можете получить доступ без mmapнее, т. Е. прямой физический адрес доступа.

Манодж Сингх
источник