Dokładność taktowania sekwencera MIDI za pomocą Arduino

11

Buduję te sekwencery muzyczne .

wprowadź opis zdjęcia tutaj

Tyle że to nie jest dokładnie sekwencer, to fizyczny interfejs dla sekwencera. Sekwencer to aplikacja działająca na laptopie, z którym łączy się sekwencer, ta funkcja pozwala użytkownikowi tworzyć pętle perkusyjne w locie. To całkiem zabawne, ale wymaga laptopa, ponieważ sekwencer nie jest „wbudowany”.

Chciałbym zrobić sekwencjonowanie na moim urządzeniu.

Załóżmy teraz, że wiem, jak rozwiązać problem z klasą zgodności dla połączenia USB MIDI, i załóżmy, że mogę wymyślić, jak podłączyć arduino, aby wysyłać notatki MIDI z 5-pinowego portu DIN. Najbardziej niepokoi mnie dryf tempa w czasie z powodu niespójnego timingu w minutach w każdym przebiegu pętli zdarzeń.

Niektóre rzeczy, które znam:

  1. Nie powinieneś polegać na delay()kontrolowaniu pętli tempa. Opóźnienie zatrzymuje wszystkie operacje oprogramowania układowego, a to nie może działać, ponieważ muszę sondować fizyczny interfejs użytkownika pod kątem zmian, gdy sekwencja jest uruchomiona.

  2. Obliczenia oparte na millis()są lepsze, ponieważ oprogramowanie układowe może nadal działać i działać po upływie określonego czasu.

  3. Mimo że żadna z moich fizycznych kontroli nie wyzwala procedur przerwania, niektóre operacje mogą opóźnić uruchomienie głównego loop(). Jeśli zaprojektuję funkcję, która czeka na dane wejściowe użytkownika, może to oczywiście powodować problem z brakiem „terminu” działania, jeśli millis()liczenie się skończy. Wiem, że ten problem jest moim własnym projektem ...

Pytania:

A. Czy arduino oparte na AVR jest odpowiednim mikrokontrolerem do odpytywania interfejsu użytkownika i uruchomienia pętli czasowej o znaczeniu krytycznym? Wiem, że Arduino oparte na ARM jest teraz znacznie szybsze. Czy Teensy 3.0 byłby lepszą alternatywą? Oba są płytkami 3,3 V, więc jest to kolejny zestaw problemów do pracy ... ale na razie to zignoruję.

B. Czy powinienem podzielić zadanie na dwa mikroprocesory? Jeden do obsługi odpytywania i aktualizacji interfejsu użytkownika, drugi do krytycznej pętli pomiaru czasu.

do. Coś innego?

Moim głównym celem jest wcale nie używanie komputera. Chcę też obliczyć dla swinga, ale w tym przypadku swing nie znaczy nic, jeśli nie mam zablokowanego i dokładnego tempa. Dzięki za radę!

Steve Cooley
źródło
1
Arduino zawsze ustawia pewne procedury przerwań, powodując jitter. W wielu przypadkach nie stanowi to problemu, ale dobrze jest o tym wiedzieć. noInterrupts();zatrzymuje drgania, ale także zatrzymuje wszystkie poszukiwane przerwania.
jippie
1
Kiedy mówisz „wykonaj sekwencjonowanie na pokładzie”, czy oznacza to skonfigurowanie uderzeń na takt, BPM i tików na pokładzie? Więc prawdopodobnie chcesz zapamiętać naciśnięcia przycisków, które miały miejsce w pasku, aby „mózgi” urządzenia mogły przesyłać midi-nuty do twojego laptopa? Czy chcesz usunąć niektóre dźwięki perkusji, jeśli uderzysz je ponownie w nuty wcześniej nagrane? Itd .. jak daleko chcesz się posunąć? Przechowywanie twoich uderzeń? Czy tworzysz sekwencję pasków odpowiadającą pełnemu utworowi? Edytujesz konkretne paski? Zmiana tempa poszczególnych pasków? Wszystko zjada procesor, więc wybierz najlepszy procesor.
Andy aka
Tak, wszystko.
Steve Cooley,
2
To jest słodka sprawa, którą stworzyłeś!
shuckc
3
Oprócz tego, co powiedzieli inni, wygląda to na myśl, że może zamierzasz produkować i sprzedawać. Arduino kosztuje 20 USD, a AVR 2 USD. Nie tylko zyskasz kontrolę nad sprzętem wymaganym przez twoją aplikację, ale również zaoszczędzisz dużo pieniędzy.
Phil Frost

Odpowiedzi:

5

Przerwania są twoim przyjacielem dla zadań wrażliwych na czas, ale tylko wtedy, gdy umieścisz krytyczne aspekty czasowe w przerwaniu i nie wystąpią żadne inne przerwania o wyższym priorytecie. Mikrokontrolery w Arduino opartym na „AVR” (np. ATmega328P) mają ustalone priorytety przerwań, jak wyszczególniono na stronie 58ff arkusza danych . Jeśli więc użyłeś TIMER2 COMPA jako krytycznego przerwania czasowego i żadnych innych przerwań, powinieneś być OK (ponieważ ma najwyższy priorytet). Jeśli chcesz również używać przerwań o niższym priorytecie, musisz upewnić się, że wszystkie z nich ponownie włączają przerwania globalne podczas wchodzenia w procedurę obsługi przerwań:

W przypadku wystąpienia przerwania I-bit Global Interrupt Enable zostaje wyczyszczony, a wszystkie przerwania są wyłączone. Oprogramowanie użytkownika może zapisać logikę jeden do bitu I, aby włączyć zagnieżdżone przerwania. Wszystkie włączone przerwania mogą następnie przerwać bieżącą procedurę przerwania.

(s. 14 arkusza danych )

Różni się to nieco w przypadku Arduinos opartych na ARM, ponieważ ich rdzeń Cortex-M3 ma „Zagnieżdżony kontroler przerwania wektora”, w którym priorytety nie są ustalone (można ustawić w oprogramowaniu), a obsługa zagnieżdżonych przerwań jest normą. Tak więc w przypadku aplikacji o krytycznym czasie synchronizacja Arduino zapewni ARM zapewnia większą elastyczność. Nie sądzę jednak, aby było to naprawdę konieczne w przypadku Twojej aplikacji.

Większe pytanie dotyczy tego, jak łatwo można te rzeczy zaimplementować za pomocą bibliotek Arduino. Aby uzyskać najlepszą wydajność, prawdopodobnie będziesz musiał do pewnego stopnia kodować poza bibliotekami, przynajmniej dla bitów krytycznych dla timingu, tj. Całkowicie unikać opóźnień () lub millis ().

To, czy chcesz podzielić, zależy od tego, ile przetwarzania zamierzasz wykonać. Ponownie wyjście poza biblioteki może potencjalnie dać lepszą wydajność.

fm_andreas
źródło
3

Można to przy odpowiednim programowaniu z całą pewnością wykonać na ATmega328P (w zależności od złożoności pętli bębna. Zakładam ~ 50 zdarzeń bębna w pętli. Czy to rozsądne?).

Zauważ, że powiedziałem ATmega328P , niekoniecznie Arduino .

Środowisko Arduino ma w tle wiele domyślnych rzeczy, co sprawia, że ​​niezwykle deterministyczne programowanie (ponieważ będziesz potrzebować czegoś krytycznego pod względem czasu) jest trudne.

Prawdziwe pytanie, które musisz tutaj zadać, to jak bardzo jesteś zainteresowany programowaniem, a jak jesteś zainteresowany opracowaniem instrumentu?

Chociaż jestem całkiem pewien, że można zrobić wszystko, co chcesz na jednym ATmega (pętla perkusyjna, wiele wejść analogowych, LCD, przyciski, interfejs MIDI), prawdziwe pytanie brzmi: ile pracy trzeba wcisnąć wszystko? Ponownie, czy chcesz nauczyć się optymalizować osadzony kod MCU, czy budować instrumenty? Jest to dość łatwo po prostu przejść do szybszego MCU jeśli potrzebne, ale trzeba określić wydajność MCU czego potrzeba teraz , więc sześć miesięcy pracy w, nie zdają sobie sprawy, nie można zupełnie dostać wszystko do pracy tak szybko jak to potrzeba.


Gdybym był tobą, pierwszą rzeczą, którą bym zrobił, to żeby działał bez arduino (w zasadzie traktuj to jako surową ATmegę i użyj studia AVR lub podobnego). Następnie możesz znacznie efektywniej analizować, jakiej wydajności potrzebujesz i czy ATmega może nią zarządzać.

Kiedy uwolnisz się od arduino, będziesz mógł swobodniej korzystać z różnych MCU (są one na ogół bardziej podobne niż różne. Jeśli możesz znaleźć jeden z jego dokumentacji, prawdopodobnie możesz zrobić to samo dla innych).

Ostatnio dużo pracuję z urządzeniami ATxmega i są naprawdę fajne. Otrzymujesz trzy priorytety przerwania, które ułatwiają zarządzanie materiałami o krytycznym czasie. Są również bardzo przyjemne w pracy (Sane urządzenia peryferyjne! Wygodne struktury portów! Itd ...).

Istnieją również urządzenia LPC od NXP, które są oparte na ARM, a także niektóre urządzenia ARM firmy Atmel (używane w Arduino Due) lub MCU STM32 od ST. Każde z nich będzie miało znacznie większą wydajność niż ATmega, a nawet ATxmega.

Podstawową wadą większego, mocniejszego procesora jest cena, ale jeśli nie produkujesz tysięcy takich jednostek, koszty montażu i produkcji na jednostkę znacznie przewyższą różnicę kosztów (prawdopodobnie będzie to tylko kilka dolarów ), że jest to w zasadzie nieistotne.

Connor Wolf
źródło
Ładnie mówiąc - w przypadku produktu komercyjnego Arduino po prostu nie jest właściwą drogą - są energochłonne, powolne, a IDE nie jest zaprojektowane pod kątem optymalnego (szybkiego / małego) kodu, a raczej wygody i łatwej nauki. Za niższy koszt możesz mieć nawet STM32 F4 (32-bitowy Cortex M4> 100 MHz) lub podobny, chociaż byłoby to przesadą. Myślę, że coś jak jeden z mniejszych PIC32, Cortex M3 lub AVR32 jest prawdopodobnie właściwą drogą, jak wspomniałeś. Liczne priorytety przerwań, DMA, wyrafinowane urządzenia peryferyjne, szybka / niska moc i duża ilość pamięci RAM sprawiają, że jest to łatwy wybór w porównaniu do Arduino.
Oli Glaser,
@OliGlaser - Myślę, że musisz wyraźnie rozdzielić Arduino i ATmega . Możesz napisać mały, szybki kod na ATmega, a ATmega może nawet znajdować się na płycie Arduino. Z drugiej strony „IDE” Arduino jest jednym z najgłupszych edytorów kodu, jakich kiedykolwiek używałem. Z drugiej strony bootloader OptiBoot jest bardzo fajny. To, że niektóre części są badziewne, nie oznacza, że ​​powinieneś je wyrzucić.
Connor Wolf,
Oczywiście - miałem na myśli Arduino jako całość, w tym płytę i IDE - nie ATmega, co, jestem pewien, jest tak dobre, jak każde inne porównywalne uC (PIC16 / 18F, itp.). Chciałbym umieścić go na mojej liście, ale Wydaje mi się, że cena między 8-bitem a 16/32-bitem jest obecnie tak bliska, że ​​prawdopodobnie dobrym pomysłem jest wydać dodatkowy 1 $ i wiedzieć, że masz dość mocy procesora (chyba że, jak wspomniałeś, mówimy o ogromnych liczbach i zbudowany w absolutnie najniższej cenie, ale wątpię, czy Arduino byłoby brane pod uwagę :-))
Oli Glaser
1

Musiałem przeczytać na temat timerów, zanim zacząłem myśleć o dokładności taktowania (także zbudowanie sekwencera midi step z arduino, chociaż z pewnością wygląda to mniej fajnie niż te ^^). Ta seria artykułów była najbardziej pouczająca:

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

Obecnie myślę, że moim rozwiązaniem będzie uzyskanie precyzyjnego pomiaru czasu.

A. Użyj arduino AVR

B. Zachowaj zadanie na jednym mikroprocesorze

C. Mądrze używaj preskalerów, timerów i przerwań, aby uzyskać potrzebną precyzję.

AKTUALIZACJA

Korzystając z podstawowego samouczka midi dla Arduino i po zapoznaniu się z tym artykułem na temat timerów i prescalerów, wymyśliłem następujący kod. Kod używa trybu timera 1 i CTC do odtwarzania nuty midi co kwadrans i nuty co kwadrans (co powinno wynosić dokładnie 120 uderzeń / min). Niestety, to wciąż przychodzi nieco wolniej niż 120 uderzeń na minutę, chociaż jest to najbliższe, jakie dostałem ...

// 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);
}

AKTUALIZACJA

Walczę z tym od około 24 godzin i wreszcie otrzymałem odpowiedzi z forum. Myślę, że kod, którego użyłem powyżej ^^ jest całkiem dobry. Używając ISR, trybu CTC i preskalerów itp. Po skontaktowaniu się z forum myślę, że rozwiązaniem nie jest osiągnięcie precyzji w sekwencerze midi, ale podłączenie całej konfiguracji sprzętowej (moich syntezatorów i samplerów) do tego samego zegar midi, niezależnie od tego, czy zegar pochodzi z Arduino.

zapalenie tchawicy
źródło
0

W zależności od tego, jak stopniowo chcesz przejść z komputera na uwięzi do systemu opartego na µC, możesz rozważyć umieszczenie Raspberry Pi w tym pudełku (25-35 USD w sklepie ). W ten sposób możesz mieć pełny (choć słabo zasilany) komputer z systemem Linux z portami USB i pinami GPIO.

Rob Starling
źródło
Jestem pewien, że istnieją tarcze rozszerzające lub jakkolwiek je nazywają dla Pi, ale płyta główna ma 17 pinów GPIO. Używam każdego pinu w arduino mega. 31 taktów + 30 diod LED, 10 wejść analogowych. 70+ I / O.
Steve Cooley,
Och, miałem na myśli, że jeśli bezpośrednim celem było usunięcie komputera zewnętrznego, możesz zatrzymać „sekwencer [to] aplikacja działająca na laptopie” i uruchomić go na Pi, wewnętrznie połączony z istniejącym systemem w ten sam sposób, w jaki jest podłączony teraz.
Rob Starling,
@ SteveCooley - Wygląda na to, że musisz zajrzeć do multipleksowania IO / matryc przycisków. Nie powinieneś potrzebować całej dedykowanej linii IO na przycisk.
Connor Wolf,
@ SteveCooley - Do diabła, naprawdę nie potrzebujesz nawet matrycy przycisków. Możesz zrobić WSZYSTKIE cyfrowe IO używając tylko 4 pinów rPi. Wystarczy zawiesić wszystkie przyciski i diody LED na niektórych rejestrach przesuwnych (równolegle-szeregowy dla przycisków, szeregowo-równoległy dla diod LED) i sterować rejestrami przesuwnymi z portu SPI rPi. Powinieneś łatwo uzyskać> 1KHz częstotliwości aktualizacji dla całej matrycy za pomocą sprzętu SPI.
Connor Wolf,
Jeśli jedynym powodem, dla którego używasz Arduino Mega, jest IO, wydajesz dużo pieniędzy na coś, co można zrobić bardzo łatwo za pomocą kilku urządzeń zewnętrznych, za <3 USD.
Connor Wolf,