querdenker engineering
Schnittstellen und Services

I2C und SPI

Serielle Busse über Systemgeräte oder bereitgestellte Services nutzen.

I2C und SPI werden in zwei Schritten betrachtet:

  1. Der Device Tree beschreibt Bus, angeschlossenes Gerät, Chip-Select, Interrupts und weitere Hardwareparameter.
  2. Die Anwendung nutzt das bereitgestellte Userspace-Gerät oder den Service.

Die Busse sind über [I2C-GERÄT] und [SPI-GERÄT] verfügbar. Vor dem Zugriff müssen Busnummer, Chip-Select, Frequenz und elektrische Randbedingungen geprüft werden.

Für die Python-Beispiele werden smbus2 [SMBUS2-VERSION] und spidev [SPIDEV-VERSION] verwendet.

I2C: [I2C-GERÄT], Adresse [I2C-ADRESSE], [I2C-FREQUENZ]
SPI: [SPI-GERÄT], Chip-Select [CHIP-SELECT], [SPI-FREQUENZ]

[PLATZHALTER: Freigegebene Geräte, Frequenzgrenzen und Beispielzugriffe]

I2C aus eigenen Programmen verwenden

Voraussetzung ist ein aktivierter I2C-Bus und ein Geräteknoten [I2C-GERÄT]. Die Geräteadresse [I2C-ADRESSE] und die Register sind bausteinspezifisch.

#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <unistd.h>

int i2c_read_register(const char *device_path, int address, unsigned char reg)
{
    unsigned char value = 0U;
    const int fd = open(device_path, O_RDWR);
    if (fd < 0 || ioctl(fd, I2C_SLAVE, address) < 0) {
        if (fd >= 0) {
            (void)close(fd);
        }
        return -1;
    }

    if (write(fd, &reg, sizeof(reg)) != (ssize_t)sizeof(reg) ||
        read(fd, &value, sizeof(value)) != (ssize_t)sizeof(value)) {
        (void)close(fd);
        return -1;
    }

    (void)close(fd);
    return (int)value;
}

/* Beispiel: i2c_read_register("/dev/i2c-1", [I2C-ADRESSE], [REGISTER]); */

SPI aus eigenen Programmen verwenden

SPI benötigt den richtigen Chip-Select, Modus, Takt und die maximale Übertragungsfrequenz.

#include <fcntl.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <unistd.h>

int spi_transfer(const char *device_path, unsigned char *buffer, unsigned int length)
{
    const int fd = open(device_path, O_RDWR);
    struct spi_ioc_transfer transfer = {
        .tx_buf = (unsigned long)buffer,
        .rx_buf = (unsigned long)buffer,
        .len = length,
        .speed_hz = [SPI-TAKT-HZ],
        .bits_per_word = 8U
    };

    if (fd < 0 || ioctl(fd, SPI_IOC_MESSAGE(1), &transfer) < 0) {
        if (fd >= 0) {
            (void)close(fd);
        }
        return -1;
    }

    (void)close(fd);
    return 0;
}

/* Beispiel: spi_transfer("/dev/spidev0.0", buffer, buffer_length); */

Für Python werden in diesen Beispielen smbus2 und spidev verwendet. Die Bibliotheken müssen Bestandteil des Images oder der Anwendungslieferung sein.