Как работает адресация ввода-вывода с отображением в памяти?
Я пытаюсь понять пример поставки 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
определяется и что происходит?
Ответы:
На компьютере вы пишете на указанный «адрес памяти». Этот адрес распознается системой как аппаратный адрес, и соответствующее оборудование получает или отправляет соответствующее значение.
Большинство аппаратных систем имеют много разных регистров, которые можно установить или прочитать. У некоторых может быть несколько, у некоторых может быть много. Эти регистры будут сгруппированы в непрерывном диапазоне. Базовый указатель указывает на первый в диапазоне, и вы пишете, например, на второй порт с 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 это связано со структурой ОС. Вы можете обойтись без,
mmap
но объявление объявлено, следовательно, нет прямого доступа. В режиме ядра вы можете обойтись безmmap
, например, вставив драйвер как модуль ядра без необходимостиmmap
. Кроме того, в простейшем случае ОС, где не используется память таблицы страниц, вы можете получить доступ безmmap
нее, т. Е. прямой физический адрес доступа.источник