mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 USB-MIDI


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von temp (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Nach dem es in diesen Thread:
Beitrag "USB CDC von Stefan Frings und WS"
eine ganze Weile um USB-CDC ging, habe ich am Coronafreiwochenende mal 
versucht dem Code von WS so zu adaptieren, dass daraus ein 
Midi-Interface mit 1 bis 4 Ports (jeweils MidiIn und MidiOut) wird. Zu 
CDC findet man häufig was im Netz, Midi ist dagegen relativ selten oder 
in komplexen Umgebungen zu finden. Getestet habe ich das mit einem 
bluepill-Board mit stm32f103c8 (und auch mit einem Fake wo ein CKS32F103 
drauf war).
Im Anhang ein abgespecktes Projekt für Segger ES.

Es ist nur der reine USB-Teil enthalten. Das Demoprogramm schickt das 
was es per USB erhält 1 zu 1 wieder zurück, nicht mehr und nicht 
weniger. Für ein richtiges Interface muss natürlich noch einiges mehr 
getan werden. Das ganze besteht nur aus den Dateien main.cpp, usbmidi.h 
und usbmidi.cpp. Alle anderen Dateien im Projekt hat Segger ES erzeugt 
und wurden nicht verändert. Aufpassen muss man in usbmidi.cpp auf den 
Namen des Interrupts, hier hat Segger seine eigene Logic. Soll das in 
andere Umgebungen übernommen werden, muss der Name angepasst werden.

Wie hier ab Seite 16 beschrieben:
https://www.usb.org/sites/default/files/midi10.pdf
wird immer 4Byte weise gearbeitet. Deshalb habe ich die Ringbuffer auf 
uint32_t umgestellt. Der Devicedescriptor ist sehr cryptisch, aber da 
verschwende ich keine Lebenszeit damit das lesbarer zu machen. Für mich 
und das was ich damit vor habe ist es halt ausreichend.
Vielleicht kann es ja jemand mal gebrauchen.

Falls Stefan oder Niklas das interessiert oder sie es in ihren Artikeln 
verlinken oder verwenden oder veröffentlichen wollen, meinen Segen dafür 
gibt es.

von Ingo (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke, das könnte mir von Nutzen sein.

von W.S. (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
temp schrieb:
> ...habe ich am Coronafreiwochenende mal
> versucht dem Code von WS so zu adaptieren, dass daraus ein
> Midi-Interface mit 1 bis 4 Ports (jeweils MidiIn und MidiOut) wird.

Ja, ganz nett.

Ich hätte dazu aber noch ne Anmerkung: Das ganze Gefummel mit 
"DisableUsbIRQ();" mißfällt mir sehr - und es ist eigentlich auch 
überflüssig, solange man ein paar Grundsätze beachtet.
Schauen wir mal das hier an:
// liefert true, wenn eine MidiMsg abholbereit ist 
bool UsbRxAvail(void)
{
  DisableUsbIRQ();
  bool res = rxr != rxw;
  EnableUsbIRQ();
  return res;
}

Diese Funktion kann ja nur liefern, ob etwas zum Lesen vorhanden ist 
oder nicht. Das macht sie, indem sie die Indizes rxr und rxw vergleicht. 
Lesen der beiden Indizes darf jeder, aber Schreiben jeweils nur einer, 
nämlich der, dem der Index gehört.

Der Index, der zum Füllen des Ringpuffers dient, ist quasi Eigentum des 
Interrupthandlers. Der darf ihn schreiben.

Der Index, der zum Entleeren des Ringpuffers dient, gehört dem 
UsbGetMidiMsg(void), diese Funktion darf ihn schreiben.

Was also kann passieren, wenn mitten in UsbRxAvail(void) ein 
USB-Interrupt hineingrätscht? Dann kann sich nur rxw ändern - und zwar 
nur in Richtung "noch mehr abholbereite Daten sind enthalten". Das 
Umgekehrte (keine Daten enthalten) kann durch den Interrupt NICHT 
passieren.

Nun gibt es prinzipiell für UsbRxAvail(void) nur 2 Möglichkeiten:
a) es gibt nix
b) es gibt was (egal wie viel)
Dabei ist es doch egal, ob ein Interrupt dazwischen dazu führt, daß es 
NOCH MEHR Daten gibt, als zuvor schon vorhanden waren. Fall b) "es gibt 
was" ändert sich nicht, wenn es noch mehr gibt.

Folglich ist das Verbieten des Interrupts in dieser Funktion schlichtweg 
überflüssig und sollte besser aus dieser Funktion beseitigt werden.

Der eherne Grundsatz lautet eigentlich: niemand soll in dem Beritt eines 
Anderen herumreiten. Hier wäre das, daß weder der Interrupt-Handler in 
den Daten von main() und den Programmteilen, die von main() aus benutzt 
werden herumschreiben sollte, noch daß main() oder eine Funktion, die 
von main() aus benutzt wird, in den Daten des Interrupthandlers 
herumschreiben sollte.

Das führt nämlich immer zu dem grundsätzlichen Problem, daß zwei "Leute" 
auf denselben Daten schreibend herumreiten - und als Notnagel müssen 
dann Interrupts verboten werden.

Das ist wirklich nur ein Notnagel und niemals ein guter Code. Man sollte 
sowas also tatsächlich NUR DANN tun, wenn es sonst überhaupt nicht 
anders zu machen geht. Aus meiner Sicht ist das aber eher "programmieren 
mit dem Holzhammer".

Ich hatte es bei meinem Ur-Treiber so gemacht, daß keine anderen 
Programmteile in den Daten des Interrupthandlers herumschreiben und daß 
man beim Benutzen sich auch nicht um inneren Befindlichkeiten wie z.B. 
das Senden von restlichen Zeichen zum Host zu kümmern hat. Andere haben 
da gemeint, dort hineingrätschen zu müssen, z.B. per UsbTxFlush() - aber 
das ist eigentlich eine Unannehmlichkeit, die bei einem virtuellen 
COM-Port nicht erforderlich ist - und auch nicht vorhanden sein sollte. 
Der VCP sollte das selbst erledigen, ohne daß sich jemand anderes drum 
kümmern müßte.

Ob sowas bei MIDI nötig wäre, weiß ich nicht, hab mich um dieses 
spezielle Thema noch nicht gekümmert. Aber m.W. basiert MIDI ja wohl 
ursprünglich auf einem COM-Port mit galvanischer Trennung und 33K 
Bitrate (oder waren es 32K ? - zu lange her).

Ob man da das Forcieren einer Übertragung nötig hat, oder mit dem 
USB-internen Tick von 1 ms auskommt, um die aufgelaufenen Daten zu 
transferieren? - ich tendiere da zu letzterem. Der interne Tick sollte 
ausreichen.

W.S.

von Carl D. (jcw2)


Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
>
> Aber m.W. basiert MIDI ja wohl ursprünglich auf einem COM-Port
> mit galvanischer Trennung und 33K Bitrate (oder waren es 32K ?
> - zu lange her).
>

USB-MIDI hat keine Bitrate, sondern 4byte-Pakete mit Midi-Event-Daten.
Das ist nicht auf Seriell aufgebaut.
Könnte an ahnen, wenn man schon mal USB-Deskriptoren angeschaut hat.

: Bearbeitet durch User
von Johannes S. (jojos)


Bewertung
1 lesenswert
nicht lesenswert
In 'Projekte & Code' hatte ich auch ein Beispiel für das Bluepill 
reingesetzt. Da benutze ich ein Stück mbed2 code, der enthält auch eine 
USBMidi Klasse. Da sind auch Midi Messages zu finden:
https://github.com/JojoS62/Bluepill-TestUSBKbdMouse/tree/master/USBDevice/USBMIDI
Beitrag "USB Keyboard und Maus mit Bluepill und mbed2"

von temp (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Ich hätte dazu aber noch ne Anmerkung: Das ganze Gefummel mit
> "DisableUsbIRQ();" mißfällt mir sehr - und es ist eigentlich auch
> überflüssig, solange man ein paar Grundsätze beachtet.

Ja, in diesem Punkt gebe ich dir Recht. Ich hatte halt nur den letzten 
Stand verwendet den Niklas in github gestellt hat.

W.S. schrieb:
> Aber m.W. basiert MIDI ja wohl
> ursprünglich auf einem COM-Port mit galvanischer Trennung und 33K
> Bitrate (oder waren es 32K ? - zu lange her).

Das würde zum tragen kommen, wenn man wirklich ein reines Interface 
bauen will mit In/Out über UART. Für alle anderen Fälle, z.B. wenn man 
ein paar Potis oder Schalter in Midi-Daten umsetzt keine Baudrate 
relevant.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:
> Ich hatte es bei meinem Ur-Treiber so gemacht, daß keine anderen
> Programmteile in den Daten des Interrupthandlers herumschreiben und daß
> man beim Benutzen sich auch nicht um inneren Befindlichkeiten wie z.B.
> das Senden von restlichen Zeichen zum Host zu kümmern hat. Andere haben
> da gemeint, dort hineingrätschen zu müssen, z.B. per UsbTxFlush() - aber
> das ist eigentlich eine Unannehmlichkeit, die bei einem virtuellen
> COM-Port nicht erforderlich ist - und auch nicht vorhanden sein sollte.
> Der VCP sollte das selbst erledigen, ohne daß sich jemand anderes drum
> kümmern müßte.

Ja die anderen haben Bugs in deinem Code gefixt, was doch ganz 
freundlich ist.
Mit einem Debugger übrigens ;)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.