MCP-USB-Bridge
"Mal kurz etwas mit I²C/SPI testen". Was einfach klingt artet gerne in vielen Programmierläufen eines Mikrocontrollers aus.
Mittlerweile haben die meisten Bastler einen Single Board Computer wie den Raspberry Pi herumliegen, in manchen Situationen wäre eine direkte Anbindung an den PC dann doch angenehmer.
Selbst hierfür gibt es Lösungen wie den Aardvark von Total Phase oder den Bus Pirate von Dangerous Prototypes, diese sind entweder vergleichsweise teuer oder umständlich in der Bedienung/Automatisierung.
Microchip hat den MCP2221 (I²C) und MCP2210 (SPI) im Angebot. Dabei handelt es sich mutmaßlich um vorprogrammierte Mikrocontroller, was ansich nicht verwerflich ist. Allerdings gibt es ein paar Ecken und Kanten, wie Zak bereits geschrieben und ich bestätigt habe.
Auch beim MCP2210 hat die im Datenblatt angegebene Datenrate nicht sehr viel mit dem tatsächlichen Durchsatz zu tun.
Um etwas zu testen sind jedoch beide Chips ok.
Vom Microchip gibt es zwar jeweils auch ein Breakout-Board, beide sind für normalsterbliche jedoch relativ schlecht verfügbar. Deshalb: EAGLE an und los geht's:
Inhaltsverzeichnis
USB-I²C-Bridge
Im Prinzip ist die Beschaltung einfach: USB rein, I²C (sowie UART, ein paar GPIOs, ADC und DAC) raus.
Da viele I²C-Bausteine mittlerweile nicht mehr mit den früher üblichen 5 Volt funktionieren, gibt es zusätzlich einen Spannungsregler und Levelshifter die, wie im Artikel über den APDS-9300, der AN10441 von NXP folgen.
Der ADC an GP3 kann zugleich für die Spannungsmessung des Reglers verwendet werden, um bei Änderungen der IO-Spannung nicht unbedingt ein Messgerät anschließen muss. Damit die interne Messung funktioniert, müssen beide Jumper gesteckt und damit die Versorgung der "VIO"-Pins aktiviert werden. Mit bisschen Gewalt bekommt man einen Jumper vertikal gesteckt und kann ohne aktivertem VIO messen... Auch ein Punkt für Revision 2.
Der verwendete LM317 hat leider einen Nachteil: da seine Feedback-Spannung gegen Vout referenziert wird, kommt er nicht sehr nahe an die Eingangsspannung heran. Praktisch kommen maximal knapp 3,3 V am Ausgang an. Reicht für die meisten Anwendungen, für manche Bauelemente ist es allerdings zu wenig. Beim nächsten Mal kommt ein anderer Regler, versprochen.
Die BOM ist überschaubar:
Menge | Referenz | Wert | Package | Reichelt Bestellcode |
---|---|---|---|---|
2 | JP1, JP2 | JP1 | ||
2 | LED1, LED2 | CHIP-LED0603 | LED EL 0603 GR1 | |
5 | SV1, SV3, SV4, SV5, SV8 | MA04-2 | ||
1 | R2 | 0 | R0603 | RND 0603 0 |
1 | R10 | 100 | R0603 | RND 0603 1 100 |
3 | C3, C4, C5 | 100n | C0603 | KEM X7R0603 100N |
1 | R1 | 10k | R0603 | RND 0603 1 10K |
1 | C2 | 10n | C0603 | KEM X7R0603 10N |
1 | C6 | 1u | C0805 | X7R-G0805 1,0/16 |
1 | R7 | 22k | R0603 | RND 0603 1 22k |
1 | R18 | 23B-500 | POT-23B | 23B-500 |
1 | R9 | 240 | R0603 | RND 0603 1 240 |
1 | R15 | 2k2 | R0603 | RND 0603 1 2,2k |
9 | R3, R4, R5, R6, R8, R11, R12, R13, R14 | 3k3 | R0603 | RND 0603 1 3,3k |
1 | C1 | 470n | C0603 | NPO 0603 CD 470N |
1 | R16 | 680 | R0603 | RND 0603 1 680 |
4 | Q1, Q2, Q3, Q4 | BSS138 | SOT23 | BSS 138 SMD |
1 | IC2 | LM317LD | SO08 | LM 317 LD |
1 | IC1 | MCP2221-I/SL | SO-14 | MCP2221-I/SL |
1 | X1 | ZX62-B-5PAHS | ZX62-B-5PA_HANDSOLDER | MIC USB BBU |
Um kurz etwas zu testen bietet sich die Software "MCP2221 I2C SMBus Terminal", die man auf der Produktseite von Mikrochip herunterladen kann.
Die C#-Implementierung von Microchip ist leider nicht die schönste, eine echte Alternative habe ich leider noch nicht gefunden (vielleicht kommt hier etwas).
USB-I²C-Bridge v1.1
Reichelt hat den 23B-500 aus dem Programm genommen. Wer ihn bestellen will, fällt wahrscheinlich auf den 23B-500K herein, der leider 3 Zehnerpotenzen daneben liegt.
Das und die relativ schlecht einstellbare IO-Spannung (Bereich und Präzision) hat mich dazu bewogen, das Design abzuwandeln.
Neben einem neuen Regler (der leider etwas weniger Strom kann) und Präzisionstrimmer gibt es nun zwei Montagelöcher. Letztere haben leider eine relativ schlechte Clearance zu den Bauteilen. Arg viel besser geht es in diesem Formfaktor leider nicht...
Als weiteres Goodie sind jetzt auch die GPIOs (wenn auch sehr klein) beschriftet:
Die BOM ist entsprechend fast gleich:
Menge | Referemz | Wert | Package | Reichelt Bestellcode |
---|---|---|---|---|
1 | JP3 | JP2Q_NN | ||
2 | LED1, LED2 | CHIP-LED0603 | LED EL 0603 GR1 | |
5 | SV1, SV3, SV4, SV5, SV8 | MA04-2NN | ||
1 | R2 | 0 | R0603 | RND 0603 0 |
1 | R10 | 100 | R0603 | RND 0603 1 100 |
3 | C3, C4, C5 | 100n | C0603 | KEM X7R0603 100N |
1 | R1 | 10k | R0603 | RND 0603 1 10K |
1 | C2 | 10n | C0603 | KEM X7R0603 10N |
1 | C7 | 1u | C0805 | X7R-G0805 1,0/16 |
1 | R17 | 200k | S64Y | 64Y-200K |
1 | R7 | 22k | R0603 | RND 0603 1 22k |
1 | R15 | 2k2 | R0603 | RND 0603 1 2,2k |
9 | R3, R4, R5, R6, R8, R11, R12, R13, R14 | 3k3 | R0603 | RND 0603 1 3,3k |
1 | C1 | 470n | C0603 | NPO 0603 CD 470N |
1 | C6 | 4u7 10V | C0603 | KEM X5R0603 4,7U |
1 | R9 | 56k | R0603 | RND 0603 1 56K |
1 | R16 | 680 | R0603 | RND 0603 1 680 |
4 | Q1, Q2, Q3, Q4 | BSS138 | SOT23 | BSS 138 SMD |
1 | IC1 | MCP2221-I/SL | SO-14 | MCP2221-I/SL |
1 | IC3 | TPS76301 | SOT23-DBV | TPS 76301 DBVR |
1 | X1 | ZX62-B-5PAHS | ZX62-B-5PA_HANDSOLDER | MIC USB BBU |
Hinsichtlich der BOM gibt es auch ein ziemliches Problem: Reichelt hat die eigentlichen Standardwerte 0603 100 nF, 0603 470 nF, 0805 1 µF/16 V aktuell (02/2020) gar nicht mehr im Programm, die USB-Buchse habe ich bis jetzt noch nie lieferbar gesehen. Auch wenn sich die Probleme einfacher umgehen lassen - was zum ... ist da los?
USB-SPI-Bridge
Der MCP2210 unterstützt von sich aus 2 IO-Spannungen: 5 V und 3,3 V. Ausreichend für die meisten SPI-Bausteine. Einen Levelshifter für weitere Spannungen wollte ich auf dem Board aus Platzgründen nicht integrieren.
Der 3,3 V-Regler kann lt. Datenblatt mit 250 mA vergleichsweise viel Strom. Bedenkt man, dass bei einer Versorgungsspannung von 5 V (tendenziell mehr) und dieser Stromstärke 425 mW verbraten werden müssen - eher nein. Dauerhaft 100 mA sollten allerdings kein größeres Problem sein.
Da mein Hauptverwendungszweck das Ansteuern von Funkmodulen sein wird, sind Buchsenleisten für die weit verbreiteten nRF24L01+- und CC1101-Module vorhanden. Ferner sind alle IOs herausgeführt, beschriftet und mit 100 Ohm im Strom begrenzt:
Auch hier ist die BOM überschaubar:
Menge | Parts | Wert | Package | Reichelt Bestellcode |
---|---|---|---|---|
1 | JP1 | JP3Q | ||
1 | LED1 | SML0603 | LED EL 0603 GR1 | |
2 | SV1, SV2 | MA08-1 | ||
1 | R1 | 0 | R0603 | RND 0603 0 |
12 | R4, R5, R6, R7, R8, R10, R11, R12, R13, R14, R15, R16 | 100 | R0603 | RND 0603 1 100 |
2 | C4, C5 | 100n | C0603 | KEM X7R0603 100N |
1 | R3 | 10k | R0603 | RND 0603 1 10k |
2 | C1, C2 | 10p | C0603 | NPO-G0603 10P |
1 | Q1 | 12M | MJ | 12,000000-MJ |
1 | R2 | 1k | R0603 | RND 0603 1 1k |
2 | C6, C7 | 1u | C0805 | KEM X5R0805 1,0U |
1 | C3 | 330n | C0603 | KEM X7R0603 330N |
2 | X2, X3 | FE04-2 | FE04-2 | |
1 | IC2 | MCP1700T-3302E/TT | SOT23 | MCP 1700-3302 |
1 | IC1 | MCP2210/SO | SO20L | MCP 2210I-SO |
1 | X1 | ZX62-B-5PAHS | ZX62-B-5PA | MIC USB BBU |
Auch hier gilt: die Implementierung von Microchip ist nicht die Beste. Eine richtige Alternative für C# und Python habe ich hier auch noch nicht gefunden.
Anmerkungen
- Der zusätzliche "Bestückungsdruck" für die Pinbezeichnungen befindet sich im Layer tSilk in Lage 100. Wenn Produktionsdaten ausgegeben werden, diese bitte nicht vergessen. Ist mir bei der SPI-Bridge passiert, weshalb dort ein Stück Papier als Ersatz.
- Der Spannungsteiler für die VIO-Messung an der I2C-Bridge ist ungünstig verschaltet. Dadurch können speziell hochohmige Signale bei ADC-Messungen nach unten "verzogen" werden.
- Die Spannungsmessung von VIO sollte auch möglich sein, wenn der Enable-Jumper nicht gesetzt ist
- Wie bereits erwähnt, ist der Bereich für VIO bei der I2C-Bridge etwas klein.
- Achtung: Unter Python >= 3.8 gibt es aktuell wohl keine "wunschlos glücklich" hidapi-Lib. Zumindest bei meinen Versuchen wollte das Teil beim Installieren nicht bauen. Workaround: Python 3.7 verwenden.
Deshalb: es wird eine Version 2 geben.
Das Datenblatt des MCP2221 enthält ein paar Fehler bzw. fehlen Informationen:
- Die Berechnung der I²C-Clock ist eher ungenau
- Es fehlen wichtige Informationen zu den Zuständen der Statemachines, die Microchip auch auf Rückfrage nicht herausrücken wollte, für die Implementierung aber zwingend erforderlich sind. Hier musste ich mutmaßen
- Im Befehl zum Setzen der SRAM-Settings ist der angegebene Wert zum Schreiben der GPIO-Settings (Byte 7) falsch
- Das Umstellen der ADC-Referenz muss nach dem Setzen der Pinfunktion erfolgen, da sonst die Referenz auf den Default-Wert gesetzt werden
Python-Lib
MCP2221
Nachdem ich keine Python-Bibliothek finden konnte, die zumindest größere Datentransfers (> 60 Byte) erlaubt, habe ich angefangen, selbst eine zu schreiben. Sie umfasst aktuell folgende Features des MCP2221:
Funktion | Status | Anmerkung |
---|---|---|
I²C Read/Write | getestet | bis 65535 Byte |
DAC | getestet | |
ADC | getestet | |
GPIO | ungetestet | |
Interrupt | nicht implementiert | |
Flash-Settings | nicht implementiert | aktuell nicht geplant |
Während der Implementierung stellte sich heraus, dass das Datenblatt an ein paar Stellen Fehler hat und auch an relevanten Stellen unvollständig ist. Z. B. ist für eine saubere Implementierung das Wissen über die Status der I²C-Engine nötig. Laut Datenblatt ist diese Information "internal". Im Linux-Treiber kann man einige dieser Werte herausziehen. Auf Anfrage teilte mir der verantwortliche Entwickler mit, dass diese Information nicht herausgegeben wird.
Insgesamt scheint die Implementierung im Controller nicht vollständig sauber zu sein, folgendes ist mir aufgefallen:
- Ungültige Anfragen (z. B. falsche Werte bei cancel current I²C transfer) werden mit "success" beantwortet
- I2C_Cancel nach einem Reset des Chips führt zu einem Deadlock (kein Workaround)
- Wird direkt nach einem Enumerate das Device geöffnet, geht der Chip ebenfalls in einen Deadlock. Kann aber auch an der HID-Lib oder an meinem PC liegen (Workaround: warten bevor das device geöffnet wird, ist implementiert)
Ferner ist anzumerken, dass die Lib noch keinen Stable-Zustand verdient. Dafür ist sie einfach zu wenig und zu einseitig getestet.
Performance
Obwohl der Chip I²C-Taktraten bis 400 kHz (und noch ein bisschen mehr) unterstützt, den damit verbundenen Datendurchsatz erreicht man leider beiweitem nicht. Das hängt zum einen mit der Verwendung des USB-HID zusammen, zum anderen scheint das I²C-Interface oder die Implementierung auf dem Controller nicht hinreichend optimiert zu sein.
Für die Messung wurden 2400 Byte schreibend bzw. lesend übertragen. Die Datenlänge entspricht dem Vielfachen der verwendeten Blockgröße von 60 Byte. Die verwendeten Scripts befinden sich im Beispielordner der Lib. Die Messung wurde mehrfach wiederholt, jedoch fließen in die Tabelle und die Diagramme die Samplegröße 1 ein. Der MCP2221 wurde an einen USB-Port ohne weitere Devices angeschlossen.
SCL freq [kHz] | write execution time [ms] | write throughput [kbit/s] | write efficiency [%] | read execution time [ms] | read throughput [kbit/s] | read efficiency [%] |
---|---|---|---|---|---|---|
50,1 | 547 | 39,5 | 78,84 | 639 | 33,81 | 67,5 |
100,4 | 313 | 69,03 | 68,75 | 479 | 45,11 | 44,9 |
150,9 | 235 | 91,95 | 60,92 | 320 | 67,52 | 44,7 |
201,7 | 235 | 91,95 | 45,59 | 320 | 67,52 | 33,5 |
252,6 | 157 | 137,63 | 54,48 | 240 | 90,03 | 35,6 |
303,8 | 158 | 136,76 | 45,02 | 240 | 90,03 | 29,6 |
347,8 | 158 | 136,76 | 39,32 | 240 | 90,03 | 25,9 |
406,8 | 158 | 136,76 | 33,62 | 240 | 90,03 | 22,1 |
452,8 | 158 | 136,76 | 30,2 | 240 | 90,03 | 19,9 |
Der sweet spot liegt also bei ungefähr 250 kHz, trotzdem werden dabei lediglich knapp 140 kbit/s erreicht. Nicht wirklich berauschend. Trotzdem bleibt das Argument: eine günstige (oder in dem Fall billige?) Lösung.
C#-Lib
Um auch aus C# heraus und nicht (wie mit der Lib von Microchip) an ein .NET-Framework gebunden zu sein, habe ich auch eine Bibliothek sowohl für den MCP2221 als auch MCP2210 in nativem C# (ohne externe DLLs oder sonstige Abhängigkeiten) geschrieben.
Einige, für den täglichen Bedarf weniger benötigte, Funktionen wurden ausgelassen; die Performance ist zumindest bei I²C ähnlich gut wie die der Python-Lib.
Codebeispiele und entsprechende Anwendungen werden folgen, sobald ich Zeit habe, sie zu vervollständigen. Der unvollständige "Release" ist einfach nur, damit der Code unter die Leute gemischt wird :)
Folgende Demos ist aktuell vorbereitet (oder geplant):
- MCP2221
- ADC/(DAC)
- TI INA219 - Current Shunt & Power Monitor
- (TI INA3221 - 3Ch Current Shunt & Power Monitor)
- Microchip MCP4725 - 12-Bit-DAC
- QMC5883L - Magnetometer
- (STM LSM-irgendwas - 6D-Sensor mit Schrittzähler)
- (Atmel/Microchip Maxtouch-Touchcontroller)
- (Avago/Broadcomm APDS-99x0 - Ambient light/Gesten-/Farb-Sensor)
- MCP2210
- Maxim MAX31855 - K-Typ Temperatursensor
- Maxim MAX7219 - LED-Treiber
- Nordic Semi nRF24L01+ - 2,4 GHz Transceiver (+ BLE-Hack, der Logitech-Hack ist aktuell nicht geplant)
- (TI CC1101 - Low-Power Sub-1 GHz RF Transceiver)
Leiterkarten
Es gibt noch unbestückte Leiterkarten. Wer eine will, kann sich gerne bei mir melden.
Backplate
Im 3D-Druck-Sammelsurium gibt es Backplates zum Selberdrucken
Blogposts
- 17.10.2019 Die perfekte USB-I2C-Bridge: TL;DR: Ich habe sie noch nicht gefunden und...
- 04.11.2018 MCP2221 mit C# - aber schnell.: Nachdem die Python-Lib ganz gut funktioniert...
- 10.09.2018 Was der MCP2221 sonst noch kann: Es gibt Dinge,...
Downloads
Datei:Mcp22xx py.zip Python3-Lib v0.2, aktuell nur für MCP2221, mit Beispielen- Git-Repo der Python 3-Lib v0.3 für MCP2221 und MCP2210, mit Beispielen
- Datei:Mcp22xx cs.zip C#-Lib v0.1, für MCP2221 und MCP2210, aktuell noch ohne Beispiele und teilweise ungetestet
- Datei:MCP-USB-Bridge.zip enthält:
- Designdaten beider Boards (jeweils Version 1.0) im EAGLE-Format
- Datei:Mcp-usb-i2c v1.1.zip enthält Version 1.1 des USB-I²C-Adapters im EAGLE-Format