15. 5.14. MMIO (Memory-Mapped I/O) Device Access
15.1. Введение
MMIO (Memory-Mapped I/O) — это механизм доступа к аппаратным устройствам через адресное пространство памяти. Он позволяет обращаться к регистрам периферийных устройств (GPIO, UART, SPI и др.) точно так же, как к обычным переменным, если известен базовый физический адрес устройства и структура его регистров.
На Raspberry Pi это особенно актуально при работе с низкоуровневыми устройствами, не обёрнутыми в готовые драйверы.
—
15.2. Как это работает
Аппаратные регистры устройств отображаются в память через физические адреса (например, 0x3F200000 для GPIO).
Драйвер резервирует и отображает (remap) эти адреса в виртуальное пространство ядра с помощью ioremap().
Доступ к значениям регистров производится через функции:
readl() / writel() — 32-битный доступ
readb() / writeb() — байтовый доступ
readw() / writew() — 16-битный доступ
По завершении работы память освобождается функцией iounmap().
—
15.3. Пример использования MMIO
Простой пример драйвера, который включает/выключает GPIO21 напрямую через регистры:
#define GPIO_BASE_PHYS 0x3F200000
#define GPIO_LEN 0xB4
static void __iomem *gpio_base;
static int __init mmio_example_init(void)
{
gpio_base = ioremap(GPIO_BASE_PHYS, GPIO_LEN);
if (!gpio_base) {
pr_err("Failed to map GPIO MMIO region\n");
return -ENOMEM;
}
// Настройка GPIO21 как выход (GPFSEL2)
u32 val = readl(gpio_base + 0x08);
val &= ~(7 << 3); // очистить биты FSEL21
val |= (1 << 3); // установить как output (001)
writel(val, gpio_base + 0x08);
// Включаем GPIO21 (GPSET0)
writel(1 << 21, gpio_base + 0x1C);
return 0;
}
static void __exit mmio_example_exit(void)
{
// Выключаем GPIO21 (GPCLR0)
writel(1 << 21, gpio_base + 0x28);
iounmap(gpio_base);
}
module_init(mmio_example_init);
module_exit(mmio_example_exit);
—
15.4. Важно
ioremap() возвращает виртуальный адрес, через который производится доступ
Нельзя просто использовать (volatile uint32_t *)0x3F200000 — это нарушает принципы безопасности ядра
Всегда вызывайте iounmap() при выгрузке модуля
Не забывайте про MODULE_LICENSE() и права доступа
—
15.5. Когда использовать MMIO
MMIO нужен, когда:
Нет стандартного драйвера для устройства
Требуется максимальная производительность
Вы реализуете прототип низкоуровневой периферии (например, на FPGA или нестандартной плате)
Нужно изучить поведение контроллера «вживую»
—
15.6. Вывод
MMIO — это мощный и универсальный способ взаимодействия с железом на Linux. Но он требует точного знания адресов, регистров и правильной работы с памятью ядра.
Мы будем использовать MMIO при разработке собственного драйвера для RGB LED и других устройств, где важно получить прямой доступ к битам конфигурации GPIO.