CircuitPython, Adafruit Feather RP2040 i I2C
Jak zapewne domyśliłeś się po tytule, artykuł ten omawia CircuitPython, Adafruit Feather RP2040 i protokół komunikacyjny I2C.
RP2040 posiada dwa kontrolery I2C - dobre na przykład, gdy chcesz uruchomić dwa urządzenia I2C z tym samym adresem I2C.
W mojej konfiguracji testowej, mam płytkę z mikrokontrolerem Adafruit Feather RP2040, i podłączyłem do niej dwa z naszych BME688 breakout boards - jeden z wykorzystaniem pinów SCL + SDA oraz jeden z wykorzystaniem A1 (dla SCL) + A0 (dla SDA).
Używam CircuitPython w wersji 7.0.0, które można pobrać stąd.
Ponadto, zainstalowałem wszystkie biblioteki Adafruit do katalogu lib w folderze Feather RP2040. (Feather RP2040 ma wystarczająco dużo miejsca na swojej pamięci Flash, aby to umożliwić)
Możesz pobrać te biblioteki w Adafruit CircuitPython Bundle tutaj. (Pobrałem adafruit-circuitpython-bundle-7.x-mpy-20211123.zip)
Uwaga: aby zainstalować te biblioteki po prostu skopiuj je do folderu lib na "dysku" CIRCUITPY, który jest zamontowany na twoim komputerze. Oczywiście będziesz musiał skopiować tylko biblioteki, nie przykłady i inne rzeczy.
Dużą zaletą korzystania z rzeczy Adafruit jest to, że dostajesz tonę przykładów, które obejmują wiele popularnych układów, i możesz bardzo łatwo zacząć od tego. Są tam takie rzeczy jak obsługa karty microSD za pomocą SPI, odczyt RTC, czy odczyt z czujnika BME680.
Testowanie I2C w CircuitPython
Mam następującą konfigurację, ponieważ chcę wysterować dwa urządzenia niezależnie od siebie (które w tym przypadku mają te same adresy):
Zauważ, że nasze płytki breakout BME688 zawierają już pullupy dla SDA i SCL. (Ty potrzebujesz pullupów na SDA i SCL).
Uwaga 2: Nasza płytka breakout BME688 ma możliwość zmiany adresu, więc ten scenariusz jest przeznaczony do celów demonstracyjnych.
Aby sekwencyjnie przejechać przez oba zestawy pinów (w celu wykrycia urządzeń), używam następującego kodu:
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()
Uwaga i2c.deinit() jest kluczem do działania tego konkretnego przykładu! (ponieważ SCL / SDA i A0 / A1 mają zarówno ten sam sprzętowy peryferyjny I2C - patrz poniżej).
Powinno to dać następujące wyniki:
Scanning SCL / SDA
[119]
Scanning A0 / A1
[119]
Tutaj, 119 jest dziesiętne dla heksadecymalnego 0x77 - który jest adresem naszej płytki BME688 w stanie domyślnym.
Obie tablice są widoczne, kolejno w poszczególnych skanach.
Problem w tym, że chcemy ich używać jednocześnie.
Uruchamianie dwóch magistral I2C jednocześnie na Adafruit Feather RP2040
CircuitPython obsługuje zarówno kontrolerów sprzętowych (SDA0/SCL0 i SDA1/SCL1). Nie musisz ustawiać żadnej konfiguracji (z którego kontrolera chcesz korzystać, czy jak muxować piny) - tym zajmuje się busio dla ciebie.
Należy jednak zwrócić uwagę, których pinów używamy, ponieważ będą one dostarczać tylko jeden z tych magistral w każdym przypadku, a jeśli zdarzy się, że wybierzesz sprzeczne piny, otrzymasz ValueError: Peryferia I2C w użyciu .
Jeśli chcesz użyć "konfliktowych" pinów, fo rexample SCL / SDA (które mają SCL1 i SDA1) i A0 / A1 (które również mają SCL1 i SDA1), będziesz musiał bitbangować jeden z portów:
Oto jak przeskanować tę konfigurację pinów bez wywoływania deinit():
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()
Używamy bitbangio aby wysterować drugorzędny I2C. W moim przypadku drugorzędny I2C jest używany do celów wewnętrznych (do ekspandera portów), i całkiem prawdopodobne, że może sobie poradzić z niższą prędkością interfejsu.
Uwaga: nie masz możliwości programowego wyboru peryferiów I2C, które są kierowane do pinów - jeśli potrzebujesz innych peryferiów, musisz użyć innych pinów.
Rozwiązywanie problemów z błędami I2C
ValueError: Peryferia I2C w użyciu
Jeśli używasz busio.I2C dla obu portów: Sprawdź, czy używasz już tego samego sprzętowego peryferium I2C - i czy musisz ponownie przypisać swoje piny.
Na przykład, zarówno SCL i SDA , jak i A0 i A1 współdzielą ten sam sprzętowy peryferyjny I2C (SCL1 / SDA1 - patrz rysunek wyprowadzeń Adafruit Feather RP2040 w tym artykule).
W przypadku, gdy chcesz użyć tej samej konfiguracji pinów, możesz użyć bitbangio do "stworzenia" dodatkowego portu I2C sterowanego programowo. Wadą tego jest mniejsza prędkość dla tego portu I2C sterowanego programowo i większe obciążenie procesora.
RuntimeError: Nie znaleziono podciągania na SDA lub SCL; sprawdź okablowanie
Jeśli wystąpi następujący błąd
RuntimeError: Nie znaleziono podciągania na SDA lub SCL; sprawdź okablowanie
to powinieneś umieścić rezystory podciągające pomiędzy 3V3 na płytce (pin 3.3V) a odpowiednio twoimi pinami SDA i SCL. Są one wymagane do normalnej pracy I2C (urządzenia ściągają piny I2C aby się komunikować, domyślnym stanem bezczynności na magistrali jest stan wysoki) - i nie są dołączone do Adafruit Feather RP2040. Są one zawarte w wielu urządzeniach peryferyjnych Adafruit, oraz w urządzeniach peryferyjnych innych firm (jak, ponownie, nasze własne BME688 breakout board).
Jeśli nie wiesz co to jest pullup: jest to w zasadzie rezystor pomiędzy danym pinem (np. SDA) a pinem zasilania 3.3 V. Nie musi być on strasznie dokładny. Powinieneś zacząć od rezystorów 10 kOhm, jeśli to nie zadziała, ewentualnie spróbuj rezystora 1 kOhm dla "sztywniejszego" podciągania.
TimeoutError: Zbyt długi odcinek zegara
Sprawdź, czy układ, z którym chcesz rozmawiać, jest prawidłowo zasilany.
Różne notatki
- Adafruit Feather RP2040 posiada diodę LED NeoPixel. NeoPiksele używają zastrzeżonego protokołu, nie korzystają z I2C.
- Strona Adafruit CircuitPython Community Bundle posiada kilka dodatkowych sterowników
- Istnieje Pomocnik DebugI2C
- Strona matryca wsparcia pokaże Ci, które moduły są obsługiwane na Twojej płytce (np. Adafruit Feather RP2040)
Referencje / Zasoby / Linki / Dalsza lektura
- Adafruit CircuitPython Bundle (biblioteki dla CircuitPython)
- Dokumentacja CircuitPython Busio
- Dokumentacja CircuitPython Board
- CircuitPython w dokumentacji RP2040
- Podstawy CircuitPython I2C
Chcesz dowiedzieć się więcej o I2C? Sprawdź nasz artykuł na ten temat tutaj.
Dziękuję za pomocny artykuł! Mam dwie sugestie:
1) Jedna z przyczyn błędu "no pull up found" (co mnie tu sprowadziło) może być również spowodowana przez głupi błąd: posiadanie luźnego przewodu! Zdarza mi się to zbyt często, ponieważ używam złączy Stemma, które są trochę finnistyczne.
2) Myślę, że twój przykładowy kod jest trochę mylący, w tym sensie, że myślę, że mógłby/powinien zacząć od najprostszego przypadku, w którym używasz dwóch dostępnych kontrolerów I2C, np.
i2c = busio.I2C(board.SCL, board.SDA)
…
si2c = busio.I2C(board.A9, board.A6)
Metody, których używasz po tym, są oczywiście nadal ważne i przydatne!
/rob
Dziękuję za Twój przemyślany komentarz, Rob! Luźne przewody są jak "czy to jest zasilane?" w świecie obsługi komputera 🙂 Lepiej sprawdzić niż spędzać godziny na debugowaniu
Dziękuję za ten artykuł.
Migruję z Raspberry Pi Pico i szukałem czegoś takiego!
Niesamowite!