Precisão de tempo do seqüenciador MIDI usando o Arduino


11

Eu construo esses seqüenciadores de música .

insira a descrição da imagem aqui

Só que não é exatamente um sequenciador, é uma interface física para um sequenciador. O sequenciador é um aplicativo que roda em um laptop ao qual o sequenciador se conecta, permitindo que o usuário faça loops de bateria em tempo real. É bem divertido, mas requer um laptop porque o seqüenciador não está 'on-board'.

O que eu adoraria é fazer o seqüenciamento a bordo do meu dispositivo.

Agora, vamos supor que eu sei como resolver a conformidade de classe para a conectividade USB MIDI, e também vamos supor que eu possa descobrir como conectar um arduino para enviar notas MIDI a partir de uma porta DIN de 5 pinos. O que mais me preocupa é o desvio do tempo ao longo do tempo devido ao tempo inconsistente em quantidades mínimas em cada execução do loop de eventos.

Algumas coisas que eu sei:

  1. Você não deve confiar delay()para controlar o loop de tempo. O atraso interrompe toda a operação do firmware, e isso não pode funcionar, porque eu preciso pesquisar na interface do usuário física se há alterações enquanto a sequência está em execução.

  2. Os cálculos baseados em millis()são melhores porque o firmware pode continuar a operar e agir quando uma certa contagem tiver decorrido.

  3. Embora nenhum dos meus controles físicos esteja acionando rotinas de interrupção, algumas operações podem atrasar a loop()execução do principal . Se eu projetar uma função que aguarda a entrada do usuário, isso obviamente pode causar o problema de perder um "prazo" para agir se a millis()contagem terminar. Eu sei que esse problema é do meu próprio projeto ...

Questões:

A. O arduino baseado no AVR é ​​um microcontrolador apropriado para pesquisar uma interface do usuário e executar um loop de tempo de missão crítica? Eu sei que há um Arduino baseado em ARM agora muito mais rápido. Um Teensy 3.0 seria uma alternativa melhor? Ambas são placas de 3,3V, então esse é outro conjunto de questões para trabalhar ... mas vou ignorar isso por enquanto.

B. Devo dividir a tarefa em dois microprocessadores? Um para lidar com pesquisas e atualização da interface do usuário e outro para o loop de temporização de missão crítica.

c. Algo mais?

Meu principal objetivo é não precisar usar um computador. Também quero calcular o balanço, mas, nesse caso, o balanço não significa nada se eu não tiver um tempo preciso e bloqueado. Obrigada pelo Conselho!


1
O Arduino sempre configura algumas rotinas de interrupção, causando tremulação. Em muitos casos, isso não é um problema, mas é bom estar ciente disso. noInterrupts();interrompe a instabilidade, mas também interrompe todas as interrupções desejadas.
Jippie

1
Quando você diz "fazer sequenciamento a bordo", isso significa configurar as batidas por barra, BPM e uma faixa de escala a bordo? Então, presumivelmente, você quer se lembrar dos pressionamentos de botão que ocorreram dentro da barra para que os "cérebros" do dispositivo possam alimentar notas médias no seu laptop? Então você deseja remover certos sons de percussão se os tocar novamente sobre a nota que foi gravada anteriormente? Etc .. até onde você quer ir? Armazenamento de suas batidas? Criando uma sequência de barras que correspondem a uma faixa completa? Editando barras específicas? Alteração do tempo de barras específicas? Tudo consome CPU, então escolha a melhor CPU.
Andy aka

Sim, tudo isso.
11133 Steve Cooley

2
Esse é um caso agradável que você fez!
shuckc

3
Além do que os outros disseram, isso parece um pensamento de que talvez você pretenda produzir e vender. Um Arduino custa US $ 20, enquanto um AVR custa US $ 2. Você não apenas obterá o controle sobre o hardware exigido pelo seu aplicativo, mas também economizará muito dinheiro.
Phil Geada

Respostas:


5

As interrupções são suas amigas para tarefas sensíveis ao tempo, mas somente se você colocar os aspectos críticos do tempo na interrupção e não houver outras interrupções acontecendo com prioridade mais alta. Os microcontroladores no Arduino "baseado em AVR" (por exemplo, o ATmega328P) fixaram prioridades de interrupção, conforme detalhado na página 58ff da folha de dados . Portanto, se você usou o TIMER2 COMPA como sua interrupção crítica de tempo e nenhuma outra interrupção, deve estar OK (pois possui a maior prioridade). Se você também deseja usar interrupções de prioridade mais baixa, certifique-se de que todas elas reativem interrupções globais ao entrar na rotina de serviço de interrupção:

Quando ocorre uma interrupção, o bit de ativação global de interrupção é limpo e todas as interrupções são desativadas. O software do usuário pode gravar uma lógica no bit I para ativar interrupções aninhadas. Todas as interrupções ativadas podem interromper a rotina de interrupção atual.

(p. 14 da folha de dados )

Isso é um pouco diferente nos Arduinos baseados em ARM, já que o núcleo do Cortex-M3 possui um "Nested Vector Interrupt Controller", onde as prioridades não são fixas (podem ser definidas no software) e o tratamento de interrupções aninhadas é a norma. Portanto, para cronometrar aplicativos críticos, o Arduino baseado em ARM ofereceria mais flexibilidade. No entanto, não acho que isso seja realmente necessário para a sua aplicação.

A grande questão é realmente quão fácil essas coisas podem ser implementadas com as bibliotecas do Arduino. Para obter o melhor desempenho, você provavelmente terá que codificar fora das bibliotecas até certo ponto, pelo menos para os bits críticos de tempo, ou seja, evitar coisas como delay () ou millis () por completo.

A necessidade de dividir ou não depende de quanto processamento você pretende fazer. Novamente, sair das bibliotecas pode potencialmente oferecer um melhor desempenho.


3

Isso pode, com a programação apropriada, ser feito definitivamente em um ATmega328P (dependendo da complexidade do loop de bateria. Estou assumindo ~ <50 eventos de bateria no loop. Isso é razoável?).

Note que eu disse ATmega328P , não necessariamente um Arduino .

O ambiente do Arduino tem muitas coisas padrão acontecendo em segundo plano, o que torna a programação extremamente determinística (como você precisará de algo crítico no tempo) desafiadora.

A verdadeira pergunta que você precisa fazer aqui é qual é o seu interesse em programação versus o interesse em desenvolver um instrumento?

Embora eu esteja bastante confiante de que é possível fazer tudo o que você deseja em um único ATmega (loop de bateria, várias entradas analógicas, LCD, botões, interface MIDI), a verdadeira questão é quanto trabalho será necessário para espremer tudo? Mais uma vez, você deseja aprender a otimizar o código MCU incorporado ou criar instrumentos? É muito fácil simplesmente acessar um MCU mais rápido, se necessário, mas você precisa determinar o desempenho do MCU necessário agora ; portanto, seis meses de trabalho, você não percebe que não consegue fazer tudo funcionar tão rápido quanto você. necessidade.


Se eu fosse você, a primeira coisa que faria seria fazê-lo funcionar sem o material do arduino (basicamente, trate-o como um ATmega bruto e use o AVR studio ou similar). Então, você pode analisar com muito mais eficiência que tipo de desempenho precisa e se o ATmega pode gerenciá-lo.

Quando você está livre do material do arduino, fica muito mais livre para usar MCUs diferentes (eles geralmente são mais parecidos do que diferentes. Se você pode descobrir um a partir da documentação, provavelmente pode fazer o mesmo com outros).

Eu tenho trabalhado muito com os dispositivos ATxmega MUITO recentemente, e eles são muito legais. Você tem três prioridades de interrupção, que facilitam o gerenciamento de itens críticos em termos de tempo. Eles também são muito bons de se trabalhar (designs periféricos da Sane! Estruturas de portas convenientes! Etc ...).

Existem também os dispositivos LPC do NXP, que são baseados em ARM, assim como alguns dos dispositivos ARM da Atmel (usados ​​no Arduino Due), ou os MCUs STM32 da ST. Qualquer um desses terá desempenho significativamente mais do que um ATmega, ou mesmo um ATxmega.

A principal desvantagem de um processador maior e mais poderoso é o preço, mas, a menos que você esteja criando milhares dessas unidades, os custos de montagem e fabricação por unidade excederão muito a diferença de custo (que provavelmente será de apenas alguns dólares) ) que é basicamente irrelevante.


Bem dito - para um produto comercial, um Arduino simplesmente não é o caminho a seguir - eles têm muita energia, são lentos e o IDE não foi projetado para um código (rápido / pequeno) ideal, mas para uma conveniência e um aprendizado fáceis. Por um custo menor, você pode até ter um STM32 F4 (Cortex M4 de 32 bits> 100MHz) ou similar, embora isso seja um exagero. Eu acho que algo como um dos menores PIC32, Cortex M3s ou AVR32 é provavelmente o caminho a percorrer, como você mencionou. Numerosas prioridades de interrupção, DMA, periféricos sofisticados, energia rápida / baixa e muita RAM tornam a escolha fácil em comparação com um Arduino.
Oli Glaser

@OliGlaser - Eu acho que você precisa delinear claramente entre um Arduino e um ATmega . Você pode criar código pequeno e rápido em um ATmega, e esse ATmega pode até estar em uma placa Arduino. O "IDE" do Arduino, por outro lado, é um dos editores de código mais ruins que eu já usei. Por outro lado, o carregador de inicialização OptiBoot é muito bom. Só porque algumas partes são ruins, não significa que você deva jogar tudo fora.
Connor Lobo

Absolutamente - eu estava me referindo ao Arduino como um todo, incluindo a placa e o IDE - não o ATmega, que tenho certeza que é tão bom quanto qualquer outro uC comparável (PIC16 / 18F, etc.), eu o teria incluído na minha lista, mas Eu acho que com o preço entre 8 e 16/32 bits sendo tão próximo hoje em dia, provavelmente é uma boa ideia gastar um dólar extra e saber que você tem o poder de sobra do processador (a menos que você mencione, estamos falando de grandes números e construído para o menor preço absoluto, mas então eu duvido que um Arduino teria sido considerado :-))
Oli Glaser

1

Eu precisava ler os cronômetros antes de começar a pensar na precisão do tempo (também construindo um sequenciador midi step com um arduino, embora seja garantido que pareça menos legal do que aqueles ^^). Esta série de artigos foi a mais informativa:

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

No momento, acho que minha solução para obter um timing preciso será.

A. Use o AVR arduino

B. Mantenha a tarefa em um microprocessador

C. Use sabiamente prescalers, temporizadores e interrupções para obter a precisão necessária.

ATUALIZAR

Usando o tutorial midi básico para o Arduino e depois de ler este artigo sobre temporizadores e pré-calibradores, o código a seguir foi o que eu vim. O código usa o modo timer1 e CTC para tocar uma nota midi a cada quarto de segundo e uma nota desativada a cada quarto de segundo (que deve ser exatamente 120 bpm). Infelizmente, isso ainda está chegando a menos de 120bpm, embora este seja o mais próximo que eu cheguei ...

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

ATUALIZAR

Estou lutando com isso há ~ 24 horas e finalmente recebi algumas respostas do fórum. Eu acho que o código que eu usei acima ^^ é muito bom. Usando o ISR, usando o modo CTC e pré-calibradores etc. Depois de entrar em contato com o fórum , acho que a solução tem menos a ver com precisão no midi sequencer, mas com toda a minha configuração de hardware (meus sintetizadores e samplers) conectada à mesma relógio midi, independentemente de o relógio ser ou não proveniente do Arduino.


0

Dependendo de quão gradualmente você deseja fazer a transição de um computador conectado a um sistema baseado em µC, considere colocar um Raspberry Pi dentro dessa caixa (US $ 25-35 no varejo ). Dessa forma, você pode ter um computador baseado em Linux completo (embora com pouca energia) com portas USB e pinos GPIO.


Tenho certeza de que existem escudos de expansão ou o que eles chamam de Pi, mas o quadro de ações possui 17 pinos GPIO. Estou usando todos os pinos no mega arduino. 31 tatos + 30 LEDs, 10 entradas analógicas. 70+ E / S.
Steve Cooley

Ah, eu quis dizer que se o objetivo imediato era remover o computador externo, você poderia manter o "sequenciador [que] é um aplicativo que roda em um laptop" e executá-lo no Pi, conectado internamente ao sistema existente da mesma maneira que é conectado agora.
Rob Starling

@SteveCooley - Parece que você precisa procurar na multiplexação de E / S / matrizes de botões. Você não precisa de toda uma linha de E / S dedicada por botão.
Connor Lobo

@SteveCooley - Inferno, você nem precisa de uma matriz de botões, na verdade. Você pode fazer TODAS as suas E / S digitais usando apenas 4 pinos rPi. Apenas desligue todos os botões e LEDs de alguns registradores de deslocamento (serial-paralelo para os botões, paralelo-serial para os LEDs) e conduza os registradores de deslocamento da porta SPI do rPi. Você deve obter facilmente taxas de atualização> 1Khz para toda a matriz com a ajuda do hardware SPI.
Connor Wolf

Se o único motivo pelo qual você está usando um Arduino Mega é o IO, você está gastando muito dinheiro em algo que pode ser feito com muita facilidade com alguns dispositivos externos, por <US $ 3.
Connor Lobo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.