Différences entre versions de « Linux sunxi armbian gpio »
Ligne 240 : | Ligne 240 : | ||
// Affichage des infos | // Affichage des infos | ||
printInfo(chip_fd, GPIO); | printInfo(chip_fd, GPIO); | ||
− | // Paramètrage de la ligne ( | + | // Paramètrage de la ligne (OUTPUT) |
setMode(chip_fd, GPIOHANDLE_REQUEST_OUTPUT); | setMode(chip_fd, GPIOHANDLE_REQUEST_OUTPUT); | ||
// Affichage des infos | // Affichage des infos |
Version du 11 juin 2020 à 14:27
Introduction
Nous allons piloter les broches d'un Orange Pi Zéro grâce à l'API C libgpiod ainsi qu'à la fonction ioctl.
- ioctl prend trois paramètres:
- un descripteur de fichier
- le code de la requête (souvent une macro)
- une valeur discrète (type primitif) ou un pointeur sur une structure de données.
#include <sys/ioctl.h>
int ioctl(int d, int requête, ...);
- libgpiod fournie les structures de données qui vont nous permettre de manipuler ou lire l'état des broches
#include <linux/gpio.h>
struct gpiochip_info {
char name[32];
char label[32];
__u32 lines;
};
struct gpioline_info {
__u32 line_offset;
__u32 flags;
char name[32];
char consumer[32];
};
Lecture
Informations sur les contrôleurs
Commençons par récupérer des informations sur les contrôleurs il faut d'abord récupérer leurs noms:
root@orangepizero:~# ll /dev/gpiochip*
crw------- 1 root root 254, 0 May 25 08:44 /dev/gpiochip0
crw------- 1 root root 254, 1 May 25 08:44 /dev/gpiochip1
Le programme ci-dessous permet d'afficher les informations de gpiochip0. Nous allons le mettre dans un fichier read_gpiochip.c:
#include <stdio.h> // pour EXIT_SUCCESS
#include <stdlib.h> // pour printf
#include <linux/gpio.h> // pour struct gpiochip_info
#include <fcntl.h> // pour open
#include <sys/ioctl.h> // pour ioctl
#include <string.h> // Pour memset
// Macro pour le nom du contrôleur
#define GPIO_CHIP "/dev/gpiochip0"
int main(int argc, char * argv[]){
// ouverture du contrôleur en lecture seule
int fd = open(GPIO_CHIP, O_RDONLY);
// création de la structure qui va contenir les informations
struct gpiochip_info chip_info;
// Initialisation de la structure avec des zéro (pour valgrind)
memset(&chip_info, 0, sizeof(struct gpiochip_info));
// Lecture des informations
ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
// Affichage
printf("name = %s, label = %s, lines = %d\n", chip_info.name, chip_info.label, chip_info.lines);
return EXIT_SUCCESS;
}
Une fois compilé, ce programme nous apprend que le contrôleur possède 224 lignes:
# gcc -o read_gpiochip.bin read_gpiochip.c # ./read_gpiochip.bin name = gpiochip0, label = 1c20800.pinctrl, lines = 224
Informations sur les broches
Pour avoir des informations sur les broches, le principe est le même, sauf que la structure utilisée est gpioline_info. Nous allons créer le fichier read_gpio.c:
#include <stdio.h> // pour EXIT_SUCCESS
#include <stdlib.h> // pour printf
#include <linux/gpio.h> // pour struct gpiochip_info
#include <fcntl.h> // pour open
#include <sys/ioctl.h> // pour ioctl
#include <string.h> // Pour memset
// Macro pour le nom du contrôleur
#define GPIO_CHIP "/dev/gpiochip0"
#define LINES 224
int main(int argc, char * argv[]){
// ouverture du contrôleur en lecture seule
int fd_chip = open(GPIO_CHIP, O_RDONLY);
// Structure contenant les informations
struct gpioline_info info;
// Itération sur toutes les lignes
for (int offset = 0; offset < LINES; offset ++) {
// Initialisation de la structure avec des zéro (pour valgrind)
memset(&info, 0, sizeof(struct gpioline_info));
// Positionnement du numéro de la ligne à lire
info.line_offset = offset;
// Lecture des informations
ioctl(fd_chip, GPIO_GET_LINEINFO_IOCTL, &info);
// Affichage
printf(" %d: consommateur = %s, Direction = %s, Autres: %s %s %s %s\n",
info.line_offset, info.consumer,
info.flags & GPIOLINE_FLAG_IS_OUT ? "OUT" : "IN ",
info.flags & GPIOLINE_FLAG_ACTIVE_LOW ? "ACTIVE_LOW " : "ACTIVE_HIGH",
info.flags & GPIOLINE_FLAG_OPEN_DRAIN ? "OPEN_DRAIN" : "",
info.flags & GPIOLINE_FLAG_OPEN_SOURCE ? "OPEN_SOURCE" : "",
info.flags & GPIOLINE_FLAG_KERNEL ? "KERNEL" : "");
}
}
Une fois compilé, on peut afficher des informations sur les 224 broches du contrôleur gpiochip0:
# gcc -std=c99 -o read_gpio.bin read_gpio.c # ./read_gpio.bin 0: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 1: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 2: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 3: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 4: consommateur = , Direction = IN , Autres: ACTIVE_HIGH 5: consommateur = , Direction = IN , Autres: ACTIVE_HIGH 6: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 7: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 8: consommateur = , Direction = IN , Autres: ACTIVE_HIGH 9: consommateur = , Direction = IN , Autres: ACTIVE_HIGH 10: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 11: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 12: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 13: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 14: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 15: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 16: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 17: consommateur = orangepi:red:status, Direction = OUT, Autres: ACTIVE_HIGH KERNEL 18: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 19: consommateur = , Direction = OUT, Autres: ACTIVE_HIGH 20: consommateur = reg_vcc_wifi, Direction = OUT, Autres: ACTIVE_HIGH KERNEL /..../ 223: consommateur = , Direction = IN , Autres: ACTIVE_HIGH
On remarque qu'il nous manque l'état de la broche et on peut le récupérer en plusieurs étapes. Tout d'abord il faut récupérer le descripteur de la ligne (GPIO) qui nous intéresse grâce à la structure suivante:
struct gpiohandle_request {
__u32 lineoffsets[GPIOHANDLES_MAX];
__u32 flags;
__u8 default_values[GPIOHANDLES_MAX];
char consumer_label[32];
__u32 lines;
int fd;
};
Cette structure contient plusieurs attributs et notamment:
- lineoffsets: qui est un tableau contenant les numéros des lignes qui nous intéresse
- flags : qui est le type de requête (GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_INPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW, etc...)
- lines : qui correspond au nombre de lignes concernée par la requête
- fd : contiendra le descripteur de la requête
Une fois la requête préparée, on peut utiliser la structure suivante pour récupérer la valeur:
struct gpiohandle_data {
__u8 values[GPIOHANDLES_MAX];
};
Cette structure contient un tableau d'entier sur 8 bits avec l'état des lignes.
Dans l'exemple suivant, on demande l'état de la ligne 199 du contrôleur gpiochip0. Nous allons créer le fichier read_gpio.c:
#include <stdio.h> // pour EXIT_SUCCESS
#include <stdlib.h> // pour printf
#include <linux/gpio.h> // pour struct gpiochip_info
#include <fcntl.h> // pour open
#include <sys/ioctl.h> // pour ioctl
#include <string.h> // Pour memset
// Macro pour le nom du contrôleur
#define GPIO_CHIP "/dev/gpiochip0"
// Macro pour le numéro de la ligne
#define GPIO 199
int main(int argc, char * argv[]){
// ouverture du contrôleur en lecture seule
int chip_fd = open(GPIO_CHIP, O_RDONLY); int offset;
// Structure contenant les informations de la ligne
struct gpiohandle_request request;
// Initialisation de la structure avec des zéro
memset(&request, 0, sizeof(struct gpiohandle_request));
// Positionnement du numéro de la ligne à lire
request.lineoffsets[0] = GPIO;
// Spécification de la direction en entrée (INPUT)
request.flags = GPIOHANDLE_REQUEST_INPUT;
// Quantité de ligne a traiter
request.lines = 1;
// Récupération du descripteur de la ligne
ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request);
// Structure contenant les valeurs de la ligne
struct gpiohandle_data values;
// Initialisation de la structure avec des zéro
memset(&values, 0, sizeof(struct gpiohandle_data));
// Lecture des valeurs présente dans le descripteur
ioctl(request.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values);
// Affichage
printf("Line %i is %s\n", GPIO, values.values[0] == 0 ? "LOW" : "HIGH");
}
Une fois compilé, on peut afficher l'état de la ligne 199 du contrôleur gpiochip0:
# gcc -o read_gpio_state.bin read_gpio_state.c # ./read_gpio_state.bin Line 199 is LOW # ./read_gpio_state.bin Line 199 is HIGH
Modification
Direction
Dans l'exemple suivant, on change la direction de la ligne 199 du contrôleur gpiochip0. Nous allons créer le fichier set_mode.c:
#include <stdio.h> // pour EXIT_SUCCESS
#include <stdlib.h> // pour printf
#include <linux/gpio.h> // pour struct gpiochip_info
#include <fcntl.h> // pour open
#include <sys/ioctl.h> // pour ioctl
#include <string.h> // pour memset
#include <unistd.h> // pour close
// Macro pour le nom du contrôleur
#define GPIO_CHIP "/dev/gpiochip0"
// Macro pour le numéro de ligne
#define GPIO 6
// Déclaration des signatures des fonctions
void setMode(int chip_fd, __u32 direction);
void printInfo(int chip_fd, unsigned int gpio);
int main(int argc, char * argv[]){
// Récupération du descripteur du contrôleur en lecture seule
int chip_fd;
if((chip_fd = open(GPIO_CHIP, O_RDONLY)) < 0){
printf("Fail opening chip handle\n");
return EXIT_FAILURE;
}
// Paramètrage de la ligne (INPUT)
setMode(chip_fd, GPIOHANDLE_REQUEST_INPUT);
// Affichage des infos
printInfo(chip_fd, GPIO);
// Paramètrage de la ligne (OUTPUT)
setMode(chip_fd, GPIOHANDLE_REQUEST_OUTPUT);
// Affichage des infos
printInfo(chip_fd, GPIO);
return EXIT_SUCCESS;
}
void setMode(int chip_fd, __u32 direction){
// Structure contenant les informations de la ligne
struct gpiohandle_request request;
// Initialisation de la structure avec des zéros
memset(&request, 0, sizeof(struct gpiohandle_request));
// Positionnement du numéro de la ligne
request.lineoffsets[0] = GPIO;
// Quantité de ligne a traiter
request.lines = 1;
// Spécification de la direction
request.flags = direction;
// Récupération du descripteur et paramètrage de la ligne
if(ioctl(chip_fd, GPIO_GET_LINEHANDLE_IOCTL, &request) < 0){
printf("Fail opening line handle\n");
exit(EXIT_FAILURE);
}
// Fermeture du descripteur avant modification ultérieur
close(request.fd);
}
void printInfo(int chip_fd, unsigned int gpio){
// Structure contenant les informations
struct gpioline_info info;
// Initialisation de la structure avec des zéros
memset(&info, 0, sizeof(struct gpioline_info));
// Spécification de la ligne
info.line_offset = gpio;
// Lecture des informations
if(ioctl(chip_fd, GPIO_GET_LINEINFO_IOCTL, &info) < 0){
printf("Fail opening line handle\n");
exit(EXIT_FAILURE);
}
// Affichage
printf("GPIO %i mode: %s\n", gpio, info.flags & GPIOLINE_FLAG_IS_OUT ? "OUT" : "IN ");
}
Une fois compilé, on peut changer la direction de la ligne 199 du contrôleur gpiochip0:
# gcc -o set_mode.bin set_mode.c # ./set_mode.bin GPIO 199 mode: IN GPIO 199 mode: OUT