<Bild mit
Karte und Kopfhörer> Noch niedrigere Ebene (avr-vusb): habr.com/ru/post/460815
USB -Einschaltregister : STM32L1 / STM32F1
USB -Einschaltregister: Massenendpunkt am Beispiel von Massenspeicher
USB auf Registern: Interrupt-Endpunkt am HID-Beispiel
Schauen wir uns heute den letzten Typ des Endpunkts an, der isochron ist. Es wurde entwickelt, um Daten zu ĂŒbertragen, die fĂŒr die Lieferzeit von entscheidender Bedeutung sind, garantiert jedoch nicht den Erfolg. Das klassischste Beispiel sind AudiogerĂ€te: Lautsprecher, Mikrofone.
Seltsamerweise stellte sich heraus, dass diese Art von Endpunkt am meisten Gehirn pumpt (und das nach allem, was ich mit stm'kami gesehen habe!). Trotzdem werden wir heute ein AudiogerĂ€t herstellen und gleichzeitig den Kern der USB-Bibliothek leicht fertigstellen. Wie ĂŒblich sind die Quellcodes verfĂŒgbar:
github.com/COKPOWEHEU/usb/tree/main/4.Audio_L1
github.com/COKPOWEHEU/usb/tree/main/4.Audio_F1
Kernel-Verfeinerung
Es ist notwendig, den Kernel zu verfeinern, da STM nur isochrone Punkte mit doppelter Pufferung haben kann, dh grob gesagt ist es unmöglich, 0x01 isochron und 0x81 zu steuern. Das heiĂt, es ist natĂŒrlich möglich, dies in den USB-Deskriptor zu schreiben, aber dies Ă€ndert nichts an der Innenseite des Controllers, und die tatsĂ€chliche Adresse des Punkts unterscheidet sich einfach von der von auĂen sichtbaren. Das erhöht natĂŒrlich das Fehlerrisiko, sodass wir nicht in diese Richtung pervertiert werden.
Es ist zu beachten, dass die doppelte Pufferung nicht nur fĂŒr isochrone Punkte, sondern auch fĂŒr die Masse auftritt und sich einschaltet und anders funktioniert. Wenn isochrone Punkte die Pufferung automatisch aktivieren, einfach weil sie nichts anderes können, mĂŒssen Sie fĂŒr die entsprechende Bulk-Einstellung das spezielle USB_EP_KIND-Bit verwenden, das zusammen mit der tatsĂ€chlichen Punkttypeinstellung gesetzt werden muss.
Pufferung bedeutet fĂŒr sich genommen, dass, wenn zuvor ein Punkt einem Puffer zum Senden und einem zum Empfangen entsprach, beide Puffer entweder zum Senden oder zum Empfangen arbeiten und nur zusammenarbeiten. Infolgedessen unterscheidet sich die Einstellung eines gepufferten Punkts stark von der ĂŒblichen, da Sie nicht einen Puffer, sondern zwei konfigurieren mĂŒssen. Daher werden wir keine unnötigen Bedingungen in die ĂŒbliche Initialisierung umwandeln, sondern darauf basierend eine separate Funktion usb_ep_init_double () erstellen.
Das Empfangen und Senden von Paketen unterscheidet sich nicht so sehr, obwohl es viel lĂ€nger gedauert hat, zuerst zu versuchen, zu verstehen, wie es gemÀà der ST-Logik funktionieren sollte, und dann den Zauber aus dem Internet anzupassen, damit es funktioniert. Wie bereits erwĂ€hnt, sind zwei Puffer fĂŒr einen gewöhnlichen Punkt unabhĂ€ngig und unterscheiden sich in der Austauschrichtung. Bei einem gepufferten Puffer sind sie gleich und unterscheiden sich nur im Versatz. Ăndern wir also die Funktionen usb_ep_write und usb_ep_read ein wenig, sodass sie keine Punktnummer, sondern eine Versatznummer akzeptieren. Das heiĂt, wenn diese Funktionen frĂŒher die Existenz von acht Doppelpunkten angenommen haben, jetzt - 16 Einzelpunkte. Dementsprechend ist die Nummer der neuen "halben Zeile" zum Schreiben nur die Nummer der ĂŒblichen, multipliziert mit zwei, und fĂŒr usb_ep_read muss man auch eine hinzufĂŒgen (siehe die Zuordnung der Puffer in der PMA). TatsĂ€chlich,Dies erfolgt durch die Inline-Funktionen usb_ep_write und usb_ep_read fĂŒr regulĂ€re Punkte. Aber schauen wir uns die gepufferte Logik genauer an.
GemÀà der Dokumentation steht ein Puffer eines solchen Punktes fĂŒr Hardware zur VerfĂŒgung, der zweite fĂŒr Software. Dann wechseln sie und stören sich wieder nicht. FĂŒr den OUT-Punkt ist das Flag auf der Hardwareseite das USB_EP_DTOG_RX-Bit, das gelesen werden muss, um zu verstehen, welcher der Puffer gerade fertig geschrieben wurde und von wo aus die Software lesen kann. Wenn er seinen Puffer liest, mĂŒssen Sie das USB_EP_DTOG_TX-Bit ruckeln, das die Puffer tatsĂ€chlich schaltet. Ich bin mir nicht sicher, ob dies gemeint ist, aber es funktioniert zumindest.
Eine symmetrische Situation sollte mit IN-Punkten gewesen sein. In der Praxis stellte sich jedoch heraus, dass Sie USB_EP_DTOG_RX ĂŒberprĂŒfen und abrufen mĂŒssen. Warum nicht TX verstehe ich immer noch nicht ... Danke an den User kuzulis fĂŒr den Link zu github.com/dmitrystu/libusb_stm32/edit/master/src/usbd_stm32f103_devfs.c
Aufgrund der Inline-Funktion wurde auĂer der Initialisierung kein spezieller Overhead hinzugefĂŒgt. Aber Sie können es, wenn Sie möchten, mit den Linker-Flags wegwerfen. Oder Sie mĂŒssen es nicht wegwerfen: Es nimmt nicht so viel Platz ein und wird nur wĂ€hrend der Initialisierung aufgerufen. Dies ist keine HAL fĂŒr Sie, bei der Funktionen nicht nur schwer sind, sondern sich auch stĂ€ndig gegenseitig anrufen.
Infolgedessen haben die Endpunkte gelernt, im gepufferten Modus zu arbeiten ... wenn Sie nicht zu schwer atmen.
FĂŒr den Benutzer ist der Unterschied gering: Verwenden Sie anstelle von usb_ep_init usb_ep_init_double und anstelle von usb_ep_write und usb_ep_read usb_ep_write_double bzw. usb_ep_read_double.
AudioDevice-GerÀt
Und jetzt, als wir den technischen Rechen herausgefunden haben, gehen wir zum interessantesten ĂŒber - dem Einrichten eines AudiogerĂ€ts.
GemÀà dem USB-Standard ist ein AudiogerĂ€t eine Reihe von EntitĂ€ten, die in einer bestimmten Topologie miteinander verbunden sind, durch die das Audiosignal geleitet wird. Jede EntitĂ€t hat ihre eigene eindeutige Nummer (bTerminalID, auch bekannt als UnitID), ĂŒber die andere EntitĂ€ten oder Endpunkte eine Verbindung herstellen können. Der Host verwendet sie auch, wenn er einige Parameter Ă€ndern möchte. Und er gilt als der einzige Ausweg aus dieser EntitĂ€t. Möglicherweise sind jedoch ĂŒberhaupt keine EingĂ€nge vorhanden (wenn es sich um einen Eingangsanschluss handelt), oder es gibt möglicherweise mehr als einen (bSourceID). Indem wir die Nummern der EntitĂ€ten, von denen die aktuelle EntitĂ€t ein Audiosignal empfĂ€ngt, in das bSourceID-Array schreiben, beschreiben wir die gesamte Topologie, was sich als sehr schnell herausstellen kann. Zum Beispiel werde ich die Topologie einer gekauften USB-Soundkarte angeben (die Zahlen zeigen bTerminalID / UnitID):
lsusb und seine EntschlĂŒsselung
Bus 001 Device 014: ID 0d8c:013c C-Media Electronics, Inc. CM108 Audio Controller
#
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0d8c C-Media Electronics, Inc.
idProduct 0x013c CM108 Audio Controller
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
#
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x00fd
bNumInterfaces 4 #
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
# 0 -
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 1 Control Device
bInterfaceProtocol 0
iInterface 0
AudioControl Interface Descriptor:
bLength 10
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdADC 1.00
wTotalLength 0x0064
bInCollection 2 # ! (2)
baInterfaceNr(0) 1 #
baInterfaceNr(1) 2 #
##### #####
# 1 InputTerminal (USB, )
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1 #
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bNrChannels 2 #
wChannelConfig 0x0003 # -
Left Front (L)
Right Front (R)
iChannelNames 0
iTerminal 0
# 2 InputTerminal ()
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0201 Microphone
bAssocTerminal 0
bNrChannels 1
wChannelConfig 0x0001
Left Front (L)
iChannelNames 0
iTerminal 0
# 6 OutputTerminal (), 9
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 6
wTerminalType 0x0301 Speaker
bAssocTerminal 0
bSourceID 9 #
iTerminal 0
# 7 OutputTerminal (USB), 8
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 7
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bSourceID 8
iTerminal 0
# 8 Selector, 10
AudioControl Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 5 (SELECTOR_UNIT)
bUnitID 8
bNrInPins 1 #
baSourceID(0) 10 #
iSelector 0
# 9 Feature, 15
AudioControl Interface Descriptor:
bLength 10
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 9
bSourceID 15
bControlSize 1
bmaControls(0) 0x01
Mute Control
bmaControls(1) 0x02
Volume Control
bmaControls(2) 0x02
Volume Control
iFeature 0
# 10 Feature, 2
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 10
bSourceID 2
bControlSize 1
bmaControls(0) 0x43
Mute Control
Volume Control
Automatic Gain Control
bmaControls(1) 0x00
iFeature 0
# 13 Feature, 2
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 13
bSourceID 2
bControlSize 1
bmaControls(0) 0x03
Mute Control
Volume Control
bmaControls(1) 0x00
iFeature 0
# 15 Mixer, 1 13
AudioControl Interface Descriptor:
bLength 13
bDescriptorType 36
bDescriptorSubtype 4 (MIXER_UNIT)
bUnitID 15
bNrInPins 2 #
baSourceID(0) 1 #
baSourceID(1) 13
bNrChannels 2
wChannelConfig 0x0003
Left Front (L)
Right Front (R)
iChannelNames 0
bmControls(0) 0x00
iMixer 0
##### #####
# 1 () -
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
# 1 () -
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 1
bDelay 1 frames
wFormatTag 0x0001 PCM
AudioStreaming Interface Descriptor:
bLength 14
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 2
bSubframeSize 2
bBitResolution 16
bSamFreqType 2 Discrete
tSamFreq[ 0] 48000
tSamFreq[ 1] 44100
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 9
Transfer Type Isochronous
Synch Type Adaptive
Usage Type Data
wMaxPacketSize 0x00c8 1x 200 bytes
bInterval 1
bRefresh 0
bSynchAddress 0
AudioStreaming Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x01
Sampling Frequency
bLockDelayUnits 1 Milliseconds
wLockDelay 0x0001
# 2 () -
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
# 2 ()
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 0
iInterface 0
AudioStreaming Interface Descriptor:
bLength 7
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 7
bDelay 1 frames
wFormatTag 0x0001 PCM
AudioStreaming Interface Descriptor:
bLength 14
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bNrChannels 1
bSubframeSize 2
bBitResolution 16
bSamFreqType 2 Discrete
tSamFreq[ 0] 48000
tSamFreq[ 1] 44100
Endpoint Descriptor:
bLength 9
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 9
Transfer Type Isochronous
Synch Type Adaptive
Usage Type Data
wMaxPacketSize 0x0064 1x 100 bytes
bInterval 1
bRefresh 0
bSynchAddress 0
AudioStreaming Endpoint Descriptor:
bLength 7
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x01
Sampling Frequency
bLockDelayUnits 0 Undefined
wLockDelay 0x0000
##### #####
# 3 " " ( )
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 3
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.00
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 60
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x87 EP 7 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0004 1x 4 bytes
bInterval 2
Wir werden etwas Einfacheres tun (ich habe das Leerzeichen von hier genommen ):
Hier sehen Sie zwei unabhĂ€ngige Signalausbreitungszweige: entweder von USB ĂŒber eine âFunktionâ zu einem âLautsprecherâ oder von einem âMikrofonâ ĂŒber eine andere âFunktionâ âAuf USB. Das Mikrofon und der Lautsprecher werden nicht nur in AnfĂŒhrungszeichen gesetzt: Sie befinden sich nicht auf meinem Debug-Board. Daher verwenden wir anstelle des Sounds selbst Tasten und LEDs. Allerdings nichts Neues. "Features" in meinem Fall tun nichts und werden mehr fĂŒr die Schönheit hinzugefĂŒgt.
Es sollte sofort klargestellt werden, dass das Signal in diesem Modell aus einem oder mehreren logischen KanĂ€len besteht. Das heiĂt, wenn ich zum Beispiel einen Mono-Lautsprecher in einen Stereo-Lautsprecher Ă€ndere, bleibt die Topologie selbst unverĂ€ndert, nur das Signalformat Ă€ndert sich.
Ich habe mich nicht eingehend mit den Unterschieden zwischen den Arten von "Features" und anderen EntitÀten befasst, aber ich werde es nicht verachten, eine Dokumentation erneut zu erzÀhlen.
1. Eingangsanschluss
Wie der Name schon sagt, gelangt das Audiosignal ĂŒber das Terminal in das AudiogerĂ€t. Es kann USB sein, es kann ein gewöhnliches Mikrofon, ein Headset-Mikrofon oder sogar ein Mikrofonarray sein.
2. Ausgangsanschluss
Es ist auch ziemlich offensichtlich, dass der Ton unser GerÀt verlÀsst. Es kann sich um denselben USB-Anschluss handeln, es kann sich um einen Lautsprecher, ein Headset, einen Lautsprecher im Monitor, Lautsprecher mit verschiedenen Frequenzen und eine Reihe anderer GerÀte handeln.
3. Mischereinheit
Es nimmt mehrere Eingangssignale auf, verstĂ€rkt jedes um einen vorbestimmten Betrag und addiert das Ergebnis zum Ausgangskanal. Falls gewĂŒnscht, können Sie die VerstĂ€rkung auf Null setzen, wodurch sie auf die nĂ€chste EntitĂ€t reduziert wird.
4. Selector Unit
Nimmt mehrere Eingangssignale auf und leitet eines davon zum Ausgang um.
5. Filter (Feature Unit)
Nimmt ein einzelnes Eingangssignal auf, Ă€ndert die Klangparameter (LautstĂ€rke, Ton usw.) und gibt es an den Ausgang aus. NatĂŒrlich werden alle diese Parameter auf die gleiche Weise auf das gesamte Signal angewendet, ohne dass logische KanĂ€le darin interagieren.
6. Verarbeitungseinheit
Mit dieser Funktion können Sie jedoch bereits einzelne logische KanĂ€le in jedem Eingang bearbeiten. DarĂŒber hinaus können Sie festlegen, dass die Anzahl der logischen KanĂ€le im Ausgang nicht der Anzahl im Eingang entspricht.
7. Erweiterungseinheit
Die gesamte Gruppe von nicht standardmĂ€Ăigen Einheiten, so dass die kranke Fantasie der GerĂ€tehersteller frei war. Dementsprechend hĂ€ngen sowohl Verhalten als auch Einstellungen von dieser Fantasie ab.
Einige EntitĂ€ten haben Parameter wie VerstĂ€rkung oder Kanalnummer, die vom Host mithilfe von setFeature / getFeature-Abfragen fĂŒr die EntitĂ€tsnummer beeinflusst werden können. Aber hier, um ehrlich zu sein, verstehe ich ĂŒberhaupt nicht, wie ich das ĂŒberprĂŒfen soll. Wahrscheinlich benötigen Sie eine spezielle Software, die ich nicht habe. Na gut, trotzdem habe ich mich darauf eingelassen, um alle Arten von Punkten zu ĂŒberprĂŒfen ... auf meinem Kopf ...
Harken Sie den Deskriptor ein
Im Gegensatz zu frĂŒheren USB-GerĂ€ten ist der Deskriptor hier komplex, vielschichtig und neigt dazu, Windows in BSOD zu erschrecken. Wie wir oben gesehen haben, kann die Topologie eines autologen GerĂ€ts sehr komplex sein und sich ausbreiten. Eine ganze Schnittstelle zeichnet sich durch ihre Beschreibung aus. Offensichtlich enthĂ€lt es keine Endpunkte, aber es enthĂ€lt eine Liste von EntitĂ€tsdeskriptoren und Beschreibungen, mit denen ihre Eingaben verbunden sind. Ich sehe hier nicht viel Sinn, es ist einfacher, sich den Code und die Dokumentation anzusehen. Ich werde nur den Hauptrechen bemerken: Hier wird beschrieben, welche Schnittstellen mit den entsprechenden Endpunkten speziell auf dieses GerĂ€t verweisen. Wenn Sie beispielsweise meine Konfiguration Ă€ndern und den Lautsprecher von dort entfernen möchten, mĂŒssen Sie nicht nur die HĂ€lfte der EntitĂ€ten löschen (dank der Makros gibt es zumindest kein Problem bei der Berechnung der LĂ€nge des Deskriptors), sondern Reduzieren Sie auĂerdem das Feld bInCollection auf 1,Entfernen Sie dann die Nummer der zusĂ€tzlichen Schnittstelle aus dem darauf folgenden Array bInterfaceNr.
Weiterhin gibt es Schnittstellen, die fĂŒr den Datenaustausch verantwortlich sind. In meinem Fall ist die 1. Schnittstelle fĂŒr das Mikrofon und die 2. fĂŒr den Lautsprecher verantwortlich. Es lohnt sich hier zunĂ€chst auf zwei Varianten jeder dieser Schnittstellen zu achten. Eine mit bAlternateSetting gleich 0, die zweite mit 1. Sie unterscheiden sich bei Vorhandensein eines Endpunkts. Das heiĂt, wenn unser GerĂ€t derzeit nicht verwendet wird, wechselt der Host einfach zu dieser alternativen Schnittstelle, die nicht mit einem Endpunkt ausgestattet ist, und verschwendet nicht mehr die Busbandbreite.
Das zweite Merkmal von Datenschnittstellen ist das Audiosignalformat. Der entsprechende Deskriptor gibt den Codierungstyp, die Anzahl der KanÀle, die Auflösung und die Abtastrate an (die durch eine 24-Bit-Nummer angegeben wird). Es gibt einige Codierungsoptionen, aber wir werden die einfachste verwenden - PCM. TatsÀchlich ist es nur eine Folge von Werten des Momentanwerts des Signals ohne Codierung, und der Wert wird als vorzeichenbehaftete Ganzzahl betrachtet . Die Signalauflösung wird an zwei Stellen festgelegt (es ist nicht klar, warum): Das Feld bSubFrameSize gibt die Anzahl der Bytes und bBitResolution die Anzahl der Bits an... Es kann wahrscheinlich darauf hingewiesen werden, dass der Bereich unserer Soundkarte nicht den gesamten Bereich des Datentyps, z. B. int16_t, erreicht und nur 10 Bit betrÀgt.
Und schlieĂlich der Deskriptor des tatsĂ€chlichen Endpunkts. Es unterscheidet sich auch geringfĂŒgig von den ĂŒblichen, da es zum einen mehrere Synchronisationsoptionen und zum anderen die Nummer der EntitĂ€t bietet, der dieser Punkt zugeordnet ist (bTerminalLink) . Synchronisationsoptionen werden in höherwertigen Bits direkt in den Endpunkttyp geschrieben (weshalb der isochrone Punkt in der Initialisierungsfunktion in den Standardzweig verschoben wurde), aber ich habe mich nicht mit ihren Details befasst, daher kann ich es Ihnen nicht sagen irgendetwas Interessantes. Anstelle der Synchronisation verwenden wir einen regulĂ€ren Controller-Timer, der Interrupts mit ungefĂ€hr der gewĂŒnschten Frequenz erzeugt.
Oh ja, ich hÀtte fast vergessen, eine andere Reihe von BSODs zu erwÀhnen, als ich die falschen Deskriptoren getestet habe. Ich möchte Sie noch einmal daran erinnern: Die Anzahl der Datenschnittstellen muss der Anzahl der bInCollection entsprechen, und ihre Anzahl muss dem darauf folgenden Array entsprechen!
Versteckter Text
, , . --.
Die Logik des GerÀts
Wie ich bereits sagte, macht es fĂŒr Tests keinen Sinn, schwenkbare Komponenten auf der Debug-Platine einzuschlieĂen, sodass alle Tests mit dem durchgefĂŒhrt werden, was bereits installiert wurde - Tasten und LEDs. In diesem Fall stellt dies jedoch kein Problem dar: Das "Mikrofon" kann einfach eine Sinuskurve mit einer Frequenz von beispielsweise 1 kHz erzeugen, und der "Lautsprecher" schaltet die LED ein, wenn der Schallschwellenwert ĂŒberschritten wird (z ĂŒber 10.000: Bei der angegebenen Auflösung von 16 Bit, die dem Bereich -32768 ... +32767 entspricht, ist dies ungefĂ€hr ein Drittel.
Beim Testen trat jedoch ein kleines Problem auf: Ich fand keine einfache Möglichkeit, das Signal vom Mikrofon zum Standard eines Programms umzuleiten. Es scheint, dass dies vorher einfach durch Lesen von / dev / dsp geschehen ist, aber jetzt ist etwas kaputt. Nichts kritisches, denn es gibt alle möglichen Bibliotheken fĂŒr die Interaktion mit Multimedia - SDL, SFLM und andere. Eigentlich habe ich in SFML ein einfaches Dienstprogramm zum Lesen von einem Mikrofon und zum Visualisieren des Signals geschrieben, falls erforderlich.
Ich werde besonders auf die EinschrĂ€nkungen unseres AudiogerĂ€ts achten: Soweit ich weiĂ, wird einmal pro Millisekunde eine isochrone IN-Anfrage gesendet (es kann jedoch viele OUTs geben), wodurch die Abtastrate begrenzt wird. Angenommen, die GröĂe des Endpunkts betrĂ€gt 64 Byte (unter BerĂŒcksichtigung der Pufferung werden 128 Byte im Speicher benötigt, der Host weiĂ jedoch nichts darĂŒber). Die Auflösung betrĂ€gt 16 Bit, dh es können 32 Abtastwerte gleichzeitig gesendet werden . Bei einem Intervall von 1 ms erhalten wir eine theoretische Grenze von 32 kHz fĂŒr einen Kanal. Der einfachste Weg, dies zu umgehen, besteht darin, den Endpunkt zu vergröĂern. Aber hier mĂŒssen wir uns daran erinnern, dass die GröĂe des gesamten PMA-Puffers nur 512 Bytes betrĂ€gt. AbzĂŒglich der Punktverteilungstabelle minus ep0 erhalten wir unter BerĂŒcksichtigung der Pufferung maximal 440 Bytes, dh 220 Bytes pro Einzelpunkt. Und das ist die theoretische Grenze.
Die Tatsache, dass der Host mehrere OUT-Anforderungen in einem Frame senden kann, legt nahe, dass das GerĂ€t dasselbe tun kann. Es bleibt zu verstehen, wie. Möglicherweise wird dies durch eine kompetente Synchronisationseinstellung gelöst. Aber fĂŒr mich ist diese Frage nicht mehr von Interesse: Die isochronen Punkte funktionieren, die gepufferten Punkte funktionieren, das AudiogerĂ€t funktioniert - die Aufgabe ist erledigt.
Schlussfolgerung (gemeinsam fĂŒr den Zyklus)
Nun, wir haben das USB-GerĂ€t in STM32F103- und STM32L151-Controllern (und anderen mit einer Ă€hnlichen Implementierung) kennengelernt und waren von der Logik einiger Architekturlösungen ĂŒberrascht (ich war besonders beeindruckt vom USB_EPnR-Register, aber die doppelte Pufferung bleibt auch nicht zurĂŒck hinter), untersuchte alle Arten von Endpunkten und ĂŒberprĂŒfte sie durch den Bau der entsprechenden GerĂ€te. Wir können also sagen, dass diese Artikelserie zu einem logischen Ergebnis gekommen ist. Obwohl dies natĂŒrlich nicht bedeutet, dass ich auf Controller oder USB verzichten werde: In den fernen PlĂ€nen muss ich mich immer noch mit Composite-GerĂ€ten (bisher sieht es einfach aus, aber isochrone Punkte waren auch kein gutes Zeichen) und USB auf Controllern auseinandersetzen von anderen Familien.