Question:
Est-il possible d'interrompre le processus de copie d'une structure par une interruption en C embarqué?
Stani
2018-09-06 14:27:06 UTC
view on stackexchange narkive permalink

Dans le pilote, j'ai une fonction pour copier les données de la structure interne dans une structure de l'application.

Ce processus peut-il être interrompu par un déclencheur d'interruption du microcontrôleur?

  uint16_t getRawData (struct Data * Data_external)
{
  if (Data_external == NULL)
  {
    return ERR_PARA;
  }
  autre
  {
    * Data_external = Data_internal;// le processus de copie.Cela pourrait-il être interrompu?
  }
  return ERR_NONE;
}
 
Il n'y a pas vraiment de "processus de copie", il y aura des instructions copiant des octets et s'ils ne sont pas atomiques, ils peuvent être interrompus, cela dépend de votre architecture, compilateur, paramètres et alignement
Il n'y a aucune garantie en C qu'un processus de copie de structure ne puisse pas être interrompu.Cependant, l'interruption est généralement censée revenir au point du code où le processus de copie peut se terminer.Donc, cela n'a probablement pas d'importance à moins que le code d'interruption n'en dépende pour une raison quelconque (peu probable dans la plupart des circonstances.) Si ces structures font partie d'une paire de pilotes d'interruption supérieure / inférieure, cela pourrait être un problème si le niveau supérieurest en train de supprimer ou d'ajouter un «morceau» à un tampon lorsqu'une interruption se produit qui doit également faire face à des «morceaux» dans le même tampon.
@jonk: Veuillez ne pas répondre à la question dans les commentaires, car cela contourne le processus normal d'examen des réponses, comme [discuté dans meta] (https://meta.stackexchange.com/questions/117251)
@DaveTweed Alors vous et ce site perdrez *** mes commentaires.Je n'écris pas de réponses à moins d'avoir le temps d'en écrire des plus complètes.C'est mon seul mode de fonctionnement et je ne le changerai pas.Si je sens que j'ai assez de temps pour une «bonne réponse» d'après ma définition, je continuerai comme avant.Mais je travaille très dur sur plusieurs projets actifs différents et je n'ai PAS le temps pour mon niveau habituel de contexte et de contenu de réponse.Donc, soit j'écris de courts commentaires en tant que commentaires, soit le site perd tout accès à mon temps.Ton appel.Mon temps est donné selon mes conditions, ou pas du tout.
@jonk: Il n'y a rien de mal à rédiger une réponse courte tant qu'elle est complète et autonome, comme votre commentaire.Votre engagement à de longues réponses est entièrement sur vous.Le site a des règles et des processus, et j'essaie simplement de vous pousser dans la bonne direction.En fin de compte, c'est entièrement à vous - vous auriez pu avoir 9 votes positifs (+90 rep) sur votre réponse ...
@DaveTweed Merci pour le coup de pouce.Les points ne sont généralement pas pertinents.Je pense qu'une fois que je suis arrivé aux "annonces réduites" de 200 pts, je ne me suis pas soucié du reste (ni utilisé.) Je ne pense pas non plus que je mérite les chiffres élevés que j'ai en ce moment.Je suis juste un amateur, pour l'amour de Dieu.Et je suis très inquiet que les gens pourraient confondre ce numéro de réputation comme signifiant plus qu'il ne le devrait pour eux.Je préfère que mes paroles restent toujours «suspectes» et méritent d'être critiquées, et non considérées comme une sorte d'évangile.Si je pouvais réduire mon nombre de représentants, je le ferais.
@jonk Si vous voulez vraiment que les gens puissent «soupçonner» vos réponses, permettez aux gens de voter correctement.Dans le cas (peu probable!) Où vous postez quelque chose de mal en tant que commentaire, les utilisateurs ne pourront pas voter contre.Cela peut particulièrement être un problème si les gens votent pour un commentaire qui semble initialement correct (encore une fois, non pas que je remette en question la qualité de vos commentaires / réponses :))
@mbrig Vous pouvez vous méprendre.Je fais le choix de * seulement * écrire *** les réponses *** en tant que telles et avec mon nom attaché si elles incluent le contexte et le contenu complets ou si je pense que je peux fournir une approche * inhabituelle * ou * unique *.Ils sont également toujours recherchés, en ce sens que je ne publierai pas de réponse avant de m'être * double * vérifié moi-même en trouvant des références et des documents à l'appui qui sont à la fois en accord avec ma position et que je peux également citer, lorsqu'on me le demande.Je n'écris pas seulement.J'écris, puis je recherche, je contre-vérifie et je vérifie.Puis postez.Sinon, cela n'apparaît pas comme une réponse de ma part.
@mbrig Enfin, mon numéro de représentant n'est pas * significatif. * Ce que j'écris peut être.Mais c'est un problème distinct.J'aimerais juste pouvoir effacer ou supprimer mon numéro de représentant.Je suis heureux que certaines personnes aient trouvé une de mes réponses (ou deux) aussi utiles.Mais il y a une tendance naturelle chez les gens à imaginer autre chose compte tenu de mon numéro de représentant et j'aimerais qu'ils ne le fassent pas.C'est tout.Votre suggestion ne répond à aucun *** de mes préoccupations.
@jonk: Vous pouvez commencer une question de prime et récompenser quelqu'un avec une réputation de 29k pour vous en débarrasser;)
@Rev1.0 Je pourrais le faire si cela ne nécessitait pas non plus de réfléchir trop sérieusement à la création d'un problème / question digne de celui-ci et peut-être n'a-t-il pas également manqué de supprimer le problème que je signale, mais simplement le transmettre àquelqu'un d'autre (qui ne répond pas à mes préoccupations.) Bonne démonstration créative, cependant.;)
@jonk: Hehe, devenons fou alors;) 1. Créer un 2ème compte 2. Ecrire une question géniale + prime avec le 1er compte 3. Répondre à la question en postant une réponse géniale en utilisant le 2ème compte 4. Supprimer le 2ème compte -> Résultat: Vous avez écrit une bonne question,une bonne réponse et vous avez même perdu votre réputation en le faisant .... tout ce que vous avez toujours voulu;)
@Rev1.0 (1) J'ai le pressentiment que cela violerait une certaine interprétation de la politique et me ferait bannir.(2) J'aimerais toujours que les gens sachent qui je suis et changer de compte complique à peu près cet objectif.(3) Quelqu'un (même si c'est moi) se retrouve toujours avec ces points de répétition.(4) J'adore la pensée créative!Merci.
Sept réponses:
#1
+25
filo
2018-09-06 16:30:30 UTC
view on stackexchange narkive permalink

Oui.Presque tout dans un MCU peut être interrompu par une demande d'interruption.Lorsque le gestionnaire d'interruption aura terminé, le code précédent continuera donc ce n'est généralement pas un problème.

Dans un cas particulier, les gestionnaires d'interruptions peuvent être eux-mêmes interrompus par des interruptions de priorité plus élevée (interruptions imbriquées).

Si une série d'instructions ne doit pas être interrompue, vous devez implémenter une section critique (essentiellement désactiver globalement les interruptions, faire le travail, réactiver).

N'oubliez pas qu'en fonction de l'architecture du processeur cible, une seule ligne de C peut être compilée en plusieurs instructions d'assemblage.Un simple i ++ sur un AVR est compilé en plusieurs instructions si i est par exemple uint32_t .

En ce qui concerne votre dernier paragraphe, je suppose que ce n'est vrai que sur les systèmes 16/8 bits, non?Je sais que vous dites AVR ... juste en vous assurant.
memcpy d'une structure (comme dans la question) est également plusieurs instructions sur ARM 32 bits.L'incrémentation de uint64_t sur ARM 32 bits n'est pas non plus atomique.Les opérations au niveau du bit sont également en lecture-modification-écriture (sauf si la bande de bits est utilisée).
@HarrySvensson no - sur toute architecture RMW et la plupart des uC sont en lecture - modification - écriture (la plupart des processeurs RISC sont RMW).Donc i ++ générera dans de nombreux cas (sauf si la valeur est simplement conservée dans le registre, ce qui n'est pas le cas ici) trois instructions sur les uC ARM 32/64 bits modernes également.
Ah, il y a eu un léger malentendu ici.Je pensais à m'occuper du report lors de l'exécution des incréments (débordement), et vous parlez tous les deux de récupérer de la mémoire et de réécrire.- Tant pis.
En général: toutes les opérations sur des types plus larges que la largeur du bus de données sont "funky".
#2
+11
Sam
2018-09-06 20:25:26 UTC
view on stackexchange narkive permalink

Toute opération qui n'est pas atomique peut être perturbée par une interruption.Ce type de programmation est souvent très différent de la plupart des autres programmes et peut être déroutant pour les personnes qui n'ont pas étudié la conception de processeurs ou l'architecture informatique.

Vous pensez peut-être: "Cela n'arrivera jamais réellement, combien de temps faut-il pour copier ce code et quelle est la probabilité d'une interruption?"Mais avec la plupart des applications intégrées de production, cela se produira car le produit est allumé pendant des années sans mises à jour.

L'autre problème avec des copies de structure comme celle-ci est que lorsqu'elles se produisent, elles sont extrêmement difficiles à déboguer car elles ne se produisent que lorsque l'interruption se produit juste au bon moment (ce qui peut être aussi peu qu'un cycle).

#3
+10
Echelon
2018-09-06 18:39:19 UTC
view on stackexchange narkive permalink

L'intérêt des interruptions est qu'elles peuvent (et se produisent) tout le temps, et sont conçues pour n'avoir aucun impact sur tout code en cours d'exécution lorsqu'elles se produisent. Tous les registres sont sauvegardés, et en fonction de l'architecture du CPU, un jeu de registres complètement différent peut être échangé, l'interruption fait son travail, puis les registres d'origine sont restaurés et le code continue de fonctionner normalement.

Des problèmes peuvent survenir lorsque la routine de service d'interruption elle-même essaie d'accéder à la mémoire à laquelle accède le code interrompu en cours d'exécution. Des erreurs encore plus subtiles peuvent se produire lorsqu'un processus d'E / S à temps critique est interrompu. Ces problèmes sont courants avec les architectures plus anciennes, plus simples et moins sécurisées où il peut y avoir peu de séparation entre le code de mode «utilisateur» et «superviseur / noyau».

Ce type de problème peut être difficile à identifier, et souvent difficile à reproduire, mais une fois identifié, il est souvent assez simple à résoudre en utilisant une programmation défensive, des mutex / sémaphores ou simplement en désactivant les interruptions dans des sections critiques du code.

La classe générale des problèmes a été étudiée de manière approfondie, et les processeurs multicœurs modernes et même les systèmes d'exploitation multi-tâches ne seraient pas possibles si plusieurs solutions n'étaient pas déjà essayées et testées.

#4
+5
Joshua
2018-09-07 04:32:01 UTC
view on stackexchange narkive permalink

Je vais simplement continuer et supposer que vous avez posé cette question pour une très bonne raison.

  * Data_external = Data_internal;
 

Peut être divisé (à l'exception de certains cas marginaux qui sont peu susceptibles d'être en jeu ici).

Je ne connais pas votre CPU mais je n'ai pas encore vu de CPU qui ne puisse pas faire l'équivalent moral de:

  cli ();/ * masque toutes les interruptions * /
* Data_external = Data_internal;
sti ();/ * restaurer le masque d'interruption * /
 

Maintenant, il ne peut pas être divisé sur un processeur à un seul cœur car rien ne peut interrompre tant que les interruptions sont désactivées.Que ce soit une bonne idée ou non dépend de beaucoup de choses que je ne suis tout simplement pas qualifié pour évaluer.

Si vous êtes multi-cœur (et je me suis enfin souvenu qu'il existe un processeur intégré multi-cœur sur le marché), ne le faites pas.Cela ne vaut rien.Vous auriez besoin de développer un verrouillage approprié.

Que sont cli et sti?de google, ils semblent être des instructions x86?
@Sam: Eh bien oui, ce sont les noms des instructions en x86.Je pense qu'ils ont les mêmes noms dans le PDP-11 parce que certains codes qui en sont issus avaient les mêmes noms de fonction pour un équivalent logique en mode utilisateur (masquer les signaux entre processus).Voici les instructions pour Arduino: https://www.tldp.org/LDP/tlk/dd/interrupts.html
Normalement, vous désactivez les interruptions, mais ne les réactivez que si elles sont réellement activées.Sinon, votre code a pour effet de toujours activer les interruptions, même si elles ont été désactivées avant l'appel du code.
#5
+3
Dmitry Grigoryev
2018-09-07 18:08:31 UTC
view on stackexchange narkive permalink

Le code tel que vous l'avez présenté peut en effet être interrompu.Cependant, avant de commencer à créer des sections critiques partout, vous devriez vérifier quelques points:

  • Vous dites que cette fonction est "à l'intérieur d'un pilote".Les interruptions sont-elles déjà désactivées lorsque cette fonction est appelée?Ou est-il appelé à l'intérieur d'un gestionnaire d'interruptions qui empêche le déclenchement d'autres interruptions?Si oui, l'opération ne peut en fait pas être interrompue.

  • Est-ce que Data_internal a déjà été accédé à l'intérieur d'un gestionnaire d'interruption?Sinon, il n'y a aucun mal même si l'opération peut être interrompue.

#6
+1
studog
2018-09-07 23:49:40 UTC
view on stackexchange narkive permalink

[Pas assez de représentants pour commenter]

Un autre gotchya avec ce genre de copie de structure est qu'il s'agit d'une copie superficielle.Vous aurez peut-être besoin d'une copie complète à la place.

Une copie superficielle pourrait éventuellement mais probablement pas être atomique, selon l'architecture de la machine.Une copie complète n'est presque certainement pas atomique sur aucune architecture.

Un bon point;mais une copie profonde est plus susceptible d'être atomique car elle est presque toujours mise en place par un échange de pointeur.Pourtant, dans ce cas, si cela aurait dû être une copie profonde, ce ne sera certainement pas atomique.
#7
  0
supercat
2018-09-07 23:51:55 UTC
view on stackexchange narkive permalink

Une implémentation de qualité adaptée à l'utilisation de systèmes embarqués documentera comment les lectures ou écritures qualifiées volatiles de différents types seront effectuées de manière suffisamment détaillée pour indiquer si et comment elles peuvent être "divisées" par des interruptions et également si les lectures et écritures volatiles sont séquencées ou non par rapport aux lectures et écritures non qualifiées. Alors que certaines implémentations peuvent se comporter comme si toutes les lectures et écritures étaient qualifiées volatiles , les implémentations sont généralement censées être libres de traiter des séquences de lectures et d'écritures non qualifiées de la manière la plus efficace quand il y a aucun accès volatile intermédiaire.

Sur un microcontrôleur 32 bits typique, lit et écrit des types d'entiers qualifiés volatils de 32 bits et moins; une affectation consistera en une lecture atomique suivie d'une écriture atomique. Si vous voulez vous assurer qu'une structure 32 bits est copiée de manière atomique, placez-la dans une union avec un uint32_t , et lisez ou écrivez ce membre pour lire ou écrire la structure dans son ensemble. Les implémentations de qualité qui sont configurées pour être adaptées à l'utilisation de systèmes embarqués permettront aux unions d'être employées de cette manière sans se soucier de savoir si la norme exigerait que les implémentations qui ne sont pas destinées à une telle utilisation fassent de même. Notez que gcc et clang ne se comporteront pas de manière fiable comme des implémentations de qualité adaptées à l'utilisation des systèmes embarqués à moins que diverses optimisations ne soient désactivées.



Ce Q&R a été automatiquement traduit de la langue anglaise.Le contenu original est disponible sur stackexchange, que nous remercions pour la licence cc by-sa 4.0 sous laquelle il est distribué.
Loading...