Saya bertanya-tanya bagaimana layaknya menggunakan bitbanging untuk menggerakkan 9600 baud serial melalui pin GPIO pada Raspberry Pi.
Jelas, Linux bukan platform yang sangat baik untuk bitbanging, karena ada sejumlah besar driver dan interupsi lain yang dapat memblokir CPU untuk periode waktu yang lama (1-10 ms). Namun, situasinya menjadi jauh lebih baik baru-baru ini, dan beberapa pre-emption sekarang diaktifkan secara teratur di kernel. Saya juga curiga bahwa kernel patch real-time dapat dengan mudah digunakan pada Raspberry Pi, dan perangkat keras serta driver yang terhubung dapat dipilih dengan hati-hati.
Standar saya untuk keandalan adalah bahwa ia harus tetap dalam toleransi serial normal 9600 baud sebagian besar waktu. Saat ini saya tidak yakin berapa banyak kesalahan yang dapat ditoleransi dalam praktiknya, tetapi ada transmisi ulang dan pengakuan dalam protokol, sehingga setidaknya sedikit toleran.
Jadi, pertanyaan saya adalah:
- Bisakah perangkat lunak penggunaland andal bit-bang 9600 baud speed?
- Apakah ini membutuhkan patch patch real-time?
- Berapa banyak kesalahan yang harus saya harapkan secara umum?
Juga, apakah ada contoh kode yang melakukan serial via GPIO bit banging? Saya tahu tentang Arduino SoftSerial, tapi hanya itu saja.
Untuk berjaga-jaga, untuk membatasi pertanyaan: ini bukan antarmuka serial standar dan UART Raspberry Pi sudah digunakan untuk tautan serial lain. Saya tidak berharap untuk jawaban yang menyarankan perangkat keras eksternal (seperti Gertboard atau Arduino) atau jawaban yang bergantung pada UART.
reliability
bisa tergantung pada tindakan dan harapan.Jawaban:
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:
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.
sumber
Tampaknya setidaknya tanpa tambalan real-time (CONFIG_PREEMPT_RT), Raspberry Pi tidak dapat diandalkan untuk menggedor serial baud 9600 dengan andal.
Saya menggunakan tester latensi sederhana yang mengkonfigurasi semua hal-hal sisi linux secara optimal (sched_fifo, priority 99, cpu_dma_latench 0us, mlockall). Saya mencoba tidur selama 100 µsec (sekitar 9600 baud) dan memeriksa latensi overruns pada sistem yang tenang selama 2 menit. Hasilnya adalah:
Min: 12 µsec Rata-rata: 24 µsec Maks: 282 µsec
Ini sepertinya hasil yang umum. Maks bervariasi dalam pengukuran yang lebih lambat antara 100 µsec dan 300 µsec. Saya juga memeriksa distribusinya dan tampaknya sebagian besar berada dalam kisaran 24 µsec. Hanya ada beberapa yang bergerak di atas 50 µsec, tetapi hampir selalu ada beberapa. Ada juga kadang-kadang latensi besar, seperti 4000 µsec, tetapi ini tidak cukup umum untuk diabaikan, setidaknya untuk saat ini.
Saya kira latensi maksimum harus di bawah 50 µsec untuk 9600 baud untuk tidak mendapatkan kesalahan dan latensi lebih dari 100 µsec menyebabkan benar-benar kehilangan sedikit transmisi atau penerimaan.
Ini semua bahkan tanpa menyentuh pin GPIO. Karena saya tidak dapat menjalankan bersih bahkan hanya dengan 2 detik, tampaknya aman untuk mengatakan bahwa tanpa tambalan waktu nyata, Raspberry Pi tidak dapat menggigit link serial baud 9600 tanpa menghasilkan kesalahan untuk waktu yang serius.
Saya akan menguji patch waktu-nyata nanti jika saya punya waktu.
(Alat yang digunakan: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary )
Pembaruan: Kernel RPi hang saat boot tanpa mendeteksi kartu SD jika dikompilasi dengan set patch CONFIG_PREEMPT_RT. Ini mungkin hal yang sederhana untuk diperbaiki, tetapi melihat perbedaan berantakan pada sumber RPi, saya pikir saya ingin menunggu sampai lebih banyak lagi ada di kernel mainline.
Jadi, menguji ini terlalu sulit, dan saya mengabaikannya.
sumber
Anda tidak perlu menggigit bang. Anda dapat mengatur interupsi tanah pengguna di rx gpio untuk mendeteksi jatuhnya bit awal. kemudian atur interupsi waktu untuk sampel di tengah bit. Modul kernel melakukan hal itu layak.
sumber