Kadangi po truputuką kurpiu savo mistinį CAN magistralės projektą, tai po truputuką pradėjau artėti ir prie to galo, kuris viską kaip ir valdys (ar, tiksliau, konfigūruos ir stebės). Tas galas, be abejo, kažkuris tai Raspberry Pi kompiuteriukas. Kadangi „RS Components“ atstovai man padovanojo trečiąją Avietę, tai pagalvojau, kad arba ją, arba kurį nors kitą daiktą panaudosiu būtent šiam poreikiui patenkinti.
O kaip dabar Raspberry Pi prijungti prie CAN tinklo? Jou. Geras klausimas, į kurį aš jau turu atsakymą sau — Canberry. Tiesa, aš užsisakiau neizoliuotą versiją, bo pigesnė, bet ir šiaip galvos dėl to per daug nesuku. Tai dabar tą daiktą pabandysime ir užkurti.
Pirmiausia tai apie pačią plokštę:
Tai — „Industrial Berry“ sukurtas Avietės skydelis su SPI-CAN konverteriu MCP2515 ir CAN signalo generatoriumi MCP2551. Plokštėje taip pat dar yra DS3231 realaus laiko laikrodukas (tas geresnis) prijungtas per I²C ir lizdas baterijai laiko išsaugojimui. Du viename, trumpai tariant. Labai džiugu.
Visi komponentai iš apatinės pusės. Viršujė tik terminalas:
Deja, prie trečiosios Avietės su jos dėžute tiko nelabai, teko prarankioti gabaliukų (o tam ši dėžutė puikiai tinka):
Dabar yra keli variantai, kaip reikalą užkurti. Vienas — susikonfigūruoti branduolį su atitinkamu CAN moduliu beigi pasidaryti laikroduko konfigūraciją. Antras — parsitįsti jau paruoštą Raspbian Jessie kopiją iš „Industrial Berry“. Kadangi laiką švaistyti turiu kur linksmiau, tai nusprendžiau naudotis antruoju variantu. Kas toliau?
Parsitįsiau atvaizdėlį, sukišau kortelėn. Tiksliau, paleidau kištis, o tuo tarpu įsijungiau lituoklį. Ant šitos plokštės yra SMD trumpiklis, kuris reikalingas galutiniam CAN mazgui, užtrumpina 120 Ω rezistoriuką:
Užkrėčiau biškį lydmetalio, vis tiek Avietė mano tinklo dizaine bus ant galo:
Tiunintas Raspbianas tuo tarpu susikišo į korčikę. Pasileidau, atlikau visus pradinius derinimus, einu ieškoti toliau.
Naminiame kataloge yra can-start.sh skriptukas. Jame viskas užkomentuota (nes branduolio modulis jau paruoštas) ir esminė likus tik viena eilutė:
ip link set can0 up type can bitrate 1000000
Čia, manau, viskas aišku — paleidžiamas can0 tinklo interfeisas su nurodyta CAN sparta. Kadangi aš naudoju 10 kbps, tai porą nuliukų nutrinu ir paleidžiu.
O toliau yra toks smagumas, kad CAN įrenginys atvaizduojamas kaip tinklo sąsaja:
~ $ ifconfig can0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 UP RUNNING NOARP MTU:16 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:10 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Kažkuris elektrodas, regis, GPIO 22, dar prikabintas ir kaip CAN pertraukimas (kai žinelė ateina), candump utėliukė tuo naudojasi.
Nagi dabar reikia išsiaiškinti, kaip su kažkokiom kitom programinėm priemonėm gauti ir siųsti CAN pranešimukus, pageidautina būtų Python, bet gali sueiti ir C — pasidaryti Python moduliuką yzy pyzy.
Pradžiai bandau prisijungti šitą daiGtą prie savo dabar turimo minimalaus CAN „tinklo“ su dviem devbordukais. Tam nuo vienos CAN plokštelės nulitavau tąjį 120 Ω rezistorių, kad galėtų būti tarpiniu mazgu tinkle:
Dar viena smulkmena, šita plokštė yra padaryta pagal Raspberry HAT specifikacijas, tai ji turi ir visas skylutes, kaip Raspberry Pi B+, B2 ir B3 Aviečių. Na, ir dar ten kažkokį identifikuojantį EEPROMą turėtų turėti, bet ar turi — nežinau.
Visgi paskui nusprendžiau Avietę iš dėžutės išsipakuoti. Kad plokštė nesilaikytų vien ant GPIO elektrodų, įsukau vieną varžčiuką su keliom veržlikėm:
Neturiu nailoninių kaištukų tam reikalui, tai išsisukau šitaip.
Toliau priartėjau prie tos vietos, kai reikia patikrinti, ar Avietė gali matyti CAN pranešimukus. Sujungiau viską taip, kaip reikia: vienam gale bandomasis CAN aparatas su FreeRTOS, per vidurį primityvus dviejų pranešimukų siuntikas, o antram gale — Avietė:
Jungiam candump ir žiūrom, kas bus.
Deja, pirmuoju bandymu nesėkmė. Pranešimukai tarp mano įrenginių skraido, o Avietė nieko nerodo 😦 Prijungiau dar ir bendrą žemę dėl visa ko — nieko. Ką gi, ne taip viskas paprasta, kaip norėtųsi, blė…
Atsisėdau nagrinėti problemų. Pirmoji buvo susijusi su tiuninto Raspbiano konfigūracija. Jiems gal ir suveikė, o man su 4.1.7 (o paskui ir su 4.1.21) kerneliu kažkaip ne viskas buvo taip, kaip pavyzdžiuose. Po paskaitymų savo /boot/config.txt failą kiek pakeičiau. O būtent eilutę:
dtoverlay=mcp2515-can0-overlay,oscillator=16000000,interrupt=22
pakeičiau cielomis trimis:
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=22 dtoverlay=spi-bcm2835-overlay dtoverlay=spi-dma-overlay
Visaip landžiodamas ir knaisiodamasis netyčiukais aptikau vieną dalyką: ogi nežinau, koks visgi tiksliai yra mano CAN magistralės greitis. Taip, aš nusistatęs kažkur tai prescalerį, pakopijuotą iš Standard Peripherals pavyzdukų… bet pasižiūrėjau, kad neaišku, kokie parinkti SJW, BS1 ir BS2 vienetai.
Kas čia per keiksmažodžiai? Nagi, šiaip iš pirmo žvilgsnio atrodo velniškai sudėtingai, bet aš padariau šį darbą už jumis, tai tik skaitykit ir kramtykit.
Kad CAN magistrale nutekėtų vienas bitukas, laidais nuskrenda krūvelė impulsų. Jų gali būti nuo varganų 3 iki cielų 28. Na, čia ribiniai atvejai, paprastai būna 8, 10 ar 16 — bent jau tokius rekomenduoja visokios gudrios lentelės. Taigi, sakykim, kad pas mus yra 8 pirstelėjimai vienam bitukui. Jeigu duomenų perdavimo greitis 1 MBps, tai CAN laidukai dirba 8 MHz dažniu. Aišku?
Tikiuosi, kad aišku. Nes čia ateina įdomioji dalis. Kad gautumėm 8 MHz CAN laidukų dažnį, reikia paskaičiuoti prescalerį, kuris tuos 8 MHz mums padarys nuo kažkokio tai sisteminio laikroduko. O koks jis yra?
STM32F10x procesoriukų atveju tai yra sisteminė magistralė APB1. Konkrečiai mano STM32F103 procesoriuko atveju ji dirba ant pusės procesoriaus dažnio. T.y. procesoriaus branduolys sukasi ant 72 MHz, o APB1 — ant 36 MHz.
Norim 1 MBps, reikia 8 MHz nešančiojo dažnio. Koks prescaleris? 36/8 = 4,5. Šūds, prescaleriai gali būti tik sveiko skaičiaus. O jei bitukui pernešti padarysim 9 pirstelėjimus? Tai valio, 36/9 = 4.
Aha, o dabar problema — pas mane irgi 9 pirstelėjimai, bet prescaleriai yra 6 pagrindo. Todėl pas mane vietoj 10000 kbps (prescaleris 600) gaunasi nei šioks nei toks greitis: 6666 bps. Dėl to Canberry su mano mikrovaldikliais ir nesusišnekėjo. Nustačiau šitą greitį ant savo Avietės:
~ $ ifconfig can0 down ~ $ ip link set can0 up type can bitrate 6666
Ir viskas suveikė! Siunčiu pranešimuką iš Avietės:
~ $ cansend can0 123#DEADBEEF
O mano mikrovaldiklis išspjauna į USART1 išskerstą CAN pranešimuką:
Received CAN2B message: ID: 00000123 IDE: 00 RTR: 00 DLC: 04 Data: DE AD BE EF FMI: 00
Va taip va, blė!
Dabar dar truputuką apie tuos prescalerius ir kitus reikalus. Štai diagrama iš legendinio RM0008 dokumento:
Va ten viršuje yra laiko diagrama vienam bitukui koduoti. „Sample point“ yra ta vieta, ties kuria bitukas nuskaitomas ir įvertinamas ar jis vienetukas, ar nuliukas. Visas šitas „Nominal bit time“ užima kažkiek tai laiko kvantų (pirstelėjimų), tq. „Nominal bit time“ naudojant Standard Peripherals konfigūruojamas šitaip:
CAN_InitTypeDef can_init; ... can_init.CAN_SJW = CAN_SJW_1tq; can_init.CAN_BS1 = CAN_BS1_3tq; can_init.CAN_BS2 = CAN_BS2_5tq;
SJW dalis yra Synchronization Jump Width — pirmas pirstelėjimas. Jis dažniausiai yra 1 tq pločio. Toliau eina BS1 (bit segment), jam duodama nuo 1 iki 16 tq. Paskutinioji dalis — BS2, nuo 1 iki 8 tq.
Taigi pas mane vienas bitukas padarytas iš 9 kvantų, o prescaleris 600. Su aukščiau aprašytais dažniais gaunasi 6666 bps… Bandysiu perdaryti šitą reikalą, kad būtų „tikri“ 10 kbps.
Persiskaičiavau, persidariau. Štai ir Canberry įrenginio statistika, žinutės tik skraido ant tų 10 kbps:
~ $ ip -d -s link show can0 3: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 10 link/can promiscuity 0 can state ERROR-ACTIVE restart-ms 0 bitrate 10000 sample-point 0.875 tq 6250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1 clock 8000000 re-started bus-errors arbit-lost error-warn error-pass bus-off 0 0 0 0 0 0 RX: bytes packets errors dropped overrun mcast 175 35 0 1 0 0 TX: bytes packets errors dropped carrier collsns 37 23 0 0 0 0
Žiauriai palengvėjo gyvenimas testavimosi prasme. Nes iki šiol tai buvo taip: vienas įrenginukas bando įgyvendinti logiką, o kitam vis sukompiliuoju firmwarę su keliom CAN žinutėm, kad susimuliuotų mano norimą situaciją. Lėtas ir nepatogus procesas. O dabar galiu siuntinėti žinutes iš komandinės eilutės ir prisidaryti krūveles shell skriptukų testavimui. Tam yra komandos cansend ir candump.
Sakykim, noriu nusiųsti žinelę įrenginiui, kad jis man atgal atsiųstų savo serijinį numerį. Šast:
~ $ cansend can0 01000000#R
Čia pirma dalis yra ExtId (ID A + ID B), o R — RTR bitukas, atseit, Request Frame. Užklausa. O candump man parodo visas — tiek išsiųstas, tiek gautas žinutes:
~ $ candump can0 can0 01000000 [0] remote request can0 01000000 [6] 48 FF 6A 06 01 01
Va, įrenginys pasipasakojo apie save: pirmi keturi duomenukai yra jo šešioliktainis serijinis numeris Little Endian formatu 0x066AFF48, toliau įrenginio tipas 0x01 ir taip pat jam logiškai priskirtas „adresas“ 0x01. Šita logika čia mano saviems poreikiams sugalvota.
Taip gražiai Linuxe galime turkštis su CAN. Yra toks CAN draiverių rinkinys Linuxui, vadinamas SocketCAN, ten viskas labai gražiai sugalvota, bent jau mano nuomone. Kadangi man reikės CAN pasiekti iš Python kodo, tai greitai pasidomėjęs radau ir python-can. Ši biblioteka veikia dviem būdais, vienas iš jų yra per minėtąjį SocketCAN, pats efektyviausias ir greičiausiu keliu iki Linux branduolio. Susiinstaliavau python-can:
~ $ sudo pip3 install python-can
Tada išsikepiau tokį greituką, candump analogą:
import can can_interface = 'can0' bus = can.interface.Bus(can_interface, bustype='socketcan_native') while 1: message = bus.recv(1.0) if message is not None: print(message)
Išsaugojau, paleidau, žinutes rodo:
~ $ python3 read-can.py 1460488707.050592 01000000 110 0 1460488707.102897 01000000 010 6 48 ff 6a 06 01 00 1460488868.652569 01040000 010 5 48 ff 6a 06 01 1460488879.215949 01000000 110 0 1460488879.267428 01000000 010 6 48 ff 6a 06 01 01
Na va, kaip viskas gražu ir paprasta, kai prescaleriai teisingai sureguliuoti, blė 😀 Grynas malonums.
Teensy 3.1, berods, CAN’ui kojas turi. Perpus pigiau (~19USD)
Na, palaukit, gerbiamasai. Jūs kažką ne taip supratote, arba į mano egzistencinio nerimo kupinus klyksmus neįsiskaitėte. Tokių Teensių pas mane pilnas stalčius — ir po $2. Juos aš ir jungiu į tinklą. Bet man reikia ir CAN „serverio“ su Linuxu, ant kurio kažką būtų galima pakurt, kokį nors frontendą su blizgučiais ir kaspinėliais.
CAN mikruškės tai iš viso centus kainuoja, bet aš tingiu gaišti laiką ir pasiėmiau gatavą bei gerą produktą. Dar ir atrodo gražiai, kur kas geriau nei koks PiCan 😀
Mano klaida, dėkuj už detalizavimą 🙂
Ai beje, €24 / 2 < $19.