62) 02/03/2018 : Rechargement de la version P sur les consoles (MJD 58179)

Déjà le mois des giboulées qui pointe son museau. Nous sommes tous ravis, car nous avons reçu les nouveaux badges avec le LOGO de la NDRMSE. C’est un peu idiot, mais une certaine fierté à le porter démontre à quel point les personnels sont attachés à ce projet. Pour le moment JEKERT est endormie, mais personne ne doute qu’elle remplira vaillamment sa mission. Sur l’orbite de transfert qui la conduit à destination, elle a franchi plus de la moitié de la distance. Maintenant le Soleil la ralentit, car durant la première moitié de la trajectoire il l’attirait dans son emprise, mais elle a franchi le périhélie avec une vitesse considérable qui va la faire « remonter » jusqu’à Mars. Elle ne commencera à réaccélérer que lorsqu’elle arrivera dans sa sphère d’influence. Ce n’est pas demain la veille, les ingénieurs ont largement le temps de lui préparer encore quelques petits programmes.

Recharger P21 version P sur l’ATmega328.

Poursuivre l’analyse des améliorations apportées au logiciel implique de le téléverser à nouveau, avec en début de son listage source la grande table Image_LOGO[228]. Elle a changé de nom pour avoir un identificateur plus parlant, mais surtout elle a subit un amaigrissement, passant de 258 octets à 228 soit une « perte de poids » de 30 octets. Nous verrons plus avant la raison de ce changement, car le dessin n’est pas modifié, impliquant qu’il a fallu compenser par tracé de segments de droite pour reconstituer l’image intégrale. Observez maintenant une autre petite modification :
• RESET > Un BP pour démarrer le programme > Touche DONNEES >
• Activer le BPccr pour allumer la LED bleue du mode graphique >
• Touche OPTIONS > BPccr pour allumer la LED SÉCURITÉ >
BPccr jusqu’à afficher l’item AFF. Nav. continu ? > OUI >
À ce stade l’écran ne montre rien de bien nouveau.
BPccr pour sélectionner la référence interne Gyroscopique :
En affichage graphique la valeur du Calage GYRO. n’est plus affichée et remplacé par « //// » car correspond à une donnée interne au MPU6050. Ce n’est pas un paramètre vraiment opérationnel et en afficher la valeur peut prêter à confusion quand on observe l’Ecart de route. C’est le « bug » du CAP Magnétique qui est affiché en permanence, car il correspond à la direction dans laquelle on désire aller. L’interprétation de l’écran est plus simple, augmentant la convivialité d’utilisation.


Représentation graphique du spectre colorimétrique.

Rentabilité toujours aussi médiocre puisque le programme à ce stade ne consomme que 84% de l’espace disponible. Il reste encore 4384 octets à dilapider dans notre escarcelle. Hors de question de laisser toutes ces cellules à $FF. Afficher les valeurs mesurées d’énergie du spectre colorimétrique sous forme d’un Barregraphe est bien plus parlant que sept valeurs numériques. La Fig.342 en donne un exemple de représentation. Chaque barre verticale présente une hauteur proportionnelle à son pourcentage énergétique. Les lettres dans la zone jaune précisent la couleur concernée :
T : Luminosité Totale     B : Bleu     M : Mauve
R : Rouge     O : Orange     J : Jaune     V : Vert
La barre pour T occupera systématiquement l’intégralité de la hauteur du cadre bleu pour « dilater » au maximum l’amplitude verticale du graphe. En 1 est indiquée la valeur totale mesurée sans la filtration. Elle correspond à la hauteur du cadre bleu. En 2 comme l’indique le symbole   est précisée la valeur pour la couleur la plus énergétique. Dans cet exemple c’est le jaune. En 4 nous trouvons la valeur numérique de la couleur la moins énergétique symbolisée par . La ligne pointillée 5 représente la valeur moyenne de toutes les couleurs. ATTENTION, ce n’est pas la valeur moyenne entre le maximum et le minimum (Qui ici vaudrait (692 + 482) / 2 = 587.) mais bien la moyenne des six valeurs énergétiques du spectre. Dans l’exemple présenté sur la Fig.342 elle vaut :  = (594 + 482 + 531 + 632 + 692 + 642) / 6 = 3573 / 6 = 595,5. Il est donc normal que la ligne pointillée 5 ne soit pas exactement à mi-hauteur entre la barre représentative du Mauve et celle du Jaune. Le barregraphe engloutit 1148 octets soit environ 5% de l’espace mémoire réservé au programme. C’est vraiment un produit de luxe ! Il faut toutefois relativiser un fifrelin. En effet, l’affichage textuel des versions précédentes ne présente plus d’intérêt. Il a donc été purement enlevé des options. Cette simplification engendre un gain en taille de programme d’autant plus important que les textes pour préciser les couleurs ont été enlevés de l’EEPROM. La place ainsi libérée a été remplacée par d’autres textes diminuant d’autant l’embonpoint du code objet. Au passage, faites afficher la Posture actuelle dans le menu EXPLOITER. Sortez correctement de cette fonction avec FIN. La petite erreur de programme est corrigée. Maintenant l’écran s’efface correctement.

Des postures à gogo !

Exagérée ce titre, en réalité on ne pourra en sauvegarder que huit au maximum. Durant les diverses campagnes de tests, notamment pour la mise au point du pilotage manuel des moteurs, des configurations originales ou séduisantes ont été expérimentées. Quand on a passé un bon moment à peaufiner une configuration particulière, l’envie de la pérenniser s’impose. Aussi, reprendre la gestion de l’EEPROM de la sonde et ajouter les instructions nécessaires pour pouvoir immortaliser plusieurs postures originales devenait « prioritaire » dans la mesure où il reste encore 3176 emplacements non utilisés dans l’espace réservé au programme. Pour la modique somme de 306 octets on peut se faire raisonnablement ce petit plaisir. Avec 91% d’occupation, on passe la barre psychologique des 9/10, coté rentabilité on commence à se sentir mieux.
Pour implanter ces données en mémoire non volatile EEPROM, il nous faut revoir « le plan d’occupation des sols ». Nous en étions à la répartition des informations représentée en Fig.288 qui laissait tout le haut de la mémoire disponible à partir de l’adresse 768. Chaque posture contient douze consignes codées sur des int soit 24 octets. Il serait possible d’en sauvegarder 255 / 24 = 10,625. (255 est la taille actuelle de la zone libre en haut de la mémoire EEPROM.) Pour simplifier le logiciel on limitera leur n° à un seul chiffre significatif. Le nombre maximum possible sera donc de neuf configurations. Initialement, pour simplifier le logiciel il a été décidé de loger chaque posture sur des zones de 32 octets. (Voir la Fig.343) Le nombre maximum possible est alors de huit, et comme on utilise la procédure de sélection d’un programme du menu APPRENDRE , si 9 a été sélectionné nous aurons génération d’une erreur E11. Au final, ce n’est pas une très bonne idée. Il serait préférable de placer les postures les unes à la suite des autres et d’en limiter naturellement le nombre à neuf lors de la saisie. Si le cœur vous en dit …
La méthode retenue pour pouvoir choisir entre les huit empreintes possibles n’est pas du tout compliquée. Elle consiste à ajouter un item vu sur la Fig.344 qui recopie la valeur de l’index de programme dans le n° de posture traitée pour l’affichage et pour l’utilisation. Le protocole pour sélectionner une posture parmi les huit possible est précisé dans le manuel d’utilisation du pupitre au chapitre > Protocole pour indexer le n° de posture EEPROM et reproduit ci-dessous pour que vous puissiez l’expérimenter avec P21P.
1) Activer le menu APPRENDRE,
2) Un pas en Rotation pour avoir l’item Changer PGM EEPROM,
3) OUI pour valider la saisie, (Le cadre jaune indique le n° actuel)
4) Rotation ou ⊆, pour imposer le n° désiré, (Valeurs de 1 à 8)
5) Sortir de la saisie par FIN,
6) Activer le menu des POSTURES,
7) Deux pas en Rotation ⊇ pour Pointer POSTURE n°N ?,
8) Touche OUI pour la valider. La consigne 99 est envoyée à la sonde. Si la valeur est valide l’ACR est OK, si N vaut 9 un E11 est généré assorti d’un BIP sonore.
Scratchhh prouitchhh bom bring protchhhh ! Normalement, avec toutes ces onomatopées vous devriez comprendre qu’un incident grave vient de se produire. Si ce n’est pas le cas, je peux vous en ajouter quelques lignes ! C’est un peu comme le SIDA. La toute première fois qu’il en a été question au journal télévisé de 20h, le présentateur n’a évoqué ce sigle qu’en quelques phrases. Et puis il est passé à des thèmes bien plus importants comme les résultats sportifs du moment. Discrétion, oublie … et quelques années plus tard, c’est mondialement que le sigle SIDA occupe la tête d’affiche. COLLISION DE PILE, ces trois mots constituent le « SIDA de l’informaticien ». Ce virus s’insère dans le programme avec une sournoiserie absolue et cause une épidémie dramatique. Particulièrement délicat à diagnostiquer ce problème vicieux peut arriver alors que tout semble normal. Par exemple, ayant ajouté la séquence qui permet d’enregistrer jusqu’à huit posture, le programme semblait fonctionner correctement. Vérification effectuée, dans le menu EXPLOITER l’item de la Fig.345 montre que maintenant en A est précisée l’empreinte actuellement pointée en mémoire. La sauvegarde ainsi que le rechargement de la posture visée s’avérait corrects et ce pour les huit emplacements possibles. Bref, nous pouvions voir la vie en rose. Et PAHTATRAKKKKkkkkkk ! (Une exclamaturgique de plus !) Allant dans le menu des DONNEES certains affichages étaient devenus totalement incohérents.
x

Collision entre la PILE et le TAS !

Phénomène particulièrement sournois, la collision de pile survient brusquement sans qu’aucun signe avant-coureur ne nous prévienne. Pour comprendre de quoi il s’agit, il faut entrer dans la vie intime du fonctionnement des microcontrôleurs. Il serait hors propos dans ces lignes d’étudier à la loupe l’agencement matériel de l’ATmega328 est d’en détailler finement le fonctionnement interne. Nous allons dans ce chapitre nous en tenir au strict minimum vital.
Fonctionnement de la mémoire vive SRAM.
La mémoire vive (256 + 2Ko) est généralement divisée en quatre zones :
• Les 256 premiers octets pour les registres généraux du microcontrôleur (Représentée en jaune sur la Fig.346) occupent « le bas » de la SRAM.
• La zone nommée BSS qui contient toutes les variables globales, allouées statiquement au moment de l’édition de lien lors de la compilation. La BSS est utilisée par de nombreux compilateurs pour désigner une zone de données contenant les variables statiques déclarées dans les initialisations, et les déclarations.
• Le TAS sur lequel on entasse du bas vers le haut est destiné aux allocations dynamiques dans lequel on peut attribuer et libérer des blocs de mémoire. (Nommé HEAP) Le TAS se fragmente généralement au cours de l’évolution du programme, (Car une variable locale libérant de la place laisse « un trou » non utilisé.) avec un risque notable de le rendre inutilisable.
Défragmenter HEAP par une séquence de code de type « Ramasse miettes » est faisable mais relativement dangereux, car si l’on déplace une variable en cours d’utilisation, les conséquences peuvent s’avérer ingérables.
(@) : Sur la Fig.345 les noms des divers pointeurs sont imposés par le compilateur de l’IDE.
• La PILE nommée STACK mémorise temporairement :
* Les paramètres associés à l’appel des fonctions et procédures,
* Les adresses de retour des fonctions et procédures,
* Les variables locales aux fonctions et procédures.
La PILE est une zone de mémoire commençant en haut de la SRAM qui se charge vers le bas de façon linéaire et continue lors des appels des fonctions ou des procédures. Elle se réduit vers le haut lors des retours. Chaque appel à une procédure suppose que lorsque cette dernière s’achève, le déroulement du programme doit passer à la suite. Pour aborder d’une façon volontairement très simplifiée le fonctionnement du compilateur, nous allons raisonner sur la fig.347 qui dans la boucle de base void loop() enchaîne deux procédures. Arrivé à la ligne d’instruction (1) l’analyseur syntaxique sait que le microcontrôleur va devoir « se brancher » sur les instructions de ce qui pour le programmeur est un identificateur nommé TRAITER_LE_CLAVIER(). L’analyseur syntaxique « saute » l’accolade { et recherche la première instruction cohérente qui suit. Il note alors l’adresse dans le programme du début de cette subroutine dans une cellule nommée Tester_le_clavier. Le déroutement ne peut se faire immédiatement. En effet, que devra faire l’ATmega328 quand toutes les instructions de la subroutine auront été déroulées, événement jalonné par la « fermeture du bloc » avec } ? .
Il faudra passer à la suite du programme, c’est à dire en ligne (2). Hors le microcontrôleur ne peut pas inventer cette adresse de retour. Donc, avant de brancher sur Tester_le_clavier par la route colorée en bleu ciel, le compilateur demande à l’ATmega328 d’EMPILER l’adresse de retour de procédure. Quand le programme arrive à l’instruction « Retour de procédure » en }, l’adresse est DÉPILÉE et le processeur se branche sur cette dernière. Vous avez noté que chaque appel à une fonction, à une procédure, à une interruption, c’est à dire toute
x
instruction qui déroute le programme, le microcontrôleur commence par empiler deux octets d’adresse. La distance qui sépare le TAS et la PILE diminue d’autant. N’oublions pas que les chaînes de caractères et les tableaux sont placée sur le TAS. Sans que nous en ayons conscience, la zone libre peut rapidement devenir trop faible pour tout contenir.

Configuration qui produit la collision de PILE avec le TAS.

Concrètement, bien que l’on utilise l’expression « COLLISION DE PILE », le pointeur PILE est injustement accusé. C’est l’inverse qui se produit. Dans notre programme, nous avons un nombre d’octets significatifs qui sont entassés sous forme des chaînes de caractères. Et puis on a dilapidé 258 emplacements pour loger le tableau qui représente notre merveilleux LOGO. Suite aux méthodes préconisées dans ce didacticiel, on privilégie des subroutines « simples » qui font appel à des procédures et des fonctions. Elles même récursivement vont invoquer d’autres séquences, avec passage de paramètres qui s’empilent à leur tour. Et puis on oublie qu’un nombre important d’interruptions se produisent en tâche de fond. Le codeur rotatif génère des interruptions … mais il est loin d’être le seul coupable. Les fonctions delay(), millis(), la PWM … une foule de ressources internes déclenche des interruptions. C’est transparent car c’est le compilateur C++ qui sur ces instructions fait sa cuisine interne. Arrive un moment, ou trop de données sont empilée sur le TAS et viennent écraser les adresses empilées. À ce stade, tout va encore pour le mieux. Puis le délimiteur } demande au processeur de dépiler une adresse de retour. Comme cette dernière contient les résidus de la variable qui a « écrasé » les octets, le programme se « branche » strictement n’importe où. Étant alors sur du code objet incohérent, le comportement du logiciel devient totalement aléatoire. C’est ce qui s’est passé sur le démonstrateur et qui nous a imposé d’apporter un remède à cette situation incongrue.
PRÉVENTIF : Aucun programmeur n’est à l’abri d’une telle « catastrophe ». Aussi, pour minimiser les risques il faut placer le minimum de chaînes de caractères dans le programme car en réalité elles sont placées sur le TAS. Il faut également minimiser les tableaux. Enfin, quand le programme est terminé, il importe de vérifier que le risque est faible en faisant afficher la place encore disponible entre la PILE et le TAS. Le compilateur C++ d’Arduino nous fournit des outils pour ça.
CURATIF : Quand se produit le Scratchhh prouitchhh bom bring protchhhh ! c’est qu’il est trop tard. Nous avons placé plein plein plein de bavardages, alors que nous savons que ces « bla bla bla » sont entassés dans la mémoire dynamique. Notre démonstrateur comporte une foule de procédures et de fonctions qui passent des paramètres, sans compter les for (byte I=1, …) qui ne sont pas gratuits. Les variables locales des boucles for doivent bien se voir loger en RAM. Enfin avec notre tableau LOGO qui se goinfre de 258 octets, avouez que l’on a poussé le bouchon un peu loin !
REMÈDE : Dégager impérativement de la place sur le TAS.
Avec un peu d’expérience, le programmeur repère assez rapidement les gros consommateurs d’octets sur le TAS. D’une façon générale il ne sera pas possible de diminuer le nombre des variables locales. De toute manière ce n’est pas la solution, car en général c’est du « gagne petit ». La première solution consiste à placer les textes en EEPROM, ce n’est pas nouveau. Pour JEKERT ce n’était pas possible puisque cette méthode a été respectée à profusion. C’est à ce stade que l’analyse du programme a montré qu’afficher en textuel le spectre colorimétrique devenait peu utile. Fonction abandonnée les emplacements ainsi libérés ont permis d’utiliser les « trous » par d’autres textes qui étaient présents dans les instructions « Bla bla bla » du programme conduisant à la version ultime de P35_Ecrire_les_textes_en_EEPROM.ino qui sur les démonstrateurs à fichu un peu la pagaille.
Examinant avec un peu plus de sagacité la belle fresque Image_LOGO[228] on observe sur la Fig.348 que le bas de l’image ne comporte pas beaucoup de pixels allumés. On peut sans vergogne supprimer dans le tableau les octets relatifs aux cinq lignes du bas ce qui économise 5 x 6 = 30 octets sur le TAS. Pour reconstituer le dessin des points coloriés en orange, il faudra tracer deux lignes et un point. Cette correction va ajouter quelques octets au code objet, pas grand chose au regard de ce qui reste encore disponible, car ces derniers seront logés en zone programme. Après ces deux mesures drastiques, le programme a retrouvé sa bonne humeur. (Et surtout le programmeur !) Bon, le pupitre ronronne, les écrans sont impeccables bref tout va bien. Au fait, sommes-nous certains que l’espace dynamique est suffisant ? L’accident est toujours possible, aussi nous allons prendre une assurance pour limiter les dégâts.

Prendre une assurance contre les collisions de PILE.

Invoquer du préventif n’est pas une arme absolue. Quand je programmais en binaire avec des assembleurs, la seule façon absolue consistait à écrire des $00 dans toute la zone située entre le TAS et le haut de la PILE. Puis le programme était activé en utilisant toutes ses fonctionnalités. (C’est plus délicat à faire qu’à dire !) Enfin, quand il avait « tourné » pendant plusieurs heures, on listait la zone en question. Les octets contigus encore à $00 vers le milieu de la mémoire dynamique étaient significatifs de la marge de sécurité. En théorie, un seul octet serait suffisant, mais pour des raisons de fiabilité, je décidais qu’il fallait au moins cinquante cellules de marge.
x
Observez le démonstrateur dans lequel, en procédure void setup() se trouve une séquence qui ressemble à celle de la Fig.349 composée de quatre lignes de remarques qui constituent notre police d’assurance. Transformez les deux lignes centrales en supprimant dans le logiciel source les // pour activer les instructions qui s’y trouvent. Téléversez cette nouvelle version du programme. Le LOGO s’affiche, donc il est actuellement sur le TAS. Cliquez sur un bouton poussoir quelconque du clavier. L’écran s’efface et affiche la valeur 261 . C’est la distance en octets qui actuellement sépare la PILE du TAS. Une longue expérience semble montrer qu’il ne faut vraiment pas descendre en dessous de 100 octets, car le risque de collision par fragmentation de la zone devient exagéré. Avec 261 emplacements on peut considérer que nous avons une bonne marge de sécurité. Notez au passage que le compilateur indique que la place disponible pour les variables locales est encore de 1329 octets de disponible … tout va bien dans le meilleur des mondes. Enfin, je vous recommande très très fortement de toujours effectuer ce test quand vous venez de terminer un programme. Marge de sécurité vérifiée, vous repassez les deux lignes en remarque. Affaire classée !
La suite est ici.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *