W końcu to rozwiązałem, ale w dość niekonwencjonalny sposób. Porzuciłem bit-biting jako zbyt zawodny i próbowałem znaleźć inne rozwiązania, które pozwoliłyby mi na to samo bez dodawania dodatkowego sprzętu. Zastanawiałem się nad napisaniem sterownika jądra, który wyzwoli przerwanie w GPIO, a następnie ponownie skonfiguruję pin, aby był SPI i użył SPI do odczytania całego bajtu danych - ale wtedy wpadłem na lepszy pomysł.
Używam SPI do próbkowania linii z prędkością 20x szybkość transmisji. Całkowicie ignoruję piny SCLK i SS, podłączam linię RX do MISO, a linię TX do MOSI. To daje mi (1-bitowy) oscyloskopowy widok na linię RX i wyraźnie widzę bity przesyłane w linii szeregowej:
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
Na tej podstawie proste jest zakodowanie, aby ustalić właściwe pozycje, z których należy próbkować rzeczywiste bity danych. Strona wysyłająca jest równie trywialna, wystarczy przekonwertować każdy bajt na długi strumień bitów z bitem początkowym i bitem stop.
Powodem, dla którego działa to lepiej niż bit-bit, jest to, że SPI ma swój własny zegar, który nie zamraża się z jądrem, a linie wysyłania i odbierania SPI mają 16-bajtowe FIFO do przesyłania, które są również niezależne od zawieszenia jądra. Dla prędkości 9600 bodów używam zegara SPI 250 kHz, co oznacza, że mogę spać nawet milisekundę między napełnianiem i opróżnianiem FIFO bez żadnych błędów transmisji. Jednak, aby się pomylić po bezpiecznej stronie, używam snu 300 µs. Krótko przetestowałem, jak daleko mogę to przesunąć i przynajmniej zegar SPI 2 MHz był nadal użyteczny, więc to rozwiązanie można skalować również do wyższych prędkości transmisji.
Jedną brzydką częścią tego rozwiązania jest to, że sterownik SPI jądra nie obsługuje takiego przesyłania strumieniowego bitów. Oznacza to, że nie mogę tego zrobić, pisząc własny moduł jądra przy użyciu sterownika SPI jądra, a także nie mogę tego zrobić przy użyciu /dev/sdidev0.0 z poziomu użytkownika. Jednak na Raspberry Pi, SPI i inne urządzenia peryferyjne są dostępne bezpośrednio z przestrzeni użytkownika za pomocą mmap (): n / dev / mem, całkowicie pomijając kontrolę jądra. Nie jestem z tego powodu bardzo zadowolony, ale działa idealnie i daje dodatkową korzyść, że błędy segmentacji w przestrzeni użytkownika nie mogą spowodować awarii jądra (chyba że przypadkowo zepsują inne urządzenia peryferyjne). Jeśli chodzi o użycie procesora, 300 uśpienia wydaje się dawać mi około 7% ciągłego użycia procesora, ale mój kod jest bardzo nieoptymalny. Wydłużenie czasu uśpienia oczywiście obniża bezpośrednio użycie procesora.
Edycja: Zapomniałem wspomnieć, użyłem ładnej biblioteki bcm2835 do sterowania SPI z przestrzeni użytkownika, rozszerzając go w razie potrzeby.
Podsumowując: Mogę niezawodnie transmitować i odbierać łącze szeregowe 9600 bodów całkowicie z obszaru użytkownika, bezpośrednio przy użyciu układu SPI przez / dev / mem przy 250 kHz na Raspberry Pi.
reliability
może zależeć od działania i oczekiwań.