Linux uart sunxi armbian

De The Linux Craftsman
Aller à la navigation Aller à la recherche

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

Cp2102.png

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
Uart cp2102 opi.png

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:

Cp1202 uart opi zero.png

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:

  • 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:
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 !