MCP-USB-Bridge

Aus Hobbyelektronik.org

"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:

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

Downloads