Interfaçage de capteurs intégrés : pilote ADC piloté par interruption

Nous avons examiné comment écrire des pilotes de convertisseur analogique-numérique (ADC) bloquants et des pilotes qui utilisent des techniques d'interrogation pour ne pas bloquer le flux d'application. Les pilotes qui interrogent les périphériques sont inefficaces et peuvent gaspiller de précieux cycles d'horloge qui seraient autrement utilisés ou gaspiller de l'énergie si le système se trouvait dans un état de faible consommation. Un moyen efficace pour un développeur d'implémenter un pilote ADC consiste à utiliser une interruption pour notifier à l'application qu'un cycle de conversion est terminé. Dans cet article, nous verrons comment procéder.

Mettre à jour la fonction d'échantillonnage du pilote ADC

Il existe plusieurs manières différentes d' écrire un pilote ADC intégré pour utiliser des interruptions. Dans cet article, nous allons examiner comment modifier le pilote ADC embarqué non bloquant présenté dans l'article précédent. Tout comme nous l'avons fait dans cet article, l'application peut démarrer la conversion ADC en appelant la fonction Adc_Sample.

C'est un bon exemple de la raison pour laquelle avoir une bonne couche d'abstraction matérielle (HAL) peut être utile. Qu'il s'agisse de bloquer, de ne pas bloquer, d'interroger ou d'interrompre, j'appelle exactement la même fonction, et le comportement change simplement en fonction des paramètres de configuration du pilote, ou il peut être lié à une version différente de la fonction Adc_Sample basée sur : Application exigences.

La fonction Adc_Sample pour un système non bloquant ressemble à ceci :

Dans notre nouvelle version, il peut être possible d'implémenter une fonction Adc_Sample similaire à la suivante :

Ouah! Qu'est-il arrivé à tous les codes ? Notre pilote non bloquant a divers contrôles et accès aux tampons, etc. Pour le pilote basé sur les interruptions, tout ce que nous avons à faire est de démarrer la conversion du canal ADC en fonction du périphérique configuré lors de l'initialisation. Ainsi, par exemple, si nous devions échantillonner les canaux 0, 1 et 3, ce seraient ceux activés lors de l'initialisation. Le pilote est conçu pour échantillonner tous les canaux spécifiés à la fois, pas seulement un ou deux. Comme je l'ai déjà mentionné, il existe de nombreuses façons de le faire et d'aider à clarifier les concepts, nous utilisons la solution la plus simple.

À ce stade, si nous appelons Adc_StartConversion, nous nous attendons à ce que le périphérique ADC échantillonne le canal, mais lorsque l'interruption se déclenche, rien ne se passera à ce stade. Nous devons remplir le gestionnaire d'interruption ADC, mais le faire dans le pilote est problématique. Au lieu de cela, nous voulons essayer d'abstraire le code du gestionnaire d'interruption si nous le pouvons.

interruption d'abstraction

L'un des problèmes que les développeurs rencontrent souvent lors de l'écriture de pilotes est qu'ils associent souvent étroitement les interruptions au code de l'application lors du développement de solutions pilotées par interruption. De manière optimale, l'interruption résidera dans le code du pilote, qui se trouve dans la couche du pilote, et non dans le code de l'application au niveau le plus élevé de l'architecture. Un couplage étroit des interruptions au code d'application peut rendre le code difficile à porter et, dans certains cas, même à étendre.

Une solution que les développeurs peuvent utiliser pour conserver les interruptions dans la couche pilote tout en personnalisant les interruptions pour l'application consiste à utiliser des rappels. Une fonction de rappel est une référence au code exécutable qui est passé comme argument à un autre code qui permet aux couches logicielles de niveau inférieur d'appeler des fonctions définies dans les couches de niveau supérieur [1]. La fonction de rappel la plus simple est juste un pointeur de fonction passé en argument à une autre fonction. Dans la plupart des cas, le rappel aura trois parties :

Rappeler

enregistrement de rappel

exécution du rappel

Le schéma ci-dessous montre comment ces trois parties fonctionnent ensemble dans une implémentation de rappel typique :

Figure : Architecture de rappel typique

Si vous vous souvenez du blog précédent, le pilote ADC HAL contient les fonctions suivantes :

Si vous regardez de plus près, la fonction est destinée à enregistrer une fonction de rappel dans le code de l'application avec le pilote ADC intégré. Le premier paramètre spécifie l'interruption à laquelle le rappel sera affecté, tandis que le second paramètre affecte la fonction à appeler en passant un pointeur de fonction à la fonction.

Le pilote de bas niveau affecte alors un pointeur de fonction à l'interruption spécifiée à ce stade. Ceci est très flexible car les développeurs peuvent facilement mettre à jour et modifier la fonction exécutée par l'interruption sans avoir à revenir en arrière et à modifier et recompiler le pilote ADC intégré . Cela permet de séparer le code de l'application du code du pilote, créant ainsi une solution évolutive et flexible.

Forts de ces connaissances, nous pouvons implémenter le gestionnaire d'interruption ADC pour ressembler à ce qui suit :

L'interruption déréférence simplement le pointeur alloué via la fonction Adc_CallbackRegister(). (Notez que dans le code de production, j'ajouterais également quelques vérifications pour m'assurer qu'un pointeur de fonction a été alloué, mais je pense que vous avez compris).

Écrire un gestionnaire d'interruption

Pour les développeurs utilisant cette approche, le gestionnaire d'interruption sera écrit dans leur couche d'application et peut avoir presque n'importe quel nom de fonction qu'ils aiment. Personnellement, je l'appelle toujours quelque chose comme Adc_InterruptCallback donc il est facile pour moi de savoir exactement ce que c'est. L'implémentation de ce rappel peut varier selon l'application. Par exemple, dans une application, le rappel peut ressembler à ceci :

Dans cet exemple, le rappel place simplement un sémaphore pour notifier à la tâche que les données ADC sont disponibles. Un autre exemple pourrait ressembler à ceci :

Comme vous pouvez le voir, c'est au développeur de décider comment il veut gérer les données simulées dans le gestionnaire d'interruptions, et cela varie beaucoup en fonction de l'application et de ses besoins.

Il est important de noter que pour ces fonctions de rappel qui sont en fait des gestionnaires d'interruptions, il est important de suivre les meilleures pratiques des gestionnaires d'interruptions. Cela signifie réduire au minimum le code et le rendre aussi rapide que possible pour minimiser l'impact sur le reste des performances du système.

en conclusion

Comme nous l'avons vu dans cet article, l'utilisation du modèle de conception de pilote basé sur les interruptions peut grandement améliorer l'efficacité du pilote. L'utilisation de rappels permet de conserver l'implémentation des interruptions dans le code de l'application et de les affecter aux interruptions via le mécanisme de rappel du pilote. Cela rend les solutions et le code hautement réutilisables, flexibles et extensibles.

L'Internet des Objets embarqué a besoin d'apprendre beaucoup. Ne vous trompez pas d'itinéraire et de contenu, ce qui fera augmenter votre salaire !

Partagez un forfait de données avec tout le monde, environ 150 G. Le contenu d'apprentissage, les écritures face à face et les projets qu'il contient sont relativement nouveaux et complets ! (Cliquez pour trouver un petit assistant à recevoir)

Guess you like

Origin blog.csdn.net/m0_70911440/article/details/131976822