CircuitPython, Adafruit Feather RP2040 en I2C
Zoals je waarschijnlijk al aan de titel kon zien, gaat dit artikel over CircuitPython, de Adafruit Feather RP2040 en het I2C-communicatieprotocol.
De RP2040 heeft twee I2C controllers - goed wanneer u bijvoorbeeld twee I2C apparaten met hetzelfde I2C adres wilt laten werken.
In mijn testopstelling heb ik een Adafruit Feather RP2040 microcontroller bord, en heb ik twee van onze BME688 breakout borden - één met de pennen SCL + SDA en één met A1 (voor SCL) + A0 (voor SDA).
Ik gebruik CircuitPython in versie 7.0.0, die u hier kunt downloaden.
Verder heb ik alle bibliotheken van Adafruit geïnstalleerd in de lib map op de Feather RP2040. (De Feather RP2040 heeft voldoende ruimte op zijn Flash om dit mogelijk te maken)
U kunt deze bibliotheken downloaden in de Adafruit CircuitPython Bundel hier. (Ik heb gedownload adafruit-circuitpython-bundel-7.x-mpy-20211123.zip)
Noot: om deze bibliotheken te installeren kopieert u ze eenvoudigweg naar de map lib op de CIRCUITPY "drive" die op uw computer is aangekoppeld. U moet natuurlijk alleen de bibliotheken kopiëren, niet de voorbeelden en andere dingen.
Het grote voordeel van het gebruik van Adafruit's spullen is dat je een heleboel voorbeelden krijgt die veel populaire chips dekken, en je kunt er heel gemakkelijk mee beginnen. Er zijn dingen zoals het aansturen van een microSD kaart met SPI, het uitlezen van een RTC, en het uitlezen van de BME680 sensor.
I2C testen in CircuitPython
Ik heb de volgende opstelling, omdat ik twee apparaten onafhankelijk van elkaar wil aansturen (die in dit geval toevallig dezelfde adressen hebben):
Merk op dat onze BME688 breakout boards al pullups bevatten voor SDA en SCL. (U heeft pullups nodig op SDA en SCL).
Noot 2: Ons BME688 breakout bord heeft de mogelijkheid om het adres te veranderen, dus dit scenario is bedoeld voor demonstratie doeleinden.
Om beide pinnenreeksen sequentieel te doorlopen (om de apparaten te ontdekken), gebruik ik de volgende code:
print("Scanning SCL / SDA")
i2c = busio.I2C(board.SCL, board.SDA)
# a scan
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
i2c.deinit()
print("Scanning A0 / A1")
si2c = busio.I2C(board.A1, board.A0)
# a scan
si2c.try_lock()
print(si2c.scan())
si2c.unlock()
Opmerking: de i2c.deinit() is de sleutel tot de werking van dit specifieke voorbeeld! (omdat SCL / SDA en A0 / A1 beide dezelfde hardware I2C periferie hebben - zie hieronder).
Dit zou het volgende moeten opleveren:
Scanning SCL / SDA
[119]
Scanning A0 / A1
[119]
Hier, 119 is decimaal voor hex 0x77 - dat is het adres van onze BME688 breakout bord in de standaard toestand.
Beide borden zijn te zien, achtereenvolgens in de afzonderlijke scans.
Het probleem is dat we ze gelijktijdig willen gebruiken.
Twee I2C bussen gelijktijdig op de Adafruit Feather RP2040
CircuitPython ondersteunt beide hardware controllers (SDA0/SCL0 en SDA1/SCL1). U hoeft geen configuratie in te stellen (welke controller u wilt gebruiken, of hoe de pinnen gemuxed moeten worden) - dit wordt verzorgd door busio voor jou.
U moet wel opletten welke pinnen u gebruikt, want de pinnen leveren alleen een van deze bussen in elk geval, en als je toevallig conflicterende pinnen kiest, krijg je ValueError: I2C randapparaat in gebruik .
Als u "conflicterende" pinnen wilt gebruiken, bijvoorbeeld SCL / SDA (die SCL1 en SDA1 hebben) en A0 / A1 (die ook SCL1 en SDA1 hebben), dan moet u een van de poorten bitbangen:
Hier is hoe je deze pin-configuratie kan scannen zonder deinit() op te roepen:
import board
import busio
import bitbangio
# https://circuitpython.readthedocs.io/en/latest/shared-bindings/bitbangio/index.html
print("Scanning SCL / SDA - main I2C")
i2c = busio.I2C(board.SCL, board.SDA)
# a scan
i2c.try_lock()
print(i2c.scan())
i2c.unlock()
# no need to call deinit here!
#i2c.deinit()
print("Scanning A0 / A1 - secondary I2C [bitbang!]")
si2c = bitbangio.I2C(board.A1, board.A0)
# a scan
si2c.try_lock()
print(si2c.scan())
si2c.unlock()
# we also do not need to call deinit here
#i2c.deinit()
We gebruiken bitbangio om een secundaire I2C aan te sturen. In mijn geval wordt de secundaire I2C gebruikt voor een intern doel (voor een poortuitbreider), en kan deze waarschijnlijk met een lagere interfacesnelheid toe.
Opmerking: u kunt het I2C-periferie dat naar de pennen wordt geleid niet softwarematig kiezen - als u een ander periferie nodig hebt, moet u andere pennen gebruiken.
Oplossen van I2C fouten
ValueError: I2C randapparaat in gebruik
Als je busio.I2C gebruikt voor beide poorten: Controleer of u al dezelfde hardware I2C periferie gebruikt - en of u uw pinnen opnieuw moet toewijzen.
Bijvoorbeeld, zowel SCL en SDA , en A0 en A1 delen dezelfde hardware I2C periferie (SCL1 / SDA1 - zie de Adafruit Feather RP2040 pinout foto in dit artikel).
In het geval dat je toch dezelfde pin setup wilt gebruiken, kun je bitbangio gebruiken om een extra software-gestuurde I2C poort te "maken". Het nadeel hiervan is een lagere snelheid voor deze software-I2C poort, en een hogere CPU belasting.
RuntimeError: Geen pull up gevonden op SDA of SCL; controleer uw bedrading
Als u de volgende foutmelding krijgt
RuntimeError: Geen pull up gevonden op SDA of SCL; controleer uw bedrading
dan moet je pullup weerstanden plaatsen tussen 3V3 op het bord (de 3.3V pin) en respectievelijk je SDA en SCL pinnen. Deze zijn nodig voor een normale I2C werking (de apparaten trekken de I2C pinnen naar beneden om te communiceren, de standaard / idle toestand op de bus is hoog) - en zijn niet inbegrepen op de Adafruit Feather RP2040. Ze zijn wel aanwezig op veel randapparatuur van Adafruit, en op randapparatuur van andere bedrijven (zoals, alweer onze eigen BME688 breakout bord).
Als u niet weet wat een pullup is: dit is in wezen een weerstand tussen de pin in kwestie (b.v. SDA) en de 3,3 V voedingspin. Hij hoeft niet erg precies te zijn. U kunt het beste beginnen met weerstanden van 10 kOhm, als dat niet werkt, probeer dan eventueel een weerstand van 1 kOhm voor een "stijvere" pullup.
TimeoutError: Klok rek te lang
Controleer of de chip waarmee u wilt praten de juiste spanning heeft.
Diverse notities
- De Adafruit Feather RP2040 heeft een NeoPixel LED erop. NeoPixels gebruiken een propriëtair protocolgebruiken ze geen I2C.
- De Adafruit CircuitPython Gemeenschapsbundel heeft een paar extra bestuurders
- Er is een DebugI2C-helper
- De ondersteuningsmatrix zal u tonen welke modules ondersteund worden op uw bord (b.v. de Adafruit Feather RP2040)
Referenties / Hulpbronnen / Links / Verdere lectuur
- Adafruit CircuitPython Bundel (bibliotheken voor CircuitPython)
- CircuitPython Busio documentatie
- CircuitPython Bord documentatie
- CircuitPython op de RP2040 documentatie
- CircuitPython I2C Essentials
Wil je meer weten over I2C? Kijk dan op ons artikel erover hier.
Bedankt voor het nuttige artikel! Ik heb twee suggesties:
1) Een oorzaak van de "no pull up found" fout (wat mij hier bracht) kan ook worden veroorzaakt door een domme fout: het hebben van een losse draad! Dit overkomt mij maar al te vaak omdat ik Stemma connectoren gebruik die een beetje finniky zijn.
2) Ik denk dat uw voorbeeldcode een beetje verwarrend is, omdat ik denk dat het had kunnen/moeten beginnen met het eenvoudigste geval waarin u de twee beschikbare I2C-controllers gebruikt, zoals
i2c = busio.I2C(board.SCL, board.SDA)
…
si2c = busio.I2C(board.A9, board.A6)
De methoden die je daarna gebruikt zijn natuurlijk nog steeds geldig en nuttig!
/rob
Bedankt voor je doordachte commentaar, Rob! Losse draden zijn als het "wordt het gevoed?" van de computer support wereld 🙂 Beter om te controleren dan uren te besteden aan debugging
Bedankt voor dit artikel.
Ik migreer van Raspberry Pi Pico en was op zoek naar iets als dit!
Geweldig!