Communiquez avec les périphériques I2C sous Linux C

introduction

Lorsque vous souhaitez utiliser un appareil I2C avec Raspberry Pi ou Jetson nano, RasPi dispose de bibliothèques telles que pigpio et WiringPi, mais Jetson n'a que Jetson.GPIO, ce qui peut être un problème lorsque vous souhaitez écrire en C / C ++. (As-tu des problèmes ??)

Pour ces moments, j'ai écrit un article sur la façon de communiquer avec les périphériques I2C à l'aide du pilote I2C polyvalent de Linux.

Environnement de confirmation

Code source

Il semble y avoir plusieurs façons de communiquer avec les périphériques I2C, mais ce code utilise ioctl I2C_RDWR.

i2c_example.c


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

static const char* dev_name = "/dev/i2c-1";

/*!Lire les données de l'appareil esclave I2C.
 * @param[in] dev_adresse de périphérique addr.
 * @param[in] reg_adresse de registre addr.
 * @param[out]data Un pointeur vers l'emplacement de stockage des données à lire.
 * @param[in]length Longueur des données à lire.
 */
int8_t i2c_read(
    uint8_t dev_addr, uint8_t reg_addr, uint8_t* data, uint16_t length) {
  /*Ouvrez le périphérique I2C. */
  int32_t fd = open(dev_name, O_RDWR);
  if (fd == -1) {
    fprintf(stderr, "i2c_read: failed to open: %s\n", strerror(errno));
    return -1;
  }

  /* I2C-Créer un message de lecture. */
  struct i2c_msg messages[] = {
      { dev_addr, 0, 1, &reg_addr },         /*Définir l'adresse du registre. */
      { dev_addr, I2C_M_RD, length, data },  /*Lire des octets de longueur dans les données. */
  };
  struct i2c_rdwr_ioctl_data ioctl_data = { messages, 2 };

  /* I2C-Lis. */
  if (ioctl(fd, I2C_RDWR, &ioctl_data) != 2) {
    fprintf(stderr, "i2c_read: failed to ioctl: %s\n", strerror(errno));
    close(fd);
    return -1;
  }

  close(fd);
  return 0;
}

/*!Ecrire des données sur un appareil esclave I2C.
 * @param[in] dev_adresse de périphérique addr.
 * @param[in] reg_adresse de registre addr.
 * @param[in]data Un pointeur vers l'emplacement de stockage des données à écrire.
 * @param[in]length Longueur des données à écrire.
 */
int8_t i2c_write(
    uint8_t dev_addr, uint8_t reg_addr, const uint8_t* data, uint16_t length) {
  /*Ouvrez le périphérique I2C. */
  int32_t fd = open(dev_name, O_RDWR);
  if (fd == -1) {
    fprintf(stderr, "i2c_write: failed to open: %s\n", strerror(errno));
    return -1;
  }

  /* I2C-Préparer un tampon pour l'écriture. */
  uint8_t* buffer = (uint8_t*)malloc(length + 1);
  if (buffer == NULL) {
    fprintf(stderr, "i2c_write: failed to memory allocate\n");
    close(fd);
    return -1;
  }
  buffer[0] = reg_addr;              /*Définissez l'adresse du registre dans le premier octet. */
  memcpy(&buffer[1], data, length);  /*Définir les données après le deuxième octet. */

  /* I2C-Créer un message d'écriture. */
  struct i2c_msg message = { dev_addr, 0, length + 1, buffer };
  struct i2c_rdwr_ioctl_data ioctl_data = { &message, 1 };

  /* I2C-Écrire. */
  if (ioctl(fd, I2C_RDWR, &ioctl_data) != 1) {
    fprintf(stderr, "i2c_write: failed to ioctl: %s\n", strerror(errno));
    free(buffer);
    close(fd);
    return -1;
  }

  free(buffer);
  close(fd);
  return 0;
}

Commentaire

Tout d'abord, l'inclusion de l'en-tête et la définition du nom de l'appareil.

python


#include <linux/i2c-dev.h>
#include <linux/i2c.h>

static const char* dev_name = "/dev/i2c-1";

Les affectations des broches pour RasPi et Jetson nano I2C Bus1 sont les mêmes, et le nom de l'appareil est le même pour / dev / i2c-1.

Processus de lecture

python


  /* I2C-Créer un message de lecture. */
  struct i2c_msg messages[] = {
      { dev_addr, 0, 1, &reg_addr },         /*Définir l'adresse du registre. */
      { dev_addr, I2C_M_RD, length, data },  /*Lire des octets de longueur dans les données. */
  };
  struct i2c_rdwr_ioctl_data ioctl_data = { messages, 2 };

  /* I2C-Lis. */
  if (ioctl(fd, I2C_RDWR, &ioctl_data) != 2) {

Deux structures i2c_msg sont requises pour la lecture. Définissez d'abord l'adresse du registre, La deuxième taille à lire et l'emplacement de stockage des données sont spécifiés.

Processus d'écriture

python


  /* I2C-Préparer un tampon pour l'écriture. */
  uint8_t* buffer = (uint8_t*)malloc(length + 1);
  buffer[0] = reg_addr;              /*Définissez l'adresse du registre dans le premier octet. */
  memcpy(&buffer[1], data, length);  /*Définir les données après le deuxième octet. */

  /* I2C-Créer un message d'écriture. */
  struct i2c_msg message = { dev_addr, 0, length + 1, buffer };
  struct i2c_rdwr_ioctl_data ioctl_data = { &message, 1 };

  /* I2C-Écrire. */
  if (ioctl(fd, I2C_RDWR, &ioctl_data) != 1) {

Au moment de l'écriture, un tampon de "longueur des données à écrire + 1" est requis. Définissez l'adresse du registre dans le 1er octet, Définissez les données après le deuxième octet.

La structure i2c_msg en sera une.

en conclusion

J'ai pu communiquer avec des appareils I2C sur RasPi et Jetson Nano avec ce code, mais veuillez noter que le code et le contenu peuvent être incorrects.

Recommended Posts

Communiquez avec les périphériques I2C sous Linux C
Segfo avec 16 caractères en langage C
Assembleur X86 sous Linux (lien avec C)
[C] [python] Lire avec AquesTalk sous Linux
Créez Amazon Linux avec AWS EC2 et connectez-vous
Essayez d'incorporer Python dans un programme C ++ avec pybind11
Bibliothèque de mesure du temps d'exécution dans les applications Linux C
Gérer les signaux en langage C
En forme de conteneur réalisé avec C # 1
Autorisations Linux sur Java
Débogage C / C ++ avec gdb
Linux (Lubuntu) avec OneMix3S
Accéder à MongoDB en C
Seurat sous Linux (installation)
API C en Python 3
Créer des pipelies Azure avec Azure DevOps dans un environnement auto-hébergé Linux
Accédez au champ de structure C avec le nom réservé dans Go.