[RÉSOLU] Erreur d'initialisation de WiringPi  [RESOLU]

Le connecteur GPIO du Raspberry Pi, comment l'utiliser sur les Mode A, B et B+

Modérateur : Francois

Pinhapple
Raspinaute
Messages : 125
Enregistré le : jeu. 23 févr. 2017 15:53
Localisation : Rouen

[RÉSOLU] Erreur d'initialisation de WiringPi

Message par Pinhapple » mer. 22 mars 2017 09:38

Bonjour,

Dans la continuité d'un de mes sujets précédents (utilisation du gyro/accéléro LSM9DS1 d'un Sense HAT en I2C), j'ai désormais un autre petit souci.

Les faits : sur un RPi 3, j'ai un programme en C/C++ qui, lorsque je le démarre, enregistre dans un fichier CSV 3 valeurs d'accélération (1 valeur par axe) et 3 valeurs de rotation (1 valeur par axe), pour un nombre spécifié de lecture (si je demande 100 lectures, ce sont 100 * (3 + 3) = 600 valeurs qui seront enregistrées). J'utilise cette bibliothèque, spécialement écrite pour le LSM9DS1, qui utilise WiringPi. Le programme fonctionne comme je le souhaite, pas de problème de ce côté-là.

Sur le même RPi 3, j'ai un autre programme en C/C++ composé d'un bouton-poussoir et de deux DEL (une rouge et une verte), équipés des résistances appropriées, qui fonctionne comme suit :
  1. Je démarre mon programme -> la DEL verte s'allume, la rouge reste éteinte
  2. J'appuie sur le bouton-poussoir -> la DEL verte s'éteint, la DEL rouge s'allume
  3. Au bout d'un temps spécifié (5 secondes dans mon cas), la DEL rouge s'éteint, la DEL verte clignote 1,5 seconde, puis reste allumée
  4. Le processus peut être relancé depuis l'étape 2
Comme le premier programme, celui-ci fonctionne comme je le souhaite, toujours pas de problème.

En revanche, lorsque j'essaie de faire fusionner mes programmes de sorte que l'étape "DEL rouge qui s'allume" soit remplacée par mon premier programme (pour en fait lancer mon programme grâce à une pression sur le bouton-poussoir, avec les DEL qui indiquent l'état du travail), j'obtiens une erreur au lancement : wiringPiSetup*: You must only call this once per program run. This is a fatal error. Please fix your code., mais aucune erreur lors de la compilation.

Le code abrégé du premier programme :

Code : Tout sélectionner

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "LSM9DS1.h" // La fameuse bibliothèque du LSM9DS1.

// Nombre de lectures.
#define nbrOfRec 10000

int main(int argc, char *argv[])
{

	LSM9DS1 imu(IMU_MODE_I2C, 0x6a, 0x1c);

	imu.begin();
	imu.calibrate();

	printf("Starting.\n");
	
	[lecture des valeurs, enregistrement dans des tableaux]
	
	printf("Ending.\n");
	
	[écriture dans un CSV]

	return 1;

}
Le code du second programme (ce ne serait pas plutôt INPUT à mettre dans les pinMode() de mes DEL..?) :

Code : Tout sélectionner

#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

#define SWITCH 0
#define LED_R  2
#define LED_V  3

void blinkLed(int led)
{

	for (int i = 0; i < 15; i++)
	{

		digitalWrite(led, !digitalRead(led));

		delay(100);

	}

}

void switchLed()
{

	wiringPiSetup();

	pinMode(SWITCH, INPUT);
	pinMode(LED_R, OUTPUT);
	pinMode(LED_V, OUTPUT);

	digitalWrite(LED_R, HIGH);
	digitalWrite(LED_V, LOW);

	while (1)
	{

		if (digitalRead(SWITCH) == HIGH)
		{

			digitalWrite(LED_R, LOW);
			digitalWrite(LED_V, HIGH);

			delay(5000);

			digitalWrite(LED_R, HIGH);

			blinkLed(LED_V);

			digitalWrite(LED_V, LOW);

		}

		delay(1);

	}

}

int main(void)
{

	switchLed();
	
	return 0;

}
Pour obtenir le programme fusionné, j'ai inséré tout le contenu du main du premier programme à la place du delay(5000) du second, tout en ajoutant les bons include et les variables.

En ajoutant quelques printf() dans mon premier programme, je me rends compte que c'est la création de mon objet LSM9DS1 imu(IMU_MODE_I2C, 0x6a, 0x1c); qui est à l'origine du message d'erreur, donc je suppose que la fonction wiringPiSetup() est appelée implicitement par la bibliothèque.

J'ai essayé de supprimer la ligne wiringPiSetup(); du second programme, mais dans ce cas les DEL ne s'allument pas et rien ne se passe lorsque j'appuie sur le bouton ; et je ne peux évidemment pas supprimer la création de mon objet LSM9DS1.

Auriez-vous une suggestion à me faire pour résoudre ce problème tout en conservant les fonctionnalités que je souhaite ? Si possible en conservant la bibliothèque LSM9DS1 et WiringPi, mais dans le pire des cas, je me passerai de WiringPi pour gérer le bouton et les DEL en C pur comme dans cet exemple qui me paraît lourd pour le peu que je souhaite faire.

Merci à vous ! :)
Modifié en dernier par Pinhapple le jeu. 23 mars 2017 10:58, modifié 1 fois.
  • RPi 3 + LibreELEC / RPi 3 + RetroPie / RPi B+ + Sense HAT ou Framboisedorf ou module caméra
  • Arduino Mega, Uno, Nano
  • Freescale FRDM KL25Z

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Erreur d'initialisation de WiringPi

Message par Bud Spencer » mer. 22 mars 2017 10:06

Le message d’erreur est suffisamment clair et à mon sens, l’erreur est évidente. En fait le message d’erreur t’explique que tu ne peux pas avoir plusieurs instances de wiringPi dans un même programme.

La librairie que tu utilises pour ton lms9ds1 initialise déjà WinringPi, donc forcément si tu ajoutes un wiringPiSetup(), ça ne peut pas le faire. Je ne sais pas comment la lib pour lms9ds1 initialise wiringPi (il y a plusieurs mode), mais fais juste l’essais en supprimant simplement wiringPiSetup() dans ta void switchLed()
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Pinhapple
Raspinaute
Messages : 125
Enregistré le : jeu. 23 févr. 2017 15:53
Localisation : Rouen

Re: Erreur d'initialisation de WiringPi

Message par Pinhapple » mer. 22 mars 2017 10:38

Bud Spencer a écrit :fais juste l’essais en supprimant simplement wiringPiSetup() dans ta void switchLed()
Déjà essayé, ça bloque les DEL et le bouton-poussoir : en lançant le programme, aucune DEL ne s'allume, et appuyer sur le bouton ne déclenche rien.
Par contre, si je sors la création de l'objet LSM9DS1 du while pour la mettre à la place de wiringPiSetup(), le programme entre dans le if (digitalWrite(SWITCH) == HIGH) et me renvoie une erreur prévue (impossible de communiquer avec le LSM), alors que je n'appuie même pas sur le bouton.

Pour plus de clarté, le code fusionné dans l'état pour lequel je m'attendais à ce qu'il fonctionne :

Code : Tout sélectionner

#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <wiringPi.h>
#include "LSM9DS1.h"

// Number of desired recordings (1 recording = 9 values).
#define nbrOfRec 10000

#define SWITCH 0
#define LED_R  2
#define LED_V  3

void blinkLed(int led)
{

	for (int i = 0; i < 155; i++)
	{

		digitalWrite(led, !digitalRead(led));

		delay(100);

	}

}

// Takes a float and rounds it.
float roundTwoDigits(float f)
{

	return round(f * 100.0) / 100;

}

int main(int argc, char *argv[])
{

	wiringPiSetup();

	pinMode(SWITCH, INPUT);
	pinMode(LED_R, OUTPUT);
	pinMode(LED_V, OUTPUT);

	digitalWrite(LED_R, HIGH);
	digitalWrite(LED_V, LOW);

	while (1)
	{

		if (digitalRead(SWITCH) == HIGH)
		{

			digitalWrite(LED_R, LOW);
			digitalWrite(LED_V, HIGH);

			// Arrays to stock values.
			// 3 dimensions to stock 3 axis.
			float accel[nbrOfRec][3];
			float angSp[nbrOfRec][3];
			float orien[nbrOfRec][3];

			// Initial angles.
			orien[0][0] = 0;
			orien[0][1] = 0;
			orien[0][2] = 0;

			// Turning on the LSM9DS1.
			LSM9DS1 imu(IMU_MODE_I2C, 0x6a, 0x1c);

			imu.begin();

			if (!imu.begin())
			{

				fprintf(stderr, "Failed to communicate with LSM9DS1.\n");

				exit(EXIT_FAILURE);

			}

			imu.calibrate();

			printf("Starting the recording.\n");

			// Recording acceleration and rotation values.
			for (int i = 0; i < nbrOfRec; i++)
			{

				imu.readAccel();

				accel[i][0] = imu.calcAccel(imu.ax);
				accel[i][1] = imu.calcAccel(imu.ay);
				accel[i][2] = imu.calcAccel(imu.az);

				imu.readGyro();

				angSp[i][0] = imu.calcGyro(imu.gx);
				angSp[i][1] = imu.calcGyro(imu.gy);
				angSp[i][2] = imu.calcGyro(imu.gz);

			}

			// Calculating orientation values.
			// The angle at time n is equal to the angle at time n-1 + angular speed at time n-1.
			for (int i = 1; i < nbrOfRec; i++)
			{

				orien[i][0] = orien[i - 1][0] + angSp[i - 1][0];
				orien[i][1] = orien[i - 1][1] + angSp[i - 1][1];
				orien[i][2] = orien[i - 1][2] + angSp[i - 1][2];

			}

			printf("Ending the recording.\n");
			printf("Now writing the recorded values in a file.\n");

			FILE *file;

			file = fopen("RecordedData.csv", "w+");

			fprintf(file, "recNbr,accX,accY,accZ,oriX,oriY,oriZ,rotX,rotY,rotZ\n");

			for (int i = 0; i < nbrOfRec; i++)
			{

				fprintf(file, "%d,", i + 1);

				fprintf(file, "%.2f,", roundTwoDigits(accel[i][0]));
				fprintf(file, "%.2f,", roundTwoDigits(accel[i][1]));
				fprintf(file, "%.2f,", roundTwoDigits(accel[i][2]));

				fprintf(file, "%.2f,", roundTwoDigits(orien[i][0]));
				fprintf(file, "%.2f,", roundTwoDigits(orien[i][1]));
				fprintf(file, "%.2f,", roundTwoDigits(orien[i][2]));

				fprintf(file, "%.2f,", roundTwoDigits(angSp[i][0]));
				fprintf(file, "%.2f,", roundTwoDigits(angSp[i][1]));
				fprintf(file, "%.2f\n", roundTwoDigits(angSp[i][2]));

			}

			fclose(file);

			digitalWrite(LED_R, HIGH);

			blinkLed(LED_V);

			digitalWrite(LED_V, LOW);

		}

		delay(1);

	}

	return 1;

}
Et au cas où, je joint le schéma de mon montage au message.
Fichiers joints
montage_bb.jpg
montage_bb.jpg (109.02 Kio) Vu 11155 fois
  • RPi 3 + LibreELEC / RPi 3 + RetroPie / RPi B+ + Sense HAT ou Framboisedorf ou module caméra
  • Arduino Mega, Uno, Nano
  • Freescale FRDM KL25Z

spourre
Raspinaute
Messages : 735
Enregistré le : lun. 22 déc. 2014 16:50
Localisation : 67380 LINGOLSHEIM

Re: Erreur d'initialisation de WiringPi

Message par spourre » mer. 22 mars 2017 11:25

Re,

Il est fort probable que l'appel d'une des fonctions de la librairie LSM9DS1 initialise déjà cet objet puisque, elle-même, fait appel à la wiringPi.
Pour s'en assurer il faut:
-) décortiquer le code de la librairie LSM9DS1 pour comprendre comment elle s'interpose à la libwiringPi (les fameux niveaux d'abstraction de la dernière discussion).
ET/OU (non exclusif)
-) débugger le code en l’exécutant pas à pas, ou avec des break-points. Pour se faire, il faut installer sur le Raspberry le programme GDB (on y avait fait allusion pour le debug croisé dans la cross-compilation):

http://www.linux-france.org/article/devl/gdb_howto.html

Pour cela, il faut que le programme soit compilé sans l'option strip mais, par défaut, ça doit être OK. C'est facile à vérifier avec la commande file:

Code : Tout sélectionner

file pcf8574_byte
pcf8574_byte: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.32, BuildID[sha1]=61701bb2cf1ecead4aec687451bbbe2cf791a898, not stripped
Bon courage.

Sylvain

guillaume9344
Raspinaute
Messages : 629
Enregistré le : mar. 6 janv. 2015 19:44
Localisation : finistere

Re: Erreur d'initialisation de WiringPi

Message par guillaume9344 » mer. 22 mars 2017 11:31

Bonjour, essayez de mètre dans le début du main juste aprés wiringpisetup, hors de la boucle while la séquence d'initialisation du lsm9ds :

Code : Tout sélectionner

   // Turning on the LSM9DS1.
         LSM9DS1 imu(IMU_MODE_I2C, 0x6a, 0x1c);

         imu.begin();

         if (!imu.begin())
         {

            fprintf(stderr, "Failed to communicate with LSM9DS1.\n");

            exit(EXIT_FAILURE);

         }

         imu.calibrate();
Pour le debugagge, code::block s'en sort pas trop mal meme en natif sur le pi , avec un petit programme comme cela ça passe bien .
rpi b+ ,osmc, motioneyes
rpi 2 raspbian , server minecraft 24h/24 , utilisation gpio
orange pi pc debian ,utilisation gpio, motion cam

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Erreur d'initialisation de WiringPi

Message par Bud Spencer » mer. 22 mars 2017 11:33

C’est normal que cela ne fonctionne pas.
Garde ton montage hardware tel qu’il est et remplace

#define SWITCH 0
#define LED_R 2
#define LED_V 3

Par

#define SWITCH 17
#define LED_R 27
#define LED_V 22

Ensuite, dans ta procédure main, enlève ça de ta boucle while:
// Turning on the LSM9DS1.
LSM9DS1 imu(IMU_MODE_I2C, 0x6a, 0x1c);
imu.begin();
if (!imu.begin())
{
fprintf(stderr, "Failed to communicate with LSM9DS1.\n");
exit(EXIT_FAILURE);
}

Et met y a la place du wiringPiSetup() en début de la procédure.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Pinhapple
Raspinaute
Messages : 125
Enregistré le : jeu. 23 févr. 2017 15:53
Localisation : Rouen

Re: Erreur d'initialisation de WiringPi

Message par Pinhapple » jeu. 23 mars 2017 09:41

Ooooh, bien vu, ça fonctionne ! Merci à vous une fois de plus ;)

@guillaume9344, je suis toujours sans IDE mais juste avec Leafpad... Mais des fois je regrette ! :D

Par contre je ne comprends pas trop pourquoi changer le numéro des pins fonctionne alors que j'utilise toujours WiringPi. :?:
EDIT : D'ailleurs j'ai remarqué que si je repasse aux anciens numéros de pins, le programme n'arrive pas à communiquer avec le LSM (normal du coup), mais que si je remets les nouveaux numéros, l'I2C est complètement déglingué et le programme ne fonctionne plus, obligé de redémarrer le RPi.

D'ailleurs Bud, tu as peut-être remarqué que j'ai ajouté un delay(1); en fin de while (1), comme suggéré en première partie de ton article "Penser 'Thread' pour simplifier vos programmes", afin de soulager un peu le CPU. ;)
  • RPi 3 + LibreELEC / RPi 3 + RetroPie / RPi B+ + Sense HAT ou Framboisedorf ou module caméra
  • Arduino Mega, Uno, Nano
  • Freescale FRDM KL25Z

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Erreur d'initialisation de WiringPi  [RESOLU]

Message par Bud Spencer » jeu. 23 mars 2017 10:19

Pinhapple a écrit :Ooooh, bien vu, ça fonctionne ! Merci à vous une fois de plus ;)
Par contre je ne comprends pas trop pourquoi changer le numéro des pins fonctionne alors que j'utilise toujours WiringPi. :?:
Tu sais, moi je me suis juste penché sur le code source de la librairie que tu utilises pour ton LSM9DS1, et j’ai vu que la méthode d’initialisation de wiringPi utilisé était ‘wiringPiSetupGpio()’ ( https://github.com/akimach/LSM9DS1_Rasp ... SM9DS1.cpp ligne 46).

Ensuite en consultant la doc de wiringPi, j’ai aussi vu qu’il y avait 4 méthodes pour l’initialiser ( http://wiringpi.com/reference/setup/ ). Pour celle qui nous concerne ici, (wiringPiSetup() et wiringPiSetupGPIO()), l’une utilise un mappage pour renuméroter les n° de pin et l’autre utilise des n° de pin sans renumérotage. Donc vu que c’est ta librairie du LMS qui initialise wiringPi et qu’elle le fait en utilisant wiringPiSetupGPIO(), tu dois utiliser le numérotage ‘BCM GPIO’ et non le numérotage wiringPi (https://projects.drogon.net/raspberry-pi/wiringpi/pins/).

moralité : RTFM ! ;)

J’ai vu que tu avais mis une petite tempo et c’est bien. Ça ralenti la boucle de détection d'appuis sur le bouton et ce n'est pas plus mal, ca fait un peu 'antirebond' et en plus ça soulage le proc. On pourrait beaucoup améliorer ton code pour le rendre plus efficace et plus robuste, mais pour un débutant, je trouve que c’est déjà très bien et en plus j'imagine que ce n’est encore qu'au stade expérimental.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Pinhapple
Raspinaute
Messages : 125
Enregistré le : jeu. 23 févr. 2017 15:53
Localisation : Rouen

Re: Erreur d'initialisation de WiringPi

Message par Pinhapple » jeu. 23 mars 2017 10:57

Bud Spencer a écrit :Ensuite en consultant la doc de wiringPi, j’ai aussi vu qu’il y avait 4 méthodes pour l’initialiser ( http://wiringpi.com/reference/setup/ ). Pour celle qui nous concerne ici, (wiringPiSetup() et wiringPiSetupGPIO()), l’une utilise un mappage pour renuméroter les n° de pin et l’autre utilise des n° de pin sans renumérotage. Donc vu que c’est ta librairie du LMS qui initialise wiringPi et qu’elle le fait en utilisant wiringPiSetupGPIO(), tu dois utiliser le numérotage ‘BCM GPIO’ et non le numérotage wiringPi (https://projects.drogon.net/raspberry-pi/wiringpi/pins/).
Bon raisonnement, je m'étais pour ma part arrêté à la deuxième étape en fouillant également dans les sources de la bibliothèque pour y trouver le wiringPiSetupGPIO() et le comparer avec la doc de WiringPi. J'aurais probablement continué de creuser si je n'avais pas eu ce problème de deux initialisations de WiringPi, puisque du coup les DEL ne se seraient pas allumées non plus. ;)
Bud Spencer a écrit :J’ai vu que tu avais mis une petite tempo et c’est bien. Ça ralenti la boucle de détection d'appuis sur le bouton et ce n'est pas plus mal, ca fait un peu 'antirebond' et en plus ça soulage le proc. On pourrait beaucoup améliorer ton code pour le rendre plus efficace et plus robuste, mais pour un débutant, je trouve que c’est déjà très bien et en plus j'imagine que ce n’est encore qu'au stade expérimental.
Là c'est le fonctionnel, je verrai après en fonction de mes besoins pour l'optimiser ! Merci pour les remarques, ça m'encourage à continuer ! :)
  • RPi 3 + LibreELEC / RPi 3 + RetroPie / RPi B+ + Sense HAT ou Framboisedorf ou module caméra
  • Arduino Mega, Uno, Nano
  • Freescale FRDM KL25Z

spourre
Raspinaute
Messages : 735
Enregistré le : lun. 22 déc. 2014 16:50
Localisation : 67380 LINGOLSHEIM

Re: Erreur d'initialisation de WiringPi

Message par spourre » jeu. 23 mars 2017 11:29

Pinhapple a écrit :Ooooh, bien vu, ça fonctionne ! Merci à vous une fois de plus ;)

@guillaume9344, je suis toujours sans IDE mais juste avec Leafpad... Mais des fois je regrette ! :D
Quel que soit l'IDE que tu finiras par adopter, il reposera sur gdb en mode serveur sur le Raspberry car le code ne peut s'éxécuter, en natif, que sur le Raspberry (surtout pour le GPIO et les périphériques).
Alors ce n'est pas une urgence mais autant s'y mettre petit à petit, en ligne de commande.
C'est comme la compil (cross ou native), il est préférable de comprendre (voire maîtriser) la CLI avant de passer aux clickodromes.
Petit complément à mon dernier post, pour utiliser gdb il faut ajouter l'option -g à la compilation et il est préférable d'avoir le fichier source, dans le même répertoire que le programme en cours de debugg. C'est beaucoup plus parlant de parler en numéro de ligne ou en nom de fonction pour poser un point d'arrêt (breakpoint).

Sylvain

Répondre

Retourner vers « Le GPIO »