Dengan mengacu pada Arduino Uno, Mega2560, Leonardo dan papan serupa:
- Bagaimana cara kerja SPI?
- Seberapa cepat SPI?
- Bagaimana saya menghubungkan antara master dan slave?
- Bagaimana cara membuat budak SPI?
Harap dicatat: Ini dimaksudkan sebagai pertanyaan referensi.
arduino-uno
arduino-mega
c++
arduino-leonardo
spi
Nick Gammon
sumber
sumber
Jawaban:
Pengantar SPI
The Peripheral Interface Serial Bus (SPI) antarmuka digunakan untuk komunikasi antara beberapa perangkat jarak pendek, dan pada kecepatan tinggi.
Biasanya ada perangkat "master" tunggal, yang memulai komunikasi dan memasok jam yang mengontrol laju transfer data. Mungkin ada satu atau lebih budak. Untuk lebih dari satu budak, masing-masing memiliki sinyal "pilih budak" sendiri, dijelaskan nanti.
Sinyal SPI
Dalam sistem SPI full-blown Anda akan memiliki empat jalur sinyal:
Ketika banyak budak terhubung ke sinyal MISO, mereka diharapkan melakukan tri-state (tetap pada impedansi tinggi) garis MISO sampai mereka dipilih oleh Slave Select. Normally Slave Select (SS) menjadi rendah untuk menegaskannya. Artinya, aktif rendah. Setelah budak tertentu dipilih, ia harus mengkonfigurasi garis MISO sebagai output sehingga dapat mengirim data ke master.
Gambar ini menunjukkan cara pertukaran data saat satu byte dikirim:
Perhatikan bahwa tiga sinyal adalah output dari master (MOSI, SCK, SS) dan satu adalah input (MISO).
Pengaturan waktu
Urutan acara adalah:
SS
pergi rendah untuk menegaskannya dan mengaktifkan budakSCK
garis matikan untuk menunjukkan ketika garis data harus sampelSCK
(menggunakan clock phase default)SCK
(menggunakan fase clock default), dengan mengubahMISO
/MOSI
jika perluSS
pergi tinggi untuk menegaskan kembali ituPerhatikan bahwa:
Karena data dikirim dan diterima pada pulsa clock yang sama, tidak mungkin bagi budak untuk segera menanggapi master. Protokol SPI biasanya mengharapkan master untuk meminta data pada satu transmisi, dan mendapatkan respons pada transmisi berikutnya.
Menggunakan perpustakaan SPI di Arduino, melakukan satu transfer terlihat seperti ini dalam kode:
Kode sampel
Contoh pengiriman saja (mengabaikan data yang masuk):
Pengkabelan untuk SPI khusus keluaran
Kode di atas (yang hanya mengirim) dapat digunakan untuk mendorong register shift serial keluaran. Ini adalah perangkat keluaran saja, jadi kami tidak perlu khawatir tentang data yang masuk. Dalam kasus mereka, pin SS mungkin disebut pin "store" atau "latch".
Contoh dari ini adalah register geser serial 74HC595, dan berbagai strip LED, hanya untuk menyebutkan beberapa. Misalnya, tampilan LED 64 piksel yang digerakkan oleh chip MAX7219:
Dalam hal ini Anda dapat melihat bahwa pembuat papan telah menggunakan nama sinyal yang sedikit berbeda:
Sebagian besar papan akan mengikuti pola yang sama. Terkadang DIN hanya DI (Data In).
Berikut adalah contoh lain, kali ini papan display LED 7-segmen (juga didasarkan pada chip MAX7219):
Ini menggunakan nama sinyal yang persis sama dengan papan lainnya. Dalam kedua kasus ini Anda dapat melihat bahwa papan hanya membutuhkan 5 kabel untuk itu, tiga untuk SPI, ditambah daya dan ground.
Fase jam dan polaritas
Ada empat cara Anda dapat mencicipi jam SPI.
Protokol SPI memungkinkan variasi pada polaritas pulsa clock. CPOL adalah polaritas jam, dan CPHA adalah fase jam.
Ini diilustrasikan dalam grafik ini:
Anda harus merujuk ke lembar data untuk perangkat Anda agar fase dan polaritasnya benar. Biasanya akan ada diagram yang menunjukkan cara mengambil sampel jam. Misalnya, dari datasheet untuk chip 74HC595:
Seperti yang Anda lihat, jam biasanya rendah (CPOL = 0) dan disampel di tepi terdepan (CPHA = 0) sehingga ini adalah mode SPI 0.
Anda dapat mengubah polaritas jam dan fase dalam kode seperti ini (pilih satu saja, tentu saja):
Metode ini sudah usang dalam versi 1.6.0 dan seterusnya dari Arduino IDE. Untuk versi terbaru, Anda mengubah mode jam dalam
SPI.beginTransaction
panggilan, seperti ini:Pesanan data
Standarnya adalah bit yang paling signifikan terlebih dahulu, namun Anda dapat memberitahu perangkat keras untuk memproses bit yang paling signifikan terlebih dahulu seperti ini:
Sekali lagi, ini sudah usang dalam versi 1.6.0 dan seterusnya dari Arduino IDE. Untuk versi terbaru, Anda mengubah urutan bit dalam
SPI.beginTransaction
panggilan, seperti ini:Kecepatan
Pengaturan default untuk SPI adalah menggunakan kecepatan jam sistem dibagi dengan empat, yaitu, satu pulsa clock SPI setiap 250 ns, dengan asumsi jam CPU 16 MHz. Anda dapat mengubah pembagi jam dengan menggunakan
setClockDivider
seperti ini:Di mana "pembagi" adalah salah satu dari:
Laju tercepat adalah "bagi 2" atau satu pulsa clock SPI setiap 125 ns, dengan asumsi clock CPU 16 MHz. Oleh karena itu, diperlukan 8 * 125 ns atau 1 μs untuk mengirimkan satu byte.
Metode ini sudah usang dalam versi 1.6.0 dan seterusnya dari Arduino IDE. Untuk versi terbaru, Anda mengubah kecepatan transfer dalam
SPI.beginTransaction
panggilan, seperti ini:Namun pengujian empiris menunjukkan bahwa perlu memiliki dua pulsa clock antara byte, sehingga tingkat maksimum di mana byte dapat clocked adalah masing-masing 1,125 μs masing-masing (dengan pembagi jam 2).
Untuk meringkas, setiap byte dapat dikirim pada tingkat maksimum satu per 1,125 μs (dengan clock 16 MHz) memberikan laju transfer maksimum teoritis 1 / 1,125 μs, atau 888.888 byte per detik (tidak termasuk overhead seperti pengaturan SS rendah dan sebagainya) di).
Menghubungkan ke Arduino
Arduino Uno
Menghubungkan melalui pin digital 10 hingga 13:
Menghubungkan melalui header ICSP:
Arduino Atmega2560
Menghubungkan melalui pin digital 50 hingga 52:
Anda juga dapat menggunakan header ICSP, mirip dengan Uno di atas.
Arduino Leonardo
Leonardo dan Micro tidak mengekspos pin SPI pada pin digital, tidak seperti Uno dan Mega. Satu-satunya pilihan Anda adalah menggunakan pin header ICSP, seperti yang diilustrasikan di atas untuk Uno.
Banyak budak
Seorang master dapat berkomunikasi dengan banyak budak (namun hanya satu per satu). Itu melakukan ini dengan menyatakan SS untuk satu budak dan membatalkannya untuk yang lain. Budak yang memiliki SS menegaskan (biasanya ini berarti RENDAH) mengkonfigurasi pin MISO sebagai output sehingga budak, dan budak itu sendiri, dapat menanggapi master. Budak lainnya mengabaikan pulsa clock yang masuk jika SS tidak ditegaskan. Dengan demikian Anda memerlukan satu sinyal tambahan untuk setiap budak, seperti ini:
Dalam grafik ini Anda dapat melihat bahwa MISO, MOSI, SCK dibagi di antara kedua budak, namun masing-masing budak memiliki sinyal SS (pemilihan budak) sendiri.
Protokol
SPI spec tidak menentukan protokol seperti itu, jadi terserah pada pasangan master / slave individual untuk menyetujui apa artinya data. Sementara Anda dapat mengirim dan menerima byte secara bersamaan, byte yang diterima tidak bisa menjadi respons langsung ke byte yang dikirim (karena mereka sedang dirangkai secara bersamaan).
Jadi akan lebih logis bagi salah satu ujung untuk mengirim permintaan (mis. 4 mungkin berarti "daftar direktori disk") dan kemudian melakukan transfer (mungkin hanya mengirim nol ke luar) hingga menerima respons lengkap. Respons mungkin berakhir dengan baris baru, atau karakter 0x00.
Baca datasheet untuk perangkat budak Anda untuk melihat urutan protokol apa yang diharapkannya.
Cara membuat budak SPI
Contoh sebelumnya menunjukkan Arduino sebagai master, mengirimkan data ke perangkat slave. Contoh ini menunjukkan bagaimana Arduino bisa menjadi budak.
Pengaturan perangkat keras
Hubungkan dua Arduino Unos bersama-sama dengan pin berikut yang terhubung satu sama lain:
13 (SCK)
+ 5v (jika diperlukan)
Pada Arduino Mega, pinnya adalah 50 (MISO), 51 (MOSI), 52 (SCK), dan 53 (SS).
Bagaimanapun, MOSI di satu ujung terhubung ke MOSI di sisi lain, Anda tidak bertukar sekitar (yaitu Anda tidak memiliki MOSI <-> MISO). Perangkat lunak mengkonfigurasi salah satu ujung MOSI (master end) sebagai output, dan ujung lainnya (slave end) sebagai input.
Contoh utama
Contoh budak
Budak sepenuhnya didorong oleh interupsi, sehingga dapat melakukan hal-hal lain. Data SPI yang masuk dikumpulkan dalam buffer, dan sebuah flag ditetapkan ketika "byte signifikan" (dalam hal ini baris baru) tiba. Ini memberitahu budak untuk memulai dan mulai memproses data.
Contoh menghubungkan master ke slave menggunakan SPI
Cara mendapatkan respons dari seorang budak
Sebagai lanjutan dari kode di atas yang mengirimkan data dari master SPI ke slave, contoh di bawah ini menunjukkan pengiriman data ke slave, setelah itu melakukan sesuatu dengannya, dan mengembalikan respons.
Masternya mirip dengan contoh di atas. Namun poin penting adalah bahwa kita perlu menambahkan sedikit keterlambatan (sekitar 20 mikrodetik). Kalau tidak, budak tidak memiliki kesempatan untuk bereaksi terhadap data yang masuk dan melakukan sesuatu dengannya.
Contoh ini menunjukkan pengiriman "perintah". Dalam hal ini "a" (tambahkan sesuatu) atau "s" (kurangi sesuatu). Ini untuk menunjukkan bahwa budak benar-benar melakukan sesuatu dengan data.
Setelah menyatakan slave-select (SS) untuk memulai transaksi, master mengirim perintah, diikuti oleh sejumlah byte, dan kemudian menaikkan SS untuk mengakhiri transaksi.
Poin yang sangat penting adalah bahwa slave tidak dapat menanggapi byte yang masuk pada saat yang sama. Responsnya harus dalam byte berikutnya. Ini karena bit yang dikirim, dan bit yang diterima, sedang dikirim secara bersamaan. Jadi untuk menambahkan sesuatu ke empat angka kita perlu lima transfer, seperti ini:
Pertama kami meminta tindakan pada nomor 10. Tapi kami tidak mendapatkan jawaban sampai transfer berikutnya (yang untuk 17). Namun "a" akan ditetapkan ke balasan ke 10. Akhirnya kami akhirnya mengirim "dummy" nomor 0, untuk mendapatkan balasan sebesar 42.
Master (contoh)
Kode untuk slave pada dasarnya melakukan hampir semua hal dalam rutinitas interupsi (dipanggil ketika data SPI yang masuk tiba). Dibutuhkan byte yang masuk, dan menambah atau mengurangi sesuai "byte perintah" yang diingat. Perhatikan bahwa respons akan "dikumpulkan" lain kali melalui loop. Inilah sebabnya mengapa master harus mengirim satu "dummy" transfer terakhir untuk mendapatkan jawaban akhir.
Dalam contoh saya, saya menggunakan loop utama untuk hanya mendeteksi ketika SS tinggi, dan menghapus perintah yang disimpan. Dengan begitu, ketika SS ditarik rendah lagi untuk transaksi berikutnya, byte pertama dianggap sebagai byte perintah.
Lebih dapat dipercaya, ini akan dilakukan dengan interupsi. Artinya, Anda akan secara fisik menghubungkan SS ke salah satu input interupsi (misalnya, pada Uno, hubungkan pin 10 (SS) ke pin 2 (input interupsi), atau gunakan pin-change interrupt pada pin 10.
Kemudian interupsi dapat digunakan untuk melihat ketika SS ditarik rendah atau tinggi.
Budak (contoh)
Contoh output
Keluaran penganalisis logika
Ini menunjukkan waktu antara mengirim dan menerima dalam kode di atas:
Fungsionalitas baru di IDE 1.6.0 dan seterusnya
Versi 1.6.0 dari IDE telah mengubah cara SPI bekerja, sampai batas tertentu. Anda masih perlu melakukannya
SPI.begin()
sebelum menggunakan SPI. Itu mengatur perangkat keras SPI. Namun sekarang, ketika Anda akan memulai berkomunikasi dengan budak Anda juga lakukanSPI.beginTransaction()
untuk mengatur SPI (untuk budak ini) dengan benar:Ketika Anda selesai berkomunikasi dengan budak, Anda menelepon
SPI.endTransaction()
. Sebagai contoh:Mengapa menggunakan SPI?
Ini adalah pertanyaan yang sangat bagus. Jawaban saya adalah:
Kedua metode memiliki tempat masing-masing. I 2 C memungkinkan Anda menghubungkan banyak perangkat ke satu bus (dua kabel, ditambah arde) sehingga akan menjadi pilihan yang lebih disukai jika Anda perlu menginterogasi sejumlah besar perangkat, mungkin cukup jarang. Namun kecepatan SPI bisa lebih relevan untuk situasi di mana Anda perlu membuat output dengan cepat (mis. Strip LED) atau input dengan cepat (mis. Konverter ADC).
Referensi
Halaman saya tentang SPI - juga memiliki detail tentang bit-banged SPI, dan menggunakan USART untuk mendapatkan SPI perangkat keras kedua pada chip Atmega328.
Serial Peripheral Interface Bus - Wikipedia
Halaman referensi perpustakaan Arduino SPI
Dokumentasi SPI di PJRC
Protokol SPI - Sparkfun
sumber
Are you going to cover the weirdness that is the Due's SPI?
- Saya tidak tahu apa-apa tentang SPI Due (selain menganggap protokol keseluruhan sama). Anda dapat menambahkan balasan yang mencakup aspek itu.