Sie sind auf Seite 1von 21

Kai Aras - Matrikel Nr.

18464 – Medieninformatik – SS08

Projektdokumenta
tion
Betreuender Professor: Prof. Walter Kriha

AlgoRythm - Mikrocontroller basierter Audio


Synthesizer
Inhaltsverzeichnis
Inhaltsverzeichnis....................................................................................................................2
Projektbeschreibung...............................................................................................................3
Motivation / Ziele.....................................................................................................................4
Konzept...................................................................................................................................5
Synthesizer..........................................................................................................................5
Klangerzeuger (DDS)..........................................................................................................6
Sequenzer...........................................................................................................................7
Hardware................................................................................................................................9
Digitaler Schaltungsteil........................................................................................................9
Verwendete Hardware.....................................................................................................9
Blockdiagramm..............................................................................................................10
Analoger Schaltungsteil.....................................................................................................10
Software................................................................................................................................11
Klangerzeugung................................................................................................................11
Abstrakt..........................................................................................................................11
Direkt Digitale Synthese.................................................................................................11
Definitionen....................................................................................................................11
Globale Variablen...........................................................................................................12
Interrupt Service Routine (ISR)......................................................................................13
Blockdiagramm..............................................................................................................13
Sequenzer ........................................................................................................................14
Abstrakt..........................................................................................................................14
Definitionen ...................................................................................................................15
Globale Variablen...........................................................................................................16
Intterupt Service Routine................................................................................................17
Blockdiagramm..............................................................................................................18
Probleme ..............................................................................................................................19
Fazit .....................................................................................................................................19
Quellen..................................................................................................................................20
Anhänge................................................................................................................................20

Seite |2
Projektbeschreibung
„Es soll ein hybrider Audio Synthesizer auf Basis eines einfachen "low-cost"
Mikrocontrollers gebaut werden.

Zur Klangerzeugung soll das Verfahren der "Direkt digitalen Synthese" verwendet
werden.

Als Hardware- Platform dienen zwei 8Bit- Atmel AVR Mikrocontroller, die mittels
freiem C-Compiler "avr-gcc" komplett in "C" programmiert werden kann.

Das vom AVR digital erzeugte Signal soll anschließend durch ein analoges
"multimode" Filter geformt werden können.

Als kleines Highlight sollen verschiedene algorithmische kompositions hilfen


implementiert werden, die es dem Benutzer ermöglichen sollen auf "andere" art und
Weise Musik zu kreieren als gewohnt.

Das Gerät soll vom funktionalen Umfang her mit kleineren kommerziellen Synthesizern
mithalten können, allerdings soll vor allem auf die Grundsätze "low-cost" und "low-parts"
großen wert gelegt werden.

Unter anderem sollte das Instrument folgendes bieten:

- zwei digitale Oszillatoren mit versch. Wellenformen ( Sinus, Square, Sawtooth +


Userdefined )

- ein analoges multimode Filter

- ein kleiner interner Sequencer

- einfache midi Implementierung

- verschiedene algorithmische Kompositionshilfen

- evtl. verschiedene digitale Effekte

Während der Entwicklung bekam ich jedoch schnell Lust auf „mehr“, so beschloss ich den
analogen Schaltungsteil um einen spannungsgesteuerten Verstärker, sowie zwei 4- stufige
Hüllkurven zu erweitern. Der Digitalteil wurde um einen Niederfrequenzoszillator (LFO)
erweitert, und das Sequenzermodul bekam eine 8x8 LED-Matrix zur Bedienung verpasst.
Alles in allem bietet das Gerät jetzt folgendes:

- zwei digitale Oszillatoren mit versch. Wellenformen ( Sinus, Square, Sawtooth +


Noise )

- ein digitaler LFO mit versch. Wellenformen ( Sinus, Square, Sawtooth + Noise )

- ein analoges multimode Filter

- ein analoger spannungsgesteuerter Verstärker (VCA)

- zwei analoge 4-stufige Hüllkurven (ADSR)

Seite |3
- 8x8 LED-Matrix-Sequenzer mit diversen algorithmischen Kompositionshilfen und
modi

Motivation / Ziele
Motiviert einen Synthesizer zu bauen haben mich verschiedene Dinge, zum einen bin ich
selbst begeisterter elektronischer Musiker, zum anderen liebe ich aber auch die
Softwareentwicklung. Da dies ganz gut Hand- in Hand mit einander geht war schnell klar,
dass ein Audioprojekt her muss. Zunächst wollte ich dies komplett in Software realisieren bis
ich zufällig über einen Podcast auf das Thema Mikrocontroller gestoßen bin, was mich
wiederum dazu bewegt hat mich intensiver mit dieser Materie auseinander zu setzen.

Obwohl ich zu diesem Punkt kaum Verständnis für Elektrontechnik mitbrachte, fand ich
schnell Spaß am löten, basteln und experimentieren. Natürlich wollte ich auch hier meine
Begeisterung für Audiotechnik einbringen und so versuchte ich auf unterschiedlichen Wegen
Klänge mit Hilfe eines Mikrocontrollers zu erzeugen. Überraschender weise ließen erste
Ergebnisse nicht lange auf sich warten und die Idee vom „billig- selbstbau- Synthi“ war
geboren.

Damals motivierte mich vor allem die Herausforderung ein Instrument vom ersten IC bis hin
zur Frontplattengestaltung selbst nach eigenen Vorstellen zu Entwickeln, bzw. die Kunst zu
erlernen die einen erst befähigt dies zu tun.

Auf den Punkt gebracht waren meine Ziele also:

- Verstehen und Realisieren der Direkt digitalen Synthese

- Wissen rund um Elektronik erweitern

- Wissen im Bereich hardwarenahe Softwareentwicklung sammeln

- Eigene Ideen umsetzen, bzw. Erfahrung sammeln um dies tun zu können

- Erschaffen eines ernsthaften Instruments

Seite |4
Konzept
Synthesizer
Folgende Grafik soll den Aufbau des Synthesizers und das Zusammenspiel von Digital- und
Analogtechnik verdeutlichen.

Sequenzer

Digital Hüllkurven Hüllkurven Analog


Generator Generator

Wie
man
der
oben Grafik entnehmen kann, besteht der digitale Teil des Gesammtsystems aus:

1. Der Klangerzeugung, realisiert in Form von 3 Oszillatoren die unabhängig von


einander Sinus, Rechteck, Sägezahn und Rauschen erzeugen können.

2. Dem Sequenzer, der Komposition von Sequenzen erlaubt, und über eine 8x8 LED-
Matrix bedien bar ist.

Der analoge Teil des Systems leistet folgendes zur Formung des Signals:

1. Ein aktives analoges multimode Filter

2. Ein analoger „Verstärker“, um Lautstärkeverläufe oder Tastenanschläge zu simulieren

3. Zwei Hüllkurven Generatoren, welche Steuerspannungen erzeugen, die wiederum


Filter und VCA beeinflussen, bzw. steuern können

Seite |5
Klangerzeuger (DDS)
Zur Klangerzeugung wurde hier das Verfahren der Direkt Digitalen Synthese implementiert.
Im Folgenden möchte ich dieses Verfahren kurz erläutern.

Ein Direkt Digitaler Synthesizer besteht mindestens aus den folgenden Bausteinen:

- Einem festen Systemtakt, der Abtastfrequenz oder eng. Samplerate

- Einer Tabelle welche eine Periode der zu erzeugenden Wellenform(en) enthält,


einem so genannten Look up Table (LuT)

- Einem Phasenakkumulator zur Adressierung des LuT

- Einem Digital-Analogwandler oder eng. DAC

- Einem Tiefpassfilter zur Glättung des Ausgangssignals

Siehe nachfolgende Grafik.

Digitale Phasenwerte Abtastwerte aus LuT Quantisiertes Signal Digital erzeugte Wellenform

Analoges
Tuningword Ausgangsignal

Abtastfrequenz

1. Tuningword
Das Tuningword ist ein Binärwort, welches dem Phasenakkumulator zugeführt wird
um ein Ausganssignal in einer bestimmten Frequenz zu erzeugen.

2. Phasenakkumulator
Hier wird bei jedem Systemtakt der neue Phasenwert des zu erzeugenden
Abtastwertes bestimmt. Wird der Phasenakkumulator getaktet läuft die Funktion:

ab.

3. Phase Truncation
Das Ergebnis des Phasenakkumulators, die „neue Phase“ repräsentiert die Adresse

Seite |6
des neuen Abtastwertes innerhalb des Look up Tables.
Da der Phasenakkumulator in der Regel „breiter“ ist als der Adressbereich des Look
up Tables,
( hier z.b. 24bit, während der LuT nur einen Adressbereich von 8bit bietet) wird in der
Phase Truncation die Bitbreite aus dem Phasenakkumulator auf den vom LuT
gegebenen Adressraum angepasst. Man tut dies, indem man die niederwertigen Bit
(LSB) abschneidet und nur die höherwertigen Bit (MSB) zur Adressierung verwendet.

4. Look up Table
im LuT liegt jeweils eine Periode der zu erzeugenden Wellenformen vor.

5. Digital-Analogwandler (DAC)
im DAC wird der momentane Amplitudenwert des aktuellen Abtastwerts erzeugt.

6. Tiefpassfilter
das Tiefpassfilter befreit das erzeugte Analogsignal von unerwünschten
Frequenzkomponenten, erst er stellt die gewünschte Wellenform wieder her.
Hier gilt das Theorem von Nyquist, was im Wesentlichen besagt, dass die
Grenzfrequenz des Filters kleiner oder gleich der halben Taktfrequenz des Systems
gewählt werden sollte.

Sequenzer
Der hier verwendete Sequenzer zeichnet sich vor allem durch seine ungewöhnliche
Bedienung aus. Während herkömmliche Sequenzer meist verlangen jede zu spielende Note
und deren Tonhöhe einzeln zu bestimmen (siehe nachfolgender Grafik), stellt mein Matrix-
Sequenzer bereits einen Pool von miteinander harmonierenden Notenwerten zur Verfügung,
der die Grundlage einer jeden Sequenz darstellt, und so eine vollkommen andere Art des
Komponierens ermöglicht.
Dieser Pool besteht in den meisten Fällen aus den Notenwerten einer bestimmten Skala,
wie z.B. der wohl bekannten A-Moll Skala, es kann hier neben den Dur- und Mollskalen aus
jeder beliebigen Kirchentonart beginnend mit jedem beliebigen Grundton gewählt werden.
Zusätzlich stehen in Abhängigkeit der jeweiligen Tonart eine Vielzahl von Akkorden und
Kadenzen zur Verfügung, um die der Notenpool erweitertet oder dezimiert werden kann.

Die Komposition von Sequenzen erfolgt durch das Setzen sogenannter Events, die entweder
einen Tastenaschlag auslösen, oder einen Wechsel der Tonart, des Grundtons oder des
Akkords… bewirken können. Man tut dies, indem man durch betätigen der Taster für die
jeweilige Zeile und Reihe, das einzelne Element der Matrix auswählt, von dem ein Event
ausgelöst werden soll. Visualisiert wird ein aktiver Event durch das „einschalten“ des LEDs,
welches das jeweilige Element repräsentiert.

Der Notenpool und aktive Events stehen, anders als beim herkömmlichen Sequenzer, in
keinem fest definierten Verhältnis zueinander, sondern können sich wie folgt verhalten:

- Der Pool kann auf unterschiedliche Weise mit den Zeilen und Spalten der Matrix
verknüpft werden.

- Die Matrix kann auf unterschiedliche Weise durchlaufen werden.

Seite |7
- Events können von diversen Algorithmen automatisch generiert oder alteriert
werden.

Nachfolgende Grafik soll den Unterschied zwischen diesen Beiden Modellen deutlich
machen.

Herkömmlicher Sequenzer Tonhöhe

(AN), wenn
Note gesetzt
Legende
Poti
Note setzen
LED

1 2 3 4 5 6 7 8 Taster

8 x Einzelnoten = 1 Takt Tonhöhe der einzelnen


Noten liegen im Pool bereit
Matrix Sequenzer
und werden auf die Matrix
abgebildet.

Takte oder Einzelnoten

(AN), wenn
Note gesetzt Legende

LED

Taster

Note setzen
Tak
te
ode
r
Ein
zel
not
en

Seite |8
Hardware
Digitaler Schaltungsteil
Verwendete Hardware
Als Hardwareplatform zur Realisierung des Projekts, wurden zwei 8Bit Mikrocontroller der
Firma Atmel verwendet:

1. AVR#1 - Atmel AVR 8Bit RISC Atmega 8

- 8kb Flashspeicher

- 1kb SRAM

- 16Mhz

- 3x Timer

- 3x PWM

- 6x ADC

Dient als Klangerzeuger und implementiert die Direkt digitale Synthese

2. AVR#2 - Atmel AVR 8Bit RISC Atmega 32

- 32kb Flashspeicher

- 2kb SRAM

- 16Mhz

- 3x Timer

- 4x PWM

- 8x ADC

Dient als Sequenzer und steuert den Klangerzeuger

ISP: Als Programmieradapter kam eine einfache Selbstbaulösung zum Zug, (Link siehe
Quellenverzeichnis) welche es durch lediglich 4 Widerständen erlaubt sämtliche 8Bit AVRs
über den LPT Port zu programmieren.

IDE: Als Programmierumgebung wurde das von Atmel stammende AVR-Studio zusammen
mit dem freien C-Compiler avr-gcc verwendet.

Seite |9
Blockdiagramm

CV to Pitch
conversion

LuT ADC DAC


Sinus LuT
Rechteck
AtMega8
… AtMega32

DDS DAC
Sequen
zer

UI UI
Tiefpass-

Filter

Analoger-
LED-
Taster LEDs Taster
Schaltungs Matrix
teil
Klangerzeuger Sequenzer

Analoger Schaltungsteil
Auf die theoretische Funktionsweise der analogen Schaltungsteile: Filter, Verstärker und
Hüllkurven wird hier nicht weiter eingegangen, da dies den Rahmen dieser Arbeit sprengen
würde. Alle analogen Schaltungen die hier verwendet wurden stammen aus selbstbau-
Modularsystemen und wurden lediglich nachgebaut. Quellen hierfür sind im Anhang verlinkt.

Trotzdem mir keine Zeit blieb mich ausgiebig mit dieser Thematik zu befassen, war es mir
doch sehr wichtig zumindest mal so etwas gebaut zu haben, wodurch ich letztendlich auch
unglaublich viel über analoge Schaltungstechnik und Elektronik allgemein gelernt habe.

S e i t e | 10
Software
Klangerzeugung
Abstrakt
Der Softwareteil der Klangerzeugung besteht im Wesentlichen aus 3 Teilen:

1. Programm- und I/O Initialisierungen

2. Endlosschleife innerhalb der Main Methode

a. Benutzer- I/O überprüfen, und aktualisieren

3. Interrupt Service Routine (ISR)

a. Tonhöhe vom ADC lesen und aktualisieren

b. DDS ausführen

c. Neuen Abtastwert auf DAC schreiben

Direkt Digitale Synthese


Die DDS ist wie folgt implementiert:

- Abtastrate = Interruptperiode generiert durch Timer0 Overflow Interrupt

- Phasenakkumulator = 24bit Integer Variable OSCx_PhaseAccu

- Phase Truncation = 16bit rechts shift des Phasenakkumulators

- Look Up Table = 8bit integer Array, abgelegt im Programmspeicher

- DAC = Pulsweitenmodulation durch Timer1 / Timer2

- Tuningword = 32bit integer Array mit Tuningwords für den Gesamten


Notenumfang (C0-C9)

Definitionen

#define F_CPU 16000000UL


Definiert den Prozessortakt mit 16Mhz
#define PINOUT_OSC2 PB1
Ausgabepin des zweiten Oszillators
#define PINOUT_OSC1 PB2
Ausgabepin des ersten Oszillators
#define PINOUT_LFO PB3
Ausgabepin des Niederfrequenzoszillators
#define OSC1_WAVELED_DATA PD5
Datenpin des Schieberegisters zur Visualisierung der ausgewählten Wellenform am
Bedienfeld des ersten Oszillators
#define OSC2_WAVELED_DATA PB4

S e i t e | 11
Datenpin des Schieberegisters zur Visualisierung der ausgewählten Wellenform am
Bedienfeld des zweiten Oszillators
#define LFO_WAVELED_DATA PD6
Datenpin des Schieberegisters zur Visualisierung der ausgewählten Wellenform am
Bedienfeld des Niederfrequenzoszillators
#define ALL_WAVELED_MR PB0
Master-Resetpin des Schieberegisters zur Visualisierung der ausgewählten
Wellenform an allen Bedienfeldern
#define ALL_WAVELED_CLK PD7
Clockpin des Schieberegisters zur Visualisierung der ausgewählten Wellenform an
allen Bedienfeldern
#define OSC1_WAVE_SELECT_BTN PD1
Eingabepin des Tasters zur Auswahl der Wellenform des ersten Oszillators
#define OSC1_OCTAVE_SELECT_BTN
Eingabepin des Tasters zur Auswahl der Oktave des ersten Oszillators
#define OSC2_WAVE_SELECT_BTN PD2
Eingabepin des Tasters zur Auswahl der Wellenform des zweiten Oszillators
#define OSC2_OCTAVE_SELECT_BTN PD3
Eingabepin des Tasters zur Auswahl der Oktave des zweiten Oszillators
#define LFO_WAVE_SELECT_BTN PD4
Eingabepin des Tasters zur Auswahl der Wellenform des Niederfrequenzoszillators
#define LFO_FREQ_POT PC5
Analogeingang – Frequenz- Potentiometer des Niederfrequenzoszillators
#define OSC1_DETUNE_POT PC4
Analogeingang – Detune- Potentiometer des ersten Oszillators
#define OSC2_DETUNE_POT PC3
Analogeingang – Detune- Potentiometer des zweiten Oszillators
#define CV_PITCH_IN PC2
Analogeingang – Tonhöhe des ersten Oszillators
#define CV_PITCH_IN2 PC1
Analogeingang – Tonhöhe des zweiten Oszillators

Globale Variablen
volatile uint16_t isr_counter=0;
Countervariable, wird mit jeder Interruptperiode imkrementiert
volatile uint16_t ms_counter=0;
Countervariable, wird jede Millisekunde inkermentiert
volatile uint8_t OSC_gate =0;
Statusvariable,
volatile uint8_t OSC1_currentNote=0;
Aktueller Notenwert des ersten Oszillators
volatile uint8_t OSC2_currentNote=0;
Aktueller Notenwert des ersten Oszillators
volatile uint16_t LFO_currentFreq=0;
Aktuelle Ausgabefrequenz des Niederfrequenzoszillators
volatile uint8_t OSC1_octave=0;
Statusvariable, dient als index von OCTAVE_SELECT[]
volatile uint8_t OSC2_octave=0;
Statusvariable, dient als index von OCTAVE_SELECT[]
volatile uint16_t OSC1_detune=0;
Aktueller Verstimmungswert des ersten Oszillators
volatile uint16_t OSC2_detune=0;
Aktueller Verstimmungswert des zweiten Oszillators
volatile uint8_t OSC1_Wave=0;

S e i t e | 12
Statusvariable, dient als index von WAVEFORMS[]
volatile uint8_t OSC2_Wave=0;
Statusvariable, dient als index von WAVEFORMS[]
volatile uint8_t LFO_Wave=0;
Statusvariable, dient als index von WAVEFORMS[]
uint32_t OSC_calibration_offset=0;
Offset zur Korrektur der Ausgangsfrequenz
const uint8_t WAVE_SELECT[4] = {1,2,4,8 };
Array mit Konstanten für die Wellenformauswahl
const uint8_t OCTAVE_SELECT[3] = { 64, 32, 16 };
Array mit Konstanten für Oktaven- Umschaltung
const uint8_t *WAVEFORMS[4] = {sinewave,sawtoothwave,squarewave,
userwave};
Array mit Zeigern auf die hinterlegten Look Up Tables

Interrupt Service Routine (ISR)


Die Interruptperiode der ISR stellt die Abtastrate des Systems dar. Diese wurde hier auf
32khz festgelegt, was nach Nyquist erlaubt ein Signal mit bis zu 16khz erzeugen zu können.
Ausgelöst wird die ISR durch einen Overflow Interrupt in Timer0.
Timer0 ist ein 8Bit Counter und wird alle 8- Systemtakte inkrementiert, erreicht der Counter
einen bestimmten Compare-Match Wert (hier 192) , wird er zurückgesetzt und ein Overflow
Interrupt ausgelöst.

Zur Berechnung der Timereinstellungen ist im Anhang ein Excel Sheet verlinkt.

While(1) { init() {
Blockdiagramm
Programminitialisierun
int main (void) { - Initialize I/O Ports
g
- Initialize Timer0 (samplefreq.)
setLEDS(…) {{
checkPots()
- Initialize Timer1 (DAC 1+2)
S e i t e | 13
} Includes - }Check
Initialize
Input
Timer2
pins(DAC 3)
- }Read display-values
Write ADCs and update to
checkButtons()
checkPots()
setLEDS(…)
Init()
- shiftregisters
global
Switch
Enablevariables
Modes
global Interrupts
Defines
Globale

Variable
n
checkButtons() {

ISR(TIMER0_OVF_vect) {

- Increment isr_counter

- Synchronize ms_counter

- Read Pitch from ADC

- run the DDS and output new


} value to DAC

Sequenzer
Abstrakt
Der Softwareteil des Sequenzers besteht im Wesentlichen aus folgenden Bestandteilen:

1. Programm und I/O Initialisierungen

S e i t e | 14
2. Endlosschleife innerhalb der Main() Funktion

a. Durchlaufen der Matrix

b. Analoge Hüllkurven triggern falls aktuelles Element aktiv ist

c. Taster zur Matrixsteuerung überprüfen und Änderungen Ausführen

3. ISR 1 (Timer0 Overflow Interrupt)

a. Steuerspannung für Synthmodul erzeugen

4. ISR 2 (Timer2 Overflow Interrupt)

a. Timing ableiten

b. Taster überprüfen und Änderungen ausführen

c. LED-Matrix anzeigen

Definitionen
#define LED_MATRIX_DATA1 PD2
Datenleitung des ersten Schieberegisters zur Steuerung der LED Matrix
#define LED_MATRIX_DATA2 PD3
Datenleitung des zweiten Schieberegisters zur Steuerung der LED Matrix
#define LED_MATRIX_MR PD7
Master- Resetpin der Schieberegister
#define LED_MATRIX_CLK PD6
Clockleitung der Schieberegister
#define BUTTON_ROW PA0
Analogeingang – 8 Taster zur Reihenwahl der Matrix
#define BUTTON_COL PA1
Analogeingang – 8 Taster zu Zeilenwahl der Matrix
#define CV_PITCH_OUT1 PD4
PWM Ausgang #1
#define CV_PITCH_OUT2 PD5
PWM Ausgang #2
#define CV_GATE_OUT1 PC0
Gate Ausgang zum triggern der analogen Hüllkurven
#define CV_GATE_OUT2 PC1
Gate Ausgang zum triggern der analogen Hüllkurven
#define LED_COL1_DATA PC6
Datenleitung Schieberegister #3
#define LED_COL2_DATA PC7
Datenleitung Schieberegister #4
#define BUTTON_LEFT0 PB4
Eingang Taster #1
#define BUTTON_RIGHT0 PD0
Eingang Taster #2
#define BUTTON_RIGHT1 PB3
Eingang Taster #3
#define BUTTON_RIGHT2 PD1
Eingang Taster #4

S e i t e | 15
Globale Variablen
uint8_t const MOD_REF_MATRIX[8] = …
Referenzwerte für Sequenzmodulation
uint16_t const RES_REF[8] = …
Referenzwerte für Modulation der Sequenzauflösung
volatile uint8_t LED_MatrixA[8][8] = {};
8x8 Array – repräsentiert die 8x8 LED Matrix
volatile uint8_t LED_MatrixB[8][8] = {};
8x8 Array – Puffer
volatile uint8_t LED_runMatrix[8][8] = { };

uint8_t LED_ROW_left =0;


Anzeigewert LED Reihe auf Benutzeroberfläche
uint8_t LED_ROW_right1 =0;
Anzeigewert LED Reihe auf Benutzeroberfläche
uint8_t LED_ROW_right2 =0;
Anzeigewert LED Reihe auf Benutzeroberfläche
volatile uint16_t ms_counter=0;
Zählervariable, von ihr wird das globale Timing abgeleitet
volatile uint16_t step_counter=0;
Zählervariable der Steps
volatile uint16_t bar_counter=0;
Zählervariable der Takte
uint8_t mod_counter=16;
Zählervariable – gibt an wann moduliert warden soll
uint8_t seq_direction=0;
Laufrichtung des Sequenzers, vertical/horizontal
volatile uint8_t CV1_currentPitch=0;
Tonhöhe des ersten Oszillators
volatile uint8_t CV2_currentPitch=0;
Tonhöhe des zweiten Oszillators
volatile uint8_t currentNote=0;
Tonhöhe des Sequenzers
volatile uint8_t currentScale[28]={0,0,0,0,0,0,0,0};
Hält die aktive Skala
volatile uint8_t currentChord[3]= {0,2,4};
Hält den aktiven Akkord
volatile uint8_t currentChordBaseNote=0;
Hält den aktiven Grundton
volatile uint8_t currentMode=0;
Hält den aktiven Sequenzermodus
uint8_t RES_counter=125;
Aktuelle Auflösung des Sequenzers
volatile uint8_t currentPitchSrc=0;
Aktive Quelle für Tonhöheninformation
volatile uint8_t *currentLEDMatrix= &LED_MatrixA[0][0];
Zeiger auf aktive Matrix
volatile uint8_t currentCadence[4] = { 0, 3,4,7 };
Hält die aktive Kadenz
volatile uint8_t majorScale[28] = …
Hält die C-Dur Skala als Grundlage für die Generierung weitererer
volatile uint8_t currentSequence[64 = …]
Hält die aktuelle Sequenz

S e i t e | 16
Intterupt Service Routine
Der Sequenzer arbeitet mit zwei Interrupt Service Routinen:

1. ISR1 Timer0 Overflow Interrupt


dieser Interrupt taktet, genau wie beim Synthesizer- Modul den DAC, der in
diesem Fall jedoch kein Audio-, sondern ein Steuerspannungssignal (CV) erzeugt.
Dieses Signal enthält die Tonhöheninformationen des Sequenzers und wird dem
Synthesizer zugeführt, der es wiederum digitalisiert und die entsprechende
Tonhöhe ausliest.

2. ISR 2 Timer2 Overflow Interrupt


die Interruptperiode von Timer2 beträgt 1ms, von ihr wird das Timing des
Sequenzers abgeleitet.

S e i t e | 17
Blockdiagramm

init() {
- Initialize I/O Ports
Includes - Initialize Timer0 (samplefreq.)
Programminitialisierun - Initialize Timer1 (DAC 1+2)
g
Defines - Initialize Timer2 (Mux freq.)
Globale }
- Enable global Interrupts
Variable
n checkButtonMatrix() {

- Read ADCs to find out which


Buttons have been pressed

- Update current Matrix


}
Init()

While(1) {
int main (void) {
checkButtonMatrix()
doSeqMode() {
- Switch to current mode
doSeqMode()
- Do the actual sequencing
}
checkStep()
}

checkStep() {
ISR(TIMER0_OVF_vect) { - Check if current step is set

- If it is, trigger Envelope to


}
- Clk DAC and output new CV generate a NoteOn
value
}
ISR(TIMER2_OVF_vect) { checkButtons() {
- Check for User input
- Ms_counter++ - Update states
}
- Sychronize to 100ms
checkButtons()
displayLedMatrix() {
displayLedMatrix()
- Calculate control words for
} shiftregisters
}
- Transfer data in serial
S e i t e | 18
Probleme
Im allgemeinen gab es glücklicherweise kaum bzw. keine größeren Probleme, der
Softwareteil des Projekts verlief größtenteils reibungslos und auch sonst konnte ich fast alle
meine Ziele verwirklichen, einzig allein die Implementierung digitaler Effekte musste ich
streichen, da die Hardwareressourcen der verwendeten Mikrocontroller, insbesondere deren
RAM dafür nicht ausreichend dimensioniert waren.

Fazit
Für mich war dieses Projekt ein voller Erfolg, der Lerneffekt war riesig, noch viel größer als
ich gedacht hätte. Zu Beginn des Projekts konnte noch kaum Widerstand und Kondensator
unterscheiden, geschweige denn Schaltpläne lesen oder gar zeichnen, heute kenne ich
Pinbelegungen auswendig und spreche fast fließend binär 
Das Entwickeln von Software auf unterstem Level und die damit verbundenen Möglichkeiten
haben mich sehr begeistertet und auch bis jetzt nicht losgelassen. Auch wenn dieses Projekt
offiziell hiermit abgeschlossen ist, bleibt noch einiges zu tun, und ich freue mich jetzt schon
daran weiterzuarbeiten und vor allem damit zu „spielen“.

Alles in allem hat dieses Projekt unglaublich viel zu meinem Gesammtverständnis für
Hardwarevorgänge, sowie digitale Audiotechnik, aber auch Elektronik beigetragen und ich
kann nur froh sein meine Zeit in dieses Projekt investiert zu haben.

S e i t e | 19
Quellen
1. Infos rund um AVR und Mikrocontroller

a. http://www.mikrocontroller.net

b. http://www.scienceprog.com

2. Datenblätter und Applicationotes zu den verwendeten Mikrocontrollern

a. www.atmel.com

3. Direkt Digitale Synthese

a. http://en.wikipedia.org/wiki/Direct_digital_synthesis

b. http://www.scienceprog.com/category/avr-controlled-signal-generator/

c. http://www.mikrocontroller.net/articles/Digitaler_Funktionsgenerator

4. AVR Programmieradapter (ISP)

a. http://mikrocontroller.com/de/isp.php

5. AVR Programmierumgebung (IDE)

a. http://www.atmel.com/dyn/Products/tools_card.asp?tool_id=2725

6. AVR C-Compiler (avr-gcc)

a. http://winavr.sourceforge.net/

7. DIY Modular Synth (Analogtechnik)

a. René Schmitz http://www.uni-bonn.de/~uzs159/

b. Yves Usson http://yusynth.net/Modular/index.html

c. Forum http://www.sequencer.de/synthesizer/

8. Schaltpläne (analoger Schaltungsteil)

a. Filter (VCF)
http://yusynth.net/archives/ElectronicDesign/N-Steiner-VCF-1974.pdf

b. Verstärker (VCA)
http://yusynth.net/Modular/index.html

c. Hüllkurven (ADSR)
http://www.uni-bonn.de/~uzs159/

Anhänge
1. Quellcode inkl. Avr-Studio Projekt des Synthesizer Moduls

2. Quellcode inkl. Avr-Studio Projekt des Sequencer Moduls

S e i t e | 20
3. Excel Sheet für sämtliche Berechnungen (Tuningwords, Timer, R/C Filter…)

4. Power Point Präsentation vom Präsentationstag

S e i t e | 21