2017-10-20 7 views
0

J'utilise une distribution RTOS sur un périphérique embarqué ARM. Actuellement, je suis dans le besoin d'un signal comme basculer cetteCommutation des broches avec vTaskDelay dans RTOS

GPIO_Write(PIN_1, LOW); 
vTaskDelay(msec_to_ticks(1)); 

GPIO_Write(PIN_1, HIGH); 
vTaskDelay(msec_to_ticks(1)); 
GPIO_Write(PIN_1, LOW); 
vTaskDelay(msec_to_ticks(3)); 

GPIO_Write(PIN_1, HIGH); 
if (option1){ 
    vTaskDelay(msec_to_ticks(3)); 
    GPIO_Write(PIN_1, LOW); 
    vTaskDelay(msec_to_ticks(1)); 
} else { 
    vTaskDelay(msec_to_ticks(1)); 
    GPIO_Write(PIN_1, LOW); 
    vTaskDelay(msec_to_ticks(3)); 
} 
GPIO_Write(PIN_1, HIGH); 
if (option2){ 
    vTaskDelay(msec_to_ticks(3)); 
    GPIO_Write(PIN_1, LOW); 
    vTaskDelay(msec_to_ticks(1)); 
} else { 
    vTaskDelay(msec_to_ticks(1)); 
    GPIO_Write(PIN_1, LOW); 
    vTaskDelay(msec_to_ticks(3)); 
} 
GPIO_Write(PIN_1, HIGH); 
vTaskDelay(msec_to_ticks(3)); 
GPIO_Write(PIN_1, LOW); 

Ce que je remarque est que, compte tenu de l'endroit où et quand j'appelle cette fonction (thread séparé/tâche), le signal peut être complètement faux (1-2ms parfois).

Je me demande si l'utilisation de taskENTER_CRITICAL() et taskEXIT_CRITICAL peut m'aider à assurer un signal assez précis. Une idée que j'ai est que les interruptions avec une priorité plus élevée peuvent démarrer et retarder le code quelque part (bien que j'ai défini la priorité max sur la tâche). L'autre est que les timings sont corrects mais GPIO_Write ne se produit pas immédiatement.

Une autre idée sur comment puis-je m'assurer que le code n'est pas interrompu?

Cordialement,

Répondre

0

Voici quelques points à considérer.

1) Quelle est la période de temporisation utilisée par vTaskDelay()? La quantité d'erreur dans la période de retard pourrait être jusqu'à une coche. Par exemple, si vous démarrez le délai juste avant que la prochaine tique ne soit sur le point de se produire, le délai peut être jusqu'à une coche trop courte. Si la période de retard est de 1 milliseconde, vous ne pouvez pas mesurer avec précision des délais de 1 milliseconde, car la résolution relativement faible du temporisateur signifie que les retards peuvent être jusqu'à une milliseconde ou 100% trop courts. Espérons que la période de tique est de 0,01 milliseconde ou moins, car cela lui permettrait de mesurer 1 milliseconde avec 1% d'erreur ou moins.

2) Le FreeRTOS documentation explique pourquoi vTaskDelay() est pas une bonne méthode de contrôle de la fréquence des tâches périodiques.

vTaskDelay() spécifie une heure à laquelle la tâche souhaite débloquer par rapport au moment où vTaskDelay() est appelé. Par exemple, spécifiant une période de blocage de 100 ticks entraînera la tâche à débloquer 100 ticks après l'appel de vTaskDelay(). vTaskDelay() n'a pas donc fournir une bonne méthode de contrôle de la fréquence d'une tâche périodique que le chemin emprunté par le code, ainsi que d'autres tâches et interrompre l'activité, aura une incidence sur la fréquence à laquelle vTaskDelay() est appelé et donc le temps à laquelle la tâche suivante s'exécute. Voir vTaskDelayUntil() pour une autre fonction API conçue pour faciliter l'exécution à fréquence fixe. Il le fait par spécifiant un temps absolu (plutôt qu'un temps relatif) auquel la tâche appelante doit se débloquer.

3) En utilisant taskENTER_CRITICAL et taskEXIT_CRITICAL autour d'appels à vTaskDelay() semble être une mauvaise idée pour moi. La raison pour appeler le vTaskDelay() est de permettre à d'autres tâches de s'exécuter pendant que cette tâche est en attente. Il semble donc contre-productif de désactiver les interruptions avec taskENTER_CRITICAL. Si vous ne souhaitez pas que d'autres tâches soient exécutées pendant les retards, appelez une fonction de délai non bloquant plutôt que vTaskDelay().Ensuite, si la synchronisation de votre fonction non bloquante est toujours affectée par des interruptions, vous pourriez peut-être envisager de la placer dans une section critique.

+0

Seule la première transition sera asynchrone à la limite de graduation car toutes les autres suivent immédiatement un délai. C'est-à-dire que vous pouvez générer avec précision un retard de 1 tick si le délai suit un délai d'une coche (tâches prioritaires et interruptions plus élevées). – Clifford

0

Un problème est que le premier jeu de broches se produit de manière asynchrone à l'horloge RTOS, donc peut se produire partout dans la période d'horloge:

Tick: |   |   |   | 
     ________  __________ 
Signal:  |____|   |__________________ 
      <---------> 
     First transition 
    may occur anywhere here. 

Cela peut être résolu en insérant un délai de tique avant la première transition.

Tick: |   |   |   | 
     __   __________ 
Signal: |__________|   |__________________ 
Delay(1)-^   
     Transition occurs on the tick boundary 

plus élevées tâches prioritaires et les interruptions peuvent retarder les transitions et la gigue de cause, mais si vous verrouillez les interruptions de planificateur ou désactiver, puis ces tâches ne fonctionnent pas, et si votre application peut prendre ce alors ces tâches ont été attribuées priorité inappropriée. De même, la gigue est importante, et là encore, vous avez des tâches avec une priorité inappropriée ou, inversement, un comportement et une ordonnancabilité inappropriés pour une tâche hautement prioritaire.

La priorité de la tâche ne concerne pas «l'importance», elle concerne l'ordonnancement et les délais. À titre indicatif, les tâches qui ont des échéances difficiles en temps réel et qui se déroulent sur de courtes périodes déterministes devraient avoir une haute priorité. Dans ce cas, la tâche passe le plus clair de son temps en retard - les commutateurs GPIO prendront très peu de cycles d'horloge, donc cette tâche peut probablement être affectée en toute sécurité.

Les tâches qui ne se comportent pas de façon déterministe devraient être de faible priorité afin de ne pas affecter les tâches critiques. Si ce fragment fait partie d'une tâche qui fait d'autres choses peut-être non déterministes, alors le partitionnement de votre tâche peut nécessiter une nouvelle réflexion. Le partitionnement des tâches ne concerne pas toujours le «travail», encore une fois, il s'agit de l'ordonnancement et une fonctionnalité ou un comportement intuitivement unique peut devoir être partagé entre plusieurs tâches. Par exemple, ce signal peut être généré par une tâche hautement prioritaire en attente d'un événement déclenché par une tâche de priorité inférieure plutôt que directement implémentée dans la tâche de priorité basse.