1
votes

FreeRTOS bloqué dans osDelay

Je travaille sur un projet utilisant un STM32F446 avec un passe-partout créé avec STM32CubeMX (pour l'initialisation des périphériques et middleware comme le FreeRTOS avec l'interface CMSIS-V1). J'ai deux threads qui communiquent en utilisant des boîtes aux lettres mais j'ai rencontré un problème: l'un des corps du thread est

void StartDispatcherTask(void const * argument)
{
    mailCommand *commandData = NULL;
    mailCommandResponse *commandResponse = NULL;
    osEvent event;
    for(;;)
    {       
        event = osMailGet(commandMailHandle, osWaitForever);
        commandData = (mailCommand *)event.value.p;

        // Here is the problem
        osDelay(5000);
    }
}

Il arrive au retard mais ne sort jamais. Y a-t-il un problème avec l'utilisation de la boîte aux lettres et le retard dans le même fil? J'ai également essayé d'amener le délai avant le pour (;;) et cela fonctionne.

EDIT: Je suppose que je peux essayer d'ajouter plus de détails au problème. Le premier thread envoie un mail d'un certain type, puis attend un mail d'un autre type; le fil dans lequel j'obtiens le problème reçoit le courrier passe au premier type et exécute du code en fonction de ce qu'il reçoit, puis envoie le résultat sous forme de courrier du deuxième type; parfois c'est qu'il doit attendre en utilisant osDelay et là il s'arrête de fonctionner mais sans entrer dans aucun gestionnaire de défauts


6 commentaires

Il est plus probable que le délai se termine et qu'il entre dans osMailGet () où il attend indéfiniment (ou du moins jusqu'à ce que quelque chose envoie un message).


Ouais, je voulais dire que le courrier est correctement reçu, puis il arrive au retard mais ne parvient jamais à nouveau à osMailGet


Mon point était plutôt de savoir comment avez-vous déterminé cela avec certitude? Votre code ne fait rien d'observable de l'extérieur dans cette boucle, vous auriez donc dû utiliser un débogueur et des points d'arrêt pour déterminer ce que vous n'avez pas mentionné. Extérieurement, il apparaîtra toujours "bloqué" en dehors de la petite période à laquelle il attribue commandData (et ne fait rien avec).


Ouais, je débogue en fait avec Keil v5; J'ai défini un point d'arrêt sur osDelay et il est atteint, mais si je le laisse fonctionner à nouveau, je peux voir qu'il est bloqué dans la fonction prvCheckTasksWaitingTermination


Le code décrit dans la "modification" ne sonne pas comme le même code. Avez-vous vérifié que le code indiqué dans la question échoue de la même manière que le code avec " exécuter du code en fonction de ce qu'il reçoit "? SYSTICK est-il en cours d'exécution? Le gestionnaire d'interruptions SYSTICK est-il en cours d'exécution? Le bit concernant prvCheckTasksWaitingTermination devrait apparaître dans la question - il est probablement pertinent . La suppression de tâches doit être considérée comme "inhabituelle" dans un système en temps réel - le code affiché ne montre pas où ni pourquoi vous faites cela.


Notez également que si une tâche de priorité plus élevée n'est pas bloquante, la tâche en retard ne sera pas planifiée après l'expiration du délai. Mettez un point d'arrêt dans la boucle de tâche inactive; si votre système n'entre pas régulièrement dans la boucle d'inactivité, vous avez un comportement et des priorités de tâches inappropriés. Chaque thread doit être garanti pour bloquer, et généralement les tâches qui ont les temps d'exécution les plus longs ou les moins déterministes doivent avoir une priorité plus faible que les tâches plus courtes et plus déterministes.


3 Réponses :


1
votes

Je préférerais utiliser l'API freeRTOS standard. L'emballage ARM CMSIS est nul.

BTW, je soupçonne plutôt osMailGet (commandMailHandle, osWaitForever);

le délai n'est dans ce cas pas du tout nécessaire. Si vous attendez les données à l'état BLOQUÉ, la tâche ne consomme aucune puissance de traitement

Si d'autres suppositions sont:

  1. Vous atterrissez dans le HF
  2. Vous êtes empilé dans le changement de contexte (mauvaises priorités d'interruption)

utilisez votre débogueur et voyez ce qui se passe.


17 commentaires

La première ligne de ceci est une opinion qui pourrait mieux être publiée sous forme de commentaire car elle ne fait pas partie de la réponse. Peut-être que c'est "nul" est pourquoi il existe une API v2, mais freeRTOS n'est pas meilleur, et subjectivement pire (IMO).


J'ai ajouté plus de détails à la question, car la façon dont le délai est appelé dans le code que j'ai montré n'est qu'un exemple simplifié; le courrier est reçu correctement, le problème est que je ne parviens plus jamais à osMailGet


@ArenaLor connectez le débogueur et voyez où il est bloqué. Probablement sur le changement de contexte comme je l'ai écrit.


Mais l ' opinion n'en reste pas moins, et n'a pas sa place dans la réponse (tout comme les questions d'opinion n'ont pas leur place dans les questions sur l'OS). Il y a des raisons pour lesquelles on pourrait avoir besoin de l'utiliser (portabilité du code par exemple)


Donc, mis à part le fait qu'il ne devrait pas y avoir de réponse basée sur l'opinion, ce n'est pas pour moi une poubelle complète car je pourrais démarrer un projet sans une connaissance approfondie de l'API freeRTOS et comme @Clifford l'a dit, la portabilité du code (je pourrait passer à Keil RTX à tout moment, par exemple)


@P__J__, j'ai également essayé de me connecter avec le débogueur; Je peux voir qu'il atteint l'appel osDelay mais il est ensuite bloqué dans la fonction prvCheckTasksWaitingTermination


@ArenaLor: P__J__ a un point sur le retard cependant, c'est une mauvaise conception; si la tâche d'envoi publie des messages plus rapidement que 5000 intervalles de graduation, la file d'attente se remplira et l'expéditeur bloquera. Normalement, les messages doivent être traités en "temps réel", et vous devez "faire confiance" au planificateur plutôt que de le deviner. Vous devez au moins effectuer une boucle pour traiter tous les messages en file d'attente avant d'entrer le délai si cela est nécessaire.


@Clifford le problème est plutôt délicat pour les débutants qui corrigent les paramètres de priorité IRQ. Et je suis presque sûr qu'il a une pile dans l'appel SV.


Il semble donc être résolu en augmentant la quantité de pile allouée pour les deux threads (de 128 octets à 512 octets pour chacun). Existe-t-il des principes pour choisir la quantité de pile à allouer à chaque thread?


@ArenaLor non - vous devez analyser vous-même la quantité de pile dont vous avez besoin


"Y a-t-il des principes pour choisir la quantité de pile à allouer à chaque thread?" @ArenaLor, oui, faites votre meilleure estimation, puis laissez votre code s'exécuter et appelez uxTaskGetStackHighWaterMark () en temps réel pour voir combien vous utilisez réellement. Vous pouvez également créer une fonction à utiliser comme vApplicationStackOverflowHook () (rappel) pour vérifier le débordement de pile. Voir 1) "Quelle doit être la taille de la pile?" freertos.org/FAQMem.html#StackSize , 2) freertos.org/Stacks-and-stack-overflow-checking.html , 3) freertos.org/uxTaskGetStackHighWaterMark.html


@ArenaLor, à partir du bas de mon lien 1 ci-dessus: "De plus, les usages de la pile de toutes les tâches RTOS peuvent être visualisés à la fois en utilisant la fonction API uxTaskGetSystemState () " (voir freertos.org/uxTaskGetSystemState.html ), et ils recommandent également de lire ce billet de blog: mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis


Merci @GabrielStaples, ce sont des liens utiles!


Heureux de vous aider! N'oubliez pas de voter pour toutes les questions ou réponses que vous trouvez utiles sur le débordement de pile, ainsi que les commentaires. Il y a une petite flèche vers le haut à côté des commentaires que vous souhaitez voter. Cela les aide à se démarquer afin que les autres les voient aussi. Je viens de voter pour votre merci, par exemple.


@Clifford - J'ai transféré votre suggestion sur le problème de l'expéditeur dans une réponse.


ArenaLor - Vous devez vous assurer qu'aucune tâche ne dépasse sa pile allouée. Sinon, toute la discussion est inutile car le RTOS ne parviendra probablement pas à maintenir ses propriétés alors. En plus de la mesure d'exécution (utile) mentionnée par @GabrielStaples, de nombreuses chaînes d'outils (y compris certaines gratuites comme atollic) fournissent une fonction d'évaluation statique (hors ligne) pour l'utilisation de la pile de graphes d'appel de fonction.


@P__J__ - Je ne suis pas d'accord sur la disqualification de l'OSAL fourni par ARM CMSIS en général. Comme ArenaLor l'a correctement souligné, cela peut simplifier le kickstart. Et, plus important de mon point de vue, vous maintenez la portabilité vers d'autres systèmes d'exploitation.



0
votes

osStatus osDelay (uint32_t millisec)

La valeur en millisecondes spécifie le nombre de ticks du minuteur.

Le délai exact dépend du temps réel écoulé depuis le dernier tick du minuteur.

Pour une valeur de 1, le système attend jusqu'à ce que le prochain tick de minuterie se produise .

=> Vous devez vérifier si le tic de la minuterie fonctionne ou non.

Vérifiez ce lien


0 commentaires

0
votes

Comme P__J__ l'a souligné dans une réponse précédente, vous ne devez pas utiliser l'appel osDelay () dans la boucle 1 parce que votre boucle de tâches attendra à l'appel osMailGet () pour la prochaine requête / mail jusqu'à ce qu'elle arrive de toute façon. Mais cet indice a attiré mon attention sur une autre raison possible de votre observation, alors j'ouvre cette nouvelle réponse: 2

Comme l'exécution de la boucle est interrompue par un retard de 5000 ticks, est-ce que le producteur des mails remplit la boîte aux lettres plus rapidement que la tâche consomme des mails? Ensuite, vous devez vérifier si cette situation est détectée / gérée dans le contexte du producteur.

Si le producteur ignore les valeurs de retour "queue pleine" et rejette les courriers avant qu'ils aient été transmis, le système ne traitera que quelques courriers toutes les 5000 ticks (ou il risque de perdre tous les courriers sauf quelques boîte aux lettres, si le producteur de votre exemple ne remplit qu'une seule fois la file d'attente de la boîte aux lettres). Cela pourrait ressembler à une tâche du consommateur bloquée, même si le problème principal concerne le contexte du producteur (tâche / ISR).


1 L'appel osDelay () ne peut vous aider que si vous voulez éviter de traiter un autre courrier dans les 5000 ticks si les courriers de demande sont produits plus rapidement que la tâche les traite. Mais alors, vous auriez un problème différent, et vous devriez ouvrir une autre question ...

2 Edit: je viens de remarquer que Clifford a déjà mentionné cette option dans l'un de ses commentaires sur la question. Je pense que cette option doit être couverte par une réponse.


0 commentaires