11 votos

Precisión de la sincronización del secuenciador MIDI con el Arduino

Construyo estos secuenciadores musicales .

enter image description here

Sólo que no es exactamente un secuenciador, sino una interfaz física para un secuenciador. El secuenciador es una aplicación que se ejecuta en un ordenador portátil al que se conecta el secuenciador, esta cosa permite al usuario hacer loops de batería sobre la marcha. Es bastante divertido, pero requiere un portátil porque el secuenciador no está 'a bordo'.

Lo que me gustaría es hacer la secuenciación a bordo de mi dispositivo.

Ahora vamos a suponer que sé cómo resolver el cumplimiento de la clase para la conectividad MIDI USB, y también vamos a suponer que puedo averiguar cómo cablear un arduino para enviar notas MIDI desde un puerto DIN de 5 pines. Lo que más me preocupa es la deriva del tempo en el tiempo debido a la inconsistencia de la sincronización en cantidades diminutas en cada ejecución del bucle de eventos.

Algunas cosas que sé:

  1. No debe confiar en delay() para controlar el bucle de tempo. El retardo detiene todo el funcionamiento del firmware, y eso no puede funcionar porque necesito sondear la interfaz de usuario física para los cambios mientras la secuencia se está ejecutando.

  2. Cálculos basados en millis() son mejores porque el firmware puede seguir operando y actuando cuando ha transcurrido un determinado recuento.

  3. Aunque ninguno de mis controles físicos está desencadenando rutinas de interrupción, algunas operaciones pueden retrasar el loop() de correr. Si diseño una función que espera la entrada del usuario, eso puede causar obviamente un problema de pérdida de un "plazo" para actuar si el millis() el recuento está muy por encima. Sé que este problema es de mi propio diseño...

Preguntas:

A. ¿Es el arduino basado en AVR un microcontrolador apropiado para sondear una interfaz de usuario y ejecutar un bucle de sincronización de misión crítica? Sé que ahora hay un Arduino basado en ARM que es mucho más rápido. ¿Sería un Teensy 3.0 una mejor alternativa? Ambos son placas de 3,3V, así que eso es otro conjunto de problemas con los que trabajar... pero lo ignoraré por ahora.

B. ¿Debo dividir la tarea en dos microprocesadores? Uno para manejar el sondeo y la actualización de la interfaz de usuario y otro para el bucle de sincronización de misión crítica.

c. ¿Algo más?

Mi principal objetivo es no tener que utilizar el ordenador para nada. También quiero calcular para el swing, pero en este caso, el swing no significa nada si no tengo un tempo cerrado y preciso. ¡Gracias por tus consejos!

6voto

Stephen Denne Puntos 218

Esto puede, con la programación adecuada, definitivamente hacerse en un ATmega328P (dependiendo un poco de la complejidad del bucle de batería. Estoy asumiendo ~<50 eventos de tambor en el bucle. ¿Es eso razonable?).

Tenga en cuenta que he dicho ATmega328P no necesariamente un Arduino .

El entorno de Arduino tiene un montón de cosas por defecto en el fondo, que hace que la programación extremadamente determinista (como usted necesitará para algo crítico de tiempo) sea un reto.

La verdadera pregunta que hay que hacerse aquí es ¿cuánto te interesa programar, frente a cuánto te interesa desarrollar un instrumento?

Aunque estoy bastante seguro de que es posible para hacer todo lo que quieres en un solo ATmega (bucle de batería, múltiples entradas analógicas, LCD, botones, interfaz MIDI), la verdadera pregunta es ¿cuánto trabajo supondrá exprimirlo todo? De nuevo, ¿quieres aprender a optimizar el código de la MCU embebida, o construir instrumentos? Es bastante fácil pasar a una MCU más rápida si es necesario, pero tienes que determinar el rendimiento de la MCU que necesitas ahora Así que a los seis meses de trabajo, no te das cuenta de que no puedes bastante conseguir que todo funcione tan rápido como necesites.


Si yo fuera tú, lo primero que haría es hacerlo funcionar sin cosas de arduino (básicamente, tratarlo como un ATmega en bruto, y usar AVR studio o similar). Entonces, podrás analizar mucho más eficazmente qué tipo de rendimiento necesitas, y si el ATmega puede manejarlo.

Una vez que te liberes de las cosas del arduino, serás mucho más libre de usar diferentes MCUs (generalmente son más similares que diferentes. Si puedes entender uno a partir de su documentación, probablemente puedas hacer lo mismo con otros).

Últimamente he trabajado mucho con los dispositivos ATxmega, y son muy buenos. Tienes tres prioridades de interrupción, lo que hace que la gestión de las cosas de tiempo crítico sea mucho más fácil. También es muy agradable trabajar con ellos (¡diseños de periféricos sanos! ¡Convenientes estructuras de puertos! Etc...).

También están los dispositivos LPC de NXP, que están basados en ARM, así como algunos de los dispositivos ARM de Atmel (como los utilizados en el Arduino Due), o los MCUs STM32 de ST. Cualquiera de ellos tendrá significativamente más rendimiento que un ATmega, o incluso un ATxmega.

La principal desventaja de un procesador más grande y potente es el precio, pero a menos que se fabriquen miles de esas unidades, los costes de ensamblaje y fabricación por unidad van a ser tan superiores a la diferencia de coste (que probablemente será de sólo unos pocos dólares) que es básicamente irrelevante.

5voto

l1feh4ck3r Puntos 81

Las interrupciones son tu amigo para las tareas sensibles a la temporización, pero sólo si pones los aspectos críticos de la temporización en la interrupción, y no hay otras interrupciones que tengan una prioridad más alta. Los microcontroladores del Arduino "basado en AVR" (por ejemplo, el ATmega328P) tienen prioridades de interrupción fijas como se detalla en la página 58 y siguientes del hoja de datos . Así que si usas TIMER2 COMPA como tu interrupción de tiempo crítica y ninguna otra interrupción deberías estar bien (ya que tiene la prioridad más alta). Si también quieres utilizar interrupciones de menor prioridad, tienes que asegurarte de que todas ellas vuelven a activar las interrupciones globales al entrar en su rutina de servicio de interrupción:

Cuando se produce una interrupción, el bit I de habilitación global de la interrupción se borra y todas las interrupciones se desactivan. El software de usuario puede escribir uno lógico en el bit I para habilitar las interrupciones anidadas. Todas las interrupciones habilitadas pueden interrumpir la rutina de interrupción actual.

(p. 14 de la hoja de datos )

Esto es ligeramente diferente en los Arduinos basados en ARM, ya que su núcleo Cortex-M3 tiene un "Controlador de Interrupciones Vectoriales Anidadas", donde las prioridades no son fijas (se pueden establecer por software), y el manejo de las interrupciones anidadas es la norma. Así que para aplicaciones críticas de tiempo, el Arduino basado en ARM le daría más flexibilidad. Sin embargo, no creo que eso sea realmente necesario para tu aplicación.

La cuestión más importante es la facilidad con la que se pueden implementar estas cosas con las librerías de Arduino. Para obtener el mejor rendimiento probablemente tendrás que codificar fuera de las bibliotecas hasta cierto punto, al menos para los bits críticos de sincronización, es decir, evitar cosas como delay() o millis() por completo.

La necesidad de dividir depende de la cantidad de procesamiento que se pretenda realizar. Una vez más, salirse de las bibliotecas puede ofrecerle un mejor rendimiento.

1voto

pufferfish Puntos 3512

Necesitaba leer sobre temporizadores antes de empezar a pensar en la precisión de los tiempos (también construir un secuenciador de pasos midi con un arduino, aunque está garantizado que se verá menos genial que aquellos^^). Esta serie de artículos ha sido la más informativa:

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

Ahora mismo creo que mi solución para conseguir una sincronización precisa será.

A. Utilizar el arduino AVR

B. Mantener la tarea en un solo microprocesador

C. Utiliza sabiamente los preescaladores, los temporizadores y las interrupciones para obtener la precisión necesaria.

ACTUALIZACIÓN

Utilizando el tutorial básico de midi para Arduino y después de mirar este artículo en los temporizadores y preescaladores, el siguiente código es lo que se me ocurrió. El código utiliza timer1 y el modo CTC para reproducir una nota midi cada cuarto de segundo y una nota cada cuarto de segundo (que debería ser exactamente 120 bpm). Lamentablemente, esto todavía viene en sólo más lento que 120bpm aunque esto es lo más cercano que he conseguido ...

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

ACTUALIZACIÓN

He estado luchando con esto durante ~ 24 horas y finalmente conseguí algunas respuestas del foro. Creo que el código que he utilizado arriba ^^ es bastante bueno. Usando el ISR, usando el modo CTC y los preescaladores, etc. Después de llegar a la foro Creo que la solución no pasa tanto por conseguir precisión en el secuenciador midi, sino por conseguir que toda mi configuración de hardware (mis sintetizadores y samplers) se conecte al mismo reloj midi, venga o no el reloj del Arduino.

0voto

ptutt Puntos 798

Dependiendo de la gradualidad con la que quieras hacer la transición de un ordenador atado a un sistema basado en µC, podrías considerar poner una Raspberry Pi dentro de esa caja (25-35 dólares venta al por menor ). De este modo, puedes tener un ordenador completo (aunque poco potente) basado en Linux con puertos USB y pines GPIO.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X