mirror of
https://github.com/erik-toth/audio-synth.git
synced 2026-04-26 17:44:58 +00:00
Cleaned up Schematics
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
Record=TopLevelDocument|FileName=DAC_MCP4728.SchDoc|SheetNumber=1
|
||||
Record=TopLevelDocument|FileName=DAC_MCP4728.SchDoc|SheetNumber=1
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
SB=SB1.R,SB1.P,SB2.R,SB2.P
|
||||
SB=SB1.R,SB1.P,SB2.R,SB2.P
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
Record=TopLevelDocument|FileName=ESP32-S3.SchDoc|SheetNumber=1
|
||||
Record=TopLevelDocument|FileName=ESP32-S3.SchDoc|SheetNumber=1
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part IC? IC ESP32-S3R8 in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC ESP32-S3R8 from DA_LIB.IntLib
|
||||
Replace Part IC? IC ESP32-S3R8 in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC ESP32-S3R8 from DA_LIB.IntLib
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part IC? IC ESP32-S3R8 in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC ESP32-S3R8 from DA_LIB.IntLib
|
||||
Replace Part IC? IC ESP32-S3R8 in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC ESP32-S3R8 from DA_LIB.IntLib
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part IC? IC W25Q128JVSIQ in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC W25Q128JVSIQ from DA_LIB.IntLib
|
||||
Replace Part IC? IC W25Q128JVSIQ in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with IC W25Q128JVSIQ from DA_LIB.IntLib
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part Y? Y X322540MPB4SI in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with Y X322540MPB4SI from DA_LIB.IntLib
|
||||
Replace Part Y? Y X322540MPB4SI in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\ESP32-S3\ESP32-S3.SchDoc with Y X322540MPB4SI from DA_LIB.IntLib
|
||||
|
||||
File diff suppressed because one or more lines are too long
16
dev/digital/Firmware_TEST/.gitignore
vendored
16
dev/digital/Firmware_TEST/.gitignore
vendored
@@ -1,8 +1,8 @@
|
||||
.pio/libdeps
|
||||
.pio/build/project*
|
||||
.pio/build/esp32-s3-devkitm-1/*
|
||||
!.pio/build/esp32-s3-devkitm-1/firmware.bin
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
.pio/libdeps
|
||||
.pio/build/project*
|
||||
.pio/build/esp32-s3-devkitm-1/*
|
||||
!.pio/build/esp32-s3-devkitm-1/firmware.bin
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"ms-vscode.cpptools-extension-pack"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,456 +1,456 @@
|
||||
# Firmware
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [Projektübersicht](#projektübersicht)
|
||||
2. [Systemarchitektur](#systemarchitektur)
|
||||
3. [Komponenten](#komponenten)
|
||||
4. [Speicheranalyse](#speicheranalyse)
|
||||
5. [Installation](#installation)
|
||||
6. [Verwendung](#verwendung)
|
||||
7. [Hauptablauf](#hauptablauf)
|
||||
|
||||
---
|
||||
|
||||
## Projektübersicht
|
||||
|
||||
### Features
|
||||
|
||||
- ✅ **Dual-Channel CV-Sequencer** - 2 unabhängige Control Voltage Ausgänge
|
||||
- ✅ **4×3 Tastaturmatrix** - Echtzeit-Tasten-Eingabe mit Entprellung
|
||||
- ✅ **Recording & Playback** - Speichere Sequenzen bis 30 Sekunden
|
||||
- ✅ **Loop-Funktion** - Endlose Wiederholung oder Einmaledition
|
||||
- ✅ **Live-Modus** - Direkte Tastatur-zu-CV Ausgabe
|
||||
- ✅ **Multi-Key Support** - Bis zu 10 gleichzeitig aktive Tasten
|
||||
|
||||
### Hardware
|
||||
|
||||
| Komponente | Modell | Funktion |
|
||||
|-----------|--------|---------|
|
||||
| Microcontroller | ESP32 | Hauptprozessor |
|
||||
| DAC | MCP4728 | 4-Kanal 12-Bit DAC |
|
||||
| I2C Bus | - | Kommunikation MCU ↔ DAC |
|
||||
| Tastatur | 4×3 Matrix | Benutzereingabe |
|
||||
| Buttons | 4× Push-Buttons | Record/Play Steuerung |
|
||||
|
||||
---
|
||||
|
||||
## Systemarchitektur
|
||||
|
||||
### 3-Schicht-Modell
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ INPUT LAYER (📥) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ Keyboard Matrix │ Sequencer Buttons │
|
||||
│ (4×3 Tasten) │ (Record/Play × 2) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
┌──────────────▼─────────────────────▼───────────────┐
|
||||
│ PROCESSING LAYER (⚙️) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ Keyboard Klasse │ SequencerBlock (2×) │
|
||||
│ (Queue-Management) │ (Recording & Playback) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
┌──────────────▼─────────────────────▼───────────────┐
|
||||
│ OUTPUT LAYER (📤) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ CV Klasse (DAC) │ CV Ausgänge │
|
||||
│ MCP4728 I2C │ (A=Ch1, B=Ch2) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
└──────────────┬───────┘
|
||||
▼
|
||||
Externe Synthesizer / Module
|
||||
```
|
||||
|
||||
### Datenfluss
|
||||
|
||||
```
|
||||
TASTATUR → KEYBOARD → SEQUENCER/LIVE → DAC → CV AUSGÄNGE
|
||||
↑
|
||||
BUTTONS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Komponenten
|
||||
|
||||
### 1. Keyboard Klasse
|
||||
|
||||
**Funktion:** Verwaltet die 4×3 Matrix-Tastatur mit Entprellung
|
||||
|
||||
```cpp
|
||||
class Keyboard {
|
||||
public:
|
||||
Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol);
|
||||
void begin();
|
||||
void update();
|
||||
int getQueueLength();
|
||||
Key getQueue(uint8_t index);
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- Debounce-Zeit: 20ms
|
||||
- Max. 10 gleichzeitig aktive Tasten
|
||||
- FIFO-Queue für Tastenreihenfolge
|
||||
- Rückmeldung als `Key(row, col)` Struktur
|
||||
|
||||
### 2. CV Klasse
|
||||
|
||||
**Funktion:** Verwaltet DAC-Ausgänge über I2C (MCP4728)
|
||||
|
||||
```cpp
|
||||
class CV {
|
||||
public:
|
||||
CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV,
|
||||
MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage,
|
||||
uint8_t row, uint8_t col);
|
||||
bool begin(uint8_t pinSDA, uint8_t pinSCL);
|
||||
void setVoltage(uint8_t cvIndex, Key k);
|
||||
void setVoltage(uint8_t cvIndex, uint16_t mV);
|
||||
void clearAll();
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- 2 CV-Kanäle (A, B)
|
||||
- I2C-Kommunikation (Pins 15, 16)
|
||||
- Voltage-Mapping von Tasten
|
||||
- Range: 0-4096mV (12-Bit)
|
||||
|
||||
### 3. SequencerBlock Klasse
|
||||
|
||||
**Funktion:** Speichert und spielt Sequenzen auf 2 Kanälen
|
||||
|
||||
```cpp
|
||||
class SequencerBlock {
|
||||
public:
|
||||
SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS);
|
||||
|
||||
// Recording
|
||||
void startRecord();
|
||||
void stopRecord();
|
||||
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||
|
||||
// Playback
|
||||
void startPlay();
|
||||
void stopPlay();
|
||||
void update(); // Must be called regularly
|
||||
void setLoop(bool loop);
|
||||
|
||||
// Status
|
||||
uint8_t getStepCount();
|
||||
uint16_t getCurrentVoltageCh1();
|
||||
uint16_t getCurrentVoltageCh2();
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- Max. 128 Steps pro Sequenz
|
||||
- Max. 30 Sekunden Aufnahmetime
|
||||
- Dual-Channel Recording
|
||||
- Loop-Funktion
|
||||
- Automatisches Time-Limit
|
||||
|
||||
### 4. Button-Verarbeitung
|
||||
|
||||
**3-Mode Play-Button-System:**
|
||||
|
||||
| Click | Aktion | Zustand |
|
||||
|-------|--------|---------|
|
||||
| 1x | Play (kein Loop) | Spielt einmalig ab |
|
||||
| 2x | Loop aktivieren | Endlosschleife |
|
||||
| 3x | Stop | Stoppt Wiedergabe |
|
||||
|
||||
**Record-Button:** Toggle zwischen Recording starten/stoppen
|
||||
|
||||
---
|
||||
|
||||
## Speicheranalyse
|
||||
```bash
|
||||
RAM: [= ] 6.5% (used 21176 bytes from 327680 bytes)
|
||||
Flash: [= ] 8.5% (used 283165 bytes from 3342336 bytes)
|
||||
```
|
||||
### RAM-Verbrauch
|
||||
|
||||
| Komponente | Größe | Menge | Gesamt | Notizen |
|
||||
|-----------|-------|-------|--------|---------|
|
||||
| SequencerBlock #1 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||
| SequencerBlock #2 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||
| Keyboard Objekt | ~130 B | 1x | 130 B | 8×8 Bool Arrays + Pointer |
|
||||
| CV Objekt | ~50 B | 1x | 50 B | DAC-Pointer + Config |
|
||||
| keyToVoltage Array | 24 B | 1x | 24 B | 12 Keys × uint16_t |
|
||||
| Button States | ~50 B | 1x | 50 B | 4 Buttons × ~12 Bytes |
|
||||
| Lokale Variablen | ~100 B | 1x | 100 B | Loop-Variablen |
|
||||
| **GESAMT (Schätzung)** | - | - | **~1.5 KB** | - |
|
||||
|
||||
### Flash-Verbrauch
|
||||
|
||||
| Komponente | Größe |
|
||||
|-----------|-------|
|
||||
| Arduino/Wire Libraries | ~150 KB |
|
||||
| Adafruit_MCP4728 | ~20 KB |
|
||||
| Firmware Code | ~80 KB |
|
||||
| Bootloader | ~60 KB |
|
||||
| **GESAMT (Schätzung)** | **~310 KB** |
|
||||
|
||||
|
||||
### Sequenzen-Speicher Detail
|
||||
|
||||
```cpp
|
||||
struct DualVoltageDurationPair {
|
||||
uint16_t voltage_ch1; // 2 Bytes
|
||||
uint16_t voltage_ch2; // 2 Bytes
|
||||
uint16_t duration; // 2 Bytes
|
||||
}; // = 6 Bytes pro Step
|
||||
|
||||
// Berechnung:
|
||||
// - N_MAX_SEQUENCE_STEPS = 128
|
||||
// - 128 Steps × 6 Bytes = 768 Bytes pro Sequenz
|
||||
// - 2 Sequenzer = 1536 Bytes (1.5 KB)
|
||||
```
|
||||
|
||||
### Optimierungspotential
|
||||
|
||||
| Feature | Größenänderung | Status |
|
||||
|---------|-----------------|--------|
|
||||
| 256 Steps statt 128 | +768 B | ✅ Problemlos möglich |
|
||||
| 60s statt 30s Limit | 0 B | ✅ Kostenloses Upgrade |
|
||||
| 4 Sequenzer statt 2 | +3.3 KB | ✅ Problemlos möglich |
|
||||
| 8×8 Tastatur statt 4×3 | ~ +30 B | ✅ Kaum Mehraufwand |
|
||||
|
||||
---
|
||||
|
||||
## Verwendung
|
||||
|
||||
### Grundlegende Konfiguration
|
||||
|
||||
`include/FIRMWARE_DEF.h`:
|
||||
|
||||
```cpp
|
||||
#define N_KEYBOARD_ROW 4 // Keyboard Reihen
|
||||
#define N_KEYBOARD_COL 3 // Keyboard Spalten
|
||||
#define N_CV_GATES 2 // CV-Ausgänge
|
||||
#define N_SB 2 // Sequencer
|
||||
|
||||
// I2C Pins
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
|
||||
// Keyboard Pins (Reihen)
|
||||
#define PIN_K_R0 7
|
||||
#define PIN_K_R1 8
|
||||
#define PIN_K_R2 9
|
||||
#define PIN_K_R3 10
|
||||
|
||||
// Keyboard Pins (Spalten)
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
```
|
||||
|
||||
### Spannung-Mapping
|
||||
|
||||
`src/main.cpp`:
|
||||
|
||||
```cpp
|
||||
// Voltage für jede Tastaturposition (in 1/12V = 83mV Schritten = 1 Halbtonschritt)
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83, // Row 0: C, E, G
|
||||
2*83, 6*83, 10*83, // Row 1: D, F, A
|
||||
3*83, 7*83, 11*83, // Row 2: E, G, B
|
||||
4*83, 8*83, 12*83 // Row 3: F, A, C (Oktave)
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hauptablauf
|
||||
|
||||
### Main Loop Flowchart
|
||||
|
||||
```
|
||||
START
|
||||
↓
|
||||
SETUP (Initialisierung)
|
||||
↓
|
||||
┌─── MAIN LOOP ───────────────────────┐
|
||||
│ │
|
||||
├─ Keyboard Update │
|
||||
│ (Tasten auslesen) │
|
||||
│ │
|
||||
├─ Button Handler │
|
||||
│ (Record/Play Buttons) │
|
||||
│ │
|
||||
├─ Sequencer Update │
|
||||
│ (sb1 & sb2 Playback) │
|
||||
│ │
|
||||
├─ Spannungen bestimmen │
|
||||
│ voltage_ch1 = Queue[0] │
|
||||
│ voltage_ch2 = Queue[1] │
|
||||
│ │
|
||||
├─ Recording Check │
|
||||
│ IF Recording: addStep() │
|
||||
│ │
|
||||
├─ Output Priority │
|
||||
│ IF sb1.playing() → Output SEQ1 │
|
||||
│ ELSE IF sb2.playing() → Output SEQ2│
|
||||
│ ELSE → Output Live │
|
||||
│ │
|
||||
├─ Time-Limit Check │
|
||||
│ IF Limit reached: Stop Record │
|
||||
│ │
|
||||
├─ Delay 10ms │
|
||||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
[Loop zurück]
|
||||
```
|
||||
|
||||
### State Machine
|
||||
|
||||
| State | Beschreibung | Aktion |
|
||||
|-------|-------------|--------|
|
||||
| **IDLE** | Leerlauf | Liest Tasten, gibt Live-Spannungen aus |
|
||||
| **REC** | Recording aktiv | Speichert Sequenzen, überwacht Zeit-Limits |
|
||||
| **PLAY** | Playback aktiv | Gibt Sequenzen aus, verwaltet Step-Übergänge |
|
||||
| **LOOP** | Endlosschleife | Wiederholt Sequenz nahtlos |
|
||||
|
||||
### Ausgabe-Prioritätssystem
|
||||
|
||||
```
|
||||
1. Sequencer 1 Playing?
|
||||
├─ JA → Gebe SEQ1 Voltages aus (höchste Priorität)
|
||||
└─ NEIN ↓
|
||||
|
||||
2. Sequencer 2 Playing?
|
||||
├─ JA → Gebe SEQ2 Voltages aus (zweite Priorität)
|
||||
└─ NEIN ↓
|
||||
|
||||
3. Live Input
|
||||
└─ Gebe Tasten-Voltages aus (Standard)
|
||||
```
|
||||
|
||||
Dies ermöglicht nahtlose Übergänge und verhindert Konflikte.
|
||||
|
||||
---
|
||||
|
||||
## Code-Beispiele
|
||||
|
||||
### Beispiel 1: Live-Modus (main.cpp.1)
|
||||
|
||||
Direkte Tastatur-zu-CV Verbindung ohne Sequencer:
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0) {
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++) {
|
||||
Key k = keyboard.getQueue(i);
|
||||
cv.setVoltage(i, k); // Taste direkt auf CV ausgeben
|
||||
}
|
||||
} else {
|
||||
cv.clearAll(); // Keine Taste → 0V
|
||||
}
|
||||
|
||||
delay(50);
|
||||
}
|
||||
```
|
||||
|
||||
### Beispiel 2: Dual-Channel Sequencer (main.cpp)
|
||||
|
||||
Vollständiger Sequencer mit 2 unabhängigen Kanälen:
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
keyboard.update();
|
||||
handleSequencerButtons();
|
||||
|
||||
sb1.update();
|
||||
sb2.update();
|
||||
|
||||
// ... Voltage determination ...
|
||||
|
||||
// Recording
|
||||
if(sb1.isRecording()) {
|
||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||
}
|
||||
if(sb2.isRecording()) {
|
||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||
}
|
||||
|
||||
// Output mit Priorität
|
||||
if(sb1.isPlaying()) {
|
||||
cv.setVoltage(0, sb1.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb1.getCurrentVoltageCh2());
|
||||
}
|
||||
else if(sb2.isPlaying()) {
|
||||
cv.setVoltage(0, sb2.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb2.getCurrentVoltageCh2());
|
||||
}
|
||||
else {
|
||||
cv.setVoltage(0, voltage_ch1);
|
||||
cv.setVoltage(1, voltage_ch2);
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
```
|
||||
project/
|
||||
├── include/
|
||||
│ ├── FIRMWARE.h # Klassen-Definitionen
|
||||
│ └── FIRMWARE_DEF.h # Konstanten & Pin-Definitionen
|
||||
│
|
||||
└── src/
|
||||
├── main.cpp # Dual-Channel Sequencer Beispiel
|
||||
├── main.cpp.1 # Live-Modus Beispiel
|
||||
├── main.cpp.2 # Dual-Channel ohne Sequencer
|
||||
└── FIRMWARE.cpp # Implementierungen
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technische Spezifikationen
|
||||
|
||||
### Timings
|
||||
|
||||
| Parameter | Wert | Funktion |
|
||||
|-----------|------|----------|
|
||||
| Keyboard Debounce | 20ms | Anti-Prellen Verzögerung |
|
||||
| Button Debounce | 50ms | Button Anti-Prellen |
|
||||
| Main Loop Delay | 10ms | Update-Rate |
|
||||
| Max Recording | 30s | Zeit-Limit pro Sequenz |
|
||||
| Min Step Duration | 50ms | Minimale Step-Länge |
|
||||
|
||||
### Voltage-Mapping
|
||||
|
||||
Verwendet gleichmäßige 83mV Schritte (1/12 Oktave):
|
||||
|
||||
```
|
||||
Key (1,0) = 1 × 83mV = 83mV (C)
|
||||
Key (1,1) = 5 × 83mV = 415mV (E)
|
||||
Key (1,2) = 9 × 83mV = 747mV (G)
|
||||
... etc
|
||||
Key (4,2) = 12 × 83mV = 996mV (C')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Firmware
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [Projektübersicht](#projektübersicht)
|
||||
2. [Systemarchitektur](#systemarchitektur)
|
||||
3. [Komponenten](#komponenten)
|
||||
4. [Speicheranalyse](#speicheranalyse)
|
||||
5. [Installation](#installation)
|
||||
6. [Verwendung](#verwendung)
|
||||
7. [Hauptablauf](#hauptablauf)
|
||||
|
||||
---
|
||||
|
||||
## Projektübersicht
|
||||
|
||||
### Features
|
||||
|
||||
- ✅ **Dual-Channel CV-Sequencer** - 2 unabhängige Control Voltage Ausgänge
|
||||
- ✅ **4×3 Tastaturmatrix** - Echtzeit-Tasten-Eingabe mit Entprellung
|
||||
- ✅ **Recording & Playback** - Speichere Sequenzen bis 30 Sekunden
|
||||
- ✅ **Loop-Funktion** - Endlose Wiederholung oder Einmaledition
|
||||
- ✅ **Live-Modus** - Direkte Tastatur-zu-CV Ausgabe
|
||||
- ✅ **Multi-Key Support** - Bis zu 10 gleichzeitig aktive Tasten
|
||||
|
||||
### Hardware
|
||||
|
||||
| Komponente | Modell | Funktion |
|
||||
|-----------|--------|---------|
|
||||
| Microcontroller | ESP32 | Hauptprozessor |
|
||||
| DAC | MCP4728 | 4-Kanal 12-Bit DAC |
|
||||
| I2C Bus | - | Kommunikation MCU ↔ DAC |
|
||||
| Tastatur | 4×3 Matrix | Benutzereingabe |
|
||||
| Buttons | 4× Push-Buttons | Record/Play Steuerung |
|
||||
|
||||
---
|
||||
|
||||
## Systemarchitektur
|
||||
|
||||
### 3-Schicht-Modell
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ INPUT LAYER (📥) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ Keyboard Matrix │ Sequencer Buttons │
|
||||
│ (4×3 Tasten) │ (Record/Play × 2) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
┌──────────────▼─────────────────────▼───────────────┐
|
||||
│ PROCESSING LAYER (⚙️) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ Keyboard Klasse │ SequencerBlock (2×) │
|
||||
│ (Queue-Management) │ (Recording & Playback) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
┌──────────────▼─────────────────────▼───────────────┐
|
||||
│ OUTPUT LAYER (📤) │
|
||||
├──────────────────────┬──────────────────────────────┤
|
||||
│ CV Klasse (DAC) │ CV Ausgänge │
|
||||
│ MCP4728 I2C │ (A=Ch1, B=Ch2) │
|
||||
└──────────────┬───────┴──────────────┬───────────────┘
|
||||
│ │
|
||||
└──────────────┬───────┘
|
||||
▼
|
||||
Externe Synthesizer / Module
|
||||
```
|
||||
|
||||
### Datenfluss
|
||||
|
||||
```
|
||||
TASTATUR → KEYBOARD → SEQUENCER/LIVE → DAC → CV AUSGÄNGE
|
||||
↑
|
||||
BUTTONS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Komponenten
|
||||
|
||||
### 1. Keyboard Klasse
|
||||
|
||||
**Funktion:** Verwaltet die 4×3 Matrix-Tastatur mit Entprellung
|
||||
|
||||
```cpp
|
||||
class Keyboard {
|
||||
public:
|
||||
Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol);
|
||||
void begin();
|
||||
void update();
|
||||
int getQueueLength();
|
||||
Key getQueue(uint8_t index);
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- Debounce-Zeit: 20ms
|
||||
- Max. 10 gleichzeitig aktive Tasten
|
||||
- FIFO-Queue für Tastenreihenfolge
|
||||
- Rückmeldung als `Key(row, col)` Struktur
|
||||
|
||||
### 2. CV Klasse
|
||||
|
||||
**Funktion:** Verwaltet DAC-Ausgänge über I2C (MCP4728)
|
||||
|
||||
```cpp
|
||||
class CV {
|
||||
public:
|
||||
CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV,
|
||||
MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage,
|
||||
uint8_t row, uint8_t col);
|
||||
bool begin(uint8_t pinSDA, uint8_t pinSCL);
|
||||
void setVoltage(uint8_t cvIndex, Key k);
|
||||
void setVoltage(uint8_t cvIndex, uint16_t mV);
|
||||
void clearAll();
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- 2 CV-Kanäle (A, B)
|
||||
- I2C-Kommunikation (Pins 15, 16)
|
||||
- Voltage-Mapping von Tasten
|
||||
- Range: 0-4096mV (12-Bit)
|
||||
|
||||
### 3. SequencerBlock Klasse
|
||||
|
||||
**Funktion:** Speichert und spielt Sequenzen auf 2 Kanälen
|
||||
|
||||
```cpp
|
||||
class SequencerBlock {
|
||||
public:
|
||||
SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS);
|
||||
|
||||
// Recording
|
||||
void startRecord();
|
||||
void stopRecord();
|
||||
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||
|
||||
// Playback
|
||||
void startPlay();
|
||||
void stopPlay();
|
||||
void update(); // Must be called regularly
|
||||
void setLoop(bool loop);
|
||||
|
||||
// Status
|
||||
uint8_t getStepCount();
|
||||
uint16_t getCurrentVoltageCh1();
|
||||
uint16_t getCurrentVoltageCh2();
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
**Merkmale:**
|
||||
- Max. 128 Steps pro Sequenz
|
||||
- Max. 30 Sekunden Aufnahmetime
|
||||
- Dual-Channel Recording
|
||||
- Loop-Funktion
|
||||
- Automatisches Time-Limit
|
||||
|
||||
### 4. Button-Verarbeitung
|
||||
|
||||
**3-Mode Play-Button-System:**
|
||||
|
||||
| Click | Aktion | Zustand |
|
||||
|-------|--------|---------|
|
||||
| 1x | Play (kein Loop) | Spielt einmalig ab |
|
||||
| 2x | Loop aktivieren | Endlosschleife |
|
||||
| 3x | Stop | Stoppt Wiedergabe |
|
||||
|
||||
**Record-Button:** Toggle zwischen Recording starten/stoppen
|
||||
|
||||
---
|
||||
|
||||
## Speicheranalyse
|
||||
```bash
|
||||
RAM: [= ] 6.5% (used 21176 bytes from 327680 bytes)
|
||||
Flash: [= ] 8.5% (used 283165 bytes from 3342336 bytes)
|
||||
```
|
||||
### RAM-Verbrauch
|
||||
|
||||
| Komponente | Größe | Menge | Gesamt | Notizen |
|
||||
|-----------|-------|-------|--------|---------|
|
||||
| SequencerBlock #1 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||
| SequencerBlock #2 | ~550 B | 1x | 550 B | 128 Steps × 6 Bytes + Variablen |
|
||||
| Keyboard Objekt | ~130 B | 1x | 130 B | 8×8 Bool Arrays + Pointer |
|
||||
| CV Objekt | ~50 B | 1x | 50 B | DAC-Pointer + Config |
|
||||
| keyToVoltage Array | 24 B | 1x | 24 B | 12 Keys × uint16_t |
|
||||
| Button States | ~50 B | 1x | 50 B | 4 Buttons × ~12 Bytes |
|
||||
| Lokale Variablen | ~100 B | 1x | 100 B | Loop-Variablen |
|
||||
| **GESAMT (Schätzung)** | - | - | **~1.5 KB** | - |
|
||||
|
||||
### Flash-Verbrauch
|
||||
|
||||
| Komponente | Größe |
|
||||
|-----------|-------|
|
||||
| Arduino/Wire Libraries | ~150 KB |
|
||||
| Adafruit_MCP4728 | ~20 KB |
|
||||
| Firmware Code | ~80 KB |
|
||||
| Bootloader | ~60 KB |
|
||||
| **GESAMT (Schätzung)** | **~310 KB** |
|
||||
|
||||
|
||||
### Sequenzen-Speicher Detail
|
||||
|
||||
```cpp
|
||||
struct DualVoltageDurationPair {
|
||||
uint16_t voltage_ch1; // 2 Bytes
|
||||
uint16_t voltage_ch2; // 2 Bytes
|
||||
uint16_t duration; // 2 Bytes
|
||||
}; // = 6 Bytes pro Step
|
||||
|
||||
// Berechnung:
|
||||
// - N_MAX_SEQUENCE_STEPS = 128
|
||||
// - 128 Steps × 6 Bytes = 768 Bytes pro Sequenz
|
||||
// - 2 Sequenzer = 1536 Bytes (1.5 KB)
|
||||
```
|
||||
|
||||
### Optimierungspotential
|
||||
|
||||
| Feature | Größenänderung | Status |
|
||||
|---------|-----------------|--------|
|
||||
| 256 Steps statt 128 | +768 B | ✅ Problemlos möglich |
|
||||
| 60s statt 30s Limit | 0 B | ✅ Kostenloses Upgrade |
|
||||
| 4 Sequenzer statt 2 | +3.3 KB | ✅ Problemlos möglich |
|
||||
| 8×8 Tastatur statt 4×3 | ~ +30 B | ✅ Kaum Mehraufwand |
|
||||
|
||||
---
|
||||
|
||||
## Verwendung
|
||||
|
||||
### Grundlegende Konfiguration
|
||||
|
||||
`include/FIRMWARE_DEF.h`:
|
||||
|
||||
```cpp
|
||||
#define N_KEYBOARD_ROW 4 // Keyboard Reihen
|
||||
#define N_KEYBOARD_COL 3 // Keyboard Spalten
|
||||
#define N_CV_GATES 2 // CV-Ausgänge
|
||||
#define N_SB 2 // Sequencer
|
||||
|
||||
// I2C Pins
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
|
||||
// Keyboard Pins (Reihen)
|
||||
#define PIN_K_R0 7
|
||||
#define PIN_K_R1 8
|
||||
#define PIN_K_R2 9
|
||||
#define PIN_K_R3 10
|
||||
|
||||
// Keyboard Pins (Spalten)
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
```
|
||||
|
||||
### Spannung-Mapping
|
||||
|
||||
`src/main.cpp`:
|
||||
|
||||
```cpp
|
||||
// Voltage für jede Tastaturposition (in 1/12V = 83mV Schritten = 1 Halbtonschritt)
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83, // Row 0: C, E, G
|
||||
2*83, 6*83, 10*83, // Row 1: D, F, A
|
||||
3*83, 7*83, 11*83, // Row 2: E, G, B
|
||||
4*83, 8*83, 12*83 // Row 3: F, A, C (Oktave)
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hauptablauf
|
||||
|
||||
### Main Loop Flowchart
|
||||
|
||||
```
|
||||
START
|
||||
↓
|
||||
SETUP (Initialisierung)
|
||||
↓
|
||||
┌─── MAIN LOOP ───────────────────────┐
|
||||
│ │
|
||||
├─ Keyboard Update │
|
||||
│ (Tasten auslesen) │
|
||||
│ │
|
||||
├─ Button Handler │
|
||||
│ (Record/Play Buttons) │
|
||||
│ │
|
||||
├─ Sequencer Update │
|
||||
│ (sb1 & sb2 Playback) │
|
||||
│ │
|
||||
├─ Spannungen bestimmen │
|
||||
│ voltage_ch1 = Queue[0] │
|
||||
│ voltage_ch2 = Queue[1] │
|
||||
│ │
|
||||
├─ Recording Check │
|
||||
│ IF Recording: addStep() │
|
||||
│ │
|
||||
├─ Output Priority │
|
||||
│ IF sb1.playing() → Output SEQ1 │
|
||||
│ ELSE IF sb2.playing() → Output SEQ2│
|
||||
│ ELSE → Output Live │
|
||||
│ │
|
||||
├─ Time-Limit Check │
|
||||
│ IF Limit reached: Stop Record │
|
||||
│ │
|
||||
├─ Delay 10ms │
|
||||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
↓
|
||||
[Loop zurück]
|
||||
```
|
||||
|
||||
### State Machine
|
||||
|
||||
| State | Beschreibung | Aktion |
|
||||
|-------|-------------|--------|
|
||||
| **IDLE** | Leerlauf | Liest Tasten, gibt Live-Spannungen aus |
|
||||
| **REC** | Recording aktiv | Speichert Sequenzen, überwacht Zeit-Limits |
|
||||
| **PLAY** | Playback aktiv | Gibt Sequenzen aus, verwaltet Step-Übergänge |
|
||||
| **LOOP** | Endlosschleife | Wiederholt Sequenz nahtlos |
|
||||
|
||||
### Ausgabe-Prioritätssystem
|
||||
|
||||
```
|
||||
1. Sequencer 1 Playing?
|
||||
├─ JA → Gebe SEQ1 Voltages aus (höchste Priorität)
|
||||
└─ NEIN ↓
|
||||
|
||||
2. Sequencer 2 Playing?
|
||||
├─ JA → Gebe SEQ2 Voltages aus (zweite Priorität)
|
||||
└─ NEIN ↓
|
||||
|
||||
3. Live Input
|
||||
└─ Gebe Tasten-Voltages aus (Standard)
|
||||
```
|
||||
|
||||
Dies ermöglicht nahtlose Übergänge und verhindert Konflikte.
|
||||
|
||||
---
|
||||
|
||||
## Code-Beispiele
|
||||
|
||||
### Beispiel 1: Live-Modus (main.cpp.1)
|
||||
|
||||
Direkte Tastatur-zu-CV Verbindung ohne Sequencer:
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0) {
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++) {
|
||||
Key k = keyboard.getQueue(i);
|
||||
cv.setVoltage(i, k); // Taste direkt auf CV ausgeben
|
||||
}
|
||||
} else {
|
||||
cv.clearAll(); // Keine Taste → 0V
|
||||
}
|
||||
|
||||
delay(50);
|
||||
}
|
||||
```
|
||||
|
||||
### Beispiel 2: Dual-Channel Sequencer (main.cpp)
|
||||
|
||||
Vollständiger Sequencer mit 2 unabhängigen Kanälen:
|
||||
|
||||
```cpp
|
||||
void loop() {
|
||||
keyboard.update();
|
||||
handleSequencerButtons();
|
||||
|
||||
sb1.update();
|
||||
sb2.update();
|
||||
|
||||
// ... Voltage determination ...
|
||||
|
||||
// Recording
|
||||
if(sb1.isRecording()) {
|
||||
sb1.addStep(voltage_ch1, voltage_ch2);
|
||||
}
|
||||
if(sb2.isRecording()) {
|
||||
sb2.addStep(voltage_ch1, voltage_ch2);
|
||||
}
|
||||
|
||||
// Output mit Priorität
|
||||
if(sb1.isPlaying()) {
|
||||
cv.setVoltage(0, sb1.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb1.getCurrentVoltageCh2());
|
||||
}
|
||||
else if(sb2.isPlaying()) {
|
||||
cv.setVoltage(0, sb2.getCurrentVoltageCh1());
|
||||
cv.setVoltage(1, sb2.getCurrentVoltageCh2());
|
||||
}
|
||||
else {
|
||||
cv.setVoltage(0, voltage_ch1);
|
||||
cv.setVoltage(1, voltage_ch2);
|
||||
}
|
||||
|
||||
delay(10);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dateistruktur
|
||||
|
||||
```
|
||||
project/
|
||||
├── include/
|
||||
│ ├── FIRMWARE.h # Klassen-Definitionen
|
||||
│ └── FIRMWARE_DEF.h # Konstanten & Pin-Definitionen
|
||||
│
|
||||
└── src/
|
||||
├── main.cpp # Dual-Channel Sequencer Beispiel
|
||||
├── main.cpp.1 # Live-Modus Beispiel
|
||||
├── main.cpp.2 # Dual-Channel ohne Sequencer
|
||||
└── FIRMWARE.cpp # Implementierungen
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technische Spezifikationen
|
||||
|
||||
### Timings
|
||||
|
||||
| Parameter | Wert | Funktion |
|
||||
|-----------|------|----------|
|
||||
| Keyboard Debounce | 20ms | Anti-Prellen Verzögerung |
|
||||
| Button Debounce | 50ms | Button Anti-Prellen |
|
||||
| Main Loop Delay | 10ms | Update-Rate |
|
||||
| Max Recording | 30s | Zeit-Limit pro Sequenz |
|
||||
| Min Step Duration | 50ms | Minimale Step-Länge |
|
||||
|
||||
### Voltage-Mapping
|
||||
|
||||
Verwendet gleichmäßige 83mV Schritte (1/12 Oktave):
|
||||
|
||||
```
|
||||
Key (1,0) = 1 × 83mV = 83mV (C)
|
||||
Key (1,1) = 5 × 83mV = 415mV (E)
|
||||
Key (1,2) = 9 × 83mV = 747mV (G)
|
||||
... etc
|
||||
Key (4,2) = 12 × 83mV = 996mV (C')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Zuletzt aktualisiert:** 2025-11-30
|
||||
@@ -1,161 +1,161 @@
|
||||
/*
|
||||
@file: FIRMARE.h
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2025-12-06
|
||||
@brief: Header for FIRMWARE.cpp (FIXED VERSION)
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_MCP4728.h>
|
||||
|
||||
#ifndef FIRMWARE_H
|
||||
#define FIRMWARE_H
|
||||
|
||||
#define N_MAX_QUEUE 10
|
||||
#define N_MAX_ROWS 8
|
||||
#define N_MAX_COLS 8
|
||||
#define MS_DEBOUNCE 20
|
||||
#define N_MAX_DAC_CH 4
|
||||
|
||||
struct Key
|
||||
{
|
||||
int row;
|
||||
int col;
|
||||
};
|
||||
|
||||
struct DualVoltageDurationPair
|
||||
{
|
||||
uint16_t voltage_ch1;
|
||||
uint16_t voltage_ch2;
|
||||
uint16_t duration;
|
||||
bool active; // NEU: true wenn Step aktive Noten hat, false für Pausen
|
||||
};
|
||||
|
||||
const Key NOT_A_KEY = {-1, -1};
|
||||
|
||||
bool isNotKey(Key k);
|
||||
bool isEqualKey(Key k1, Key k2);
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
public:
|
||||
Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol);
|
||||
void begin();
|
||||
void update();
|
||||
int getQueueLength();
|
||||
Key getQueue(uint8_t index);
|
||||
|
||||
private:
|
||||
uint8_t _nRows;
|
||||
uint8_t _nCols;
|
||||
uint8_t *_pinsRow;
|
||||
uint8_t *_pinsCol;
|
||||
|
||||
bool _keyState[N_MAX_COLS][N_MAX_ROWS];
|
||||
bool _keyStateLatest[N_MAX_COLS][N_MAX_ROWS];
|
||||
unsigned long _lastChangeTime[N_MAX_COLS][N_MAX_ROWS];
|
||||
|
||||
Key _activeKeys[N_MAX_QUEUE];
|
||||
uint8_t _nActiveKeys;
|
||||
uint8_t _nSticky;
|
||||
|
||||
void _addActiveKey(uint8_t row, uint8_t col);
|
||||
void _removeActiveKey(uint8_t row, uint8_t col);
|
||||
bool _inQueue(uint8_t row, uint8_t col);
|
||||
bool _inQueue(Key k);
|
||||
bool _isNotKey(Key k);
|
||||
bool _isEqualKey(Key k1, Key k2);
|
||||
};
|
||||
|
||||
class CV
|
||||
{
|
||||
public:
|
||||
CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col);
|
||||
|
||||
bool begin(uint8_t pinSDA, uint8_t pinSCL);
|
||||
void setVoltage(uint8_t cvIndex, Key k);
|
||||
void setVoltage(uint8_t cvIndex, uint16_t mV);
|
||||
void clearAll();
|
||||
|
||||
private:
|
||||
Adafruit_MCP4728 *_dac;
|
||||
TwoWire *_wire;
|
||||
uint8_t _nCV;
|
||||
uint8_t _row;
|
||||
uint8_t _col;
|
||||
MCP4728_channel_t _cvChannelMap[N_MAX_DAC_CH];
|
||||
uint16_t *_keyToVoltage;
|
||||
uint8_t _getKeyToVoltageIndex(uint8_t row, uint8_t col);
|
||||
uint8_t _getKeyToVoltageIndex(Key k);
|
||||
};
|
||||
|
||||
class SequencerBlock
|
||||
{
|
||||
public:
|
||||
SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount);
|
||||
|
||||
// Aufnahme-Funktionen
|
||||
void startRecord();
|
||||
void stopRecord();
|
||||
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||
bool isRecording();
|
||||
|
||||
// Wiedergabe-Funktionen
|
||||
void startPlay();
|
||||
void stopPlay();
|
||||
void update();
|
||||
bool isPlaying();
|
||||
|
||||
// Sequenz-Verwaltung
|
||||
void clear();
|
||||
void setLoop(bool loop);
|
||||
|
||||
// Status-Abfragen
|
||||
bool timeLimitReached();
|
||||
bool stepLimitReached();
|
||||
uint16_t getStepCount();
|
||||
uint16_t getCurrentVoltageCh1();
|
||||
uint16_t getCurrentVoltageCh2();
|
||||
bool isCurrentStepActive(); // NEU: Prüft ob aktueller Step aktive Noten hat
|
||||
uint16_t getTotalDuration();
|
||||
|
||||
private:
|
||||
/*!
|
||||
* @brief Memory limiting
|
||||
* @return (uint16_t) 1024
|
||||
* @attention Increasing the value might lead to an overflow
|
||||
* @note sizeOf(DualVoltageDurationPair) = 8 Byte ==> 8 Byte * 1024 = 8192 Byte
|
||||
*/
|
||||
const static uint16_t _MAX_SEQUENCE_STEPS = 1024;
|
||||
|
||||
// Sequenz memory
|
||||
DualVoltageDurationPair _sequence[_MAX_SEQUENCE_STEPS];
|
||||
uint16_t _stepCount;
|
||||
uint16_t _currentStep;
|
||||
|
||||
// Time management
|
||||
uint16_t _maxDurationMS;
|
||||
uint16_t _maxStepCount;
|
||||
unsigned long _recordStartTime;
|
||||
unsigned long _lastStepTime;
|
||||
unsigned long _playStartTime;
|
||||
unsigned long _stepStartTime;
|
||||
unsigned long _lastAddStepTime; // NEU: Rate-Limiting
|
||||
|
||||
// Status flags
|
||||
bool _isRecording;
|
||||
bool _isPlaying;
|
||||
bool _loop;
|
||||
|
||||
// Last recorded Voltage: at n-th step minus one
|
||||
uint16_t _lastVoltageCh1;
|
||||
uint16_t _lastVoltageCh2;
|
||||
|
||||
// helper functions
|
||||
void _finishCurrentStep();
|
||||
bool _canAddStep();
|
||||
};
|
||||
|
||||
/*
|
||||
@file: FIRMARE.h
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2025-12-06
|
||||
@brief: Header for FIRMWARE.cpp (FIXED VERSION)
|
||||
*/
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_MCP4728.h>
|
||||
|
||||
#ifndef FIRMWARE_H
|
||||
#define FIRMWARE_H
|
||||
|
||||
#define N_MAX_QUEUE 10
|
||||
#define N_MAX_ROWS 8
|
||||
#define N_MAX_COLS 8
|
||||
#define MS_DEBOUNCE 20
|
||||
#define N_MAX_DAC_CH 4
|
||||
|
||||
struct Key
|
||||
{
|
||||
int row;
|
||||
int col;
|
||||
};
|
||||
|
||||
struct DualVoltageDurationPair
|
||||
{
|
||||
uint16_t voltage_ch1;
|
||||
uint16_t voltage_ch2;
|
||||
uint16_t duration;
|
||||
bool active; // NEU: true wenn Step aktive Noten hat, false für Pausen
|
||||
};
|
||||
|
||||
const Key NOT_A_KEY = {-1, -1};
|
||||
|
||||
bool isNotKey(Key k);
|
||||
bool isEqualKey(Key k1, Key k2);
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
public:
|
||||
Keyboard(uint8_t nRows, uint8_t nCols, uint8_t *pinsRow, uint8_t *pinsCol);
|
||||
void begin();
|
||||
void update();
|
||||
int getQueueLength();
|
||||
Key getQueue(uint8_t index);
|
||||
|
||||
private:
|
||||
uint8_t _nRows;
|
||||
uint8_t _nCols;
|
||||
uint8_t *_pinsRow;
|
||||
uint8_t *_pinsCol;
|
||||
|
||||
bool _keyState[N_MAX_COLS][N_MAX_ROWS];
|
||||
bool _keyStateLatest[N_MAX_COLS][N_MAX_ROWS];
|
||||
unsigned long _lastChangeTime[N_MAX_COLS][N_MAX_ROWS];
|
||||
|
||||
Key _activeKeys[N_MAX_QUEUE];
|
||||
uint8_t _nActiveKeys;
|
||||
uint8_t _nSticky;
|
||||
|
||||
void _addActiveKey(uint8_t row, uint8_t col);
|
||||
void _removeActiveKey(uint8_t row, uint8_t col);
|
||||
bool _inQueue(uint8_t row, uint8_t col);
|
||||
bool _inQueue(Key k);
|
||||
bool _isNotKey(Key k);
|
||||
bool _isEqualKey(Key k1, Key k2);
|
||||
};
|
||||
|
||||
class CV
|
||||
{
|
||||
public:
|
||||
CV(Adafruit_MCP4728 *dac, TwoWire *wire, uint8_t nCV, MCP4728_channel_t *cvChannelMap, uint16_t *keyToVoltage, uint8_t row, uint8_t col);
|
||||
|
||||
bool begin(uint8_t pinSDA, uint8_t pinSCL);
|
||||
void setVoltage(uint8_t cvIndex, Key k);
|
||||
void setVoltage(uint8_t cvIndex, uint16_t mV);
|
||||
void clearAll();
|
||||
|
||||
private:
|
||||
Adafruit_MCP4728 *_dac;
|
||||
TwoWire *_wire;
|
||||
uint8_t _nCV;
|
||||
uint8_t _row;
|
||||
uint8_t _col;
|
||||
MCP4728_channel_t _cvChannelMap[N_MAX_DAC_CH];
|
||||
uint16_t *_keyToVoltage;
|
||||
uint8_t _getKeyToVoltageIndex(uint8_t row, uint8_t col);
|
||||
uint8_t _getKeyToVoltageIndex(Key k);
|
||||
};
|
||||
|
||||
class SequencerBlock
|
||||
{
|
||||
public:
|
||||
SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount);
|
||||
|
||||
// Aufnahme-Funktionen
|
||||
void startRecord();
|
||||
void stopRecord();
|
||||
void addStep(uint16_t voltage_ch1, uint16_t voltage_ch2);
|
||||
bool isRecording();
|
||||
|
||||
// Wiedergabe-Funktionen
|
||||
void startPlay();
|
||||
void stopPlay();
|
||||
void update();
|
||||
bool isPlaying();
|
||||
|
||||
// Sequenz-Verwaltung
|
||||
void clear();
|
||||
void setLoop(bool loop);
|
||||
|
||||
// Status-Abfragen
|
||||
bool timeLimitReached();
|
||||
bool stepLimitReached();
|
||||
uint16_t getStepCount();
|
||||
uint16_t getCurrentVoltageCh1();
|
||||
uint16_t getCurrentVoltageCh2();
|
||||
bool isCurrentStepActive(); // NEU: Prüft ob aktueller Step aktive Noten hat
|
||||
uint16_t getTotalDuration();
|
||||
|
||||
private:
|
||||
/*!
|
||||
* @brief Memory limiting
|
||||
* @return (uint16_t) 1024
|
||||
* @attention Increasing the value might lead to an overflow
|
||||
* @note sizeOf(DualVoltageDurationPair) = 8 Byte ==> 8 Byte * 1024 = 8192 Byte
|
||||
*/
|
||||
const static uint16_t _MAX_SEQUENCE_STEPS = 1024;
|
||||
|
||||
// Sequenz memory
|
||||
DualVoltageDurationPair _sequence[_MAX_SEQUENCE_STEPS];
|
||||
uint16_t _stepCount;
|
||||
uint16_t _currentStep;
|
||||
|
||||
// Time management
|
||||
uint16_t _maxDurationMS;
|
||||
uint16_t _maxStepCount;
|
||||
unsigned long _recordStartTime;
|
||||
unsigned long _lastStepTime;
|
||||
unsigned long _playStartTime;
|
||||
unsigned long _stepStartTime;
|
||||
unsigned long _lastAddStepTime; // NEU: Rate-Limiting
|
||||
|
||||
// Status flags
|
||||
bool _isRecording;
|
||||
bool _isPlaying;
|
||||
bool _loop;
|
||||
|
||||
// Last recorded Voltage: at n-th step minus one
|
||||
uint16_t _lastVoltageCh1;
|
||||
uint16_t _lastVoltageCh2;
|
||||
|
||||
// helper functions
|
||||
void _finishCurrentStep();
|
||||
bool _canAddStep();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,49 +1,49 @@
|
||||
/*
|
||||
@file: FIRMARE_DEF.h
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2026-03-08
|
||||
@brief: Header for constant definitions
|
||||
*/
|
||||
|
||||
#ifndef FIRMWARE_DEF_H
|
||||
#define FIRMWARE_DEF_H
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
// CONSTANTS DEFINITONS
|
||||
#define N_KEYBOARD_ROW 5
|
||||
#define N_KEYBOARD_COL 5
|
||||
#define N_CV_GATES 2
|
||||
#define N_SB 2
|
||||
#define BAUDRATE 115200
|
||||
#define N_MAX_SEQ_STEPS 512
|
||||
// PIN DEFENTITIONS
|
||||
// I2C PINS
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
// KEYBOARD PINS
|
||||
#define PIN_K_R0 7
|
||||
#define PIN_K_R1 8
|
||||
#define PIN_K_R2 9
|
||||
#define PIN_K_R3 10
|
||||
#define PIN_K_R4 11
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
#define PIN_K_C3 5
|
||||
#define PIN_K_C4 6
|
||||
// SEQUENCER BUTTON PINS
|
||||
#define PIN_SB_1_REC 33
|
||||
#define PIN_SB_1_PLAY 34
|
||||
#define PIN_SB_2_REC 35
|
||||
#define PIN_SB_2_PLAY 36
|
||||
// MISC/INFO PINS
|
||||
#define PIN_VCO1_EN 38
|
||||
#define PIN_VCO2_EN 39
|
||||
#define PIN_REC 37
|
||||
#define PIN_BPM 12
|
||||
#define PIN_B_METRONOME 14
|
||||
#define PIN_L_METRONOME 13
|
||||
|
||||
/*
|
||||
@file: FIRMARE_DEF.h
|
||||
@author: Erik Tóth
|
||||
@contact: etoth@tsn.at
|
||||
@date: 2025-10-26
|
||||
@updated: 2026-03-08
|
||||
@brief: Header for constant definitions
|
||||
*/
|
||||
|
||||
#ifndef FIRMWARE_DEF_H
|
||||
#define FIRMWARE_DEF_H
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
// CONSTANTS DEFINITONS
|
||||
#define N_KEYBOARD_ROW 5
|
||||
#define N_KEYBOARD_COL 5
|
||||
#define N_CV_GATES 2
|
||||
#define N_SB 2
|
||||
#define BAUDRATE 115200
|
||||
#define N_MAX_SEQ_STEPS 512
|
||||
// PIN DEFENTITIONS
|
||||
// I2C PINS
|
||||
#define PIN_SDA 15
|
||||
#define PIN_SCL 16
|
||||
// KEYBOARD PINS
|
||||
#define PIN_K_R0 7
|
||||
#define PIN_K_R1 8
|
||||
#define PIN_K_R2 9
|
||||
#define PIN_K_R3 10
|
||||
#define PIN_K_R4 11
|
||||
#define PIN_K_C0 1
|
||||
#define PIN_K_C1 2
|
||||
#define PIN_K_C2 4
|
||||
#define PIN_K_C3 5
|
||||
#define PIN_K_C4 6
|
||||
// SEQUENCER BUTTON PINS
|
||||
#define PIN_SB_1_REC 33
|
||||
#define PIN_SB_1_PLAY 34
|
||||
#define PIN_SB_2_REC 35
|
||||
#define PIN_SB_2_PLAY 36
|
||||
// MISC/INFO PINS
|
||||
#define PIN_VCO1_EN 38
|
||||
#define PIN_VCO2_EN 39
|
||||
#define PIN_REC 37
|
||||
#define PIN_BPM 12
|
||||
#define PIN_B_METRONOME 14
|
||||
#define PIN_L_METRONOME 13
|
||||
|
||||
#endif
|
||||
@@ -1,37 +1,37 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the convention is to give header files names that end with `.h'.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the convention is to give header files names that end with `.h'.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into the executable file.
|
||||
|
||||
The source code of each library should be placed in a separate directory
|
||||
("lib/your_library_name/[Code]").
|
||||
|
||||
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
Example contents of `src/main.c` using Foo and Bar:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries by scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into the executable file.
|
||||
|
||||
The source code of each library should be placed in a separate directory
|
||||
("lib/your_library_name/[Code]").
|
||||
|
||||
For example, see the structure of the following example libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
Example contents of `src/main.c` using Foo and Bar:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries by scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32-s3-devkitm-1]
|
||||
platform = espressif32
|
||||
board = esp32-s3-devkitm-1
|
||||
framework = arduino
|
||||
build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_JTAG_ON_BOOT=1
|
||||
lib_deps = adafruit/Adafruit MCP4728@^1.0.10
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:esp32-s3-devkitm-1]
|
||||
platform = espressif32
|
||||
board = esp32-s3-devkitm-1
|
||||
framework = arduino
|
||||
build_flags = -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_JTAG_ON_BOOT=1
|
||||
lib_deps = adafruit/Adafruit MCP4728@^1.0.10
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,50 @@
|
||||
/*
|
||||
* Example Code One
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
|
||||
static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
||||
static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
||||
|
||||
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
||||
|
||||
Adafruit_MCP4728 MCP4728;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
4*83, 8*83, 12*83
|
||||
};
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Serial.printf("\n\rCurrent queue length: %i", n);
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++)
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
cv.setVoltage(i, k);
|
||||
if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i);
|
||||
else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col);
|
||||
}
|
||||
}
|
||||
else cv.clearAll();
|
||||
|
||||
delay(50);
|
||||
/*
|
||||
* Example Code One
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
|
||||
static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
||||
static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
||||
|
||||
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
||||
|
||||
Adafruit_MCP4728 MCP4728;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
4*83, 8*83, 12*83
|
||||
};
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Serial.printf("\n\rCurrent queue length: %i", n);
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++)
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
cv.setVoltage(i, k);
|
||||
if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i);
|
||||
else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col);
|
||||
}
|
||||
}
|
||||
else cv.clearAll();
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -1,60 +1,60 @@
|
||||
/*
|
||||
* Example Code Two
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
|
||||
static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
||||
static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
||||
|
||||
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
||||
|
||||
Adafruit_MCP4728 MCP4728;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
4*83, 8*83, 12*83
|
||||
};
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Serial.printf("\n\rCurrent queue length: %i", n);
|
||||
if(n == 1)
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, NOT_A_KEY);
|
||||
}
|
||||
else if(n >= 2)
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, keyboard.getQueue(1));
|
||||
}
|
||||
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++)
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i);
|
||||
else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col);
|
||||
}
|
||||
}
|
||||
else cv.clearAll();
|
||||
|
||||
delay(50);
|
||||
/*
|
||||
* Example Code Two
|
||||
*/
|
||||
#include "FIRMWARE_DEF.h"
|
||||
#include "FIRMWARE.h"
|
||||
|
||||
static byte pins_keyboard_row[N_KEYBOARD_ROW] = {PIN_K_R0, PIN_K_R1, PIN_K_R2, PIN_K_R3};
|
||||
static byte pins_keyboard_col[N_KEYBOARD_COL] = {PIN_K_C0, PIN_K_C1, PIN_K_C2};
|
||||
|
||||
Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboard_col);
|
||||
|
||||
Adafruit_MCP4728 MCP4728;
|
||||
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
|
||||
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = {
|
||||
1*83, 5*83, 9*83,
|
||||
2*83, 6*83, 10*83,
|
||||
3*83, 7*83, 11*83,
|
||||
4*83, 8*83, 12*83
|
||||
};
|
||||
|
||||
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(BAUDRATE);
|
||||
keyboard.begin();
|
||||
cv.begin(PIN_SDA, PIN_SCL);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
keyboard.update();
|
||||
|
||||
int n = keyboard.getQueueLength();
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
Serial.printf("\n\rCurrent queue length: %i", n);
|
||||
if(n == 1)
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, NOT_A_KEY);
|
||||
}
|
||||
else if(n >= 2)
|
||||
{
|
||||
cv.setVoltage(0, keyboard.getQueue(0));
|
||||
cv.setVoltage(1, keyboard.getQueue(1));
|
||||
}
|
||||
|
||||
for(int i = 0; (i < N_CV_GATES) && (i < n); i++)
|
||||
{
|
||||
Key k = keyboard.getQueue(i);
|
||||
if(isNotKey(k)) Serial.printf("\n\rQueue position %i: NOT A KEY", i);
|
||||
else Serial.printf("\n\rQueue position %i: R%iC%i", i, k.row, k.col);
|
||||
}
|
||||
}
|
||||
else cv.clearAll();
|
||||
|
||||
delay(50);
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
Record=TopLevelDocument|FileName=Keyboard.SchDoc|SheetNumber=1
|
||||
Record=TopLevelDocument|FileName=Keyboard.SchDoc|SheetNumber=1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,50 +1,50 @@
|
||||
Change Component Designator: Old Designator=D? New Designator=D1
|
||||
Change Component Designator: Old Designator=D? New Designator=D2
|
||||
Change Component Designator: Old Designator=D? New Designator=D3
|
||||
Change Component Designator: Old Designator=D? New Designator=D4
|
||||
Change Component Designator: Old Designator=D? New Designator=D5
|
||||
Change Component Designator: Old Designator=D? New Designator=D6
|
||||
Change Component Designator: Old Designator=D? New Designator=D7
|
||||
Change Component Designator: Old Designator=D? New Designator=D8
|
||||
Change Component Designator: Old Designator=D? New Designator=D9
|
||||
Change Component Designator: Old Designator=D? New Designator=D10
|
||||
Change Component Designator: Old Designator=D? New Designator=D11
|
||||
Change Component Designator: Old Designator=D? New Designator=D12
|
||||
Change Component Designator: Old Designator=D? New Designator=D13
|
||||
Change Component Designator: Old Designator=D? New Designator=D14
|
||||
Change Component Designator: Old Designator=D? New Designator=D15
|
||||
Change Component Designator: Old Designator=D? New Designator=D16
|
||||
Change Component Designator: Old Designator=D? New Designator=D17
|
||||
Change Component Designator: Old Designator=D? New Designator=D18
|
||||
Change Component Designator: Old Designator=D? New Designator=D19
|
||||
Change Component Designator: Old Designator=D? New Designator=D20
|
||||
Change Component Designator: Old Designator=D? New Designator=D21
|
||||
Change Component Designator: Old Designator=D? New Designator=D22
|
||||
Change Component Designator: Old Designator=D? New Designator=D23
|
||||
Change Component Designator: Old Designator=D? New Designator=D24
|
||||
Change Component Designator: Old Designator=D? New Designator=D25
|
||||
Change Component Designator: Old Designator=S? New Designator=S1
|
||||
Change Component Designator: Old Designator=S? New Designator=S2
|
||||
Change Component Designator: Old Designator=S? New Designator=S3
|
||||
Change Component Designator: Old Designator=S? New Designator=S4
|
||||
Change Component Designator: Old Designator=S? New Designator=S5
|
||||
Change Component Designator: Old Designator=S? New Designator=S6
|
||||
Change Component Designator: Old Designator=S? New Designator=S7
|
||||
Change Component Designator: Old Designator=S? New Designator=S8
|
||||
Change Component Designator: Old Designator=S? New Designator=S9
|
||||
Change Component Designator: Old Designator=S? New Designator=S10
|
||||
Change Component Designator: Old Designator=S? New Designator=S11
|
||||
Change Component Designator: Old Designator=S? New Designator=S12
|
||||
Change Component Designator: Old Designator=S? New Designator=S13
|
||||
Change Component Designator: Old Designator=S? New Designator=S14
|
||||
Change Component Designator: Old Designator=S? New Designator=S15
|
||||
Change Component Designator: Old Designator=S? New Designator=S16
|
||||
Change Component Designator: Old Designator=S? New Designator=S17
|
||||
Change Component Designator: Old Designator=S? New Designator=S18
|
||||
Change Component Designator: Old Designator=S? New Designator=S19
|
||||
Change Component Designator: Old Designator=S? New Designator=S20
|
||||
Change Component Designator: Old Designator=S? New Designator=S21
|
||||
Change Component Designator: Old Designator=S? New Designator=S22
|
||||
Change Component Designator: Old Designator=S? New Designator=S23
|
||||
Change Component Designator: Old Designator=S? New Designator=S24
|
||||
Change Component Designator: Old Designator=S? New Designator=S25
|
||||
Change Component Designator: Old Designator=D? New Designator=D1
|
||||
Change Component Designator: Old Designator=D? New Designator=D2
|
||||
Change Component Designator: Old Designator=D? New Designator=D3
|
||||
Change Component Designator: Old Designator=D? New Designator=D4
|
||||
Change Component Designator: Old Designator=D? New Designator=D5
|
||||
Change Component Designator: Old Designator=D? New Designator=D6
|
||||
Change Component Designator: Old Designator=D? New Designator=D7
|
||||
Change Component Designator: Old Designator=D? New Designator=D8
|
||||
Change Component Designator: Old Designator=D? New Designator=D9
|
||||
Change Component Designator: Old Designator=D? New Designator=D10
|
||||
Change Component Designator: Old Designator=D? New Designator=D11
|
||||
Change Component Designator: Old Designator=D? New Designator=D12
|
||||
Change Component Designator: Old Designator=D? New Designator=D13
|
||||
Change Component Designator: Old Designator=D? New Designator=D14
|
||||
Change Component Designator: Old Designator=D? New Designator=D15
|
||||
Change Component Designator: Old Designator=D? New Designator=D16
|
||||
Change Component Designator: Old Designator=D? New Designator=D17
|
||||
Change Component Designator: Old Designator=D? New Designator=D18
|
||||
Change Component Designator: Old Designator=D? New Designator=D19
|
||||
Change Component Designator: Old Designator=D? New Designator=D20
|
||||
Change Component Designator: Old Designator=D? New Designator=D21
|
||||
Change Component Designator: Old Designator=D? New Designator=D22
|
||||
Change Component Designator: Old Designator=D? New Designator=D23
|
||||
Change Component Designator: Old Designator=D? New Designator=D24
|
||||
Change Component Designator: Old Designator=D? New Designator=D25
|
||||
Change Component Designator: Old Designator=S? New Designator=S1
|
||||
Change Component Designator: Old Designator=S? New Designator=S2
|
||||
Change Component Designator: Old Designator=S? New Designator=S3
|
||||
Change Component Designator: Old Designator=S? New Designator=S4
|
||||
Change Component Designator: Old Designator=S? New Designator=S5
|
||||
Change Component Designator: Old Designator=S? New Designator=S6
|
||||
Change Component Designator: Old Designator=S? New Designator=S7
|
||||
Change Component Designator: Old Designator=S? New Designator=S8
|
||||
Change Component Designator: Old Designator=S? New Designator=S9
|
||||
Change Component Designator: Old Designator=S? New Designator=S10
|
||||
Change Component Designator: Old Designator=S? New Designator=S11
|
||||
Change Component Designator: Old Designator=S? New Designator=S12
|
||||
Change Component Designator: Old Designator=S? New Designator=S13
|
||||
Change Component Designator: Old Designator=S? New Designator=S14
|
||||
Change Component Designator: Old Designator=S? New Designator=S15
|
||||
Change Component Designator: Old Designator=S? New Designator=S16
|
||||
Change Component Designator: Old Designator=S? New Designator=S17
|
||||
Change Component Designator: Old Designator=S? New Designator=S18
|
||||
Change Component Designator: Old Designator=S? New Designator=S19
|
||||
Change Component Designator: Old Designator=S? New Designator=S20
|
||||
Change Component Designator: Old Designator=S? New Designator=S21
|
||||
Change Component Designator: Old Designator=S? New Designator=S22
|
||||
Change Component Designator: Old Designator=S? New Designator=S23
|
||||
Change Component Designator: Old Designator=S? New Designator=S24
|
||||
Change Component Designator: Old Designator=S? New Designator=S25
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
Record=TopLevelDocument|FileName=PS_Main.SchDoc|SheetNumber=1
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_3V3|SchDesignator=PS_3V3|FileName=PS_3V3.SchDoc|SheetNumber=3|SymbolType=Normal|RawFileName=PS_3V3.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_10V|SchDesignator=PS_10V|FileName=PS_10V.SchDoc|SheetNumber=4|SymbolType=Normal|RawFileName=PS_10V.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_USB|SchDesignator=PS_USB|FileName=PS_USB.SchDoc|SheetNumber=2|SymbolType=Normal|RawFileName=PS_USB.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
Record=TopLevelDocument|FileName=PS_Main.SchDoc|SheetNumber=1
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_3V3|SchDesignator=PS_3V3|FileName=PS_3V3.SchDoc|SheetNumber=3|SymbolType=Normal|RawFileName=PS_3V3.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_10V|SchDesignator=PS_10V|FileName=PS_10V.SchDoc|SheetNumber=4|SymbolType=Normal|RawFileName=PS_10V.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
Record=SheetSymbol|SourceDocument=PS_Main.SchDoc|Designator=PS_USB|SchDesignator=PS_USB|FileName=PS_USB.SchDoc|SheetNumber=2|SymbolType=Normal|RawFileName=PS_USB.SchDoc|DesignItemId= |SourceLibraryName= |ObjectKind=Sheet Symbol|RevisionGUID= |ItemGUID= |VaultGUID=
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part IC? IC LM321DTR(XBLW) in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_10V.SchDoc with IC LM321DTR(XBLW) from DA_LIB.IntLib
|
||||
Replace Part IC? IC LM321DTR(XBLW) in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_10V.SchDoc with IC LM321DTR(XBLW) from DA_LIB.IntLib
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part D? D PESD2USB3UV-TR in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_Main.SchDoc with D PESD2USB3UV-TR from DA_LIB.IntLib
|
||||
Replace Part D? D PESD2USB3UV-TR in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_Main.SchDoc with D PESD2USB3UV-TR from DA_LIB.IntLib
|
||||
|
||||
@@ -1 +1 @@
|
||||
Replace Part IC? IC HUSB237-AA001-DN06R in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_Main.SchDoc with IC HUSB237-AA001-DN06R from DA_LIB.IntLib
|
||||
Replace Part IC? IC HUSB237-AA001-DN06R in C:\HTL\5AHEL\DA\github\audio-synth\dev\digital\Powersupply\PS_Main.SchDoc with IC HUSB237-AA001-DN06R from DA_LIB.IntLib
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user