J'ai finalement résolu cela, mais d'une manière assez peu orthodoxe. J'ai abandonné le bit banging comme trop peu fiable et j'ai essayé de trouver d'autres solutions qui me permettraient de faire la même chose sans ajouter plus de matériel. J'envisageais d'écrire un pilote de noyau, ce qui déclencherait une interruption sur GPIO, puis reconfigurerait la broche en SPI et utiliser SPI pour lire un octet de données entier - mais j'ai eu une meilleure idée.
J'utilise SPI pour échantillonner les lignes à 20 fois la vitesse de transmission. J'ignore entièrement les broches SCLK et SS, connecte la ligne RX à MISO et la ligne TX à MOSI. Cela me donne une vue semblable à un oscilloscope (1 bit) dans la ligne RX et clairement voir les bits transmis dans la ligne série:
00 00 00 00 00 00
00 00 00 00 01 FF
FF FF FF FF 00 00
01 FF FF FF FF FF
FF FF E0 00 00 00
00 00 07 FF FF FF
FF FF
À partir de cela, il suffit de coder pour déterminer les positions correctes à partir desquelles échantillonner les bits de données réels. Le côté d'envoi est tout aussi trivial, j'ai juste besoin de convertir chaque octet en un long flux de bits avec le bit de début et le bit d'arrêt inclus.
La raison pour laquelle cela fonctionne mieux que le bit banging est que SPI a sa propre horloge qui ne se fige pas avec le noyau et que les lignes d'envoi et de réception SPI ont un FIFO de 16 octets pour le transfert qui est également indépendant des blocages du noyau. Pour 9600 bauds, j'utilise une horloge SPI à 250 kHz et cela signifie que je peux dormir même une milliseconde entre le remplissage et la vidange des FIFO sans aucune erreur de transmission. Cependant, pour me tromper, j'utilise des périodes de sommeil de 300 µs. J'ai brièvement testé jusqu'où je pouvais pousser cela et au moins une horloge SPI à 2 MHz était toujours utilisable, donc cette solution s'adapte également à des taux de transmission plus élevés.
La seule partie laide de cette solution est que le pilote SPI du noyau ne prend pas en charge un tel transfert de bits en continu. Cela signifie que je ne peux pas faire cela en écrivant mon propre module de noyau en utilisant le pilote SPI du noyau, et je ne peux pas non plus le faire en utilisant /dev/sdidev0.0 depuis le pays utilisateur. Cependant, sur le Raspberry Pi, le SPI et les autres périphériques sont accessibles directement depuis l'espace utilisateur par mmap (): n / dev / mem, contournant entièrement le contrôle du noyau. Je ne suis pas terriblement satisfait de cela, mais cela fonctionne parfaitement et cela offre l'avantage supplémentaire que les erreurs de segmentation dans l'espace utilisateur ne peuvent pas planter le noyau (à moins de jouer avec les autres périphériques par accident). En ce qui concerne l'utilisation du processeur, une veille de 300 µs semble me donner environ 7% d'utilisation du processeur en permanence, mais mon code n'est pas optimal. L'augmentation de la durée de veille réduit évidemment l'utilisation du processeur directement.
Edit: J'ai oublié de mentionner, j'ai utilisé la belle bibliothèque bcm2835 pour contrôler le SPI depuis l'espace utilisateur, en l'étendant si nécessaire.
Donc, pour résumer: je peux transmettre et recevoir de manière fiable sur une liaison série à 9600 bauds entièrement à partir de l'espace utilisateur en utilisant directement la puce SPI via / dev / mem à 250 kHz sur le Raspberry Pi.
reliability
pourrait dépendre de l'action et des attentes.