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.
Réponses:
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.
la source
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.)
la source
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:
la source
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.
la source