Interruption matérielle pour l’acquisition de données synchrones

Je cherche un moyen simple de déclencher mon logiciel d’acquisition de données en utilisant une impulsion TTL externe. Je dois échantillonner les données de plusieurs sources de manière synchrone avec une horloge de référence de 5 Hz. L’acquisition ne nécessite pas de priorité en temps réel, mais je veux m’assurer que mon logiciel est déclenché le plus rapidement possible et exactement une fois par cycle d’horloge externe. Je préférerais faire cela en obtenant en quelque sorte une interruption du déclencheur externe sans avoir besoin d’utiliser une boucle d’interrogation rapide. Autant que je sache, vous ne pouvez pas simplement utiliser une broche de port parallèle pour une interruption dans un système d’exploitation moderne comme Linux. Des idées?

Je pense également à générer des paquets de diffusion sur mon réseau pour signaler aux autres machines du réseau qu’un événement déclencheur s’est produit. En raison de la latence du réseau, le temps disponible dans les 200 ms entre les déclencheurs pour effectuer l’acquisition peut ne pas être suffisant.

Plutôt que d’utiliser le port parallèle, avez-vous envisagé d’utiliser un périphérique série? Comme vous avez un signal TTL, vous aurez peut-être besoin d’un convertisseur de niveau pour convertir le TTL en niveaux RS232 +/- 12V. Une fois que vous utilisez un périphérique série, vous pouvez utiliser les appels série ioctl() standard pour détecter un changement d’état du signal de contrôle.

Plus précisément, vous pouvez utiliser l’ioctl TIOCMIWAIT sur le périphérique série connecté pour attendre un changement, par exemple la ligne DCD, que vous souhaitez connecter à votre source d’horloge.

Votre application de l’espace utilisateur serait bloquée dans l’appel système TIOCMIWAIT ioctl jusqu’à ce qu’il y ait un changement d’état sur votre ligne d’horloge, à quel point votre application deviendrait exécutable et reviendrait de l’ioctl. Vous devrez peut-être veiller à gérer le cas où vous obtenez une modification de l’interruption de l’état sur les fronts montants et descendants de vos signaux de contrôle série. Sur certains matériels UART (ex: TL16C554A UART), il est possible que vous n’obteniez une interruption que pour une transition de signal dans une seule direction. Pour le TL16C554A, par exemple, le TIOCMIWAIT ne tomberait que sur le front montant de tout changement de signal de sonnerie.

L’utilisation des ioctls série de cette manière présente également l’avantage de pouvoir utiliser un dongle USB-Serial TIOCMIWAIT charge TIOCMIWAIT si nécessaire (par exemple, PL2303) tout en conservant la compatibilité logicielle au niveau utilisateur, mais avec une latence accrue.

Si vous avez besoin d’une latence inférieure à celle que vous pouvez obtenir via l’espace utilisateur, il serait préférable d’écrire un module de pilote du kernel capable de gérer la synchronisation et l’échantillonnage, mais je ne suggérerais cette route que si cela est absolument nécessaire. Il est plus facile de développer le code de l’espace utilisateur.

Voici quelques exemples de fragments de code C incomplets pour l’utilisation de l’ioctl TIOCMIWAIT .

 int serial_fd = open(cmdline.device_name, O_RDWR | O_NONBLOCK | O_NOCTTY); static const unsigned int ri_flag = TIOCM_RNG; /* Set up serial port here using tcsetattr. Set CRTSCTS | CLOCAL to ensure status interrupts * are generated. */ while (1) { /* Wait for positive RI transition. TIOCMIWAIT takes a mask * as argument, only returning when the appropriate signal has changed. */ if (ioctl(serial_fd, TIOCMIWAIT, ri_flag)) { fprintf(stderr, "ioctl() failed waiting for RI edge [%s]\n", strerror(errno)); break; } /* Do sensor sampling here. You could use TIOCMGET to first verify that * the clock line is in the expected state, eg high, before continuing. */ } 

L’interrogation est une bonne méthode pour un débit de données aussi lent. Sondage à 1 ms. Cela devrait être bien. Essayer d’utiliser une interruption matérielle va causer beaucoup de douleur.

Google pour “Interrupt Linux GPIO” si vous voulez le faire à la dure. 🙂

https://developer.ridgerun.com/wiki/index.php/How_to_use_GPIO_signals

J’ai fini par utiliser la ligne CTS du port série pour le déclencheur en utilisant l’ioctl TIOCMIWAIT par réponse d’Austin Phillips. Étant donné que RS232 nécessite des niveaux de +/- 12V, j’ai pu obtenir la puissance nécessaire pour ce déphaseur à partir des autres lignes de contrôle série.

Schéma de changement de niveau

Le code Python pour implémenter cette solution peut être trouvé en question: Port de connexion du moniteur série Python (RS-232)

Envisagez de connecter la source d’impulsion externe au ping ‘CD’ d’un port série réel (! Pas un convertisseur USB vers RS232). Ensuite, vous pouvez utiliser le “api PPS” pour obtenir un horodatage exact à partir duquel la broche “est allée” autant que possible.

Vous pourriez avoir besoin d’un décaleur de signal TTL; tous les ports série ne fonctionnent pas correctement avec les niveaux de signal TTL.

Le PPS api est normalement utilisé pour le chronométrage. Par exemple, connectez la broche PPS d’un module GPS à votre PC et laissez NTP synchroniser avec cela. Cela vous donne une précision microseconde.

Cet api de PPS est supposé être plus précis que toute autre solution d’espace utilisateur (par exemple, le TIOCMIWAIT ioctl) car il est complètement géré dans le kernel, dès que l’interruption (déclenchée par le changement de signal du CD) entre en jeu. avoir au moins un changement de contexte. J’ai fait des tests sur un Raspberry Pi et une solution en espace utilisateur donne au moins 6us d’instabilité.

Le PPS api vous donne un horodatage à partir du moment où l’impulsion a été détectée.

Pourquoi ne pas utiliser un convertisseur USB vers RS232: je lis quelque part (en relation avec le chronométrage) que les périphériques USB sont interrogés une fois toutes les +/- 1ms. Cette fréquence d’interrogation dépend également du niveau d’occupation du système par d’autres périphériques USB et je pense que l’horloge interne du périphérique USB peut également influencer les choses. Je n’ai jamais mesuré cela.

URL pertinentes:

En ce qui concerne la fonctionnalité réseau: utilisez les diffusions UDP, n’utilisez pas TCP.