Wie kann man USB auf STM32F1xx _deaktivieren_?

Ich habe ein batteriebetriebenes Gerät mit einem STM32F107 . Das Gerät funktioniert und ich arbeite gerade daran, den Stromverbrauch zu minimieren.

Einer der größeren Stromverbraucher ist das USB-Subsystem selbst, das im Leerlauf etwa 8 mA verbraucht. Der USB wird nur für Konfigurationszwecke verwendet; Es ist fast immer unnötig, es zu aktivieren.

Ich verwende die USB-Bibliothek v2.1.0 von ST . Er kommuniziert als virtueller COM-Port ("VCP") der CDC-Klasse. Ich verwende die eingebettete Full-Speed-PHY.

Beim Einschalten möchte ich, dass der USB initialisiert und beispielsweise 30 Sekunden lang aktiv ist. Danach möchte ich, vorausgesetzt, es besteht keine Verbindung zu einem Host, einfach die USB-Funktionalität herunterfahren. Als ob ich es nie aktiviert hätte.

Ich sehe nichts in der API, was dies möglich machen würde. Es gibt ein paar bemerkenswerte Funktionen, aber sie scheinen nicht das zu sein, was ich brauche:

  • aus der API-Vorlage:usbDeInit()

    Dies ist für benutzerdefinierten Benutzercode vorgesehen. Es wird jedoch von der Gerätetreiberfunktion aufgerufen usbd_cdc_DeInit(), die, soweit ich sehen kann, nie wirklich aufgerufen wird.

  • in der cdc_core-Bibliothek:usbd_cdc_DeInit()

    Dies ist die Datei, die niemals in der Treiberquelle aufgerufen wird. Es schließt die Endpunkte und ruft dann die (vorher erwähnte) usbDeInit()Funktion auf. Es scheint vielversprechend; es ist jedoch staticin der Treiberquelle als deklariert. Ich zögere, den Treiberbibliothekscode direkt zu ändern, da dieser bei der zukünftigen Aktualisierung des ST-Treibers überschrieben wird.

  • aus der device_core-Bibliothek:USBD_DeInit()

    Diese wird an einigen Stellen vom Fahrer aufgerufen, ist aber leer. Das heißt, die Funktion enthält überhaupt keinen Code. Auch hier möchte ich die Treiberquelle von ST lieber nicht ändern.

Mein Initialisierungsrouting sieht so aus:

// Configure USB Clock Source
RCC_OTGFSCLKConfig(RCC_OTGFSCLKSource_PLLVCO_Div3);

// Enable USB Clock
RCC_AHBPeriphClockCmd(USB_AHB_CLK, ENABLE);

// Initialize USB
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_CDC_cb, &USR_cb);

Wenn ich die USB-Taktquelle einfach deaktiviere, hängt sich der Mikrocontroller natürlich auf.

Ich habe dafür gesorgt, dass der USB_OTG_FS_LOW_PWR_MGMT_SUPPORTSchalter in der Datei usb_conf.h aktiviert ist, aber die aktuelle Auslosung bleibt bestehen. Ich gehe davon aus, dass es nicht in den Suspend-Modus wechselt (was, wie Ali Chen sagt, die richtige Lösung wäre).

  1. Weiß jemand, wie ich das erreichen kann, was ich suche?
  2. Muss ich auf der Host-Seite etwas Besonderes tun, um dem Gerät mitzuteilen, dass es angehalten werden soll?
Warum möchten Sie die SUSPEND-Funktion nicht verwenden? Es sollte eine Standard-Power-Management-API geben. Heutzutage ist jeder USB-Stick zunächst aus der Perspektive des Energiemanagements konzipiert. Die Suspend-Funktion ist genau die Funktion, die Sie brauchen, sie sollte die PHY-Uhr und die Controller-Uhr richtig stoppen.
STM32-Peripheriegeräte haben typischerweise ein Energieverwaltungsbit und ein Taktaktivierungsbit. Deaktivieren Sie alle Softwarekomponenten, die sich beschweren würden, deaktivieren Sie diese Aktivierungen gemäß dem Programmiererhandbuch oder der von Ihnen verwendeten HAL, und wenn Sie die Anwesenheitserkennung / den Geschwindigkeits-Pullup deaktivieren können. Das Plaudern mit dem Host über das, was Sie vorhaben, ist ziemlich optional ... Sie könnten einfach so aussehen, als wären Sie nicht angeschlossen. Natürlich könnte man den USB-Block auch immer nur starten, wenn man Vbus sieht.
Danke, @ChrisStratton, ich mag die Idee "auf Vbus prüfen".

Antworten (2)

Das Deaktivieren von Funktionsblöcken wie USB in einem modernen SoC ist etwas, das vom Benutzer nicht auf Registerebene durchgeführt werden sollte. Der USB-IP-Block enthält mehrere Unterblöcke und Schnittstellen zwischen ihnen: Access Fabric, Core Controller, FIFOs/SIPOs, PHY. Alle Schnittstellen arbeiten normalerweise mit einigen Handshake-Protokollen, die normalerweise ein gewisses Vorhandensein von Uhren auf beiden Seiten der Schnittstelle erfordern, sodass willkürliches Mocken mit Uhrensteuerregistern zu Deadlocks führen kann. Daher wird dringend empfohlen, vorgefertigte Funktionen (wie SUSPEND) von Software-IP zu verwenden, um die USB-Blockierung zu verwalten. In der Dokumentation heißt es teilweise:

Die OTG_HS-Schnittstelle hat folgende Features: ... - Powersaving-Features wie Stopp der Systemuhr während USB-Suspend, Abschalten der internen Taktdomänen des digitalen Kerns, PHY- und DFIFO-Power-Management ...

Und

Suspendierung des Geräts Wenn das Gerät einen Suspend-Zustand am USB erkennt, stoppt die Bibliothek alle Operationen und versetzt das System in den Suspend-Zustand (wenn der Energiesparmodus in der Datei usb_conf.h aktiviert ist).

Um die Energiesparaufgabe zu erfüllen, würde ich daher dringend empfehlen, bereits entwickelte Funktionen aus der STM-USB-Bibliothek zu verwenden.

ZUSÄTZLICH: Das STM-Paket scheint eine Einschränkung zu haben, dass der Suspend- oder Disconnect-Modus nicht durch die Benutzer-Firmware erzwungen werden kann. Hier ist eine Idee: Nachdem die Gerätefunktion beendet ist, schalten Sie den OTG-Controller in den HOST-MODUS. Fahren Sie dann aber nicht mit der Initialisierung der HOST-Funktion fort oder beenden Sie die HOST-Funktion. Dies kann zu einer vollständig deaktivierten USB-Blockierung führen.

Danke, und ich stimme dir zu. Ich sehe nirgendwo in der API, um den Suspend-Modus zu erzwingen; es scheint vom Host gesteuert zu werden. Ich habe den USB_OTG_FS_LOW_PWR_MGMT_SUPPORTSchalter in der Datei usb_conf.h aktiviert, aber die aktuelle Auslosung existiert noch. Sollte der Benutzer in der Lage sein, den Suspend-Modus zu erzwingen?
Sie haben Recht, die normale Suspend-Funktion sollte automatisch in 3 ms auftreten, nachdem die Upstream-Verbindung die USB-Aktivität (Fluss von SOFs) beendet hat. Auf der Geräteseite sollte jedoch eine erzwungene Trennfunktion vorhanden sein. Ich bin kein Software-Typ, ich möchte Sie nur vor der allgemeinen Komplexität von Takt und Power-Gating im USB-IP-Block warnen.
Ja, ich sehe auch nicht die Funktion "Trennen erzwingen" im Paket. Schade. Normalerweise wird die erzwungene Trennungsfunktion verwendet, wenn ein Entwickler die Rollen des Geräts ändern muss, beispielsweise vom Debug-Modus in den normalen Modus, oder nach dem Laden/Aktualisieren der Geräte-Firmware mit Änderung der VID/PID. Dann müssen Sie diese Funktion erstellen, was eine Herausforderung darstellt, da feine Details von Registerschnittstellen normalerweise vom Hersteller geschützt und gesichert sind.
Einige Designs implementieren "Force Disconnect" mit analogen Schaltern, die die Datenleitungen außerhalb des Chips öffnen.

Sie müssen wahrscheinlich alles in umgekehrter Reihenfolge deaktivieren. Versuchen:

USBD_DeInit();
RCC_AHBPeriphClockCmd(USB_AHB_CLK, ENABLE);

Oder vielleicht das Gegenteil.

Die API für STM32 enthält spezielle Funktionen, um den USB-Controller und PHY in SUSPEND zu versetzen . Das ist genau die Funktion, die "alles deaktiviert" in der richtigen Reihenfolge, ohne "oder" oder "vielleicht". Das Hacken dieser Funktionalität auf Registerebene ist höchst unklug.