SPI kernelio modulis
Kadangi jau išmokome rašyti labas pasauli kernel modulius, reikia imtis ko nors rimtesnio. Šį kartą mokinsimės rašyti kernelio draiverį nusiųsti duomenims SPI įrenginiui. Kaip ir *”labas pasauli”* pavyzdyje, duomenys bus siunčiami modulio prijungimo (inicializavimo) metu.
Taip pat, dėl įdomumo panaudosime dinamiškai moduliui galimą priskirti parametrą, kurį bus galima nurodyti prijungiant modulį.
Kaip veikia SPI įrenginio prijungimas Linux kernelyje
Iš pradžių reikia susirasti masterį. Masteris randamas pagal magistralės numerį (kompiuteriukas gali turėti kelis masterius — spi kontrolerius). Mūsų pavyzdyje masterio numerį bus galima nurodyti kaip parametrą, o jeigu jis nebus nurodytas, bus imama numatytoji reikšmė — 0, kuri turėtų tikti daugeliu atvejų.
Kai jau turime masterį, reikia susikurti kanalą per kurį vyks bendravimas. To kanalo tipas yra struct spi_device*\. Sėkmingai jį sukūrus reikėtų nepamiršti jo atlaisvinti modulį atjungiant.
Sukuriant kanalą reikia nurodyti šiek tiek informacijos apie mūsų prijungiamą įrenginį (slave) — kokiu greičiu jis gali priimti duomenis, modaliasą, kokiu režimu jis dirba, naudojamas CS (chip select) numeris ir pan.
Inicializavus kanalą jau galime pradėti apsikeitinėti duomenimis. Tam galime rinktis iš daugybės SPI duomenų apsikeitimo funkcijų:
- spi_write — siųsti duomenis sinchroniškai;
- spi_read — gauti duomenis sinchroniškai;
- spi_sync_transfer — sinchroniškai siųsti ir gauti duomenis tuo pačiu metu;
- spi_w8r8 — sinchronikai išsiųsti 8 bitus ir tada nuskaityti 8 bitus;
- spi_w8r16 — sinchronikai išsiųsti 8 bitus ir tada nuskaityti 16 bitų;
- spi_w8r16be — sinchronikai išsiųsti 8 bitus ir tada nuskaityti 16 bitų big-endian formatu;
- spi_async — siųsti duomenis asinchroniškai;
- spi_async_locked — siųsti ir gauti duomenis asinchroniškai, bet užrakinti magistralę;
- spi_sync — siųsti ir gauti duomenis sinchroniškai;
- spi_sync_locked — siųsti duomenis sinchroniškai ir užrakinti magistralę;
- spi_write_then_read — sinchroniškai siųsti duomenis, o po to skaityti.
Pavyzdyje nusiųsime 8 bitus ir nieko nenuskaitinėsime.
Kodas
Kodo gavosi ne tiek ir daug. Atskirai jo neaprašinėsiu, viskas matyti komentaruose.
1 |
|
Testuojame
Kaip ir *”labas pasauli”* atveju naudosime insmod komandą, tačiau dar papildomai nurodysime ir busnum parametrą. Jo nurodyti nebūtina, nes numatytoji reikšmė ir taip 0, bet ko nepadarysi dėl skaitytojo.

Kaip matome komanda nieko negražino. Vadinasi viskas gerai. Dėl viso pikto pasitikrinkime dmesg:

Jeigu jums nepasisekė ir gaunate klaidą “chipselect 0 already in use ? spidev.”, vadinasi pamiršote po LPH9157-2 bandymų atkeisti device-tree (ten bus likusi spidev sekcija).
O kaip būti tikriems, kad duomenys tikrai buvo išsiųsti? Ar nelieka nieko kito, kaip tik pasitikėti dmesg žinute? Ne, visada į pagalbą galima pasitelkti osciloskopą. Taip ir padarykime:

Viskas taip, kaip ir turėtų būti — CLK signalas yra, duomenų signalas (MOSI) irgi atitinka siunčiamus duomenis, o CS yra žemas (0). Apačioje netgi iššifruoti siunčiami duomenys 0b11010011 atitinka kintamojo komanda_kuria_siusime_irenginiui reikšmę.
Kaip visada, kodą rasite github’e.