Échec de lecture / écriture I2C sous une forte charge d'interruption

10

Dans mon système, j'utilise I2C et je me rends compte que sous une forte charge d'interruption (provenant d'autres sources), la communication I2C est facilement interrompue. Est-ce ce comportement attendu pour I2C? Je me serais attendu à ce que malgré la charge d'interruption, ce serait toujours bien puisque I2C n'est pas exactement une interface à temps critique, l'horloge est fournie avec des données.

Mise à jour:

Le processeur est STM32. Les interruptions sont dues à l'ADC, je ne peux pas désactiver les interruptions pendant les événements de lecture, je dois donc trouver une solution où je peux rendre la communication i2c plus stable. Le STM32 est maître et l'esclave est un autre appareil (accéléromètre).

Update2:

Lorsque je connecte un analyseur logique à l'horloge avec un petit câble volant, le problème disparaît. Fait intéressant, il n'y a pas de charge d'interruption, la lecture-écriture fonctionne bien, quand il y a une charge d'interruption, ce n'est pas le cas. Cependant, si j'attache la sonde à l'horloge, la lecture et l'écriture fonctionnent également sous charge d'interruption. Je pense qu'il y a un problème de capacité quelque part.

Ktc
la source
1
Votre question est très générique car tout dépend de la conception de votre système. La façon dont I2C gère dépend vraiment des périphériques sur le bus. Pouvez-vous les ignorer et venir au plus tard? Dans un FPGA, vous pouvez concevoir une logique pour prendre soin de beaucoup de choses pour vous et éviter cela. Encore une fois, nous avons besoin de plus d'informations sur le microcontrôleur et sur les autres éléments dont vous disposez. Habituellement, une bonne solution consiste à utiliser un RTOS et à concevoir correctement les tâches.
Gustavo Litovsky
Deux choses à rechercher, l'affaissement de la tension sur les tractions ou sur l'alimentation de votre maître et esclave i2c, ou des problèmes d'emi ou de capacité. En ce qui concerne la charge d'interruption, voulez-vous dire que votre maître s'arrête pour gérer une interruption? Certaines puces ne permettent pas d'étirement d'horloge infini.
Passerby
@GustavoLitovsky vous avez raison mais 80% des cycles CPU traitent l'interruption ADC et il n'y a pas assez de temps pour faire un cycle de lecture pendant la fenêtre non ISR. La lecture sera donc interrompue, quelle que soit la façon dont je conçois le système d'exploitation.
Ktc
@Passerby vous avez peut-être raison. Le problème a disparu lorsque j'ai attaché la sonde de l'analyseur logique à la ligne d'horloge.
Ktc
Quelle est votre valeur actuelle pour les tractions. Avez-vous essayé de les changer en une valeur différente? (Essayez 10k ou 4k7 ou 2k juste pour une première estimation)
Tom L.

Réponses:

9

Il s'agit d'un problème logiciel, vous passez trop de temps à réparer les interruptions et votre routine I2C n'est pas en mesure de le gérer (c'est donc deux choses qui ne sont pas correctes). J'ai vécu plusieurs situations similaires.

Premièrement: vous devez faire le moins possible dans les interruptions, ne lire et stocker que les données, ne faire aucun traitement que vous pourriez faire en dehors de l'ISR, les mathématiques peuvent prendre BEAUCOUP de cycles CPU et le CPU ne peut rien faire d'autre pendant cette interruption.

Deuxièmement: étudiez DMA pour automatiser les choses, afin que vos interruptions deviennent presque un processus automatisé en arrière-plan.

Troisièmement: Si I2C est important, mettez également cela en interruption, mais assurez-vous de définir les priorités!

Quatrièmement: déterminez pourquoi votre routine I2C échoue, I2C lui-même peut résister à des temporisations, des pauses et des attentes très intermittentes, de sorte que votre routine devra peut-être être modifiée pour permettre cela.

Cinquièmement: voyez si vous pouvez "chaîner" les interruptions, vous pouvez constater que vous pouvez entretenir les lectures ADC plus efficacement, ou mettre l'ADC dans un mode différent où il fait plus de travail pour vous avant de l'interrompre (EG attendez que toutes les lectures soient disponibles, puis lisez tout en un seul coup, plutôt que 8 interruptions distinctes pour 8 lectures de canal ADC distinctes).

Sixièmement: utilisez un oscilloscope ou un analyseur logique et des broches d'E / S de rechange sur la carte pour tracer le temps que vous passez dans chaque bit de code, pour voir si vous pouvez l'accélérer. (Réglez la broche haute lorsque vous entrez dans une fonction / ISR, réglez-la à nouveau à la sortie).

Septièmement: Décidez si vous avez vraiment besoin de lire l'ADC, est-ce que le ralentissement va empirer les choses? C'est contre-intuitif, mais parfois courir plus lentement donne en fait de meilleurs résultats, en faisant le travail de moyenne du signal pour vous et en réduisant les pointes / transitoires qui pourraient causer des problèmes ou nécessiter un traitement supplémentaire pour les supprimer. Nous avons amélioré une routine PID de contrôle moteur en la faisant simplement tourner 1/4 de la vitesse, libérant ainsi une charge de temps CPU dans le processus.

John U
la source
Merci pour vos suggestions. Le problème pointe en quelque sorte vers le matériel.
Ktc
4

Un esclave de bus qui est occupé par d'autres choses a la capacité de s'étirer pour gagner du temps jusqu'à ce qu'il soit en mesure de poursuivre sa fin de communication. Il le fait en n'envoyant pas immédiatement l'impulsion d'horloge ACK / NACK, en maintenant la communication dans un état intermédiaire jusqu'à ce qu'elle soit prête à répondre.

L'étirement de l'horloge est le moyen approprié pour faire face à ce genre de situation. Un périphérique qui ne s'étire pas et fait d'autres mauvaises choses (blocage / redémarrage du bus, NACK une adresse ou une commande valide, etc.) peut être problématique, et impose une charge supplémentaire au maître pour garder les choses triées (il doit répéter les commandes , garder une trace des NACK, etc.)

Adam Lawrence
la source
Vous avez raison mais le problème est l'hôte. L'hôte est occupé avec d'autres choses, pas esclave. Donc, je ne suis pas sûr de pouvoir faire un étirement d'horloge.
Ktc
Utilisez-vous du matériel I2C intégré ou frappez-vous le protocole sur des lignes GPIO? Aucun délai d'expiration I2C spécifique n'est défini dans la norme, les esclaves doivent donc attendre indéfiniment que le maître termine un paquet.
Adam Lawrence
J'utilise les API STM32 IC2. Veuillez voir la mise à jour, cela ressemble à un problème de capacité.
Ktc
1

Selon les capacités du STM32 (je n'en ai jamais utilisé), vous pouvez essayer l'une des approches suivantes. Si vous pouvez fournir plus de détails sur ce que vous essayez de faire et avoir un argument convaincant sur la raison pour laquelle chaque interruption est nécessaire sous la forme que vous avez maintenant, alors une réponse plus spécifique peut être envisagée. Plus précisément dans votre cas, cependant, I2C est suffisamment lent pour que cela ne soit pas un problème avec des routines d'interruption bien écrites.

  • Les interruptions pour n'importe quoi peuvent généralement être désactivées. Il y a au plus une ou deux interruptions non masquables dans n'importe quel contrôleur habituel, dont l'une est réinitialisée. Si vous n'avez pas besoin d' un contrôle par interruption de quelque chose (ADC ou I2C, dans votre cas), transformez ce code périphérique en un code qui n'utilise pas d'interruptions, puis désactivez les interruptions.

  • Les gestionnaires d'interruption ne devraient pas être longs. Essayez d'en faire le moins possible à partir du vecteur d'interruption lui-même. L'approche minimaliste extrême des interruptions consiste à simplement définir un indicateur à partir de la routine de gestion des interruptions et à faire, par exemple, la boucle principale faire tout le travail à partir de ce moment. cela, mais cela vaut vraiment la peine de faire l'effort de voir ce qui doit vraiment être fait à partir des interruptions.

  • Si vous avez un DMA périphérique, utilisez-le au lieu d'interrompre à chaque octet. En règle générale, il serait plus facile de mettre l'ADC sur DMA par opposition à I2C, mais différentes puces ont des implémentations différentes. Je ne serais pas surpris s'il existait également un moyen propre de supprimer un échange I2C vers le DMA. Le DMA vous permet de réduire le nombre d'interruptions et laisse votre cœur de processeur libre de devoir traiter chaque bloc de données.

  • Essayez d'identifier les cas spécifiques où vous voyez une corruption de données et le mécanisme par lequel la corruption de données se produit. C'est beaucoup plus difficile à faire, mais avec l'utilisation créative d'un oscilloscope / analyseur logique moderne, vous pourrez peut-être voir certains des problèmes. Plus précisément, assurez-vous que le problème est lié au timing et non à la mémoire (ce qui est possible avec une combinaison de code terrible et d'un compilateur libéral)

EDIT: Quelques notes spécifiques concernant cette instance du problème, à partir de vos commentaires sur la question:

  • Avoir 80% de CPU utilisé pour lire l'ADC n'est généralement pas une chose intéressante à faire. La collecte de données est inutile si vous ne pouvez pas agir sur elle ou même enregistrer les données.
  • Même si vous collectez en quelque sorte (utilement) une énorme quantité de données, les interruptions ADC ne devraient pas être assez longues pour supprimer complètement le périphérique I2C pendant un temps suffisamment long pour lui faire perdre des données. I2C fonctionne au maximum à 100 / 400KHz. Vous auriez besoin d'une très, très longue interruption pour interrompre assez longtemps pour que cela ressemble à quelque chose de plus grave que la gigue d'horloge sur I2C.
Chintalagiri Shashank
la source
Merci. Notre système nécessite ce type d'ISR complexe et long, c'est une longue histoire. Vous avez raison cependant, I2C doit maintenir même sous cette charge d'interruption et il ne peut pas. Je soupçonne que le problème est dans le matériel, voir la mise à jour.
Ktc
Pour ce que ça vaut, d'après mon expérience, la plupart des cas d'utilisation qui semblent imposer un ISR incroyablement long sont en fait ceux qui méritent un RTOS. Et oui, selon votre dernière modification, cela semble être un problème matériel. Essayez de mettre un petit condensateur sur la ligne où se trouvait votre analyseur logique et vous irez probablement bien. Il est cependant plus difficile de savoir pourquoi cela est nécessaire. Je vérifierais les résistances de pullup I2C (peut être trop faible pour la capacité de votre bus) et vérifier les fiches techniques de tous les tampons / répéteurs I2C que vous utilisez.
Chintalagiri Shashank
0

Dans un système donné, il pourrait y avoir du bruit entrant dans l'horloge et les bus de données. Le fait que votre incrustateur logique supprime le problème le montre. Pour une mise en œuvre pratique et rapide, suivez simplement le signal donné par votre observation. Sur un bus i2c avec une implémentation de 400 kbits / sec, sur la base d'une observation similaire, j'ai connecté 2M en parallèle avec 12pf à la masse à partir de points d'horloge et de données et j'ai constaté que le problème était résolu. Cela supprime / filtre le bruit en dehors de la bande d'intérêt requise pour la communication i2c spécifique. Veuillez essayer et conseiller.

user41360
la source