RTOS pour systèmes embarqués

57

J'ai vu de nombreux articles me dire que je devrais utiliser RTOS pour la gestion du temps et des ressources. Mon temps n'a pas permis mes propres recherches, alors je viens demander conseil à chiphacker.

J'utilise des microcontrôleurs à faibles ressources (MSP430, PIC) et je cherchais des RTOS que je pourrais utiliser.

Jusqu'au point:

  1. Coût de la ressource du système
  2. Avantages du système
  3. Inconvénients du système
  4. Trucs d'implémentation
  5. Situations dans lesquelles le RTOS ne devrait / devrait pas être utilisé.

Je n'utilise pas de systèmes comme l'arduino, les projets avec lesquels je travaille ne peuvent supporter le coût d'un tel système.

Kortuk
la source
2
Je suis confus quant à la raison pour laquelle cela a suscité un vote négatif. Si l'électeur pouvait me donner un retour, j'essaierai d'éviter une telle action à l'avenir.
Kortuk
1
idem. C'est une excellente question ....
Jason S
J'ai accepté une question parce que, même si cela était ouvert, j'avais un certain nombre d'excellentes réponses et je voulais récompenser au moins un auteur pour cet effort.
Kortuk

Réponses:

29

Je n'ai pas beaucoup d'expérience personnelle avec RTOS, à part QNX (ce qui est génial dans l'ensemble, mais ce n'est pas bon marché et j'ai eu une très mauvaise expérience avec un fournisseur de cartes en particulier et l'attitude we-ne-care de QNX pour les systèmes autres que leur plus commun) qui est trop grand pour les PIC et MSP430.

Un RTOS dans lequel vous bénéficierez est dans des domaines tels que

  • gestion des threads / ordonnancement
  • communications inter-thread + synchronisation
  • E / S sur des systèmes avec stdin / stdout / stderr ou des ports série ou un support ethernet ou un système de fichiers (pas un MSP430 ou un PIC pour la plupart, à l'exception des ports série)

Pour les périphériques d'un PIC ou MSP430: pour les ports série, j'utiliserais un tampon en anneau + des interruptions ... quelque chose que j'écris une fois par système et que je réutilise; Je ne pense pas que vous trouveriez un support beaucoup plus important d’un RTOS, car ils sont spécifiques à chaque fournisseur.

Si vous avez besoin d'une synchronisation à la microseconde près, un RTOS ne vous aidera probablement pas - les RTOS ont une synchronisation limitée, mais ont généralement une gigue de synchronisation dans leur planification en raison de retards de commutation de contexte ... QNX exécuté sur un PXA270 avait gigue dans les dizaines de microsecondes typiques, maximum 100-200us, donc je ne l'utiliserais pas pour des choses qui doivent courir plus vite que 100Hz ou qui a besoin d'un timing beaucoup plus précis que 500us. Pour ce genre de choses, vous devrez probablement implémenter votre propre gestion des interruptions. Certains RTOS vont bien jouer avec ça, et d'autres vont en faire une douleur royale: votre timing et leur timing peuvent ne pas bien coexister.

Si la synchronisation / planification n'est pas trop complexe, il peut être préférable d'utiliser une machine à états bien conçue. Je vous recommande fortement de lire Practic Statecharts en C / C ++ si vous ne l’avez pas déjà fait. Nous avons utilisé cette approche dans certains de nos projets où je travaille et elle présente de réels avantages par rapport aux machines d'état traditionnelles pour la gestion de la complexité ... C'est la seule raison pour laquelle vous avez besoin d'un RTOS.

Jason S
la source
Je travaille dans une entreprise en démarrage où les gars les plus expérimentés en systèmes embarqués viennent tout juste de sortir de l'université (c'est-à-dire moi-même et l'autre gars qui travaille avec moi depuis environ 2 ans). Je passe beaucoup de temps à m'instruire des pratiques de l'industrie au cours de ma semaine de travail. Pendant que je lisais, j’ai été informé pour tous, mais notre système le moins coûteux, un RTOS constituerait une amélioration considérable.
Kortuk
Il semble exister un système RTOS avec très peu de ressources pour des éléments tels que les PIC et les MSP430, qui peut aider à créer un système déterministe à partir d’un système très complexe, tout en simplifiant considérablement notre gestion des services de séparation des modules. Je fais partie d'une équipe de deux personnes qui a construit efficacement un système de collecte et d'acheminement de données sur le terrain. Maintenant que je regarde RTOS, je vois que c'est parfait pour ce que nous avons conçu.
Kortuk
Désolé de vous servir de trois postes de publication, votre réponse est très utile. Je recherche une solution de ressources très faibles, mais cette information est précieuse, merci de votre aide.
Kortuk
ne vous inquiétez pas pour le nombre de commentaires (l’un des monstres, le cadre StackExchange manque, c’est le support des discussions ... le format Q / A couvre la plupart des choses, mais pas certaines) ... on dirait que vous savez très bien quoi faire vous cherchez. Je n'ai pas examiné le FreeRTOS mentionné par Steve, mais s'il a été porté sur des microcontrôleurs bas de gamme, il se chargera peut-être de la gestion de la planification dont vous avez besoin.
Jason S
Il semble sauver l’état de chaque thread à travers la pile (environ 50 déclarations push / pull) et peut gérer des interruptions temporisées. Mon système utiliserait normalement une interruption de port pour la commutation de threads, mais la tâche semble réalisable. Je souhaite que ce type de site gère la discussion dans un meilleur format.
Kortuk
26

Avez-vous essayé FreeRTOS ? C'est gratuit (sous réserve de conditions), et il a été porté à la fois sur le MSP430 et sur plusieurs versions de PIC.

C'est petit comparé à d'autres, mais cela facilite aussi l'apprentissage, surtout si vous n'avez pas utilisé de RTOS auparavant.

Une licence commerciale (non libre) est disponible, ainsi qu'une version CEI 61508 / SIL 3.

Steve Melnikoff
la source
Merci beaucoup, j'examinerai dans la semaine, je laisserai la question ouverte pour d'autres réponses, mais vous nous aidez beaucoup!
Kortuk
12

Je viens de découvrir le RTOS NuttX , qui peut même fonctionner sur un système 8052 (8 bits). Cela n'a pas beaucoup de ports, mais ça a l'air intéressant. POSIX peut être un avantage, car il peut rendre une partie de votre code un peu plus portable si vous passez à un processeur plus puissant et que vous souhaitez exécuter Linux ou QNX en temps réel.

Je n'ai aucune expérience avec les RTOS commerciaux, mais j'utilise ceux faits maison depuis des années! Ils sont très efficaces pour vous aider à répartir le développement de votre code entre de nombreux programmeurs, car ils peuvent essentiellement obtenir chacun une "tâche" ou un "thread". Vous devez toujours vous coordonner et quelqu'un doit superviser l'ensemble du projet pour s'assurer que chaque tâche peut respecter son échéance.

Je vous recommande également d'effectuer des recherches sur l' analyse monotonique de taux ou sur le RMA lors de l'utilisation d'un RTOS. Cela vous aidera à garantir que vos tâches critiques respecteront leurs délais.

J'examinerais également le cadre de programmation piloté par les événements QP-nano de Miro Samek, qui peut fonctionner avec ou sans RTOS tout en vous offrant une capacité en temps réel. Grâce à cela, vous divisez votre conception en machines à états hiérarchiques au lieu de tâches traditionnelles. Jason S a mentionné le livre de Miro dans son message. Une excellente lecture!

Jay Atkinson
la source
9

Une chose que j'ai trouvée utile sur un certain nombre de machines est un simple commutateur de pile. Je n'en ai pas écrit pour le PIC, mais je m'attendrais à ce que l'approche fonctionne correctement sur le PIC18 si les deux / tous les threads utilisent un total de 31 niveaux de pile ou moins. Sur le 8051, la routine principale est la suivante:

_taskswitch:
  xch a, SP
  xch a, _altSP
  xch a, SP
  ret

Sur le PIC, j'oublie le nom du pointeur de la pile, mais la routine ressemblerait à ceci:

_taskswitch:
  movlb _altSP >> 8
  movf _altSP, w, b
  movff _STKPTR, altSP 
  movwf _STKPTR, c
  revenir

Au début de votre programme, appelez une routine task2 () qui charge altSP avec l'adresse de la pile alternative (16 fonctionnerait probablement bien pour un PIC18Fxx) et exécute la boucle task2; cette routine ne doit jamais revenir, sinon les choses vont mourir d'une mort douloureuse. Au lieu de cela, il doit appeler _taskswitch chaque fois qu'il souhaite céder le contrôle à la tâche principale; la tâche principale doit ensuite appeler _taskswitch chaque fois qu'elle souhaite se soumettre à la tâche secondaire. Souvent, on aura de jolies petites routines comme:

void delay_t1 (unsigned short val)
{
  faire
    interrupteur de tâches ();
  while ((unsigned short) (millisecond_clock - val)> 0xFF00);  
}

Notez que le sélecteur de tâches n'a aucun moyen de faire une "attente de condition"; tout ce qu'il supporte est un spinwait. Par ailleurs, le changement de tâche est si rapide qu’une tentative de répercussion sur une tâche () alors que l’autre tâche attend l’expiration du temporisateur bascule vers l’autre tâche, vérifie le temporisateur et revient plus rapidement qu’un commutateur de tâches typique. déterminerait qu'il n'a pas besoin de taskwitch.

Notez que le multitâche coopératif a certaines limites, mais il évite le recours à de nombreux codes de verrouillage et autres codes liés aux mutex dans les cas où les invariants temporairement perturbés peuvent être rétablis rapidement.

(Edit): Quelques mises en garde concernant les variables automatiques et autres:

  1. si une routine qui utilise la commutation de tâches est appelée à partir des deux threads, il sera généralement nécessaire de compiler deux copies de la routine (éventuellement en incluant # le même fichier source deux fois, avec des instructions #define différentes). N'importe quel fichier source ne contiendra pas le code d'un seul thread ou le code qui sera compilé deux fois - une fois pour chaque thread - afin que je puisse utiliser des macros du type "#define delay (x) delay_t1 (x)" ou #define delay (x) delay_tx (x) "en fonction du thread que j'utilise.
  2. Je pense que les compilateurs PIC qui ne peuvent pas "voir" une fonction appelée supposent qu'une telle fonction peut détruire tous les registres de la CPU, évitant ainsi la sauvegarde de registres dans la routine de commutation de tâches [un avantage intéressant par rapport à multitâche préemptif]. Toute personne envisageant un sélecteur de tâches similaire pour toute autre CPU doit connaître les conventions de registre utilisées. Pousser des registres avant un changement de tâche et les afficher après est un moyen facile de s’occuper des choses, en supposant qu’il existe suffisamment d’espace de pile.

Le multitâche coopératif ne permet pas d’échapper complètement aux problèmes de verrouillage, mais il simplifie grandement les choses. Dans un RTOS préemptif avec un ramasse-miettes compacté, par exemple, il est nécessaire de permettre aux objets d'être épinglés. Lorsque vous utilisez un commutateur coopératif, cela n'est pas nécessaire, à condition que le code suppose que les objets GC peuvent être déplacés à tout moment de l'appel de taskswitch (). Un collecteur compacteur qui ne doit pas s'inquiéter des objets épinglés peut être beaucoup plus simple qu'un autre.

supercat
la source
1
Réponse géniale. Je pense qu’il serait intéressant d’obtenir des liens sur des ressources pour aborder mon propre RTOS. Mon objectif ici était vraiment d'obtenir un RTOS de haute qualité d'un fournisseur qui a veillé à ce qu'il soit dur en temps réel, mais cela pourrait être un projet d'amusement amusant pour moi-même.
Kortuk
1
Cool, jamais pensé à des tâches comme juste changer de SP ...
NickHalden
1
@JGord: J'ai effectué de petits changements de tâches sur le 8x51 et sur un DSP TI. Le 8051, illustré ci-dessus, est conçu pour deux tâches précises. Le DSP one est utilisé avec quatre et c'est un peu plus compliqué. Cependant, je venais juste d'avoir une idée folle: on pouvait gérer quatre tâches simplement en utilisant trois commutateurs de tâches. Chaque fois que l'une des deux premières tâches souhaite effectuer une commutation de tâche, elle doit appeler TaskSwitch1 et TaskSwitch2. Lorsque l’une des deux secondes tâches souhaite effectuer un basculement entre tâches, elle doit appeler Taskswitch1 et Taskswitch3. Supposons que le code commence par stack0 et que chaque commutateur de tâches est défini avec son numéro de pile correspondant.
Supercat
@ JGord: Hmm ... ça ne marche pas tout à fait; il semble donner un round robin à trois et ignore le troisième commutateur. Eh bien, expérimentez et je pense que vous trouverez probablement une bonne formule.
Supercat
7

J'ai utilisé Salvo sur le MSP430. C'était très léger sur les ressources du processeur et, à condition de respecter les règles d'implémentation, très facile à utiliser et fiable. Il s’agit d’un système d’exploitation coopératif qui nécessite que les commutations de tâches soient effectuées au niveau de l’appel de fonction externe des fonctions de tâches. Cette contrainte permet au système d'exploitation de fonctionner sur de très petits périphériques de mémoire sans utiliser de grandes quantités d'espace de pile en maintenant des contextes de tâche.

Sur l’AVR32, j’utilise FreeRTOS. Encore une fois, très fiable jusqu'à présent, mais il y a des différences de configuration / version entre la version publiée par FreeRTOS et la version fournie avec le framework Atmel. Cela a cependant l'avantage d'être gratuit!

uɐɪ
la source
5

L'édition de décembre de Everyday Practical Electronics contient la troisième partie d'une série sur les systèmes d'exploitation en temps réel pour les PIC (dans la colonne PIC n 'Mix), ainsi que des détails sur la configuration de FreeRTOS avec MPLAB et un PICKit 2. Les deux articles précédents n’ai pas vu) semble avoir discuté des avantages de diverses RTOS et s’être installé sur FreeRTOS. Une fois que l’article en cours a configuré l’environnement de développement, il commence à concevoir une horloge numérique binaire. Il semble qu’il reste au moins une partie à venir sur ce sujet.

Je ne sais pas dans quelle mesure EPE est disponible aux États-Unis, mais il semble y avoir un magasin américain relié à son site et des copies électroniques sont peut-être disponibles.

Amos
la source
4

Le compilateur CCS pour le PIC est livré avec un simple RTOS. Je ne l'ai pas essayé, mais si vous avez ce compilateur, ce serait facile à expérimenter.

Jeanne Pindar
la source
1
J'ai effectivement essayé ceci comme mon premier. Ce n'est pas une RTOS dans le vrai sens du mot. Ce n'est en aucun cas préemptif. Il faut utiliser régulièrement des commandes de rendement pour que le RTOS puisse décider de la prochaine exécution. Vous devez les insérer intentionnellement de manière constante au cas où un autre programme devrait prendre la relève.
Kortuk
2
Je pense que cela s'appelle toujours un RTOS. On dirait simplement qu’il dispose d’un planificateur coopératif au lieu d’un planificateur totalement préemptif.
Jay Atkinson
Oui, techniquement, c’est toujours une RTOS, mais j’ai eu et j’ai encore très peu de valeur pour cela. Je sais que c'est une chose personnelle, mais pour moi, il faut être préemptif pour avoir de la valeur. Je reste +1 car c'était une bonne réponse et de valeur.
Kortuk
3

Question étroitement liée: https://stackoverflow.com/questions/1624237/multithreading-using-c-on-pic18

davidcary
la source
Merci! On dirait que la plupart des gens n'ont pas compris la question, mais c'est quand même intéressant.
Kortuk
J'ai posté sur la question sur SO invitant l'utilisateur à venir à E & R pour obtenir de l'aide!
Kortuk
Je pense que nous avons "compris" la question SO, elle demandait quelque chose de différent mais lié à cette question. Quant à votre commentaire là-bas sur la certification; cela dépend de beaucoup de choses. En regardant les réponses ici, j'aime bien la réponse de DoxaLogos faisant référence à QP-nano; mon expérience m'amène à préférer le code événementiel aux threads et au changement de contexte implicite des threads.
Janm
2

Vous n'avez pas beaucoup parlé de votre candidature. Que vous utilisiez un RTOS dépend beaucoup de ce que vous devez faire dans le PIC. À moins que vous ne fassiez plusieurs choses asynchrones différentes, qui nécessitent des limites de temps strictes, ou que plusieurs threads soient en cours d'exécution, un RTOS risque d'être excessif.

Il existe de nombreuses façons d’organiser l’heure sur un microcontrôleur en fonction de ce qui est le plus important:

  1. Taux de trame constant: Pour un PIC exécutant un servo-contrôleur qui doit fonctionner à 1000 Hz par exemple. Si l'exécution de l'algorithme PID prend moins de 1 ms, vous pouvez utiliser le reste de la milliseconde pour effectuer d'autres tâches, telles que la vérification du bus CAN, la lecture de capteurs, etc.

  2. Toutes les interruptions: tout ce qui se passe dans le PIC est déclenché par une interruption. Les interruptions peuvent être classées par ordre de priorité en fonction de l'importance de l'événement.

  3. Collez-le en boucle et faites tout aussi vite que vous le pouvez. Vous trouverez peut-être que cela fournit des limites de temps convenables.

Rocketmagnet
la source
Je comprends d’autres méthodes, mais je souhaite développer un système RTOS. Je vais exécuter plusieurs tâches et avoir un système en temps réel difficile, mais je suis prêt à commencer sans les exigences du temps réel difficile. Merci d’avoir pris le temps de répondre, mais je souhaite apprendre un RTOS afin de pouvoir l’utiliser dans une situation de forte demande.
Kortuk