Timing-Genauigkeit des MIDI-Sequenzers mit dem Arduino

Ich baue diese Musiksequenzer .

Geben Sie hier die Bildbeschreibung ein

Nur ist es nicht gerade ein Sequenzer, es ist eine physische Schnittstelle für einen Sequenzer. Der Sequenzer ist eine Anwendung, die auf einem Laptop läuft, mit dem der Sequenzer verbunden ist. Mit diesem Ding kann der Benutzer Drum-Loops im Handumdrehen erstellen. Es macht ziemlich viel Spaß, erfordert aber einen Laptop, da der Sequenzer nicht „an Bord“ ist.

Was ich lieben würde, ist die Sequenzierung an Bord meines Geräts.

Nehmen wir nun an, ich weiß, wie ich die Klassenkonformität für USB-MIDI-Konnektivität lösen kann, und nehmen wir auch an, ich kann herausfinden, wie man ein Arduino verkabelt, um MIDI-Noten von einem 5-poligen DIN-Anschluss zu senden. Worüber ich mir am meisten Sorgen mache, ist die Tempodrift im Laufe der Zeit aufgrund von inkonsistentem Timing in Minutenbeträgen bei jedem Durchlauf der Ereignisschleife.

Einige Dinge, die ich weiß:

  1. Sie sollten sich nicht darauf verlassen delay(), die Temposchleife zu steuern. Die Verzögerung stoppt den gesamten Betrieb der Firmware, und das kann nicht funktionieren, da ich die physische Benutzeroberfläche nach Änderungen abfragen muss, während die Sequenz ausgeführt wird.

  2. Berechnungen basierend auf millis()sind besser, da die Firmware weiterarbeiten und handeln kann, wenn eine bestimmte Anzahl abgelaufen ist.

  3. Obwohl keine meiner physischen Steuerungen Interrupt-Routinen auslöst, können einige Operationen die loop()Ausführung der Hauptroutine verzögern. Wenn ich eine Funktion entwerfe, die auf Benutzereingaben wartet, kann dies offensichtlich zu einem Problem führen, wenn eine "Frist" verpasst wird, um zu handeln, wenn die millis()Zählung weit vorbei ist. Ich weiß, dass dieses Problem von mir selbst verursacht wurde ...

Fragen:

A. Ist das AVR-basierte Arduino ein geeigneter Mikrocontroller, um eine Benutzeroberfläche abzufragen und eine missionskritische Zeitschleife auszuführen? Ich weiß, dass es jetzt ein ARM-basiertes Arduino gibt, das viel schneller ist. Wäre ein Teensy 3.0 eine bessere Alternative? Beides sind 3,3-V-Platinen, also ist das eine weitere Reihe von Problemen, mit denen man arbeiten kann ... aber ich werde das vorerst ignorieren.

B. Soll ich die Aufgabe auf zwei Mikroprozessoren aufteilen? Einer für die Abfrage und Aktualisierung der Benutzeroberfläche und einer für die unternehmenskritische Zeitschleife.

c. Etwas anderes?

Mein Hauptziel ist es, überhaupt keinen Computer benutzen zu müssen. Ich möchte auch für Swing rechnen, aber in diesem Fall bedeutet Swing nichts, wenn ich kein festgelegtes und genaues Tempo habe. Danke für deinen Rat!

Arduino richtet immer einige Interrupt-Routinen ein, die Jitter verursachen. In vielen Fällen ist dies kein Problem, aber es ist gut, sich dessen bewusst zu sein. noInterrupts();stoppt den Jitter, stoppt aber auch alle gewünschten Interrupts.
Wenn Sie sagen, "sequenzieren Sie an Bord", bedeutet das, dass Sie die Beats pro Takt, BPM und einen Tick-Track an Bord einrichten? Dann möchten Sie sich vermutlich die Tastendrücke merken, die innerhalb der Leiste aufgetreten sind, damit das "Gehirn" des Geräts Ihrem Laptop Midi-Noten zuführen kann? Möchten Sie dann bestimmte Percussion-Sounds entfernen, wenn Sie sie erneut über der zuvor aufgenommenen Note anschlagen? Etc.. wie weit willst du gehen? Aufbewahrung deiner Beats? Erstellen einer Sequenz von Takten, die einem vollständigen Track entsprechen? Bestimmte Takte bearbeiten? Tempoänderung bestimmter Takte? Es frisst alles CPU, also nimm die beste CPU.
Ja, alles.
Das ist ein süß aussehender Fall, den Sie gemacht haben!
Danke! das ist jetzt der alte Fall. Ich habe einen Laser und einen Dunstabzug gekauft und kann jetzt Acrylgehäuse herstellen, die mir viel besser gefallen. Sie sind auch viel einfacher zu machen.
Zusätzlich zu dem, was andere gesagt haben, sieht dies nach einer Überlegung aus, die Sie vielleicht produzieren und verkaufen möchten. Ein Arduino kostet 20 $, während ein AVR 2 $ kostet. Sie erhalten nicht nur die Kontrolle über die Hardware, die Ihre Anwendung benötigt, sondern Sie sparen auch viel Geld.
Es geht wirklich nicht ums Geld. Ich weiß, das ist wahrscheinlich schwer zu verstehen, aber meine Zeit ist wertvoller, also muss ich unter der Arduino-IDE arbeiten. Es tut mir leid, wenn mein Wunsch, dies mit der Arduino-IDE zu tun, Ihre Sensibilität beleidigt. Das kann ich respektieren. Ich habe einfach keine vernünftige Möglichkeit, Elektrotechnik auf dem Niveau zu betreiben, auf dem Sie sich befinden, wenn mein gewünschter Weg lahm und teuer erscheint. Ich kaufe auch vorgefertigte Möbel. Und manchmal Fertiggerichte. Es geht wirklich darum, Bargeld gegen Fachwissen und Bequemlichkeit einzutauschen. Glauben Sie mir, es ist frustrierend, so viel zu wissen wie ich und auch zu wissen, dass es nicht genug ist.

Antworten (4)

Interrupts sind Ihr Freund für zeitkritische Aufgaben, aber nur, wenn Sie die zeitkritischen Aspekte in den Interrupt stecken und es keine anderen Interrupts gibt, die eine höhere Priorität haben. Die Mikrocontroller auf dem "AVR-basierten" Arduino (z. B. der ATmega328P) haben feste Interrupt-Prioritäten, wie auf Seite 58ff des Datenblatts beschrieben . Wenn Sie also TIMER2 COMPA als kritischen Timing-Interrupt und keine anderen Interrupts verwendet haben, sollten Sie in Ordnung sein (da er die höchste Priorität hat). Wenn Sie auch Interrupts mit niedrigerer Priorität verwenden möchten, müssen Sie sicherstellen, dass alle von ihnen globale Interrupts wieder aktivieren, wenn Sie in ihre Interrupt-Serviceroutine eintreten:

Wenn ein Interrupt auftritt, wird das globale Interrupt-Freigabe-I-Bit gelöscht und alle Interrupts werden deaktiviert. Die Benutzersoftware kann eine logische Eins in das I-Bit schreiben, um verschachtelte Interrupts zu aktivieren. Alle aktivierten Interrupts können dann die aktuelle Interrupt-Routine unterbrechen.

(S. 14 des Datenblatts )

Dies ist bei ARM-basierten Arduinos etwas anders, da ihr Cortex-M3-Kern über einen "Nested Vector Interrupt Controller" verfügt, bei dem die Prioritäten nicht festgelegt sind (in der Software festgelegt werden können) und die Behandlung von verschachtelten Interrupts die Norm ist. Für zeitkritische Anwendungen bietet Ihnen der ARM-basierte Arduino also mehr Flexibilität. Ich glaube aber nicht, dass das für deine Bewerbung wirklich notwendig ist.

Die größere Frage ist wirklich, wie einfach diese Dinge mit den Arduino-Bibliotheken implementiert werden können. Um die beste Leistung zu erzielen, müssen Sie wahrscheinlich bis zu einem gewissen Grad außerhalb der Bibliotheken codieren, zumindest für die zeitkritischen Bits, dh Dinge wie delay() oder millis() ganz vermeiden.

Ob Sie aufteilen müssen oder nicht, hängt davon ab, wie viel Verarbeitung Sie beabsichtigen. Auch hier kann das Verlassen der Bibliotheken möglicherweise zu einer besseren Leistung führen.

Dies kann mit der entsprechenden Programmierung auf jeden Fall auf einem ATmega328P durchgeführt werden (abhängig von der Komplexität des Drum-Loops. Ich gehe von ~ <50 Drum-Events im Loop aus. Ist das vernünftig?).

Beachten Sie, dass ich ATmega328P gesagt habe , nicht unbedingt ein Arduino .

In der Arduino-Umgebung laufen im Hintergrund viele Standardfunktionen ab, die eine extrem deterministische Programmierung (wie Sie sie für etwas Timing-kritisches benötigen) zu einer Herausforderung machen.

Die eigentliche Frage, die Sie hier stellen müssen, ist, wie interessiert Sie am Programmieren sind, im Vergleich dazu, wie interessiert Sie daran sind, ein Instrument zu entwickeln?

Obwohl ich ziemlich zuversichtlich bin, dass es möglich ist, alles, was Sie wollen, auf einem einzigen ATmega zu machen (Drum-Loop, mehrere analoge Eingänge, LCD, Tasten, MIDI-Interface), ist die eigentliche Frage, wie viel Arbeit es sein wird, alles unterzubringen? Wollen Sie noch einmal lernen, eingebetteten MCU-Code zu optimieren oder Instrumente zu bauen? Es ist ziemlich einfach, bei Bedarf einfach zu einer schnelleren MCU zu wechseln, aber Sie müssen die MCU-Leistung bestimmen, die Sie jetzt benötigen , also erkennen Sie nach sechs Monaten Arbeit nicht, dass Sie nicht alles so schnell zum Laufen bringen können wie Sie müssen.


Wenn ich Sie wäre, würde ich es als erstes ohne Arduino-Zeug zum Laufen bringen (behandeln Sie es im Grunde wie einen rohen ATmega und verwenden Sie AVR Studio oder ähnliches). Dann können Sie viel effektiver analysieren, welche Art von Leistung Sie benötigen und ob der ATmega sie bewältigen kann.

Sobald Sie von dem Arduino-Zeug befreit sind, können Sie verschiedene MCUs viel freier verwenden (sie sind im Allgemeinen ähnlicher als unterschiedlich. Wenn Sie eine aus ihrer Dokumentation herausfinden können, können Sie wahrscheinlich dasselbe für andere tun).

Ich habe in letzter Zeit viel mit den ATxmega-Geräten gearbeitet, und sie sind wirklich nett. Sie erhalten drei Interrupt-Prioritäten, die die Verwaltung zeitkritischer Dinge viel einfacher machen. Es ist auch wirklich schön, mit ihnen zu arbeiten (vernünftige Peripherie-Designs! Praktische Port-Strukturen! Etc ...).

Es gibt auch die LPC-Geräte von NXP, die ARM-basiert sind, sowie einige der ARM-Geräte von Atmel (wie sie auf dem Arduino Due verwendet werden) oder die STM32-MCUs von ST. Jedes davon hat deutlich mehr Leistung als ein ATmega oder sogar ein ATxmega.

Der Hauptnachteil eines größeren, leistungsstärkeren Prozessors ist der Preis, aber wenn Sie nicht Tausende dieser Einheiten herstellen, werden die Montage- und Herstellungskosten pro Einheit die Kostendifferenz (die wahrscheinlich nur ein paar Dollar betragen wird) so stark übersteigen ), dass es im Grunde egal ist.

Schön ausgedrückt - für ein kommerzielles Produkt ist ein Arduino einfach nicht der richtige Weg - sie sind leistungshungrig, langsam und die IDE ist nicht für optimalen (schnellen/kleinen) Code ausgelegt, sondern für Bequemlichkeit und einfaches Lernen. Für weniger Kosten könnten Sie sogar einen STM32 F4 (32-Bit-Cortex M4 > 100 MHz) oder ähnliches haben, obwohl dies übertrieben wäre. Ich denke, so etwas wie einer der kleineren PIC32, Cortex M3 oder ein AVR32 ist wahrscheinlich der richtige Weg, wie Sie bereits erwähnt haben. Zahlreiche Interrupt-Prioritäten, DMA, ausgeklügelte Peripheriegeräte, schneller/niedriger Stromverbrauch und viel RAM machen es zu einer einfachen Wahl im Vergleich zu einem Arduino.
@OliGlaser - Ich denke, Sie müssen klar zwischen einem Arduino und einem ATmega abgrenzen . Sie können auf einem ATmega kleinen, schnellen Code schreiben, und dieser ATmega kann sogar auf einem Arduino-Board sein. Die Arduino "IDE" hingegen ist einer der beschissensten Code-Editoren, die ich je benutzt habe. Andererseits ist der OptiBoot-Bootloader sehr nett. Nur weil einige Teile Mist sind, heißt das nicht, dass Sie das ganze Ding wegwerfen sollten.
Absolut - ich bezog mich auf das Arduino als Ganzes, einschließlich Board und IDE - nicht auf das ATmega, von dem ich sicher bin, dass es so gut ist wie jedes andere vergleichbare uC (PIC16 / 18F usw.). Ich hätte es aber in meine Liste aufgenommen Ich denke, da der Preis zwischen 8-Bit und 16/32-Bit heutzutage so nah beieinander liegt, ist es wahrscheinlich eine gute Idee, einen zusätzlichen Dollar auszugeben und zu wissen, dass Sie die Prozessorleistung übrig haben (es sei denn, wir sprechen, wie Sie bereits erwähnt haben, über große Zahlen und zum absolut niedrigsten Preis gebaut, aber dann bezweifle ich, dass ein Arduino in Betracht gezogen worden wäre :-) )

Ich musste mich über Timer informieren, bevor ich anfing, über Timing-Genauigkeit nachzudenken (auch den Bau eines Midi-Step-Sequenzers mit einem Arduino, obwohl es garantiert weniger cool aussieht als diese ^^). Diese Artikelserie war die informativste:

http://maxembedded.com/category/microcontrollers-2/atmel-avr/avr-timers-atmel-avr/

Im Moment denke ich, dass meine Lösung, um ein genaues Timing zu erhalten, sein wird.

A. Verwenden Sie das AVR-Arduino

B. Behalten Sie die Aufgabe auf einem Mikroprozessor

C. Vorteilhafte Verwendung von Prescalern, Timern und Interrupts, um die erforderliche Genauigkeit zu erreichen.

AKTUALISIEREN

Unter Verwendung des grundlegenden Midi-Tutorials für Arduino und nachdem ich diesen Artikel über Timer und Prescaler gelesen habe, habe ich mir den folgenden Code ausgedacht. Der Code verwendet timer1 und den CTC-Modus, um jede Viertelsekunde eine Midi-Note und jede Viertelsekunde eine Note zu spielen (was genau 120 bpm sein sollte). Leider kommt dies immer noch langsamer als 120 bpm, obwohl dies das nächste ist, das ich bekommen habe ...

// Includes
#include <avr/io.h>
#include <avr/interrupt.h>

int last_action=0;

void setup()
{
    //  Set MIDI baud rate:
    Serial.begin(31250);

    // initialize Timer1
    cli();          // disable global interrupts
    TCCR1A = 0;     // set entire TCCR1A register to 0
    TCCR1B = 0;     // same for TCCR1B

    // set compare match register to desired timer count:
    OCR1A = 15624;
    // turn on CTC mode:
    TCCR1B |= (1 << WGM12);
    // Set CS12 bits for 256 prescaler:
    TCCR1B |= (1 << CS12);
    // enable timer compare interrupt:
    TIMSK1 |= (1 << OCIE1A);
    // enable global interrupts:
    sei();
}

void loop()
{
    // do some crazy stuff while my midi notes are playing
}

ISR(TIMER1_COMPA_vect)
{
  // Turn notes on
  if (last_action == 0) {
    send_note(0x90, 60, 0x45);
    last_action = 1;

  // Turn notes off
  } else {
    send_note(0x90, 60, 0x00);
    last_action = 0;
  }
}

//  plays a MIDI note
void send_note(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

AKTUALISIEREN

Ich kämpfe jetzt seit ~ 24 Stunden damit und habe endlich einige Antworten aus dem Forum bekommen. Ich denke, dass der Code, den ich oben verwendet habe ^^ ziemlich gut ist. Verwenden des ISR, Verwenden des CTC-Modus und Prescaler usw. Nachdem ich mich an das Forum gewandt habe, denke ich, dass die Lösung weniger darin besteht, die Präzision des Midi-Sequenzers zu erreichen, sondern mein gesamtes Hardware-Setup (meine Synthesizer und Sampler) an dasselbe anzuschließen Midi Clock, egal ob die Uhr vom Arduino kommt oder nicht.

Je nachdem, wie schrittweise Sie den Übergang von einem angebundenen Computer zu einem µC-basierten System vollziehen möchten, sollten Sie in Betracht ziehen, einen Raspberry Pi in diese Box zu packen (25-35 US-Dollar im Einzelhandel ). Auf diese Weise können Sie einen vollwertigen (wenn auch stromsparenden) Linux-basierten Computer mit USB-Anschlüssen und GPIO-Pins haben.

Ich bin mir sicher, dass es Erweiterungsschilde oder wie auch immer sie für den Pi heißen, aber die Standardplatine hat 17 GPIO-Pins. Ich benutze jeden einzelnen Pin auf dem Arduino Mega. 31 Takte + 30 LEDs, 10 analoge Eingänge. 70+ E/A.
Oh, ich meinte, wenn das unmittelbare Ziel darin bestand, den externen Computer zu entfernen, könnten Sie den "Sequenzer [das] eine Anwendung ist, die auf einem Laptop läuft" behalten und auf dem Pi ausführen, der intern mit Ihrem vorhandenen System verbunden ist, so wie es ist jetzt verbunden.
@SteveCooley - Klingt so, als müssten Sie sich mit IO-Multiplexing/Button-Matrizen befassen. Sie sollten keine ganze dedizierte IO-Leitung pro Taste benötigen.
@SteveCooley - Verdammt, du brauchst wirklich nicht einmal eine Knopfmatrix. Sie könnten ALLE Ihre digitalen E / A mit nur 4 rPi-Pins ausführen. Hängen Sie einfach alle Tasten und LEDs an einige Schieberegister (parallel-seriell für die Tasten, seriell-parallel für die LEDs) und treiben Sie die Schieberegister vom SPI-Port des rPi. Mit Hilfe der SPI-Hardware sollten Sie problemlos > 1-kHz-Aktualisierungsraten für die gesamte Matrix erhalten.
Wenn der einzige Grund, warum Sie ein Arduino Mega verwenden, das IO ist, geben Sie eine Menge Geld für etwas aus, das mit ein paar externen Geräten sehr einfach für <3 US-Dollar erledigt werden kann.
Stimmt, obwohl µCs jetzt irgendwie lächerlich billig sind und ein ATXMega128B unter 5 US-Dollar kostet, (glaube ich) die Anzahl der erforderlichen E / A-Leitungen hat und sogar über integrierte Hardware verfügt, um USB zu sprechen, wenn Sie dies bevorzugen, um eine Verbindung herzustellen zum Sequenzer — mouser.com/ProductDetail/Atmel/ATXMEGA128B1-AU/…
Ich werde unsere Zeit nicht damit verschwenden, meine Projektdesign-Entscheidungen hier zu erläutern. Trau dich auch nicht zu antworten. Es ist wirklich sinnlos.