zaterdag 15 mei 2021

CAN-bus - Deel 3: Bit stuffing

In deel 1 en deel 2 van de 'serie' over de CAN-bus is al wat verteld over het principe van deze communicatiebus. In dit deel wil ik wat vertellen over het praktisch meten aan de bus. De ESP32-microcontroller bevat hardware aan boord voor het CAN-protocol. Mijn software gebruikt deze hardware via een driver die door Espressif (de bouwer van de ESP32) aangeboden wordt. De CAN-hardware van de chip gebruikt twee GPIO's - TX en RX - voor de verbinding met de bus. De ESP32 kan echter niet rechtstreeks aan de bus gekoppeld worden, hier moet nog een transceiver tussen.

Om de CAN-bus te kunnen debuggen kan gebruik gemaakt worden van een protocol analyser of een oscilloscoop. Ik heb de beschikking over een HP 54603B digitale scope met nog zo'n prachtig groen schermpje. Deze heeft twee ingangskanalen, ideaal om de CAN-High en CAN-Low signalen gelijktijdig te bekijken. Ben wel benieuwd of alles op beeld er een beetje netjes uit ziet en of ik het allemaal snap.

Mijn testopstelling

Om te testen wordt de knipperlichtaansturing gebruikt. Vanuit de centrale dashboard-node (in bovenstaande foto het bread board) worden achtereenvolgend twee CAN-berichten verstuurd: knipperlicht-links-aan en knipperlicht-links-uit. In mijn CAN-berichtenlijst zijn dit de berichten met respectievelijk de berichtnummers 14hex en 15hex. De scope wordt zo ingesteld dat deze triggert op een opgaande flank van CAN-high en plukt zo een volledig bericht van de bus:

Een volledig CAN-bus-bericht.

Op het plaatje is te zien dat voordat het bericht begint er geen verschil is tussen de spanning op kanaal 1 en kanaal 2. Zowel CAN-High als CAN-Low voeren een spanning van iets minder dan 2.5 volt. Da's ongeveer de helft van de voedingsspanning van 5 volt. Dit is de recessive status en komt overeen met een digitale '1'. Het bericht begint met een startbit waarbij CAN-high en CAN-low actief uit elkaar getrokken worden. Er staat nu iets meer dan 2 volt spanning tussen CAN-low en CAN-high. Dit wordt de dominant status genoemd en komt overeen met een digitale '0'.

In de software is voorlopig gekozen voor een bussnelheid van 25 kbit per seconde (nog niet al te snel dus) wat neerkomt op een tijdsduur van 40 microseconde per bit. In het scope-beeld zie je de t1-cursor op 200.0us, en de t2-cursor op 240.0us staan, hetgeen precies overeen komt met het verwachte verschil van 40us. Eens kijken of het bericht ontcijferd kan worden. Hieronder de twee berichten om het linker knipperlicht aan en uit te zetten:

Knipperlicht uit.

Knipperlicht aan.

In bovenstaande plaatjes heb ik bij de elektrische niveaus de digitale nullen en enen geplaatst. Wat direct opvalt is dat de twee berichten niet dezelfde lengte hebben, het knipperlicht aan-bericht is een bit langer... Het koste even wat hoofdbrekens om te achterhalen wat dit zou kunnen veroorzaken. Google bracht het antwoord, maar eigenlijk had ik het moeten weten. Leeftijd zullen we maar zeggen.

Alle nodes op de CAN-bus gebruiken de opgaande en neergaande flanken van het elektrische signaal om zich met elkaar te synchroniseren. Als er nu bijvoorbeeld veel nullen opeenvolgend in het bericht zitten, dan ontbreekt gedurende een relatief lange tijd een flank waarop nodes zich kunnen synchroniseren met als potentieel gevolg dat een node uit sync raakt en zich kan vergissen in het aantal nullen. Om dit te voorkomen wordt in het CAN-bericht telkens wanneer er vijf gelijke bits voorkomen een extra bit van tegengestelde waarde toegevoegd. Hiermee wordt een signaalflank geïntroduceerd en zo een mogelijkheid om de communicatie synchroon te houden. Dit principe wordt bit stuffing genoemd. De versturende partij stuft de bits in het bericht, de ontvangende partij haalt ze er weer uit. Er kunnen in het ene bericht meer stuffed bits zitten dan in het andere bericht. Zo ook in het knipperlicht-aan-bericht.


Het ontrafelen van het knipperlicht uit-bericht gaat als volgt. Na vijf gelijke bits zit er dus een stuffed bit in dit bericht.

Bericht met stuffed bits (twee stuks) nog aanwezig. Zie bovenstaand scope-beeld:
00000100101010000010000101100011100110

Bericht met stuffed bits verwijderd:
000000010101000000000101100011100110

De onderdelen van het bericht zijn:
0                    Startbit
00000010101          Berichtnummer (id)
0                    RTR
0                    Extended Format
0                    Reserved
0000                 Data Length
0010110001110011     CRC + delimiter
0                    Acknowledge bit

  • Het berichtnummer klopt, 000 0001 0101 komt overeen met 15hex.
  • Het RTR-bit klopt. Het is geen Remote Transmission Request maar een normaal bericht.
  • Het Extended Format wordt niet gebruikt. Gewoon 11-bits berichtnummer.
  • Er wordt geen gebruik gemaakt van data-bytes, de Data Length staat dus op 0.
  • De Cyclic Redundancy Checksum zal juist zijn, anders wordt het bericht niet geaccepteerd.
  • Het Acknowledge-bit wordt door de ontvangende node(s) naar '0' geforceerd.
In de scope-beelden is het acknowledge bit (het gele cirkeltje) te herkennen omdat het een net ietsje afwijkend spanningsniveau heeft. Dat niveau wordt niet bepaald door de zendende maar door de ontvangende node, vandaar.


Voor het bericht knipperlicht aan gaat dat op gelijke wijze. Het bericht bevat drie stuffed bits en is dus precies één bit langer dan het knipperlicht uit-bericht:

Bericht met stuffed bits (drie stuks) nog aanwezig:
000001001010000010000011101000010101010

Hieruit volgt het berichtnummer 00000010100 ofwel 14hex.

Met een oscilloscoop is een CAN-bericht dus vrij gemakkelijk te debuggen. Alweer een mooie eigenschap van de CAN-bus. Geen wonder dat de bus zo populair is in (o.a.) de automobielindustrie. 

PS.
Voor de die hard nerds onder ons 😉, het principe dat een '0' en een '1' ieder hun eigen specifieke elektrische niveau hebben wordt het NRZ-principe (Non Return to Zero) genoemd. Een alternatief hierop is het Manchester-principe waarbij bijvoorbeeld een '1' met een opgaande en een '0' met een neergaande flank gepresenteerd wordt. Bit stuffing is dan niet nodig omdat er inherent veel flanken zijn waarop gesynchroniseerd kan worden.

2 opmerkingen:

  1. Rare term vind ik, mijn associatie met 'stuffing' is dat het erbij gestopt kan worden, omdat er nog plaats is, maar het is eigenlijk bit 'adding', want er komt gewoon iets bovenop/erbij.

    BeantwoordenVerwijderen
  2. Ja dat heb ik ook wel een beetje met de term 'stuffing'. Terwijl het eigenlijk op zijn Brabants "er tussen frommelen" is. En later weer weghalen. Maar wel goed bedacht...

    BeantwoordenVerwijderen