3 défis courants auxquels sont confrontés les développeurs d’applications RTOS
Il est essentiel de traiter ces éléments pour exploiter avec succès les avantages de l’utilisation d’un système d’exploitation en temps réel (RTOS) dans les applications embarquées.
Les systèmes d’exploitation en temps réel (RTOS) sont désormais inclus dans de nombreuses applications embarquées. Ils peuvent considérablement simplifier la gestion du temps et des tâches dans un système et aider à améliorer l’évolutivité et la maintenabilité (si l’application est conçue correctement).
J’ai découvert qu’il existe plusieurs défis communs auxquels sont confrontés les développeurs d’applications RTOS. Examinons ces défis et discutons de quelques solutions potentielles.
Défi n° 1 – Sélectionner les priorités des tâches
Curieusement, le défi le plus courant que je vois et sur lequel on me pose des questions est assez fondamental ; comment sélectionner les bonnes priorités pour les tâches. Il s’avère qu’il existe plusieurs façons de sélectionner la priorité des tâches. Premièrement, il y a le temps de réponse le plus court.
Dans cette méthode, un développeur examine les exigences de temps de réponse pour chaque tâche et attribue la priorité la plus élevée à la tâche avec l’exigence de temps de réponse la plus courte.
Ensuite, il y a la première méthode de travail la plus courte. Dans cette méthode, un développeur examine les temps d’exécution des tâches et la tâche qui a le temps d’exécution le plus court est la priorité la plus élevée (évidemment suivie par la prochaine plus élevée et ainsi de suite).
Enfin, il y a la méthode qui est le plus souvent utilisée dans les systèmes embarqués temps réel, la période la plus courte en premier ou plus communément « l’ordonnancement monotone de débit (RMS) ». Dans cette méthode, la tâche avec la période la plus courte a la priorité la plus élevée.
Suivre RMS vous permettra d’atteindre 95 pour cent du chemin parcouru, puis il y a généralement une tâche étrange ou apériodique qui nécessite une affectation prioritaire. Ces tâches apériodiques peuvent se voir attribuer une période dans le pire des cas ou elles peuvent être attribuées en fonction de leur importance, de leur temps d’exécution ou du fait qu’elles doivent être exécutées avant une autre tâche pouvant nécessiter ses données. (Rappelez-vous qu’il n’y a pas de bonne ou de mauvaise réponse aux priorités des tâches, juste des systèmes qui peuvent fonctionner mieux ou être plus efficaces que d’autres).
Défi #2 – Voir la grande image avec un diagramme de flux de données
Tout en consultant et encadrant des équipes de développement, je rencontre souvent des développeurs qui mettent en œuvre leur application RTOS sans vraiment comprendre où les données sont produites, où elles vont et comment elles y arrivent. Comme vous pouvez l’imaginer, cela donne un logiciel qui ressemble un peu à du code spaghetti et nécessite souvent des remaniements constants à mesure que de plus en plus d’éléments d’application sont mis en place. Le moyen de minimiser ce remaniement et de comprendre l’ensemble de l’application est de développer un diagramme de flux de données simple. Ce diagramme contient plusieurs éléments clés :
- Les producteurs de données
- Les consommateurs de données
- Mécanismes de transfert de données
- Mécanismes de stockage
- Mécanismes de coordination des tâches
Par exemple, vous trouverez ci-dessous un diagramme de flux de données simple pour un thermostat intelligent :
Ce diagramme fournit au développeur une compréhension du flux de données mais également des principaux composants RTOS requis pour l’application :
- Tâches (en gris)
- Ressources de mémoire partagées (vert)
- Mécanismes RTOS (en bleu : files d’attente (q), mutex (m), sémaphores (s), etc)
- Périphériques d’entrée et de sortie (bleu foncé)
Disposer de ce diagramme de flux de données peut répondre à de nombreuses questions sur la conception de l’application et éviter de perdre beaucoup de temps à retravailler l’implémentation ou le débogage.
Défi n°3 – Protéger correctement la mémoire partagée
Dans la section précédente, j’ai souligné que la section en vert est une région de mémoire partagée. Cette région mémoire est accessible à la fois par la tâche Process Inputs et la tâche Application.
Un mutex est utilisé pour protéger la ressource de mémoire partagée, mais lors de la mise en œuvre, je vois souvent des développeurs créer le mutex séparément des données protégées. Bien que cela puisse sembler correct à première vue, le problème est que si le mutex est créé séparément de la structure de données et que quelqu’un utilise la structure de données, il peut ne pas se rendre compte qu’il s’agit d’une ressource partagée et protégée. (Oui, la documentation, la conception et bien d’autres choses devraient rendre cela évident, mais s’il est déclaré séparément, il est si facile de l’ignorer).
La solution consiste à considérer la mémoire partagée comme un objet et à inclure le mutex dans la structure de données de la mémoire partagée. Par exemple, la mémoire partagée peut contenir des données provenant de capteurs d’humidité, de température et de courant. Nous pourrions normalement déclarer la structure des données comme suit :
struct typedef
{
uint16_t Humidité;
uint16_t Température ;
uint16_t Actuel ;
}DonnéesCapteur_t;
Encore une fois, le mutex déclaré séparément peut rendre moins évident le partage des données. Au lieu de cela, nous pouvons définir la structure comme suit :
struct typedef
{
mutex_t SensorDataMutex;
uint16_t Humidité;
uint16_t Température ;
uint16_t Actuel ;
}Données Capteur_t
Désormais, chaque fois qu’un développeur examine la structure des données, essaie de faire une saisie semi-automatique et ainsi de suite, il lui est rappelé qu’il s’agit de données protégées. Lorsqu’ils voient qu’il est protégé, cela doit leur rappeler qu’avant d’accéder aux données, ils doivent acquérir le mutex.
Les développeurs oublient souvent que, simplement parce qu’un mutex est créé pour protéger les données, rien ne garantit que le mutex sera utilisé pour accéder aux données. (C’est aussi pourquoi il peut être utile de visualiser la structure de données comme un objet et de créer des fonctions qui limitent l’accès et le contrôle à la ressource de données qui fait abstraction du mutex au niveau de l’application).
Conclusion
Les systèmes d’exploitation en temps réel peuvent simplifier la gestion du temps et des ressources des systèmes embarqués. Malheureusement, le RTOS ajoute de la complexité au système, ce qui peut créer des défis inattendus qui affectent les calendriers de développement et la qualité du code. Dans le post d’aujourd’hui, nous avons examiné plusieurs défis communs que les développeurs rencontrent souvent et que je vois souvent lorsque je travaille avec des équipes de développement. Comme nous l’avons vu, ces défis peuvent être surmontés assez facilement en suivant quelques bonnes pratiques.