3.26. CAN-väylä koodissa¶
machine.CAN kääräisee laitteiston CAN-ohjaimen. Tuo se käyttöön väylän tunnisteella ja bittinopeudella:
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None) # accept all incoming IDs
Bittinopeuden on vastattava jokaista muuta väylän solmua täsmälleen – 125_000, 250_000, 500_000 ja 1_000_000 ovat tavallisia arvoja. set_filters() määrittää, mitkä tunnisteet ohjain päästää läpi; None tarkoittaa kaiken hyväksymistä (hyödyllistä linkkiä käyttöön tuotaessa, vähemmän hyödyllistä, kun väylä on kiireinen).
3.26.1. Ohjaimen sisällä¶
Kolme laitteistopalaa sijaitsee kameran Python-koodin ja väylän välissä – TX-postilaatikot, hyväksyntäsuodatin ja RX-FIFO. Kukin niistä kuvautuu osaan alla käytetystä CAN-API:sta.
Ohjaimen TX-postilaatikot, hyväksyntäsuodatin ja RX-FIFO ohjelmiston ja väylän välissä.¶
TX-postilaatikot. Pieni joukko laitteistopaikkoja (tyypillisesti kolme), jotka pitävät lähteviä kehyksiä, jotka kamera on luovuttanut
send()-kutsulla mutta jotka eivät ole vielä saavuttaneet väylää. Kun väylä on vapaana, ohjain valitsee postilaatikon, jolla on pienin tunnisteen numero (korkein prioriteetti), ja arbitroi väylästä sen puolesta. Kamera ei valitse postilaatikkoa; ohjain määrää sen ja palauttaa sen indeksinsend()-kutsusta.Hyväksyntäsuodatin. Määritettävä laitteisto, joka vertaa kunkin saapuvan kehyksen tunnistetta kuvioluetteloon ja hylkää kaiken, mikä ei täsmää. Läpäisevät kehykset jatkavat RX-FIFO:on; hylätyt kehykset ohjain heittää pois ne koskaan saavuttamatta Pythonia.
set_filters()määrittää nämä kuviot.RX-FIFO. First-in, first-out -jono – ensimmäinen sisään tullut kehys on myös ensimmäinen ulos tuleva, kuten jono lipunmyyntiluukulla. Ohjain lisää vastaanotetut kehykset jonon perään niiden saapuessa, ja
recv()poimii ne edestä samassa järjestyksessä. Jonolla on merkitystä, koska väylä nappaa kehyksiä taustalla Pythonin ollessa kiireinen muualla; kamera tyhjentää ne sitten yksitellen menettämättä yhtäkään, kunhan FIFO ei ole ylivuotanut.
3.26.2. Kehyksen lähettäminen¶
send() asettaa kehyksen jonoon lähetystä varten:
can.send(0x123, b"\x01\x02\x03\x04")
Ensimmäinen argumentti on tunniste (11-bittinen kokonaisluku vakiokehykselle); toinen on hyötykuorma (0–8 tavua CAN Classicissa). Kutsu palauttaa pienen kokonaislukuindeksin, joka yksilöi laitteiston postilaatikon, johon kehys meni. Ohjain arbitroi väylän muiden lähettimien kanssa ja lähettää uudelleen tarpeen mukaan ilman ohjelmiston lisäapua.
Laajennettuihin (29-bittisiin) tunnisteisiin yhdistä CAN.FLAG_EXT_ID -lippu OR-operaatiolla kolmanteen argumenttiin:
can.send(0x18FF1234, b"hello", CAN.FLAG_EXT_ID)
3.26.3. Kehysten vastaanottaminen¶
Ohjain käynnistyy ilman asennettua suodatinta ja pudottaa jokaisen saapuvan kehyksen. Ennen kuin recv() palauttaa mitään, kutsu set_filters() kerran – yksinkertaisin muoto on None, joka hyväksyy jokaisen tunnisteen:
can.set_filters(None) # accept every frame
recv() palauttaa sitten seuraavan kehyksen vastaanotto-FIFO:sta tai None, jos mitään ei odota:
msg = can.recv()
if msg is not None:
can_id, data, flags, errs = msg
print("got", hex(can_id), bytes(data))
Väylä täyttää RX-FIFO:n taustalla, joten pääsilmukka vain tyhjentää sitä niin nopeasti kuin se iteroi. Niin kauan kuin FIFO on syvempi kuin pisin tyhjennysten välinen aukko, kehyksiä ei häviä.
3.26.4. Suodattimet¶
Todellinen väylä on yleensä kiireinen kehyksistä, joista kamera ei välitä. Laitteistosuodattimet antavat ohjaimen pudottaa ei-toivotut tunnisteet ennen kuin ne saavuttavat FIFO:n. set_filters() ottaa listan (id, mask, flags) -monikoita; kehys läpäisee suodattimen, jos sen tunniste, mask:lla maskattuna, vastaa määritettyä id:tä:
# Accept only IDs 0x100 - 0x10F (mask off the bottom 4 bits)
can.set_filters(((0x100, 0x7F0, 0),))
# Accept IDs 0x300 and 0x700 exactly
can.set_filters(((0x300, 0x7FF, 0),
(0x700, 0x7FF, 0)))
Vastaamattomat kehykset ohjain hylkää, eivätkä ne koskaan ilmesty recv():ssä, mikä säästää sekä puskuritilaa että suoritinaikaa.
3.26.5. Virhetilat ja palautuminen¶
Todellinen CAN-väylä kerää lähetysvirheitä – oikosulkuja maahan, puuttuvia solmuja, bittejä turmelevaa sähköistä kohinaa. Ohjain pitää kahta laskuria, jotka seuraavat tätä käyttäytymistä: Transmit Error Counter (TEC) ja Receive Error Counter (REC), joista kumpaakin kasvatetaan ohjaimen havaitessa virheen ja vähennetään onnistuneen siirron jälkeen. Laskurien arvot asettavat ohjaimen yhteen neljästä tilasta:
Error Active (TEC ja REC molemmat alle 96). Normaali toiminta. Kun solmu havaitsee väylävirheen, se lähettää dominantin aktiivisen virhekehyksen, joka pakottaa jokaisen muun solmun hylkäämään käynnissä olevan kehyksen, jotta lähettäjä voi yrittää uudelleen.
Error Warning (jompikumpi laskuri saavuttaa 96). Yhä täysin aktiivinen väylällä – varoitustila on ohjelmistosignaali siitä, että virheitä kertyy, ei käyttäytymismuutos.
Error Passive (jompikumpi laskuri saavuttaa 128). Solmu on yhä väylällä mutta lopettaa dominanttien virhekehysten lähettämisen; virheet ilmoitetaan nyt passiivisilla (resessiivisillä) virhekehyksillä, jottei viallinen solmu voi jatkuvasti repiä väylää muiden vahingoksi.
Bus Off (TEC saavuttaa 256). Ohjain on päättänyt, että tämä solmu on liian epäluotettava osallistumaan. Se irtoaa väylästä, lopettaa lähettämisen ja kuittaamisen ja pysyy poissa, kunnes ohjelmisto nimenomaisesti käynnistää sen uudelleen.
Kolme ensimmäistä siirtymää ovat täysin automaattisia – kun laskurit vähenevät onnistuneiden kehysten jälkeen, ohjain siirtää itsensä takaisin kohti Error Active -tilaa ilman puuttumista.
Bus Off on se yksi tila, joka vaatii ohjelmistotoimia. restart() nollaa ohjaimen ja palauttaa sen Error Active -tilaan. Tyypillinen kuvio on tarkistaa tila pääsilmukasta ja käynnistää uudelleen lyhyen viiveen jälkeen, jotta väylä ehtii asettua:
import time
from machine import CAN
can = CAN(1, 500_000)
can.set_filters(None)
while True:
if can.state() == CAN.STATE_BUS_OFF:
time.sleep_ms(100)
can.restart()
# ... rest of the loop
Nykyiset laskuriarvot ovat saatavilla get_counters()-kutsusta diagnostiikkaa varten – TEC, joka kohoaa tasaisesti muuten hiljaisella väylällä, viittaa yleensä johdotukseen, päätevastukseen tai väärin määritettyyn bittinopeuteen.