Saya akhirnya menyelesaikan ini, tetapi dengan cara yang tidak lazim. Saya meninggalkan bit-banging karena terlalu tidak dapat diandalkan dan mencoba mencari solusi lain yang memungkinkan saya melakukan hal yang sama tanpa menambahkan lebih banyak perangkat keras. Saya sedang mempertimbangkan untuk menulis driver kernel, yang akan memicu interupsi pada GPIO dan kemudian mengkonfigurasi ulang pin menjadi SPI dan menggunakan SPI untuk membaca seluruh byte data - tetapi kemudian saya mendapat ide yang lebih baik.
Saya menggunakan SPI untuk sampel garis pada 20x baud rate. Saya mengabaikan sepenuhnya pin SCLK dan SS, hubungkan garis RX ke MISO dan garis TX ke MOSI. Ini memberi saya (1-bit) tampilan seperti osiloskop ke jalur RX dan melihat dengan jelas bit yang ditransmisikan dalam baris serial:
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
Dari ini, ini adalah masalah pengkodean sederhana untuk mengetahui posisi yang benar dari mana untuk sampel bit data yang sebenarnya. Sisi pengiriman sama-sama sepele, saya hanya perlu mengkonversi setiap byte ke aliran bit yang panjang dengan bit mulai dan berhenti bit disertakan.
Alasan ini bekerja lebih baik daripada bit-banging adalah bahwa SPI memiliki jam sendiri yang tidak membeku dengan kernel dan SPI mengirim dan menerima jalur memiliki FIFO 16-byte untuk transfer yang juga independen dari pembekuan kernel. Untuk 9600 baud, saya menggunakan jam SPI 250kHz dan itu berarti saya bisa tidur bahkan dalam milidetik antara mengisi dan menguras FIFO tanpa kesalahan transmisi. Namun, untuk berbuat salah di sisi yang aman, saya menggunakan 300 μs tidur. Saya secara singkat menguji seberapa jauh saya bisa mendorong ini dan setidaknya jam 2MHz SPI masih dapat digunakan sehingga solusi ini juga skala ke tingkat baud yang lebih tinggi.
Bagian buruk dari solusi ini adalah bahwa driver kernel SPI tidak mendukung transfer bit streaming. Ini berarti saya tidak bisa melakukan ini dengan menulis modul kernel saya sendiri menggunakan driver kernel SPI, dan saya juga tidak bisa melakukannya dengan menggunakan /dev/sdidev0.0 dari tanah pengguna. Namun, pada Raspberry Pi, SPI dan periferal lainnya dapat diakses langsung dari userland oleh mmap (): n / dev / mem, melewati kontrol kernel sepenuhnya. Saya tidak terlalu senang dengan ini, tetapi bekerja dengan sempurna dan ini memberikan manfaat tambahan bahwa kesalahan segmentasi di userland tidak dapat crash kernel (kecuali mengacaukan dengan perangkat lain secara tidak sengaja). Sedangkan untuk penggunaan CPU, 300 μs tidur tampaknya memberi saya sekitar 7% penggunaan CPU terus-menerus, tetapi kode saya sangat tidak optimal. Meningkatkan durasi tidur jelas menurunkan penggunaan CPU secara langsung.
Sunting: Lupa untuk menyebutkan, saya menggunakan pustaka bcm2835 yang bagus untuk mengontrol SPI dari userland, memperluasnya jika perlu.
Jadi, untuk meringkas: Saya dapat mengirim dan menerima dengan andal pada 9600 baud serial seluruhnya dari userland dengan langsung menggunakan chip SPI via / dev / mem pada 250kHz pada Raspberry Pi.
reliabilitybisa tergantung pada tindakan dan harapan.