Введение #
Современные одноплатные компьютеры, такие как Repka Pi, позволяют управлять периферийными устройствами напрямую, минуя библиотеки и абстракции. Это возможно благодаря технике под названием MMIO (Memory-Mapped I/O) — отображение регистров оборудования в адресное пространство памяти процессора.
Рассмотрим, как это работает, как получить доступ к таким регистрам на Linux и как с их помощью напрямую управлять GPIO.
Что такое MMIO #
MMIO (Memory-Mapped I/O) — это механизм, при котором специальные области памяти не содержат обычные данные, а представляют собой аппаратные регистры. Эти регистры отвечают за управление различными функциями чипа: GPIO, таймерами, SPI, UART и т. д.
Когда процессор обращается к определённому адресу памяти — например, 0x01C20800
— он фактически читает или пишет значение в регистр периферийного устройства. Благодаря этому, управление внешними модулями становится возможным без драйверов или библиотек — напрямую на уровне байтов и битов.
Такой способ:
-
Очень быстрый и низкоуровневый,
-
Не зависит от библиотек,
-
Требует точного знания адресов и битовой разметки регистров (из datasheet).
Использование /dev/mem
и mmap()
В Linux физическая память (включая MMIO-области) недоступна обычным процессам. Однако системное устройство /dev/mem
предоставляет доступ к физическому адресному пространству.
Чтобы с ним работать:
-
Открываем
/dev/mem
с правами суперпользователя. -
С помощью функции
mmap()
отображаем нужный диапазон физических адресов в виртуальное адресное пространство нашего процесса. -
Работаем с полученным указателем как с обычным массивом памяти.
Ниже представлен пример кода на языке программирования C:
int fd = open("/dev/mem", O_RDWR | O_SYNC);
void *map = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, phys_addr);
volatile uint32_t *reg = (uint32_t *)map;
reg[offset] = 1; // записываем значение в регистр