CircuitPython, Adafruit Feather RP2040 och I2C

RP2040 har två I2C-kontroller - bra till exempel när du vill köra två I2C-enheter med samma I2C-adress.

I min testuppställning har jag ett Adafruit Feather RP2040-mikrokontrollerkort och har kopplat två av våra BME688 breakout-kort - en med hjälp av stiften SCL + SDA och en med hjälp av A1 (för SCL) + A0 (för SDA).

Jag använder CircuitPython i version 7.0.0.0, som du kan ladda ner här.

Dessutom har jag installerat alla Adafruits bibliotek på lib på Feather RP2040. (Feather RP2040 har tillräckligt med utrymme på Flash för att möjliggöra detta).

Du kan ladda ner dessa bibliotek i Adafruit CircuitPython Bundle här. (Jag laddade ner adafruit-circuitpython-bundle-7.x-mpy-20211123.zip)

Obs: För att installera dessa bibliotek kopierar du dem helt enkelt till lib-mappen på CIRCUITPYs "enhet" som är monterad på din dator. Du måste naturligtvis bara kopiera biblioteken, inte exemplen och andra saker.

Den stora fördelen med att använda Adafruits produkter är att du får massor av exempel som täcker många populära chip, och du kan mycket enkelt börja med dem. Det finns saker som att driva ett microSD-kort med hjälp av SPI, läsa en RTC och läsa från BME680-sensorn.

Testning av I2C i CircuitPython

Jag har följande inställning, eftersom jag vill driva två enheter oberoende av varandra (som råkar ha samma adresser i det här fallet):

Feather RP2040 och två BME688 breakout-kort

Observera att våra BME688 breakoutkort redan innehåller Pullups för SDA och SCL. (Du behöver pullups på SDA och SCL).

Anmärkning 2: Vårt BME688-breakoutkort har möjlighet att ändra adressen, så detta scenario är avsett för demonstrationsändamål.

För att köra igenom båda stiftuppsättningarna sekventiellt (för att upptäcka enheterna) använder jag följande kod:

print("Skanning av SCL / SDA")
i2c = busio.I2C(board.SCL, board.SDA)
# en skanning
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
i2c.deinit()

print("Skanning av A0 / A1")
si2c = busio.I2C(board.A1, board.A0)
# en skanning
si2c.try_lock()
print(si2c.scan())
si2c.unlock()

Observera: den i2c.deinit() är nyckeln till att detta exempel fungerar! (eftersom SCL / SDA och A0 / A1 har båda samma I2C-periferi - se nedan).

Detta bör ge följande resultat:

Skanning SCL / SDA
[119]
Skanning A0 / A1
[119]

Här är 119 decimal för hex 0x77 - vilket är adressen till vårt BME688 breakoutkort i standardtillstånd.

Båda brädorna syns i tur och ordning i de enskilda skanningarna.

Problemet är att vi vill använda dem samtidigt.

Kör två I2C-bussar samtidigt på Adafruit Feather RP2040

CircuitPython stöder båda hårdvarukontroller (SDA0/SCL0 och SDA1/SCL1). Du behöver inte ställa in någon konfiguration (vilken styrenhet du vill använda, eller hur du ska muxa stiftstiftet) - detta tas om hand av busio för dig.

Du måste dock vara uppmärksam på vilka stift du använder, eftersom stiften endast ger dig en av dessa bussar i varje enskilt fall, och om du råkar välja motstridiga stift får du en Värdefel: I2C-periferi i bruk .

Adafruit Feather RP2040 Pinout

Om du vill använda "motstridiga" stift, till exempel SCL/SDA (som har SCL1 och SDA1) och A0/A1 (som också har SCL1 och SDA1), måste du bitbanga en av portarna:

Så här skannar du den här stiftkonfigurationen utan att anropa deinit():

importkort.
importera busio
importera bitbangio
# https://circuitpython.readthedocs.io/en/latest/shared-bindings/bitbangio/index.html

print("Skanning av SCL / SDA - huvud I2C")
i2c = busio.I2C(board.SCL, board.SDA)
# en skanning
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
# ingen anledning att anropa deinit här!
#i2c.deinit()

print("Skanning av A0 / A1 - sekundär I2C [bitbang!]")
si2c = bitbangio.I2C(board.A1, board.A0)
# en skanning
si2c.try_lock()
print(si2c.scan())
si2c.unlock()

# Vi behöver inte heller kalla deinit här.
#i2c.deinit()

Vi använder bitbangio för att driva en sekundär I2C. I mitt fall används den sekundära I2C för ett internt ändamål (för en port expander), och kan sannolikt klara sig med en lägre gränssnittshastighet.

Observera: Du kan inte välja vilken I2C-periferi som ska kopplas till stiften i programvaran - om du behöver en annan periferi måste du använda andra stiften.

Felsökning av I2C-fel

Värdefel: I2C-periferi i bruk

Om du använder busio.I2C för båda portarna: Kontrollera om du redan använder samma I2C-periferiutrustning - och om du behöver omfördela dina stift.

Till exempel delar både SCL och SDA och A0 och A1 samma I2C-periferi (SCL1/SDA1 - se bilden av Adafruit Feather RP2040-pinnutformningen i den här artikeln).

Om du vill använda samma stiftuppsättning kan du använda bitbangio för att "skapa" en extra mjukvarustyrd I2C-port. Nackdelen med detta är lägre hastighet för denna mjukvaru-I2C-port och en högre CPU-belastning.

RuntimeError: Kontrollera din kabeldragning: Ingen pull up hittades på SDA eller SCL.

Om du får följande fel

RuntimeError: Kontrollera din kabeldragning: Ingen pull up hittades på SDA eller SCL.

då bör du sätta pullupmotstånd mellan 3V3 på kortet (3,3V-stiftet) och dina SDA- respektive SCL-stift. Dessa krävs för normal I2C-drift (enheterna drar ner I2C-stiften för att kommunicera, standardläget/viloläget på bussen är högt) - och ingår inte i Adafruit Feather RP2040. De finns med på många Adafruit-periferier och på periferier från andra företag (som, återigen, vår egen BME688 breakoutkort).

Om du inte vet vad en pullup är: det är i princip ett motstånd mellan pinnen i fråga (t.ex. SDA) och 3,3 V-försörjningspinnen. Den behöver inte vara särskilt exakt. Du bör börja med ett motstånd på 10 kOhm, om det inte fungerar kan du eventuellt prova ett motstånd på 1 kOhm för en "styvare" pullup.

TimeoutFel: Klockan sträcker sig för länge

Kontrollera att chipet som du vill prata med är ordentligt strömförsörjt.

Diverse anteckningar

Referenser / resurser / länkar / ytterligare läsning

Lämna en kommentar