Différences entre versions de « Linux uart sunxi armbian »
(Page créée avec « = Introduction = Nous allons utiliser le protocole [https://fr.wikipedia.org/wiki/UART UART] sur une platine Sunxi (ARM AllWinner) OrangePi Zero. La connexion se fera entr... ») |
|||
(6 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 18 : | Ligne 18 : | ||
|} | |} | ||
=Activation du port UART1= | =Activation du port UART1= | ||
− | Il faut spécifier au système d'exploitation que nous voulons utiliser les broches 7 et 6 pour le port UART et non pas comme GPIO. Cela se fait en ajoutant les lignes | + | Il faut spécifier au système d'exploitation que nous voulons utiliser les broches 7 et 6 pour le port UART et non pas comme GPIO. Cela se fait en ajoutant les lignes suivantes dans le fichier ''/boot/armbianEnv.txt''. Il faut modifier la directive ''overlays'' pour ajouter simplement ''uart1'' : |
<pre> | <pre> | ||
# Exemple d'ajout en plus des overlays USB et du protocole oneWire: | # Exemple d'ajout en plus des overlays USB et du protocole oneWire: | ||
Ligne 24 : | Ligne 24 : | ||
</pre> | </pre> | ||
Il ne reste plus qu'à redémarrer le système pour appliquer les modifications. | Il ne reste plus qu'à redémarrer le système pour appliquer les modifications. | ||
+ | |||
= Programmation C = | = Programmation C = | ||
− | Ci-dessous un ''petit'' exemple de programme qui accède au port | + | Passons en revue les différentes étapes qui nous permettent d'utiliser le port UART: |
+ | * la première étape consiste à ouvrir le port, cela se fait avec la fonction ''open'' | ||
+ | <source lang="c"> | ||
+ | int fd = open(tty, O_RDWR | O_NOCTTY); | ||
+ | </source> | ||
+ | * Une fois le port ouvert on peut écrire avec la fonction ''write'' en utilisant le descripteur de fichier retourné par ''open'': | ||
+ | <source lang="c"> | ||
+ | write(fd, message, strlen(message)); | ||
+ | </source> | ||
+ | * On peut lire avec la fonction ''read'' en utilisant également le descripteur de fichier ainsi qu'un tampon (tableau de caractères). N'oubliez pas le ''\0'' qu'il faut ajouter si vous voulez manipuler votre tampon ! | ||
+ | <source lang="c"> | ||
+ | char buf[10] = ""; | ||
+ | int len = read(fd, buf, 9); | ||
+ | buf[len] = '\0'; | ||
+ | </source> | ||
+ | N'oubliez pas que l'opération de lecture (''read'') est bloquante ! Il faudra donc la mettre dans un thread si vous voulez faire une autre action en même temps. | ||
+ | |||
+ | Ci-dessous un ''petit'' exemple de programme ''serial.c'' qui: | ||
+ | * accède au port série | ||
+ | * démarre un thread pour la lecture de la console (message de l'utilisateur) | ||
+ | * démarre un thread de lecture du port série | ||
<source lang="c"> | <source lang="c"> | ||
+ | #include <stdio.h> | ||
+ | #include <stdlib.h> | ||
+ | #include <string.h> | ||
+ | #include <unistd.h> | ||
+ | #include <errno.h> | ||
+ | #include <fcntl.h> | ||
+ | #include <pthread.h> | ||
+ | |||
+ | int open_uart(const char * tty) | ||
+ | { | ||
+ | int fd = open(tty, O_RDWR | O_NOCTTY); | ||
+ | if (fd == -1){ | ||
+ | printf("Unable to open %s: %s\n", tty, strerror(errno)); | ||
+ | } else { | ||
+ | printf("Opening %s\n", tty); | ||
+ | } | ||
+ | return fd; | ||
+ | } | ||
+ | |||
+ | void * writeSerial(void * arg){ | ||
+ | printf("Enter \"exit\" to quit program\n"); | ||
+ | int fd = *((int*) arg); | ||
+ | char buffer[80] = ""; | ||
+ | // Stocke la longeur du message reçu | ||
+ | int len = 0; | ||
+ | int code = 0; | ||
+ | while(1){ | ||
+ | // On lit jusqu'au caractère '\n' | ||
+ | len = scanf("%[^\n]", buffer); | ||
+ | if(len < 0){ | ||
+ | perror("Fail reading from console !\n"); | ||
+ | code = 1; | ||
+ | break; | ||
+ | } | ||
+ | if(strncmp("exit", buffer, 4) == 0){ | ||
+ | break; | ||
+ | }else if(write(fd, buffer, strlen(buffer)) < 0){ | ||
+ | perror("Fail writting to UART !\n"); | ||
+ | code = 1; | ||
+ | break; | ||
+ | } | ||
+ | // Supprime le caractère '\n' | ||
+ | fgetc(stdin); | ||
+ | } | ||
+ | //Fermeture du port série | ||
+ | close(fd); | ||
+ | // Fermeture du programme | ||
+ | pthread_exit(0); | ||
+ | exit(code); | ||
+ | } | ||
+ | void * readSerial(void * arg){ | ||
+ | int fd = *((int*) arg); | ||
+ | // Lecture par bloc de 10 octets | ||
+ | char buf[10] = ""; | ||
+ | // Stocke la longeur du message reçu | ||
+ | int len = 0; | ||
+ | // Lecture en boucle, jusqu'à erreur | ||
+ | while(1){ | ||
+ | // Lecture des caractères | ||
+ | len = read(fd, buf, 9); | ||
+ | if(len < 0){ | ||
+ | // erreur | ||
+ | printf("Fail reading from serial: %s\n", strerror(errno)); | ||
+ | break; | ||
+ | } | ||
+ | // Ajout du terminateur de chaîne | ||
+ | buf[len] = '\0'; | ||
+ | // Affichage du message | ||
+ | if(len > 0){ | ||
+ | printf("%s", buf); | ||
+ | } | ||
+ | } | ||
+ | //Fermeture du port série | ||
+ | close(fd); | ||
+ | // Fermeture du programme | ||
+ | pthread_exit(0); | ||
+ | exit(EXIT_FAILURE); | ||
+ | } | ||
+ | |||
+ | int main(int argc, char * argv[]){ | ||
+ | // Récupération des arguments | ||
+ | if(argc < 2){ | ||
+ | perror("You must specify an UART to open !\n"); | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | // Ouveture du port série | ||
+ | int fd = open_uart(argv[1]); | ||
+ | if(fd < 0){ | ||
+ | return EXIT_FAILURE; | ||
+ | } | ||
+ | // Thread pour la lecture du port série | ||
+ | pthread_t lecture = 0; | ||
+ | // Thread pour écouter le clavier et écrire dans le port série | ||
+ | pthread_t ecriture = 0; | ||
+ | // Démarrage du thread de lecture | ||
+ | pthread_create(&lecture, NULL, readSerial, &fd); | ||
+ | // Démarrage du thread d'écriture | ||
+ | pthread_create(&ecriture, NULL, writeSerial, &fd); | ||
+ | // On attend que l'utilisateur stop le programme en envoyant "exit" | ||
+ | pthread_join(ecriture, NULL); | ||
+ | // On ferme proprement le port série | ||
+ | close(fd); | ||
+ | return EXIT_SUCCESS; | ||
+ | } | ||
+ | </source> | ||
+ | Une fois compilé: | ||
+ | <pre> | ||
+ | # gcc -o serial.bin serial.c -l pthread | ||
+ | </pre> | ||
+ | On peut lire et écrire sur le port série depuis le CP1202 à 9600 bauds: | ||
+ | [[Fichier:Cp1202 uart opi zero.png|centré]] | ||
+ | = Modification de la vitesse = | ||
+ | Pour changer la vitesse du port série il faudra utiliser l'interface POSIX [http://manpagesfr.free.fr/man/man3/termios.3.html ''termios'']. Sans recopier l'intégralité du script précédent, voici les étapes qu'ils suffit de suivre: | ||
+ | * inclure le fichier de définition | ||
+ | <source lang="c"> | ||
+ | #include <termios.h> | ||
+ | </source> | ||
+ | * créer la structure qui va permettre de manipuler le port série: | ||
+ | <source lang="c"> | ||
+ | struct termios options; | ||
+ | </source> | ||
+ | * récupérer les options du port: | ||
+ | <source lang="c"> | ||
+ | tcgetattr(fd, &options); | ||
+ | </source> | ||
+ | * modifier la vitesse, ici 115200 bauds: | ||
+ | <source lang="c"> | ||
+ | cfsetispeed(&options, B115200); | ||
+ | cfsetospeed(&options, B115200); | ||
+ | </source> | ||
+ | * appliquer les modifications immédiatement (''TCSCANOW''): | ||
+ | <source lang="c"> | ||
+ | tcsetattr(fd, TCSANOW, &options); | ||
</source> | </source> | ||
+ | N'hésitez pas à parcourir [https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2 cette page] pour plus d'information sur les options disponibles ! |
Version actuelle datée du 14 novembre 2020 à 11:58
Introduction
Nous allons utiliser le protocole UART sur une platine Sunxi (ARM AllWinner) OrangePi Zero. La connexion se fera entre l'OrangePi et un convertisseur USB / UART CP2102
Montage
Nous allons connecter le CP2102 au port UART1 de l'OrangePi. Il faudra donc raccorder les deux de la sorte:
CP2102 -> OrangePi GND -> GND RX -> TX TX -> RX |
Activation du port UART1
Il faut spécifier au système d'exploitation que nous voulons utiliser les broches 7 et 6 pour le port UART et non pas comme GPIO. Cela se fait en ajoutant les lignes suivantes dans le fichier /boot/armbianEnv.txt. Il faut modifier la directive overlays pour ajouter simplement uart1 :
# Exemple d'ajout en plus des overlays USB et du protocole oneWire: overlays=usbhost2 usbhost3 w1-gpio uart1
Il ne reste plus qu'à redémarrer le système pour appliquer les modifications.
Programmation C
Passons en revue les différentes étapes qui nous permettent d'utiliser le port UART:
- la première étape consiste à ouvrir le port, cela se fait avec la fonction open
int fd = open(tty, O_RDWR | O_NOCTTY);
- Une fois le port ouvert on peut écrire avec la fonction write en utilisant le descripteur de fichier retourné par open:
write(fd, message, strlen(message));
- On peut lire avec la fonction read en utilisant également le descripteur de fichier ainsi qu'un tampon (tableau de caractères). N'oubliez pas le \0 qu'il faut ajouter si vous voulez manipuler votre tampon !
char buf[10] = "";
int len = read(fd, buf, 9);
buf[len] = '\0';
N'oubliez pas que l'opération de lecture (read) est bloquante ! Il faudra donc la mettre dans un thread si vous voulez faire une autre action en même temps.
Ci-dessous un petit exemple de programme serial.c qui:
- accède au port série
- démarre un thread pour la lecture de la console (message de l'utilisateur)
- démarre un thread de lecture du port série
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
int open_uart(const char * tty)
{
int fd = open(tty, O_RDWR | O_NOCTTY);
if (fd == -1){
printf("Unable to open %s: %s\n", tty, strerror(errno));
} else {
printf("Opening %s\n", tty);
}
return fd;
}
void * writeSerial(void * arg){
printf("Enter \"exit\" to quit program\n");
int fd = *((int*) arg);
char buffer[80] = "";
// Stocke la longeur du message reçu
int len = 0;
int code = 0;
while(1){
// On lit jusqu'au caractère '\n'
len = scanf("%[^\n]", buffer);
if(len < 0){
perror("Fail reading from console !\n");
code = 1;
break;
}
if(strncmp("exit", buffer, 4) == 0){
break;
}else if(write(fd, buffer, strlen(buffer)) < 0){
perror("Fail writting to UART !\n");
code = 1;
break;
}
// Supprime le caractère '\n'
fgetc(stdin);
}
//Fermeture du port série
close(fd);
// Fermeture du programme
pthread_exit(0);
exit(code);
}
void * readSerial(void * arg){
int fd = *((int*) arg);
// Lecture par bloc de 10 octets
char buf[10] = "";
// Stocke la longeur du message reçu
int len = 0;
// Lecture en boucle, jusqu'à erreur
while(1){
// Lecture des caractères
len = read(fd, buf, 9);
if(len < 0){
// erreur
printf("Fail reading from serial: %s\n", strerror(errno));
break;
}
// Ajout du terminateur de chaîne
buf[len] = '\0';
// Affichage du message
if(len > 0){
printf("%s", buf);
}
}
//Fermeture du port série
close(fd);
// Fermeture du programme
pthread_exit(0);
exit(EXIT_FAILURE);
}
int main(int argc, char * argv[]){
// Récupération des arguments
if(argc < 2){
perror("You must specify an UART to open !\n");
return EXIT_FAILURE;
}
// Ouveture du port série
int fd = open_uart(argv[1]);
if(fd < 0){
return EXIT_FAILURE;
}
// Thread pour la lecture du port série
pthread_t lecture = 0;
// Thread pour écouter le clavier et écrire dans le port série
pthread_t ecriture = 0;
// Démarrage du thread de lecture
pthread_create(&lecture, NULL, readSerial, &fd);
// Démarrage du thread d'écriture
pthread_create(&ecriture, NULL, writeSerial, &fd);
// On attend que l'utilisateur stop le programme en envoyant "exit"
pthread_join(ecriture, NULL);
// On ferme proprement le port série
close(fd);
return EXIT_SUCCESS;
}
Une fois compilé:
# gcc -o serial.bin serial.c -l pthread
On peut lire et écrire sur le port série depuis le CP1202 à 9600 bauds:
Modification de la vitesse
Pour changer la vitesse du port série il faudra utiliser l'interface POSIX termios. Sans recopier l'intégralité du script précédent, voici les étapes qu'ils suffit de suivre:
- inclure le fichier de définition
#include <termios.h>
- créer la structure qui va permettre de manipuler le port série:
struct termios options;
- récupérer les options du port:
tcgetattr(fd, &options);
- modifier la vitesse, ici 115200 bauds:
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
- appliquer les modifications immédiatement (TCSCANOW):
tcsetattr(fd, TCSANOW, &options);
N'hésitez pas à parcourir cette page pour plus d'information sur les options disponibles !