Akurasi waktu sequencer MIDI menggunakan Arduino

11

Saya membangun sequencer musik ini .

masukkan deskripsi gambar di sini

Hanya saja itu bukan sequencer, itu adalah antarmuka fisik untuk sequencer. Sequencer adalah aplikasi yang berjalan pada laptop yang terhubung dengan sequencer, hal ini memungkinkan pengguna membuat drum loop dengan cepat. Ini cukup menyenangkan, tetapi membutuhkan laptop karena sequencer tidak 'on-board'.

Yang ingin saya lakukan adalah melakukan sequencing di perangkat saya.

Sekarang mari kita asumsikan saya tahu bagaimana menyelesaikan kepatuhan kelas untuk konektivitas USB MIDI, dan mari kita juga berasumsi saya bisa mencari cara untuk memasang arduino untuk mengirim catatan MIDI dari port DIN 5 pin. Yang paling saya pedulikan adalah tempo melayang dari waktu ke waktu karena waktu yang tidak konsisten dalam jumlah menit setiap kali putaran acara.

Beberapa hal yang saya tahu:

  1. Anda seharusnya tidak mengandalkan delay()untuk mengontrol lingkaran tempo. Delay menghentikan semua operasi firmware, dan itu tidak dapat berfungsi karena saya perlu melakukan polling pada antarmuka pengguna fisik untuk perubahan ketika urutan sedang berjalan.

  2. Perhitungan berdasarkan millis()lebih baik karena firmware dapat terus beroperasi dan bertindak ketika jumlah tertentu telah berlalu.

  3. Meskipun tidak ada kontrol fisik saya yang memicu rutinitas interupsi, beberapa operasi dapat menunda operasi utama loop(). Jika saya mendesain fungsi yang menunggu input pengguna, itu jelas dapat menyebabkan masalah kehilangan "tenggat waktu" untuk bertindak jika millis()hitungannya sudah berakhir. Saya tahu masalah ini adalah desain saya sendiri ...

Pertanyaan:

A. Apakah Arduino berbasis AVR mikrokontroler yang tepat untuk polling antarmuka pengguna dan menjalankan loop waktu misi kritis? Saya tahu ada Arduino berbasis ARM sekarang jauh lebih cepat. Akankah Teensy 3.0 menjadi alternatif yang lebih baik? Kedua ini adalah papan 3.3V, jadi itu satu set masalah untuk dikerjakan ... tapi saya akan mengabaikannya untuk saat ini.

B. Haruskah saya membagi tugas menjadi dua mikroprosesor? Satu untuk menangani polling dan memperbarui antarmuka pengguna dan satu untuk loop timing misi kritis.

c. Sesuatu yang lain

Tujuan utama saya adalah tidak harus menggunakan komputer sama sekali. Saya juga ingin menghitung untuk ayunan, tetapi dalam kasus ini, ayunan tidak berarti apa-apa jika saya tidak mendapatkan tempo yang akurat dan tepat waktu. Terima kasih atas saranmu!

Steve Cooley
sumber
1
Arduino selalu mengatur beberapa rutinitas interupsi, menyebabkan jitter. Dalam banyak kasus ini bukan masalah, tetapi baik untuk menyadarinya. noInterrupts();menghentikan jitter, tetapi juga menghentikan semua interupsi yang diinginkan.
jippie
1
Ketika Anda mengatakan "lakukan sequencing on-board", apakah itu berarti mengatur beat per bar, BPM dan tick-track on-board? Maka mungkin Anda ingin mengingat penekanan tombol yang terjadi di bar sehingga "otak" perangkat dapat memberi makan midi-note ke laptop Anda? Lalu apakah Anda ingin menghapus suara perkusi tertentu jika Anda menekannya lagi pada not yang sebelumnya direkam? Dll. Seberapa jauh Anda ingin pergi? Penyimpanan ketukan Anda? Membuat urutan bilah yang sesuai dengan trek lengkap? Mengedit bilah tertentu? Perubahan tempo pada bilah tertentu? Semuanya memakan CPU jadi pilihlah CPU terbaik.
Andy alias
Yap, semuanya.
Steve Cooley
2
Itu adalah kasing yang kamu buat!
shuckc
3
Selain apa yang dikatakan orang lain, ini seperti pemikiran bahwa mungkin Anda berniat untuk memproduksi dan menjual. Arduino berharga $ 20, sedangkan AVR berharga $ 2. Anda tidak hanya akan mendapatkan kendali atas perangkat keras yang dibutuhkan aplikasi Anda, tetapi Anda akan menghemat banyak uang.
Phil Frost

Jawaban:

5

Interupsi adalah teman Anda untuk tugas-tugas sensitif waktu, tetapi hanya jika Anda memasukkan aspek-aspek penting timing ke dalam interupsi, dan tidak ada interupsi lain yang terjadi yang memiliki prioritas lebih tinggi. Mikrokontroler pada Arduino "berbasis AVR" (mis. ATmega328P) telah memperbaiki prioritas interupsi sebagaimana dirinci pada halaman 58ff dari lembar data . Jadi jika Anda menggunakan TIMER2 COMPA sebagai interupsi waktu kritis Anda dan tidak ada interupsi lain, Anda harusnya OK (karena memiliki prioritas tertinggi). Jika Anda juga ingin menggunakan interupsi prioritas yang lebih rendah, Anda perlu memastikan bahwa semuanya mengaktifkan kembali interupsi global saat memasuki rutinitas layanan interupsi mereka:

Ketika interupsi terjadi, Global Interrupt Enable I-bit dihapus dan semua interupsi dinonaktifkan. Perangkat lunak pengguna dapat menulis logika satu ke bit-I untuk mengaktifkan interupsi bersarang. Semua interupsi yang diaktifkan kemudian dapat mengganggu rutin interupsi saat ini.

(hal. 14 dari lembar data )

Ini sedikit berbeda pada Arduinos berbasis ARM karena inti Cortex-M3 mereka memiliki "Nested Vector Interrupt Controller", di mana prioritasnya tidak diperbaiki (dapat diatur dalam perangkat lunak), dan penanganan interupsi bersarang adalah norma. Jadi untuk aplikasi waktu kritis, Arduino berbasis ARM akan memberi Anda lebih banyak fleksibilitas. Namun, saya tidak berpikir itu benar-benar diperlukan untuk aplikasi Anda.

Pertanyaan yang lebih besar adalah betapa mudahnya hal-hal ini dapat diimplementasikan dengan perpustakaan Arduino. Untuk mendapatkan kinerja terbaik, Anda mungkin harus kode di luar perpustakaan sampai tingkat tertentu, setidaknya untuk bit waktu kritis, yaitu menghindari hal-hal seperti delay () atau millis () sama sekali.

Apakah Anda perlu membagi atau tidak tergantung pada seberapa banyak pemrosesan yang ingin Anda lakukan. Sekali lagi, pergi ke luar perpustakaan berpotensi memberi Anda kinerja yang lebih baik.

fm_andreas
sumber
3

Ini bisa, dengan pemrograman yang sesuai, paling pasti dilakukan pada ATmega328P (agak tergantung pada kompleksitas drum-loop. Saya mengasumsikan ~ <50 kejadian drum dalam loop. Apakah itu masuk akal?).

Perhatikan bahwa saya mengatakan ATmega328P , belum tentu Arduino .

Lingkungan Arduino memiliki banyak hal standar yang terjadi di latar belakang, yang membuat pemrograman yang sangat deterministik (karena Anda akan membutuhkan sesuatu yang kritis-waktu) yang menantang.

Pertanyaan sebenarnya yang perlu Anda tanyakan di sini adalah seberapa tertarik Anda dalam pemrograman, vs seberapa tertarik Anda dalam mengembangkan instrumen?

Sementara saya cukup yakin itu mungkin untuk melakukan semua yang Anda inginkan pada ATmega tunggal (loop drum, beberapa input analog, LCD, tombol, antarmuka MIDI), pertanyaan sebenarnya adalah berapa banyak pekerjaan yang akan dilakukan untuk memeras semuanya? Sekali lagi, apakah Anda ingin belajar untuk mengoptimalkan kode MCU tertanam, atau membangun instrumen? Ini cukup mudah untuk hanya pergi ke cepat MCU jika diperlukan, tetapi Anda perlu menentukan kinerja MCU Anda perlu sekarang , sehingga enam bulan bekerja, Anda tidak sadar bahwa Anda tidak bisa cukup mendapatkan segala sesuatu untuk bekerja secepat Anda perlu.


Jika saya jadi Anda, hal pertama yang akan saya lakukan adalah membuatnya bekerja tanpa barang Arduino (pada dasarnya, memperlakukannya sebagai ATmega mentah, dan menggunakan AVR studio atau serupa). Kemudian, Anda dapat menganalisis secara lebih efektif kinerja seperti apa yang Anda butuhkan, dan jika ATmega dapat mengelolanya.

Setelah Anda bebas dari hal-hal Arduino, Anda akan jauh lebih bebas untuk menggunakan MCU yang berbeda (mereka umumnya lebih mirip daripada yang berbeda. Jika Anda dapat menemukan satu dari dokumentasi itu, Anda mungkin dapat melakukan hal yang sama untuk orang lain).

Saya telah bekerja dengan perangkat ATxmega BANYAK baru-baru ini, dan mereka sangat bagus. Anda mendapatkan tiga prioritas interupsi, yang membuat mengelola hal-hal penting waktu menjadi lebih mudah. Mereka juga sangat bagus untuk bekerja dengan (desain periferal Sane! Struct port Nyaman! Dll ...).

Ada juga perangkat LPC dari NXP, yang berbasis ARM, serta beberapa perangkat ARM Atmel (seperti yang digunakan pada Arduino Due), atau STM32 MCU dari ST. Semua ini akan memiliki kinerja yang lebih signifikan daripada ATmega, atau bahkan ATxmega.

Kelemahan utama dari prosesor yang lebih besar, lebih kuat adalah harga, tetapi kecuali jika Anda membuat ribuan unit tersebut, biaya perakitan per unit dan manufaktur akan jauh melebihi selisih biaya (yang kemungkinan hanya beberapa dolar saja) ) bahwa itu pada dasarnya tidak relevan.

Connor Wolf
sumber
Dengan baik - untuk produk komersial, Arduino bukan cara yang tepat - mereka haus daya, lambat, dan IDE tidak dirancang untuk kode yang optimal (cepat / kecil), melainkan kenyamanan dan pembelajaran yang mudah. Untuk biaya yang lebih murah, Anda bahkan dapat memiliki STM32 F4 (32-bit Cortex M4> 100MHz) atau serupa, meskipun ini akan berlebihan. Saya pikir sesuatu seperti salah satu PIC32 yang lebih kecil, Cortex M3 atau AVR32 mungkin adalah cara yang harus dilakukan, seperti yang Anda sebutkan. Sejumlah prioritas interupsi, DMA, periferal canggih, daya cepat / rendah, dan banyak RAM menjadikannya pilihan yang mudah dibandingkan dengan Arduino.
Oli Glaser
@ OliGlaser - Saya pikir Anda perlu menggambarkan dengan jelas antara Arduino dan ATmega . Anda dapat melakukan kode kecil dan cepat pada ATmega, dan ATmega itu bahkan bisa berada di papan Arduino. Arduino "IDE", di sisi lain, adalah salah satu editor kode shittiest yang pernah saya gunakan. Di sisi lain, bootloader OptiBoot sangat bagus. Hanya karena beberapa bagian omong kosong tidak berarti Anda harus membuang semuanya.
Connor Wolf
Tentu saja - saya merujuk ke Arduino secara keseluruhan, termasuk board dan IDE - bukan ATmega, yang saya yakin sama bagusnya dengan UC lainnya (PIC16 / 18F, dll.) Saya akan memasukkannya ke dalam daftar tetapi Saya pikir dengan harga antara 8-bit dan 16/32-bit yang sangat dekat saat ini, mungkin ide yang baik untuk menghabiskan $ 1 tambahan dan tahu Anda memiliki kekuatan prosesor untuk cadangan (kecuali seperti yang Anda sebutkan, kita berbicara angka yang sangat besar dan dibangun dengan harga terendah absolut, tapi kemudian saya ragu Arduino akan dipertimbangkan :-))
Oli Glaser
1

Saya perlu membaca tentang penghitung waktu sebelum saya mulai berpikir tentang ketepatan waktu (juga membangun sequencer langkah midi dengan arduino, meskipun dijamin terlihat kurang keren daripada ^^). Seri artikel ini adalah yang paling informatif:

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

Saat ini saya berpikir bahwa solusi saya untuk mendapatkan waktu yang tepat adalah.

A. Gunakan Arduino AVR

B. Simpan tugas pada satu mikroprosesor

C. Dengan bijak gunakan prescaler, timer dan interupsi untuk mendapatkan presisi yang dibutuhkan.

MEMPERBARUI

Menggunakan tutorial dasar midi untuk Arduino dan setelah melihat artikel ini tentang timer dan prescaler, kode berikut adalah apa yang saya dapatkan. Kode ini menggunakan mode timer1 dan CTC untuk memainkan catatan midi pada setiap seperempat detik dan catatan dari setiap seperempat detik (yang harus tepat 120 bpm). Sayangnya, ini masih datang lebih lambat dari 120bpm meskipun ini adalah yang terdekat yang saya dapatkan ...

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

MEMPERBARUI

Saya telah berjuang dengan ini selama ~ 24 jam sekarang dan akhirnya mendapat jawaban dari forum. Saya pikir kode yang saya gunakan di atas ^^ cukup bagus. Menggunakan ISR, menggunakan mode CTC dan prescaler dll. Setelah menjangkau forum saya berpikir bahwa solusinya kurang tentang mendapatkan presisi pada sequencer midi, tetapi mendapatkan seluruh pengaturan perangkat keras saya (synthesizer dan sampler saya) dihubungkan dengan hal yang sama jam midi, apakah jam itu berasal dari Arduino atau tidak.

crunkchitis
sumber
0

Bergantung pada seberapa bertahap Anda ingin melakukan transisi dari komputer yang ditambatkan ke sistem berbasis μC, Anda mungkin mempertimbangkan untuk meletakkan Raspberry Pi di dalam kotak itu ( ritel $ 25-35 ). Dengan begitu Anda dapat memiliki komputer berbasis linux penuh (walaupun berdaya rendah) dengan port USB dan pin GPIO.

Rob Starling
sumber
Saya yakin ada perisai ekspansi atau apa pun mereka menyebutnya Pi, tetapi papan stok memiliki 17 pin GPIO. Saya menggunakan setiap pin pada arduino mega. 31 taktik + 30 LED, 10 analog masuk. 70+ I / O.
Steve Cooley
Oh, maksud saya jika tujuan langsungnya adalah menghapus komputer eksternal, Anda bisa menjaga "sequencer [itu] adalah aplikasi yang berjalan di laptop" dan menjalankannya di Pi, terhubung secara internal ke sistem Anda yang ada dengan cara yang sama terhubung sekarang.
Rob Starling
@SteveCooley - Kedengarannya Anda perlu melihat IO multiplexing / tombol-matriks. Anda tidak perlu membutuhkan seluruh jalur IO khusus per tombol.
Connor Wolf
@SteveCooley - Sial, Anda bahkan tidak perlu tombol matrik, sungguh. Anda dapat melakukan SEMUA IO digital Anda hanya menggunakan 4 pin rPi. Cukup gantung semua tombol dan LED dari beberapa register geser (paralel-serial untuk tombol, paralel-paralel untuk LED), dan kendalikan register geser dari port SPI rPi. Anda harus dengan mudah mendapatkan kecepatan pembaruan> 1KHz untuk seluruh matriks dengan bantuan perangkat keras SPI.
Connor Wolf
Jika satu-satunya alasan Anda menggunakan Arduino Mega adalah IO, Anda menghabiskan banyak uang untuk sesuatu yang dapat dilakukan dengan sangat mudah dengan beberapa perangkat eksternal, dengan harga <$ 3.
Connor Wolf