Tutorial · Beginner · 30 min

Hoe de I2C-bus werkt: adressen en pull-upweerstanden

Twee draden en een gedeelde bus: waarvoor de pull-upweerstanden dienen, waarom stapelen van breakout-borden het breekt en hoe je een adresconflict oplost.

Inleiding

Elke sensorpagina op deze site zegt dat je SDA en SCL moet aansluiten, en geen enkele vertelt je wat die twee draden daar doen. De meeste tijd heb je dat niet nodig—je sluit aan, de bibliotheek werkt en de sensor leest.

Dan voeg je een tweede bord toe en houdt het eerste op met antwoorden. Of de bibliotheek geeft nullen zonder foutmelding. Of blijken twee apparaten hetzelfde adres te willen en staat in geen enkele documentatie wat je daarmee moet doen.

Dat zijn allemaal dezelfde kleine verzameling feiten over I²C, en er zijn er minder dan de symptomen doen vermoeden.

Twee draden, veel apparaten

I²C hangt elk apparaat aan één gedeeld paar draden:

  • SDA — de datalijn.
  • SCL — de klok, altijd gestuurd door de controller.

Op een Arduino Uno zijn dat A4 en A5 (plus de dubbele pins naast AREF—dezelfde twee pins, geen extra). Elk apparaat wordt parallel aan dezelfde twee aangesloten. Er is geen chip-selectdraad en geen ring: een apparaat toevoegen betekent het aan hetzelfde paar vast solderen.

Dat is waarom het zo goed schaalt voor robots. Een MPU-6050, een VL53L0X en een PCA9685 delen allemaal die twee draden en worden van elkaar onderscheiden door adres, niet door bedrading.

Niemand trekt de lijn hoog

Dit is het feit waaruit al het andere volgt.

Een I²C-apparaat kan een lijn alleen laag trekken. Het kan hem niet hoog sturen—de uitgang is open-drain, wat betekent dat het een schakelaar naar aarde is en verder niets. Zonder andere invloed zou de lijn op een willekeurige spanning blijven zweven.

De pull-upweerstanden zijn wat de lijn hoog maakt. Ze zijn geen robuustheidsmaatregel en geen optionele extra; ze zijn de helft van de schakeling, en zonder ze heeft de bus geen rusttoestand en werkt er niets.

Open-drain heeft een echt voordeel, en daarom wordt het zo gedaan: als twee apparaten tegelijk praten, de een trekt laag en de andere laat los, dan is het resultaat laag. Er vecht niets, er wordt niets kortgesloten, en het apparaat dat verloor kan het detecteren. Op een bus waar elk apparaat mag spreken telt dat.

Het venster waarin een pull-up moet passen

Aan beide kanten zijn er grenzen, en die zijn te berekenen.

Te laag en geen enkel apparaat kan de lijn omlaag trekken. De specificatie schrijft voor dat een apparaat minstens 3 mA afvoert terwijl het de lijn onder 0,4 V houdt, dus:

R_min = (Vcc − V_OL) / I_sink = (5 − 0.4) / 0.003 = 1533 Ω

Te hoog en de stijgende flank is te traag. De lijn stijgt als een RC-curve tegen de buscapaciteit, en de klok wacht niet:

t_rise ≈ 0.85 × R × C        ≤ 1000 ns at 100 kHz, ≤ 300 ns at 400 kHz
Een grafiek op log-schaal van de toegestane pull-upweerstand tegen de totale buscapaciteit. Twee dalende curves markeren de bovengrens voor de stijgtijd bij 100 kilohertz en 400 kilohertz, en een horizontale rode lijn op 1533 ohm markeert de ondergrens waaronder geen enkel apparaat genoeg stroom kan afvoeren om de lijn laag te trekken. Vier horizontale stippellijnen markeren de effectieve weerstand van één, twee, drie en vier gestapelde breakout-borden op 4700, 2350, 1567 en 1175 ohm; de lijn van vier borden zakt onder de ondergrens.
Het bruikbare bereik ligt tussen de ondergrens van de afgevoerde stroom en de bovengrens van de stijgtijd. Let op waar 400 kHz belandt op een zwaar beladen bus: voorbij ongeveer 250 pF zakt zijn bovengrens onder de ondergrens, dus fast mode is daar met gewone weerstanden helemaal niet haalbaar. SVG downloaden

Nu komt het deel waarover mensen struikelen. Vrijwel elk hobby-breakoutbord heeft zijn eigen pull-ups al ingebouwd, meestal 4,7 kΩ. Sluit je er meerdere op dezelfde bus aan, dan staan die weerstanden parallel:

Borden op de bus Effectieve pull-up Oordeel
1 4700 Ω Goed
2 2350 Ω Goed
3 1567 Ω Grensgeval — 34 Ω boven de ondergrens
4 1175 Ω Onder de ondergrens

De storing heeft dus een vaste vorm: één sensor werkt, twee werken, drie werken op een goede dag, en het vierde bord laat de hele bus stilvallen. Er is niets kapot. De apparaten kunnen de lijn alleen niet laag genoeg meer trekken om nog als laag te worden afgelezen.

De oplossing is de pull-upweerstanden van alle borden behalve één verwijderen—het zijn meestal twee kleine oppervlaktemontageweerstanden met de markering 472, en in de documentatie van het bord staat welke. Desolderen voelt de eerste keer verkeerd en is het juiste antwoord.

Scan de bus voordat je iets anders uitzoekt

Raak een bibliotheek niet aan voordat je de bus vraagt wat erop zit. Deze sketch probeert elk adres en meldt welke antwoorden:

#include <Wire.h>

void setup() {
  Wire.begin();
  Serial.begin(115200);
  while (!Serial) {}

  Serial.println(F("Scanning I2C..."));
  uint8_t found = 0;
  for (uint8_t addr = 1; addr < 127; addr++) {
    Wire.beginTransmission(addr);
    if (Wire.endTransmission() == 0) {
      Serial.print(F("  device at 0x"));
      Serial.println(addr, HEX);
      found++;
    }
  }
  Serial.println(found ? F("done") : F("nothing answered — check wiring and pull-ups"));
}

void loop() {}

Het resultaat vertelt je welk probleem je hebt:

  • Niets antwoordt → bedrading, voeding of ontbrekende pull-ups. Niet de bibliotheek.
  • Het apparaat antwoordt op een onverwacht adres → een strap pin voor het adres staat anders dan je aannam.
  • Het apparaat antwoordt, maar de bibliotheek geeft nullen → de bus is in orde en het probleem ligt erboven.

Die laatste regel is de hele sketch waard. Hij scheidt “de draad is verkeerd” netjes van “de code is verkeerd”, en dat is anders de meeste debugtijd.

Adressen, en de 0xD0-verwarring

Een I²C-adres is 7 bits. Zestien waarden zijn gereserveerd, waardoor er 112 bruikbaar blijven.

Hier zit de valkuil. Op de draad wordt het adres als zeven bits gevolgd door een lees/schrijfbit verstuurd, dus het lijkt op een 8-bits waarde. Datasheets noemen die 8-bits vorm dan ook. De Wire-bibliotheek van Arduino wil de 7-bits vorm.

Een MPU-6050-datasheet noemt 0xD0 voor schrijven en 0xD1 voor lezen. De Wire-bibliotheek wil 0x68:

0xD0 = 1101 0000
0x68 = 0110 1000        the same bits, shifted right by one

Antwoordt een apparaat niet op het adres uit zijn datasheet, probeer dan die waarde één bit naar rechts geschoven voordat je concludeert dat het bord dood is. Het is de meest voorkomende I²C-fout die er is.

Als twee apparaten hetzelfde adres willen

Adressen worden door de fabrikant vastgesteld, dus botsingen zijn routine. Drie oplossingen, in volgorde van hoe graag je ze hebt:

1. Een strap pin voor het adres. De goedkoopste oplossing, als het onderdeel er een heeft. Een MPU-6050 staat op 0x68, of op 0x69 met zijn AD0-pin hoog—er leven dus twee naast elkaar met één draad. Een PCA9685 heeft zes soldeerjumpers die 64 adressen geven, en daarom kun je tot 62 borden aan één bus hangen.

2. Houd de anderen in reset terwijl je er één een nieuw adres geeft. Sommige onderdelen hebben een vast adres maar kunnen tijdens het draaien geprogrammeerd worden. Een VL53L0X is uit de doos altijd 0x29, en dit is de standaardmanier om er meerdere te gebruiken: houd de XSHUT-pin van elke sensor laag, breng één omhoog, laat hem naar een nieuw adres gaan, en herhaal. Het nieuwe adres staat in RAM, dus de reeks draait bij elke start opnieuw.

3. Een multiplexer. Een TCA9548A is één apparaat op 0x70 met erachter acht geschakelde bussen. Kies een kanaal, praat met het apparaat erop, kies het volgende. Het is het antwoord bij acht identieke sensoren zonder strap pin en zonder heradressering—ten koste van een extra onderdeel en van de bus die nu één voor één moet worden afgehandeld.

Snelheid, lengte en wat er echt misgaat

I²C is ontworpen om tussen chips op één bord te draaien. Een robot rekt het uit over een chassis, en daar beginnen de grenzen te bijten.

  • Capaciteit is de echte grens, niet de lengte. De specificatie staat 400 pF totaal toe. Ribbonkabel voegt ongeveer 50–100 pF per meter toe en elk apparaat ongeveer 10 pF. Lange afstanden falen doordat de stijgende flank te traag wordt—in de figuur hierboven zie je dat als de bovengrens zakt.
  • Verlaag het tempo voordat je opgeeft. Wire.setClock(50000) halveert de standaardsnelheid en levert echte marge op een marginale bus. Een robot die een sensor op 100 Hz uitleest heeft 400 kHz niet nodig.
  • Houd SDA en SCL uit elkaar. Loop je ze als naast elkaar liggend paar door een ribbon, dan koppelen klokflanken in de data. Een aarddraad ertussen helpt.
  • Klokrekken. Een apparaat dat tijd nodig heeft kan SCL laag houden, en de controller moet wachten. Echte hardware voor I²C handelt dit af; sommige bit-banged implementaties niet, en het symptoom is een apparaat dat alleen werkt en de data bederft wanneer de bus druk is.
  • Een vastgelopen bus. Als een apparaat midden in een overdracht is herstart, kan het SDA voor altijd laag houden en geeft elke scan niets terug. SCL negen keer pulsen laat het het byte afmaken dat het dacht te versturen en de lijn loslaten—precies wat de herstelroutine in een goede bibliotheek doet.

3,3 V en 5 V mengen

Een ESP32 en een Raspberry Pi draaien hun I²C op 3,3 V; een Uno draait hem op 5 V. Omdat de bus open-drain is, bepaalt de pull-upspanning het hoge niveau voor iedereen die eraan hangt. Trek je op naar 5 V met een onderdeel dat alleen 3,3 V aankan, dan stop je 5 V in een pin die voor 3,6 V is gespecificeerd.

Twee dingen redden je meestal, en het is de moeite waard te weten waarop je leunt:

  • Veel breakouts die “5 V compatibel” heten zijn een 3,3 V-chip met al een regelaar én niveauverschuiving op het bord. Controleer dat voordat je aanneemt—de aanwezigheid van alleen een spanningsregelaar betekent niet dat de signaalpins beveiligd zijn.
  • Waar dat niet zo is, is een bidirectionele MOSFET-niveauverschuiver het standaardantwoord. Een spanningsdeler niet: die breekt het open-drain-gedrag juist in de richting die ertoe doet.

Als het misgaat

Symptoom Meestal
De scanner vindt helemaal niets Ontbrekende pull-ups, SDA/SCL omgewisseld, of geen gedeelde aarde
Werkt met drie borden, stopt met vier Parallelle pull-ups onder de grens voor afgevoerde stroom
Apparaat ontbreekt op het adres uit de datasheet 8-bits adres genoemd; één bit naar rechts schuiven
Twee identieke sensoren, maar één antwoordt Adresconflict — strap pin, XSHUT of een multiplexer
Leest prima kort, faalt op een lange kabel Buscapaciteit; verlaag de klok of verkort de afstand
Terugkerende dataverstoring terwijl de motoren draaien Ruis op de voeding — zie voeding en brown-outs
De scanner geeft opeens niets terug na een crash Een apparaat houdt SDA laag; geef SCL negen keer een puls
Werkt alleen, verpest de bus wanneer die druk is Klokrekken dat de controller niet nakomt

De nuttige gewoonte is de scanner altijd als eerste te draaien, vóór het openen van de bron van een bibliotheek. Het kost dertig seconden en het deelt het probleem in twee—en de helft van alle I²C-debugwerk is niet weten aan welke kant van de draad de fout zit.

Verken de graaf

Onderdeel van deze bouwprojecten

Projecten en leerroutes waarin deze tutorial voorkomt.

Verder lezen

Bronnen