Toute la vérité sur RTOS. Article # 31. Diagnostics et vérification des erreurs RTOS



La gestion des erreurs n'est pas la chose la plus courante pour les systèmes d'exploitation conçus pour les applications de systèmes embarqués. Il s'agit d'un résultat inévitable de ressources limitées, car tous les systèmes embarqués ont certaines restrictions. Et seul un petit nombre de ces systèmes ont la capacité de se comporter comme des systèmes de bureau, c'est-à-dire d'offrir à l'utilisateur la possibilité de choisir des actions en cas d'événements exceptionnels.

Dans Nucleus SE, en général, il existe trois types de vérification des erreurs:
  • des moyens pour vĂ©rifier la santĂ© de la configuration sĂ©lectionnĂ©e pour s'assurer que les paramètres sĂ©lectionnĂ©s ne conduisent pas Ă  des erreurs;
  • Ă©ventuellement inclus du code pour vĂ©rifier le comportement d'exĂ©cution;
  • Certaines fonctions API qui contribuent au dĂ©veloppement de code plus robuste.

Tout cela sera discuté dans cet article, ainsi que quelques idées concernant les diagnostics par l'utilisateur.

Articles précédents de la série:
Article # 30. Procédures d'initialisation et de démarrage de Nucleus SE
Article # 29. Interruptions dans Nucleus SE
Article # 28. Minuteries logicielles
Article # 27. Heure système
Article # 26. Canaux: services auxiliaires et structures de données
Article # 25. Canaux de données: introduction et services de base
Article # 24. Files d'attente: services auxiliaires et structures de données
Article # 23. Files d'attente: introduction et services de base
Article # 22. Boîtes aux lettres: services auxiliaires et structures de données
Article # 21. Boîtes aux lettres: introduction et services de base
Article # 20. Sémaphores: services auxiliaires et structures de données
Article # 19. Sémaphores: introduction et services de base
Article # 18. Groupes d'indicateurs d'événements: services d'assistance et structures de données
Article # 17. Groupes de drapeaux d'événements: introduction et services de base
Article # 16. Signaux
Article # 15. Partitions de mémoire: services et structures de données
Article # 14. Sections de mémoire: introduction et services de base
Article # 13. Structures de données de tâche et appels d'API non pris en charge
Article # 12. Services pour travailler avec des tâches
Article # 11. Tâches: configuration et introduction à l'API
Article # 10. Scheduler: fonctionnalités avancées et préservation du contexte
Article # 9. Scheduler: implémentation
Article # 8. Nucleus SE: conception interne et déploiement
Article # 7. Nucleus SE: Introduction
Article # 6. Autres services RTOS
Article # 5. Interaction et synchronisation des tâches
Article # 4. Tâches, changement de contexte et interruptions
Article # 3. Tâches et planification
Article # 2. RTOS: Structure et mode temps réel
Article # 1. RTOS: introduction.


Vérifier les paramètres


Nucleus SE a été conçu en mettant l'accent sur une configurabilité utilisateur élevée, ce qui devrait garantir la meilleure utilisation des ressources disponibles. Une telle configurabilité est une tâche complexe, car le nombre de paramètres possibles et les interdépendances entre eux sont énormes. Comme indiqué dans de nombreux articles précédents, la plupart des étapes utilisateur pour configurer Nucleus SE sont effectuées à l'aide des directives #define dans le fichier nuse_config.h .

Pour aider à identifier les erreurs de configuration, nuse_config_check.h est inclus dans le fichier nuse_config.c via #include , qui effectue des vérifications d'intégrité sur les directives #define . Voici un extrait de ce fichier:
/*** Tasks and task control ***/ #if NUSE_TASK_NUMBER < 1 || NUSE_TASK_NUMBER > 16 #error NUSE: invalid number of tasks - must be 1-16 #endif #if NUSE_TASK_RELINQUISH && (NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER) #error NUSE: NUSE_Task_Relinquish() selected - not valid with priority scheduler #endif #if NUSE_TASK_RESUME && !NUSE_SUSPEND_ENABLE #error NUSE: NUSE_Task_Resume() selected - task suspend not enabled #endif #if NUSE_TASK_SUSPEND && !NUSE_SUSPEND_ENABLE #error NUSE: NUSE_Task_Suspend() selected - task suspend not enabled #endif #if NUSE_INITIAL_TASK_STATE_SUPPORT && !NUSE_SUSPEND_ENABLE #error NUSE: Initial task state enabled - task suspend not enabled #endif /*** Partition pools ***/ #if NUSE_PARTITION_POOL_NUMBER > 16 #error NUSE: invalid number of partition pools - must be 0-16 #endif #if NUSE_PARTITION_POOL_NUMBER == 0 #if NUSE_PARTITION_ALLOCATE #error NUSE: NUSE_Partition_Allocate() enabled – no partition pools configured #endif #if NUSE_PARTITION_DEALLOCATE #error NUSE: NUSE_Partition_Deallocate() enabled – no partition pools configured #endif #if NUSE_PARTITION_POOL_INFORMATION #error NUSE: NUSE_Partition_Pool_Information() enabled – no partition pools configured #endif #endif 

Le code ci-dessus effectue les vérifications suivantes:
  • vĂ©rifier qu'au moins une, mais pas plus de seize tâches sont configurĂ©es;
  • Confirmation que les fonctions API sĂ©lectionnĂ©es sont compatibles avec le planificateur sĂ©lectionnĂ© et d'autres paramètres spĂ©cifiĂ©s;
  • vĂ©rification que pas plus de seize instances d'autres objets du noyau ont Ă©tĂ© créées;
  • Confirmation que les fonctions API liĂ©es aux objets non dĂ©clarĂ©s n'ont pas Ă©tĂ© sĂ©lectionnĂ©es.
  • s'assurer que les fonctions API pour les signaux et l'heure système ne sont pas utilisĂ©es lorsque la prise en charge de ces services est dĂ©sactivĂ©e;
  • vĂ©rification du type d'ordonnanceur sĂ©lectionnĂ© et des paramètres associĂ©s.

Dans tous les cas, la détection d'erreurs conduit à l'exécution de la directive #error lors de la compilation. Cela provoque généralement l'arrêt de la compilation et l'affichage du message correspondant.

Ce fichier ne garantit pas l'impossibilité de créer une configuration / configuration incorrecte, mais le rend très peu probable.

Vérification des paramètres de l'API


Comme Nucleus RTOS, Nucleus SE a la possibilité d'inclure du code pour vérifier les paramètres d'appel des fonctions API au moment de l'exécution. Habituellement, cela n'est utilisé que lors du débogage et des tests initiaux, car dans le code de programme final, une consommation excessive de mémoire n'est pas souhaitable.

La vérification des paramètres est activée en définissant le paramètre NUSE_API_PARAMETER_CHECKING dans le fichier nuse_config.h sur TRUE . Cela conduit à la compilation du code supplémentaire requis. Voici un exemple de vérification des paramètres d'une fonction API:
 STATUS NUSE_Mailbox_Send(NUSE_MAILBOX mailbox, ADDR *message, U8 suspend) { STATUS return_value; #if NUSE_API_PARAMETER_CHECKING if (mailbox >= NUSE_MAILBOX_NUMBER) { return NUSE_INVALID_MAILBOX; } if (message == NULL) { return NUSE_INVALID_POINTER; } #if NUSE_BLOCKING_ENABLE if ((suspend != NUSE_NO_SUSPEND) && (suspend != NUSE_SUSPEND)) { return NUSE_INVALID_SUSPEND; } #else if (suspend != NUSE_NO_SUSPEND) { return NUSE_INVALID_SUSPEND; } #endif #endif 

Une telle vérification des paramètres peut conduire au fait que l'appel API produira un code d'erreur. Il s'agit d'une valeur négative de la forme NUSE_INVALID_xxx (par exemple, NUSE_INVALID_POINTER ) - un ensemble complet de définitions est contenu dans le fichier nuse_codes.h .

Pour traiter les valeurs d'erreur, un code d'application supplémentaire (éventuellement créé à l'aide d'une compilation conditionnelle) peut être ajouté, cependant, pour les détecter, il est préférable d'utiliser les outils de surveillance des données des débogueurs de firmware modernes.

La vérification des paramètres entraîne une consommation de mémoire supplémentaire (code supplémentaire) et affecte les performances du code, par conséquent, son utilisation affectera l'ensemble du système. Étant donné que l'intégralité du code source de Nucleus SE est disponible pour le développeur, la vérification et le débogage peuvent être effectués manuellement sur le code d'application final si une précision absolue est requise.

Vérification de la pile des tâches


Jusqu'à ce que le planificateur d'exécution jusqu'à l'exécution soit utilisé, Nucleus SE offre la possibilité de vérifier la pile de tâches, qui est similaire à une fonction similaire dans Nucleus RTOS et affiche l'espace restant sur la pile. Cet appel d'utilitaire API ( NUSE_Task_Check_Stack () ) a été décrit en détail dans un article précédent (# 12). Quelques idées pour vérifier les erreurs de pile sont fournies plus loin dans cet article dans la section Diagnostics personnalisés.

Informations sur la version


Nucleus RTOS et Nucleus SE ont une fonction API qui renvoie simplement les informations de version / build du noyau.

Appel de l'API Nucleus RTOS


Prototype d'appel de service:
CHAR * NU_Release_Information (VOID);

Paramètres: aucun.

Valeur de retour:
Pointeur vers une chaîne contenant des informations de version se terminant par un octet nul.

Appel API Nucleus SE


Cet appel d'API prend en charge la fonctionnalité principale de l'API Nucleus RTOS.

Prototype d'appel de service:
char * NUSE_Release_Information (void);

Paramètres: aucun.

Valeur de retour:
Pointeur vers une chaîne contenant des informations de version se terminant par un octet nul.

Passer un appel pour obtenir des informations sur l'assemblage Nucleus SE


L'implémentation de cet appel API est assez simple. Un pointeur est renvoyé sur la ligne constante NUSE_Release_Info , qui est déclarée et initialisée dans le fichier nuse_globals.c .

Cette ligne a la forme Nucleus SE - Xyymmmdd , oĂą:
X - état de construction: A = alpha; B = bêta; R = libération
aa - année de sortie
mm - mois de sortie
jj - jour de sortie

Compatible avec Nucleus RTOS


Nucleus RTOS contient la prise en charge optionnelle du magazine historique. Le noyau enregistre les détails des différentes actions du système. Il existe des fonctions API qui permettent aux programmes de:
  • activer / dĂ©sactiver la journalisation;
  • crĂ©er une entrĂ©e de journal;
  • Obtenez une entrĂ©e de journal.

Cette fonctionnalité n'est pas prise en charge dans Nucleus SE.

Nucleus RTOS dispose également de plusieurs macros de gestion des erreurs qui vous permettent de ne pas effectuer de confirmation d'erreur (ASSERT) et offrent la possibilité d'appeler des fonctions d'erreur critique définies par l'utilisateur. Ils sont éventuellement inclus dans l'assemblage du système d'exploitation. Nucleus SE ne prend pas en charge cette fonctionnalité.

Diagnostics utilisateur


Jusqu'à présent, dans cet article, nous avons examiné les outils de diagnostic et de vérification des erreurs fournis par Nucleus SE lui-même. Maintenant, il vaut la peine de dire comment les outils de diagnostic définis par l'utilisateur ou orientés vers une application spécifique peuvent être implémentés en utilisant les outils fournis par le noyau et / ou nos connaissances sur sa structure interne et son implémentation

Diagnostics spécifiques à l'application


Dans presque toutes les applications, vous pouvez ajouter du code supplémentaire pour vérifier son intégrité lors de l'exécution. Le noyau multitâche facilite et simplifie la création d'une tâche spéciale pour ce travail. Évidemment, dans cet article, nous ne considérerons pas les cas de diagnostic trop inhabituels, mais considérons quelques idées générales.

Vérifications de la mémoire


De toute évidence, le bon fonctionnement de la mémoire est essentiel à l'intégrité de tout système de processeur. Il n'est pas moins évident qu'une erreur critique ne vous permettra pas d'exécuter, pas seulement des diagnostics, mais l'ensemble du produit logiciel dans son ensemble ( Note du traducteur: Au fait, c'est exactement le cas que nous avons examiné dans l' article «Fake Blue Pill» ). Cependant, il existe des situations où une certaine erreur apparaît, ce qui est une source de grave préoccupation, mais n'interfère pas avec l'exécution du code. Les tests de mémoire sont un sujet assez compliqué qui dépasse le cadre de cet article, donc je ne donnerai que quelques idées générales.

Les deux erreurs les plus courantes qui se produisent dans la RAM sont:
  • «Bits collants» lorsque le bit a une valeur de 0 ou 1, qui ne peut pas ĂŞtre modifiĂ©e;
  • «Diaphonie» lorsque des bits adjacents provoquent des interfĂ©rences entre eux.

Les deux erreurs peuvent être vérifiées en écrivant et en lisant tour à tour certains modèles de test dans chaque zone RAM. Certaines vérifications ne peuvent être effectuées qu'au démarrage, avant même la formation de la pile ( note du traducteur: dans l'article mentionné ci-dessus, il s'est avéré que c'était la première utilisation de la pile qui détruisait tout à la fois ). Par exemple, une vérification «unité en cours d'exécution», dans laquelle chaque bit de mémoire se voit attribuer une valeur de un, et tous les autres bits sont vérifiés pour s'assurer qu'ils sont égaux à zéro. D'autres modèles de test au niveau du bit peuvent être effectués pendant le fonctionnement, à condition que, même si la zone RAM est endommagée, la commutation de contexte ne se produira pas. L'utilisation des macros de restriction des sections critiques de Nucleus SE NUSE_CS_Enter () et NUSE_CS_Exit () est assez simple et évolutive.

Différents types de ROM sont également sujets à des erreurs périodiques, mais il n'y a pas beaucoup d'outils pour les vérifier. Une somme de contrôle calculée après assemblage du code pourrait être utile ici. Cette vérification peut être effectuée au démarrage et éventuellement au moment de l'exécution.

Une erreur dans la logique d'adressage de la mémoire peut affecter à la fois la ROM et la RAM. Vous pouvez développer une vérification spéciale pour cette erreur, mais elle sera très probablement détectée dans le cadre des vérifications décrites ci-dessus.

Test des périphériques


En plus du CPU, les circuits périphériques peuvent également être sujets aux erreurs. Bien sûr, cela varie considérablement d'un système à l'autre, cependant, dans la plupart des appareils, il existe différentes façons de vérifier leur intégrité à l'aide d'un logiciel de diagnostic. Par exemple, un canal de communication peut avoir un mode de vérification de bouclage dans lequel toutes les données entrant dans le canal sont immédiatement renvoyées.

Service de surveillance


Les développeurs intégrés utilisent souvent un chien de garde. Il s'agit d'un périphérique qui interrompt le CPU et attend une réponse, ou (plus préférablement) nécessite un accès périodique depuis le logiciel. Dans les deux cas, un résultat courant d'une horloge de surveillance est une réinitialisation du système.

L'utilisation efficace d'un chien de garde dans un environnement multitâche est un problème complexe. Si vous effectuez une tâche qui y accède périodiquement (horloge de surveillance), cela confirmera que cette tâche particulière fonctionne. Une solution possible pourrait être la mise en œuvre de la «tâche de répartiteur». Un exemple d'une telle tâche sera donné ci-dessous.

Vérification du dépassement de pile


Si vous n'utilisez pas le Planificateur d'exécution jusqu'à la fin, une pile sera créée pour chaque tâche dans l'application Nucleus SE. L'intégrité de ces piles est très importante, mais la quantité de RAM est susceptible d'être limitée, par conséquent, il est important de rendre la taille d'application optimale. La prévision statique des exigences pour la pile de chaque tâche est possible, mais très difficile. La pile doit être suffisamment grande pour même les fonctions les plus imbriquées, ainsi que le gestionnaire d'interruption le plus exigeant. Une approche plus simple pour résoudre ce problème serait d'utiliser des tests d'exécution exhaustifs.

De manière générale, il existe deux approches pour vérifier la pile. Si vous utilisez un débogueur de logiciel intégré sophistiqué, les limites de la pile peuvent être surveillées et toutes les violations seront détectées. L' emplacement et la taille des piles Nucleus SE sont disponibles dans les structures de données ROM globales: NUSE_Task_Stack_Base [] et NUSE_Task_Stack_Size [] .

Une alternative est le test d'exécution. Une approche courante consiste à utiliser des «mots de garde» à la fin de chaque pile, généralement le premier élément de chaque zone des données de la pile. Ces mots sont initialisés avec une valeur non nulle reconnue. La tâche de service / diagnostic vérifie ensuite si ces mots ont changé et effectue les actions appropriées. Écraser le mot de sécurité ne signifie pas que la pile est pleine, mais indique que cela est sur le point de se produire. Par conséquent, le logiciel peut continuer à fonctionner, vous devrez peut-être prendre des mesures correctives ou signaler une erreur à l'utilisateur.

Tâche du superviseur


Malgré le fait que Nucleus SE ne réserve aucune des seize tâches possibles à ses propres besoins, l'utilisateur peut sélectionner une tâche pour les diagnostics. Il peut s'agir d'une tâche de faible priorité qui utilise simplement n'importe quel temps de processeur «libre» ou d'une tâche de haute priorité qui s'exécute périodiquement, en prenant une courte période de temps, ce qui garantit que les diagnostics sont effectués régulièrement.

Voici un exemple de fonctionnement d'une tâche similaire.

Les indicateurs de signal de la tâche de répartiteur sont utilisés pour suivre le fonctionnement de six tâches système critiques. Chacune de ces tâches utilise un indicateur spécifique (du bit 0 au bit 5) et doit le définir régulièrement. La tâche de répartiteur réinitialise tous les indicateurs, puis suspend son travail pendant une certaine période de temps. Lorsqu'elle reprend le travail, elle s'attend à ce que les six tâches soient "vérifiées" en définissant l'indicateur approprié, puis elle recherche une correspondance exacte avec la valeur de b00111111 (à partir du fichier nuse_binary.h ). Si tout répond aux exigences, il réinitialise les indicateurs et s'arrête à nouveau. Sinon, il appelle la routine de gestion des erreurs critiques, qui à son tour peut, par exemple, redémarrer le système.

Dans une implémentation alternative, des groupes de drapeaux d'événements pourraient être utilisés. Cela a du sens si les signaux ne sont pas utilisés ailleurs dans l'application (sinon cela entraînera une utilisation excessive de la RAM par toutes les tâches) et surtout si les indicateurs d'événement sont utilisés à d'autres fins.

Traçage et profilage


Malgré le fait que de nombreux débogueurs de logiciels embarqués modernes ont un haut degré de personnalisation et peuvent être utilisés pour fonctionner avec RTOS, le débogage d'une application multithread peut toujours être difficile. Une approche largement utilisée est le profilage post-exécution, dans lequel le code (RTOS) est mis en œuvre afin qu'un audit détaillé de son travail puisse être analysé rétrospectivement. En règle générale, la mise en œuvre d'un tel service comprend deux composants:
  1. Un code supplémentaire est ajouté au RTOS pour consigner les actions. En règle générale, il sera enveloppé dans des directives de préprocesseur pour utiliser la compilation conditionnelle. Ce code enregistre plusieurs octets d'informations lorsqu'un événement important se produit (par exemple, appeler une fonction API ou changer de contexte). Ces informations peuvent comprendre:
    • adresse actuelle (PC);
    • ID de la tâche en cours (index);
    • indices d'autres objets utilisĂ©s;
    • code correspondant Ă  l'opĂ©ration effectuĂ©e.

  2. Tâche allouée pour décharger le tampon d'informations de profil sur un stockage externe, généralement sur l'ordinateur hôte.

L'analyse des données ainsi obtenues nécessitera également un certain travail, mais ce n'est pas plus compliqué que d'utiliser une feuille de calcul Excel régulière.

Dans le prochain article, nous examinerons en détail la compatibilité de Nucleus SE et Nucleus RTOS.

À propos de l'auteur: Colin Walls travaille dans l'industrie électronique depuis plus de trente ans, consacrant la majeure partie de son temps au micrologiciel. Il est maintenant ingénieur firmware chez Mentor Embedded (une division de Mentor Graphics). Colin Walls intervient souvent lors de conférences et séminaires, auteur de nombreux articles techniques et de deux livres sur le firmware. Vit au Royaume-Uni. Blog professionnel de Colin , e-mail: colin_walls@mentor.com.

Source: https://habr.com/ru/post/fr463403/


All Articles