Precisione di temporizzazione del sequencer MIDI usando Arduino


11

Costruisco questi sequencer musicali .

inserisci qui la descrizione dell'immagine

Solo che non è esattamente un sequencer, è un'interfaccia fisica per un sequencer. Il sequencer è un'applicazione che gira su un laptop a cui si collega il sequencer, questa cosa consente all'utente di realizzare loop di batteria al volo. È piuttosto divertente, ma richiede un laptop perché il sequencer non è "integrato".

Quello che mi piacerebbe è fare il sequenziamento a bordo del mio dispositivo.

Ora supponiamo che io sappia come risolvere la conformità di classe per la connettività USB MIDI e supponiamo anche che io possa capire come collegare un arduino per inviare note MIDI da una porta DIN a 5 pin. Ciò di cui sono più preoccupato è la deriva del tempo nel tempo a causa di un tempo incoerente in quantità minime su ogni esecuzione del loop degli eventi.

Alcune cose che so:

  1. Non dovresti fare affidamento sul delay()controllo del tempo loop. Il ritardo interrompe tutte le operazioni del firmware e questo non può funzionare perché devo eseguire il polling dell'interfaccia utente fisica per le modifiche mentre la sequenza è in esecuzione.

  2. I calcoli basati su millis()sono migliori perché il firmware può continuare a funzionare e agire quando è trascorso un determinato conteggio.

  3. Sebbene nessuno dei miei controlli fisici stia attivando routine di interruzione, alcune operazioni possono ritardare l' loop()esecuzione del main . Se progetto una funzione che attende l'input dell'utente, ciò può ovviamente causare un problema di mancato rispetto di una "scadenza" se il millis()conteggio è finito. So che questo problema è di mio disegno ...

Domande:

R. L'arduino basato su AVR è un microcontrollore appropriato per eseguire il polling di un'interfaccia utente ed eseguire un loop di temporizzazione mission-critical? So che c'è un Arduino basato su ARM ora che è molto più veloce. Un Teensy 3.0 sarebbe un'alternativa migliore? Entrambe sono schede da 3,3 V, quindi è un'altra serie di problemi con cui lavorare ... ma per ora lo ignorerò.

B. Dovrei dividere l'attività in due microprocessori? Uno per gestire il polling e l'aggiornamento dell'interfaccia utente e uno per il loop di temporizzazione mission-critical.

c. Qualcos'altro?

Il mio obiettivo principale è non dover usare affatto un computer. Voglio anche calcolare lo swing, ma in questo caso lo swing non significa nulla se non ho un tempo bloccato e con tempismo preciso. Grazie per il tuo consiglio!


1
Arduino imposta sempre alcune routine di interruzione, causando jitter. In molti casi questo non è un problema, ma è bene esserne consapevoli. noInterrupts();ferma il jitter, ma ferma anche tutti gli interrupt desiderati
jippie,

1
Quando dici "esegui il sequenziamento a bordo", significa impostare i battiti per barra, i BPM e un tick-track a bordo? Quindi presumibilmente vuoi ricordare le pressioni dei pulsanti che si sono verificate all'interno della barra in modo che i "cervelli" del dispositivo possano alimentare note MIDI sul tuo laptop? Quindi vuoi rimuovere alcuni suoni di percussione se li colpisci di nuovo sulla nota precedentemente registrata? Ecc. Quanto lontano vuoi andare? Conservazione dei tuoi battiti? Stai creando una sequenza di barre che corrispondono a una traccia completa? Modifica di barre specifiche? Alterazione del tempo di barre specifiche? Mangia tutto CPU quindi scegli la migliore CPU.
Andy aka

Sì, tutto.
Steve Cooley,

2
Questa è una custodia dall'aspetto dolce che hai realizzato!
shuckc,

3
Oltre a ciò che altri hanno detto, sembra un pensiero che forse hai intenzione di produrre e vendere. Un Arduino costa $ 20, mentre un AVR costa $ 2. Non solo otterrai il controllo sull'hardware richiesto dalla tua applicazione, ma risparmierai un sacco di soldi.
Phil Frost,

Risposte:


5

Gli interrupt sono i tuoi amici per le attività sensibili di temporizzazione, ma solo se metti gli aspetti critici di temporizzazione nell'interruzione e non ci sono altri interruzioni in corso che hanno una priorità più alta. I microcontrollori su Arduino "basato su AVR" (ad es. ATmega328P) hanno priorità di interruzione fisse come dettagliato a pagina 58 segg del foglio dati . Quindi, se hai usato TIMER2 COMPA come interruzione della temporizzazione critica e nessun altro interruzione, dovresti essere OK (poiché ha la massima priorità). Se si desidera utilizzare anche interrupt con priorità inferiore, è necessario assicurarsi che tutti riattivano gli interrupt globali quando si accede alla routine del servizio di interrupt:

Quando si verifica un interrupt, l'I-bit Abilita interrupt globale viene cancellato e tutti gli interrupt sono disabilitati. Il software utente può scrivere una logica sull'I-bit per abilitare gli interrupt nidificati. Tutti gli interrupt abilitati possono quindi interrompere la routine di interrupt corrente.

(p. 14 della scheda tecnica )

Questo è leggermente diverso sugli Arduinos basati su ARM poiché il loro core Cortex-M3 ha un "Controller di interruzione vettoriale nidificato", in cui le priorità non sono fisse (possono essere impostate nel software) e la gestione degli interruzioni nidificate è la norma. Quindi per applicazioni critiche di temporizzazione, Arduino basato su ARM ti darebbe maggiore flessibilità. Tuttavia, non credo sia davvero necessario per la tua applicazione.

La domanda più grande è davvero quanto sia facile implementare queste cose con le librerie Arduino. Per ottenere le migliori prestazioni dovrete probabilmente codificare al di fuori delle librerie in una certa misura, almeno per i bit critici di temporizzazione, vale a dire evitare cose come delay () o millis () del tutto.

La necessità o meno di dividere dipende dalla quantità di elaborazione che si intende eseguire. Ancora una volta, uscire dalle librerie può potenzialmente offrirti prestazioni migliori.


3

Questo, con la programmazione appropriata, può sicuramente essere fatto su un ATmega328P (dipende in qualche modo dalla complessità del drum-loop. Sto assumendo ~ <50 eventi drum nel loop. È ragionevole?).

Nota che ho detto ATmega328P , non necessariamente un Arduino .

L'ambiente Arduino ha molte cose predefinite in corso in background, il che rende la programmazione estremamente deterministica (di cui avrai bisogno per qualcosa di critico nei tempi) stimolante.

La vera domanda che devi porre qui è quanto sei interessato alla programmazione, rispetto a quanto sei interessato allo sviluppo di uno strumento?

Mentre sono abbastanza sicuro che sia possibile fare tutto ciò che vuoi su un singolo ATmega (drum loop, più ingressi analogici, LCD, pulsanti, interfaccia MIDI), la vera domanda è: quanto lavoro sarà necessario per spremere tutto? Ancora una volta, vuoi imparare a ottimizzare il codice MCU incorporato o costruire strumenti? E 'abbastanza facile basta andare ad un più veloce MCU, se necessario, ma è necessario per determinare le prestazioni MCU è necessario ora , in modo da sei mesi di lavoro in, non ti rendi conto che non si può del tutto ottenere tutto al lavoro il più velocemente bisogno.


Se fossi in te, la prima cosa che farei sarebbe farlo funzionare senza roba arduino (in sostanza, trattalo come un ATmega grezzo e usa AVR studio o simile). Quindi, puoi analizzare in modo molto più efficace il tipo di prestazioni di cui hai bisogno e se l'ATmega può gestirlo.

Una volta che sei libero dalle cose di Arduino, sei molto più libero di usare MCU diversi (sono generalmente più simili che diversi. Se riesci a capirne uno dalla sua documentazione, probabilmente puoi fare lo stesso per gli altri).

Di recente ho lavorato molto con i dispositivi ATxmega e sono davvero carini. Ottieni tre priorità di interruzione, che rendono più facile la gestione delle cose critiche in termini di tempo. Sono anche molto belli con cui lavorare (design periferico Sane! Pratiche strutture portuali! Ecc.).

Ci sono anche i dispositivi LPC di NXP, che sono basati su ARM, così come alcuni dei dispositivi ARM di Atmel (usati su Arduino Due), o le MCU STM32 di ST. Ognuno di questi avrà prestazioni significativamente maggiori rispetto ad un ATmega o persino ad un ATxmega.

Il principale svantaggio di un processore più grande e più potente è il prezzo, ma a meno che non si realizzino migliaia di quelle unità, i costi di assemblaggio e produzione per unità supereranno notevolmente la differenza di costo (che probabilmente sarà solo di pochi dollari ) che è sostanzialmente irrilevante.


In parole povere - per un prodotto commerciale un Arduino non è semplicemente la strada da percorrere - sono affamati di energia, lenti e l'IDE non è progettato per un codice ottimale (veloce / piccolo), piuttosto praticità e facile apprendimento. Per un costo inferiore potresti anche avere un STM32 F4 (Cortex M4 a 32 bit> 100 MHz) o simile, anche se questo sarebbe eccessivo. Penso che qualcosa come uno dei PIC32 più piccoli, Cortex M3 o un AVR32 sia probabilmente la strada da percorrere, come dici tu. Numerose priorità di interrupt, DMA, periferiche sofisticate, potenza veloce / bassa e molta RAM lo rendono una scelta facile rispetto ad un Arduino.
Oli Glaser,

@OliGlaser - Penso che devi delineare chiaramente tra un Arduino e un ATmega . Puoi fare un piccolo codice veloce su un ATmega e quel ATmega può persino essere su una scheda Arduino. L '"IDE" di Arduino, d'altra parte, è uno degli editor di codice più schifosi che io abbia mai usato. D'altra parte, il bootloader OptiBoot è molto bello. Solo perché alcune parti sono una schifezza non significa che dovresti buttare via tutto.
Connor Wolf,

Assolutamente - mi riferivo ad Arduino nel suo insieme, inclusa la scheda e l'IDE - non l'ATmega, che sono sicuro sia buono come qualsiasi altro UC comparabile (PIC16 / 18F, ecc.) Lo avrei incluso nella mia lista ma Penso che il prezzo tra 8 e 16/32 bit sia così vicino al giorno d'oggi è probabilmente una buona idea spendere un extra di $ 1 e sapere che hai la potenza del processore da risparmiare (a meno che, come dici, non stiamo parlando di numeri enormi e costruito al prezzo più basso in assoluto, ma dubito che un Arduino sarebbe stato considerato :-))
Oli Glaser

1

Avevo bisogno di leggere i timer prima di iniziare a pensare alla precisione del timing (anche costruendo un sequencer midi step con un arduino, sebbene sia garantito un aspetto meno interessante di quelli ^^). Questa serie di articoli è stata la più informativa:

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

In questo momento penso che la mia soluzione per ottenere un tempismo preciso sarà.

A. Usa l'AVR arduino

B. Mantenere l'attività su un microprocessore

C. Usa saggiamente i prescaler, i timer e gli interrupt per ottenere la precisione necessaria.

AGGIORNARE

Usando il tutorial midi di base per Arduino e dopo aver visto questo articolo su timer e prescaler, ho trovato il seguente codice. Il codice utilizza la modalità timer1 e CTC per riprodurre una nota MIDI ogni quarto di secondo e una nota ogni quarto di secondo (che dovrebbe essere esattamente 120 bpm). Purtroppo, questo sta ancora arrivando a un ritmo più lento di 120 bpm, anche se questo è il più vicino che ho ottenuto ...

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

AGGIORNARE

Ho lottato con questo per circa 24 ore e finalmente ho ottenuto alcune risposte dal forum. Penso che il codice che ho usato sopra ^^ sia abbastanza buono. Uso dell'ISR, utilizzo della modalità CTC e dei prescaler ecc. Dopo aver raggiunto il forum, penso che la soluzione sia meno quella di ottenere la precisione sul sequencer midi, ma ottenere la mia intera configurazione hardware (i miei sintetizzatori e campionatori) collegati allo stesso midi clock, indipendentemente dal fatto che l'orologio provenga o meno dall'Arduino.


0

A seconda di quanto gradualmente si desidera effettuare la transizione da un computer collegato a un sistema basato su µC, è possibile considerare di inserire un Raspberry Pi all'interno di quella scatola ($ 25-35 al dettaglio ). In questo modo puoi avere un computer completo (anche se a bassa potenza) basato su Linux con porte USB e pin GPIO.


Sono sicuro che ci sono scudi di espansione o come li chiamano per il Pi, ma la scheda madre ha 17 pin GPIO. Sto usando ogni singolo pin sul mega arduino. 31 tatto + 30 LED, 10 ingressi analogici. 70+ I / O.
Steve Cooley,

Oh, intendevo dire che se l'obiettivo immediato fosse quello di rimuovere il computer esterno, potresti tenere il "sequencer [che] è un'applicazione che gira su un laptop" ed eseguirlo sul Pi, collegato internamente al tuo sistema esistente allo stesso modo in cui è connesso ora.
Rob Starling

@SteveCooley - Sembra che tu abbia bisogno di esaminare IO multiplexing / matrici di pulsanti. Non dovresti aver bisogno di un'intera linea IO dedicata per pulsante.
Connor Wolf,

@SteveCooley - Cavolo, non hai nemmeno bisogno di una matrice di pulsanti, davvero. Puoi fare TUTTI i tuoi IO digitali usando solo 4 pin rPi. Basta appendere tutti i pulsanti e i LED su alcuni registri a scorrimento (parallelo-seriale per i pulsanti, seriale-parallelo per i LED) e guidare i registri a scorrimento dalla porta SPI di rPi. Dovresti ottenere facilmente> 1 KHz di velocità di aggiornamento per l'intera matrice con l'aiuto dell'hardware SPI.
Connor Wolf,

Se l'unica ragione per cui stai usando un Arduino Mega è l'IO, stai spendendo molti soldi in qualcosa che può essere fatto molto facilmente con pochi dispositivi esterni, per <$ 3.
Connor Wolf,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.