Files
wikipedia/Linux/Embedded Linux/Linux SBC - Hardware.md
T
2026-04-22 19:55:16 +03:00

307 lines
9.7 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#linux #GPIO #i2c #spi #hardware #userspase #libgpiod
Контроль и управление периферией в Linux
https://habr.com/ru/articles/520488/
---
Устройства в Linux представлены в виде файлов и живут в системной директории: `/dev`
Например :
- Устройства i2c
`/dev/i2c-0`
`/dev/i2c-1`
- Последовательные порты (Виртуальная консоль)
`/dev/ttyUSB0`
- SPI устройства
`/dev/spidev*`
## GPIO Driver
Полезная информация:
https://devdotnet.org/post/rabota-s-gpio-v-linux-chast-6-biblioteka-libgpiod/
Способы управления:
1. Userspace driver -прямое управление
2. Libgpiod - управление через библиотеку (API для Python и C/C++)
3. Python library
#### User Space
Прямой доступ к регистрам, минуя медленные системные вызовы.
Посредством открытия `/dev/mem` и мапирование базового адреса GPIO.
==Подводные камни:==
1. Обход GPIO Subsystem
2. Нет контроля конкуренции (может управлять несколько процессов)
3. Можно сломать драйвер
4. Нет безопасности
##### GPIO Output from userspace
```cpp title:userspace_gpio_control.cpp
#include <iostream> // вывод сообщений
#include <fcntl.h> // открытие файлов
#include <sys/mman.h> // mmap и munmap
#include <unistd.h> // usleep и close
#include <cstring> // perror
#include <cstdint> // для uint32_t
/*
1. Userspace драйвер GPIO.
Управление GPIO Raspberry Pi через mmap обеспечивает прямой доступ к регистрам периферии,
минуя медленные системные вызовы. Это реализуется через открытие /dev/mem,
мапирование базового адреса GPIO
*/
#define GPIO_BASE 0x3F200000 // физический адрес начала блока регистров GPIO на SoC BCM2835
#define BLOCK_SIZE 4096 // Размер отображ. памяти Регистры GPIO занимают 41 байт, но мы отображаем целую страницу для простоты.
#define TIME_SLEEP 500000 // Время задержки в микросекундах
int main() {
// открытие спец.файла физической памяти. Флаги - чтение и запись + отключение кэширования
int mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
// Если не удалось открыть - вывод ошибки
if (mem_fd < 0) {
perror("open");
return 1;
}
/*
Отображение памяти регистров в виртуальное адресное пространство
mmap создаёт отображение физической памяти, начиная с адреса GPIO_BASE, размером BLOCK_SIZE, в виртуальную память процесса.
NULL – ядро само выбирает адрес для отображения.
BLOCK_SIZE – количество байт.
PROT_READ | PROT_WRITE – разрешено чтение и запись.
MAP_SHARED – изменения видны другим процессам и синхронизируются с файлом (важно для доступа к реальной памяти).
mem_fd – файловый дескриптор /dev/mem.
GPIO_BASE – смещение в файле (физический адрес).
*/
void* gpio_map = mmap(
NULL,
BLOCK_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
mem_fd,
GPIO_BASE
);
if (gpio_map == MAP_FAILED) {
perror("mmap");
return 1;
}
// Указатель приводится к типу volatile uint32_t*, чтобы:
// Обращаться к памяти 32-битными словами.
// volatile запрещает компилятору оптимизировать обращения, т.к. значения регистров могут меняться аппаратно.
volatile uint32_t* gpio = (volatile uint32_t*)gpio_map;
// GPIO17 = бит 21 в GPFSEL1
gpio[1] &= ~(7 << 21); // очистить
gpio[1] |= (1 << 21); // output
while (true) {
gpio[7] = (1 << 17); // set
usleep(TIME_SLEEP);
gpio[10] = (1 << 17); // clear
usleep(TIME_SLEEP);
}
// освобождение ресурсов, при выходе
munmap(gpio_map, BLOCK_SIZE);
close(mem_fd);
}
```
---
#### Libgpiod - library control
Library General Purpose Input/Output device - Библиотека и набор утилит в Linux для управления пинами GPIO (ввод/вывод общего назначения) через символьные устройства (`/dev/gpiochip*`) или контроллеры GPIO
Состав библиотеки:
- **gpiodetect**
- **gpioinfo**
- **gpioset**
- **gpioget**
Установка:
``` bash
sudo apt-get update
sudo apt-get install -y libgpiod-dev libgpiod-doc gpiod
```
Проверка корректности установки:
``` bash
pkg-config --cflags --libs libgpiod
```
Компиляция:
``` bash
g++ -o gpio_control gpio_control.cpp -lgpiod
```
##### Example GPIO Output
``` cpp title:libgpiod_control.cpp
#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define GPIO_CHIP "gpiochip0"
#define GPIO_PIN 17
int main(int argc, char *argv[]) {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    int ret;
    // Open the GPIO chip
    chip = gpiod_chip_open_by_name(GPIO_CHIP);
    if (!chip) {
        perror("gpiod_chip_open_by_name");
        return EXIT_FAILURE;
    }
   
    // Get the GPIO line
    line = gpiod_chip_get_line(chip, GPIO_PIN);
    if (!line) {
        perror("gpiod_chip_get_line");
        gpiod_chip_close(chip);
        return EXIT_FAILURE;
    }
   
    // Request the line as output
    ret = gpiod_line_request_output(line, "gpio-control", 0);
    if (ret < 0) {
        perror("gpiod_line_request_output");
        gpiod_chip_close(chip);
        return EXIT_FAILURE;
    }
    for(int i = 0; i < 50; i++){
        // Set GPIO to HIGH
        ret = gpiod_line_set_value(line, 1);
        if (ret < 0) {
            perror("gpiod_line_set_value");
            gpiod_chip_close(chip);
            return EXIT_FAILURE;
        }
        printf("GPIO 17 set to HIGH\n");
        sleep(2);
        // Set GPIO to LOW
        ret = gpiod_line_set_value(line, 0);
        if (ret < 0) {
            perror("gpiod_line_set_value");
            gpiod_chip_close(chip);
            return EXIT_FAILURE;
        }
        printf("GPIO 17 set to LOW\n");
        sleep(2);
    }
    // Release resources
    gpiod_chip_close(chip);
    return EXIT_SUCCESS;
}
```
Запуск программы (находясь в папке)
``` bash
./gpio_control
```
##### Example GPIO Input
```c
#include <gpiod.h>
#include <iostream>
#include <unistd.h>
int main() {
const char* chipname = "gpiochip0";
unsigned int line_num = 27;
gpiod_chip* chip = gpiod_chip_open_by_name(chipname);
if (!chip) {
perror("chip open");
return 1;
}
gpiod_line* line = gpiod_chip_get_line(chip, line_num);
if (!line) {
perror("get line");
return 1;
}
// Запрос линии как input с событием
if(gpiod_line_request_falling_edge_events(line,"button") < 0) {
perror("request events");
return 1;
}
std::cout << "Waiting for button press..." << std::endl;
while (true) {
int ret = gpiod_line_event_wait(line, NULL);
if (ret < 0) {
perror("event wait");
break;
}
if (ret == 1) {
struct gpiod_line_event event;
gpiod_line_event_read(line, &event);
std::cout << "Button pressed!" << std::endl;
}
}
gpiod_line_release(line);
gpiod_chip_close(chip);
return 0;
}
```
Запуск компиляции
```bash
g++ -std=c++11 gpio_button.cpp -lgpiod -o gpio_button
```
---
## I2C Bus. Integrates
Представление:
- `/sys/bus/i2c/devices/` - управление конфигурацией устройств через драйверы ядра
- `/dev/i2c-0` - прямой доступ к шине через userspace
По умолчанию шина отключена.
Включить можно следующими способами:
1 - Через raspi - config
``` bash
sudo raspi-config
```
2 - корректировкой `/boot/firmware/config.txt`
раскомментировать параметр `dtparam=i2c_arm=on`
Затем в устройство должно появиться в `/dev` как `i2c-1`
Набор утилит для работы с шиной i2c: `i2c-tools`
Установка:
```bash
sudo apt-get install i2c-tools
```
Состав библиотеки:
- **i2cdetect**
- **i2cdump**
- **i2cget**
- **i2cset**
## SPI
Команды для работы:
```bash
```
## Commands
Система:
`vcgencmd get_config int` - параметры, которые передает GPU
`cat /etc/os-release` - просмотр версии системы