Saya mengode sesuatu menggunakan kontrol langsung GPIO, ada beberapa sumber daya yang bagus untuk ini, seperti http://elinux.org/RPi_Low-level_peripherals#GPIO_hardware_hacking ; prosesnya melibatkan open ("/ dev / mem") dan kemudian operasi mmap secara efektif memetakan alamat fisik yang diinginkan ke dalam ruang alamat virtual Anda. Kemudian Anda membaca bagian 6 dari http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf ini untuk mengetahui bagaimana I / O dikontrol.
Untuk mengubah ke fungsi pin (input, atau output, atau berbagai fungsi khusus) Anda memodifikasi bidang 3-bit ini di register I / O GPFSELx (000 = input, 001 = output musuh contoh). Operasi modifikasi ini dikompilasi ke operasi dengan pemuatan dan penyimpanan biasa (mis. Untuk mengubah GPIO0 menjadi input: * (regptr) & = ~ 7; yang mengkompilasi ke sesuatu seperti
ldr r2, [r3, #0] ; r = *ptr (load r2 from I/O register)
bic r2, r2, #7 ; r2 &= ~7
str r2, [r3, #0] ; *ptr = r2 (store r2 to I/O register)
Masalahnya adalah ini: jika terjadi interupsi antara beban dan penyimpanan, dan proses lain atau ISR memodifikasi register I / O yang sama, operasi penyimpanan (berdasarkan basi yang dibaca dalam r2) akan mengembalikan efek dari operasi lainnya. Jadi mengubah register I / O ini benar-benar perlu dilakukan dengan operasi baca / modifikasi / penulisan atom (terkunci). Contoh yang saya lihat tidak menggunakan operasi yang terkunci.
Karena register I / O ini umumnya diubah hanya ketika mengatur sesuatu, kecil kemungkinan masalah akan terjadi, tetapi 'tidak pernah' selalu lebih baik daripada 'tidak mungkin'. Juga, jika Anda memiliki aplikasi di mana Anda bit-bashing untuk meniru keluaran kolektor terbuka, maka (sejauh yang saya tahu) ini melibatkan pemrograman output ke 0 dan kemudian beralih antara output (untuk rendah) atau input ( untuk off / high). Jadi dalam hal ini akan sering ada mod untuk register I / O ini, dan modifikasi yang tidak aman akan jauh lebih mungkin menyebabkan masalah.
Jadi, mungkin ada 'bandingkan dan set' ARM atau operasi serupa yang dapat digunakan di sini untuk melakukan ini, adakah yang bisa mengarahkan saya ke sana, dan bagaimana membuat itu terjadi dari kode C?
[Catatan, tidak ada hal khusus yang diperlukan ketika Anda memprogram I / O sebagai output dan hanya mengubahnya dari 0 menjadi 1 atau sebaliknya; karena ada register I / O tempat Anda menulis, untuk mengatur bit yang dipilih menjadi 1 dan yang lain untuk menghapus bit yang dipilih menjadi 0. Tidak diperlukan baca / tulis untuk operasi ini, sehingga tidak ada bahaya dari interupsi].
/dev/mem
, sepertinya kode Anda adalah kode userspace. Saya tidak berpikir bahwa dalam OS modern kita harus berhati-hati tentang interupsi perubahan nilai register dalam kode userspace. Saya percaya bahwa ini tidak akan menjadi masalah bahkan dalam kode ruang kernel karena Linux mengembalikan semua register ketika interrupt handler menyelesaikan tugasnya.Jawaban:
Saya melihat ke dalam ini, ARM memiliki instruksi 'ldrex dan' strex ', strex akan mengembalikan hasil yang gagal jika eksklusivitas hilang (atau mungkin telah hilang) sejak ldrex, yang mencakup sakelar konteks (atau prosesor lain yang memodifikasi yang sama) daftar di lingkungan multi-prosesor). Jadi bisa dilakukan menggunakan itu; jika strex gagal Anda loop up, dan lakukan kembali operasi (dengan ldrex segar).
ref: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dht0008a/ch01s02s01.html
Rutinitas di bawah ini tampaknya bekerja pada Raspberry Pi (dalam hal mereka menghasilkan assembler yang saya harapkan; dan bahwa efek pada bit ketika saya menggunakannya seperti yang diharapkan. Saya belum memverifikasi bahwa mereka melindungi terhadap masalah beralih konteks) . Perhatikan bahwa ini adalah inline daripada fungsi, sehingga harus dimasukkan ke dalam file header.
[ EDIT : Ini tidak berfungsi untuk tujuan yang didiskusikan, sepertinya itu tidak diizinkan. Jika saya menggunakan rutinitas ini di mana * addr adalah variabel biasa, itu berfungsi dengan baik. Ketika saya menggunakannya di mana * addr diarahkan ke register GPIO yang dipetakan, proses mendapatkan kesalahan bus. (Ketika saya mengubah ldrex / strex ke ldr / str dan menonaktifkan do loop, itu kemudian berfungsi). Jadi sepertinya monitor eksklusif ARM tidak dapat, atau tidak diatur, berfungsi pada I / O yang dipetakan di memori, dan pertanyaannya tetap terbuka.]
sumber