Eureka analogisyntikka ja Arduino

HEI!

Olen 47 vuotias IT-asiantuntija ja koulutukseltani elektroniikka-asentaja vuodelta 1989. Olen uusi Arduinomaailmassa. Hankin Arduinon noin vuosi sitten mutta vielä ei ole tullut sillä juuri mitään väännettyä. Viimeksi olen ohjelmoinut Z80 prossuun perustuvaa microprofessoria ja Commodore 64:sta joskus 80-90 luvulla. Pikkuhiljaa olen yrittänyt ottaa haltuun tuota Arduinon ohjelmointia lukemalla perusteita ja testailemalla esimerkkikoodinpätkiä. Hiljalleen olen päässyt vähän jyvälle tästäkin laitteesta.

Haaveissa on jo pidempään ollut rakentaa oma analogisyntetisaattori. Ensimmäisen syntikkani olen päättänyt rakentaa joko NE566 tai XR2206 piirejä käyttäen, joita molempia löytyy hyllystä. Muistaessani taas tuon Arduinon olemassaolon päätinkin tehdä pelkän MIDI ohjattavan analogisyntikka modulin. Eli Arduinolla hoitaisin MIDI signaalin lukemisen ja nuottitiedon muuttamisen VCO:n vaatimaksi jännitetasoksi 12-bitin R2R D/A muunninta käyttäen. Siitä eteenpäin signaalitie olisi puhtaasti analoginen.

Koodia olen jo hiukan kyseiseen hommaan vääntänyt joskin se on vielä monelta osin kesken ja puutteellinen varsinkin MIDI:n osalta. Taidan tehdä koodin MIDI kirjastoa käytäen. Opiskelen sitä parhaillaan. Tekninenkin toteutus on hiukan vielä auki joskin pääkohdat ovat suunnilleen jo selvillä.

Liitteenä on periaatekuva digitaalipuolen rakenteesta ja alla keskeneräinen koodi jonka tähän mennessä olen saanut rustattua kasaan.

Pyöritellessäni vielä tuota VCO:n prototyyppiä niin trimmailin sen siihen kuntoon että 2-12 voltin ohjausjännittellä siitä saa 24Hz - 4,5 KHz taajuudet ulos. Arduinon jälkeen täytyy siis laittaa TTL-CMOS tasomuunnin sekä CMOS latchit joilla saa sitten isommat jännitteet D/A muuntimelle/muuntimelta.

Syntikkaan tulee 2 VCO.ta ja yksi virtuaali VCO joka on oma ideani ja viritykseni.
Syntikan VCO:sta rakensin prototyypin jonka toimintaa näet:

https://www.youtube.com/watch?v=RnQRGBBpNEo

Olisi kiva kuulla mietteitä projektista ja olenko koodin kanssa ihan pielessä jossain kohdin.

/*
EUREKA synth program

Tämä ohjelma lukee midiliitännästä nuottitietoa ja muodostaa sen mukaan
digitaalisen arvon D/A muuntimelle. D/A muunnin koostuu kahdentoista
D-kiikun (TTL 74174) muodostamasta latch piiristä sekä R2R D/A muuntimesta.
D/A muunnin muodostaa luettua nuottia vastaavan ohjausjännitteen
analogisyntetisaattorin oskillaattoreille.

Arduinon kortilta D/A latch piireille lähtee 6-bittinen dataväylä (pinnit 8-13),
1-bittinen osoiteväylä (digitaalipinni 2) sekä 1-bittinen kelloväylä (Digitaalipinni 3).

Digitaaliset pinnit 0 ja 1 toimivat MIDI tiedon sarjaliikenteessä

*/

// Määritetään globaalit muuttujat osoite- ja kelloväylän käsittelemiseen

const int osoitebus = 2; //osoiteväylänä toimii digitaalipinni 2
const int kellobus = 3; //latchien kelloväylänä toimii digitaalipinni 3
const byte noteOn = 144; //MIDI note on komento
const byte noteOff = 128; //MIDI note off komento
byte MIDIcomm; //MIDI komentotavu
byte MIDInote; //MIDI nuottitavu
byte MIDIvelo; //MIDI voimakkuustavu

// Taulukko josta haetaan MIDI nuottia vastaavat jännitearvot 12 bitin sanoina A/D muuntimelle

int janniteData[128]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0};

void setup()
{
// Alustetaan sarjaliikenne 31250 bittiä per sekunti
// Alustetaan D/A muuntimen muuttujat ja nollataan muunnin

Serial.begin(31250); // Alustetaan sarjaportti MIDI liitäntää varten
DDRB = B00111111; // digital pinnit -,-,13,12,11,10,9,8 // asetetaan pinnit 8…13 lähdöiksi
PORTB = B00000000; //asetetaan PorttiinB (pinnit 8-13) nollat
pinMode(osoitebus, OUTPUT); //määritellään osoiteväylä lähdöksi
pinMode(kellobus, OUTPUT); //määritellään kelloväylä lähdöksi
digitalWrite(osoitebus, LOW); //asetetaan osoiteväylä nollaksi osoittamaan LSB 8-bitin latchiä
digitalWrite(kellobus, LOW); //asetetaan kelloväylä nollaksi
delayMicroseconds(2); // pieni viive että väylä ehtii asettua
digitalWrite(kellobus, HIGH); //Kelloväylä ylös jolloin nollat kirjoittuvat Portista B latch piiriin
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, LOW); //kelloväylä alas
digitalWrite(osoitebus, HIGH); //Osoiteväylä osoittamaan MSB 8-bitin latchia
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, HIGH); //Kelloväylä ylös jolloin nollat kirjoittuvat latch piiriin
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, LOW); //Kelloväylä alas
digitalWrite(osoitebus, LOW); //Osoiteväylä takaisin alas osoittamaan LSB 8-bitin latchiä
}

// MIDIn nuottiarvon mukaan taulukosta noudettu jännitearvo muutetaan kahdeksi 6 bittiseksi tavuksi jotka syötetään D/A muuntimelle ja saadaan 12 bittinen jännitearvo.

void loop(){

do{
if (Serial.available()) //tutkitaan onko midiviestiä tulossa
{
MIDIcomm = Serial.read();//Luetaan komentotavu
MIDInote = Serial.read();//Luetaan nuottitavu
MIDIvelo = Serial.read();//Luetaan voimakkuustavu
}
}
while (Serial.available() > 2);//when at least three bytes available

int dataSana=janniteData[MIDInote]; //hae taulukosta (jannitedata) nuottia (MIDInote) vastaava jännitearvo 12-bitin sanana

byte tavu1 = dataSana; //haetaan muuttujaan tavu1 kahdeksan vähiten merkitsevää bittiä muuttujasta sana, esim. 110011010101 -> 11010101
// Nollataan 8 bitin tavusta kaksi eniten merkitsevää bittiä jotka kuuluvat seuraavaan tavuun niin saadaan ensimmäinen 6-bitin tavu
bitClear(tavu1,6); //nollataan toiseksi eniten merkitsevä bitti -> 10010101
bitClear(tavu1,7); //nollataan eniten merkitsevä bitti -> tavu1 -> 00010101
byte tavu2 = (dataSana >>6); //Siirretään eniten merkitsevät 6 bittiä sanasta vähiten merkitsevien paikalle ja tallennetaan tavu muuttujaan tavu2 -> 110011010101 -> 00110011

// Kirjoitetaan tavu1 LSB latchiin

PORTB = tavu1; //kirjoitetaan 6 bittiä tavu1:sta porttiin B, Digitaalipinnit 8-13 00010101 --> 010101
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, HIGH); //Kelloväylä ylös jolloin tavu1 kirjoittuu Portista B LSB latch piiriin
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, LOW); //kelloväylä alas

// Kirjoitetaan tavu2 MSB latchiin
digitalWrite(osoitebus, HIGH); //asetetaan osoiteväylä nollaksi osoittamaan MSB 8-bitin latchiä
PORTB = tavu2; //Kirjoitetaan 6 bittiä tavu2:sta porttiin B, 00110011 --> 110011
delayMicroseconds(2); // pieni viive että väylä ehtii asettua
digitalWrite(kellobus, HIGH); //Kelloväylä ylös jolloin tavu2 kirjoittuu Portista B latch piiriin
delayMicroseconds(2); //pieni viive
digitalWrite(kellobus, LOW); //kelloväylä alas
digitalWrite(osoitebus, LOW); //asetetaan osoiteväylä takaisin nollaksi osoittamaan LSB 8-bitin latchiä

}

Pääsin jo alkuun rakentelussa. Kovin siistiähän ei jälki ole mutta muuten ei kaikki tarvittava mahdu millään tuohon levylle :nerd:
Mittauksissa kaikki toimii tähän asti :wink:
Piiri kerrallaan paikoilleen ja mittaus…