Firmware MCU: Update sequencer block to support dynamic step count and enhance documentation

This commit is contained in:
2025-12-01 22:45:58 +01:00
parent b106859252
commit 855fd01821
6 changed files with 82 additions and 50 deletions

View File

@@ -66,6 +66,23 @@ DItemRevisionGUID=
GenerateClassCluster=0 GenerateClassCluster=0
DocumentUniqueId=QMXNWCKL DocumentUniqueId=QMXNWCKL
[Document2]
DocumentPath=ESP32-S3.Harness
AnnotationEnabled=1
AnnotateStartValue=1
AnnotationIndexControlEnabled=0
AnnotateSuffix=
AnnotateScope=All
AnnotateOrder=-1
DoLibraryUpdate=1
DoDatabaseUpdate=1
ClassGenCCAutoEnabled=1
ClassGenCCAutoRoomEnabled=0
ClassGenNCAutoScope=None
DItemRevisionGUID=
GenerateClassCluster=0
DocumentUniqueId=
[Parameter1] [Parameter1]
Name=ProjectTitle Name=ProjectTitle
Value=ESP32-S3 Value=ESP32-S3

Binary file not shown.

View File

@@ -16,9 +16,7 @@
#define N_MAX_ROWS 8 #define N_MAX_ROWS 8
#define N_MAX_COLS 8 #define N_MAX_COLS 8
#define MS_DEBOUNCE 20 #define MS_DEBOUNCE 20
#define N_MAX_DAC_CH 4 #define N_MAX_DAC_CH 4
#define N_MAX_SEQUENCE_STEPS 128
struct Key struct Key
{ {
@@ -94,7 +92,7 @@ class CV
class SequencerBlock class SequencerBlock
{ {
public: public:
SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS); SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount);
// Aufnahme-Funktionen // Aufnahme-Funktionen
void startRecord(); void startRecord();
@@ -105,7 +103,7 @@ class SequencerBlock
// Wiedergabe-Funktionen // Wiedergabe-Funktionen
void startPlay(); void startPlay();
void stopPlay(); void stopPlay();
void update(); // Muss regelmäßig aufgerufen werden void update();
bool isPlaying(); bool isPlaying();
// Sequenz-Verwaltung // Sequenz-Verwaltung
@@ -114,35 +112,44 @@ class SequencerBlock
// Status-Abfragen // Status-Abfragen
bool timeLimitReached(); bool timeLimitReached();
uint8_t getStepCount(); bool stepLimitReached();
uint16_t getStepCount();
uint16_t getCurrentVoltageCh1(); uint16_t getCurrentVoltageCh1();
uint16_t getCurrentVoltageCh2(); uint16_t getCurrentVoltageCh2();
uint16_t getTotalDuration(); uint16_t getTotalDuration();
private: private:
// Sequenz-Speicher /*!
DualVoltageDurationPair _sequence[N_MAX_SEQUENCE_STEPS]; * @brief Memory limiting
uint8_t _stepCount; * @return (uint16_t) 1024
uint8_t _currentStep; * @attention Increasing the value might lead to an overflow
* @note sizeOf(DualVoltageDurationPair) = 6 Byte ==> 6 Byte * 1024 = 6144 Byte
*/
const static uint16_t _MAX_SEQUENCE_STEPS = 1024;
// Zeitverwaltung // Sequenz memory
DualVoltageDurationPair _sequence[_MAX_SEQUENCE_STEPS];
uint16_t _stepCount;
uint16_t _currentStep;
// Time management
uint16_t _maxDurationMS; uint16_t _maxDurationMS;
uint16_t _minStepDurationMS; uint16_t _maxStepCount;
unsigned long _recordStartTime; unsigned long _recordStartTime;
unsigned long _lastStepTime; unsigned long _lastStepTime;
unsigned long _playStartTime; unsigned long _playStartTime;
unsigned long _stepStartTime; unsigned long _stepStartTime;
// Status-Flags // Status flags
bool _isRecording; bool _isRecording;
bool _isPlaying; bool _isPlaying;
bool _loop; bool _loop;
// Letzte aufgenommene Spannungen // Last recorded Voltage: at n-th step minus one
uint16_t _lastVoltageCh1; uint16_t _lastVoltageCh1;
uint16_t _lastVoltageCh2; uint16_t _lastVoltageCh2;
// Hilfsfunktionen // helper functions
void _finishCurrentStep(); void _finishCurrentStep();
bool _canAddStep(); bool _canAddStep();
}; };

View File

@@ -11,11 +11,12 @@
#include <Arduino.h> #include <Arduino.h>
#include <Wire.h> #include <Wire.h>
// CONSTANTS DEFINITONS // CONSTANTS DEFINITONS
#define N_KEYBOARD_ROW 4 #define N_KEYBOARD_ROW 4 // for PROD. change to 5
#define N_KEYBOARD_COL 3 #define N_KEYBOARD_COL 3 // for PROD. change to 5
#define N_CV_GATES 2 #define N_CV_GATES 2
#define N_SB 2 #define N_SB 2
#define BAUDRATE 115200 #define BAUDRATE 115200
#define N_MAX_SEQ_STEPS 512
// PIN DEFENTITIONS // PIN DEFENTITIONS
// I2C PINS // I2C PINS
#define PIN_SDA 15 #define PIN_SDA 15
@@ -25,15 +26,22 @@
#define PIN_K_R1 8 #define PIN_K_R1 8
#define PIN_K_R2 9 #define PIN_K_R2 9
#define PIN_K_R3 10 #define PIN_K_R3 10
#define PIN_K_R4 // 11 NOT IN USE #define PIN_K_R4 11 // DEV. not in use
#define PIN_K_C0 1 #define PIN_K_C0 1
#define PIN_K_C1 2 #define PIN_K_C1 2
#define PIN_K_C2 4 #define PIN_K_C2 4
#define PIN_K_C3 // 5 NOT IN USE #define PIN_K_C3 5 // DEV. not in use
#define PIN_K_C4 // 6 NOT IN USE #define PIN_K_C4 6 // DEV. not in use
// SEQUENCER BUTTON PINS // SEQUENCER BUTTON PINS
#define PIN_SB_1_REC 37 // 33 not available on dev board #define PIN_SB_1_REC 37 // for PROD. change to 33 / not available on dev board
#define PIN_SB_1_PLAY 38 // 34 not available on dev board #define PIN_SB_1_PLAY 38 // for PROD. change to 34 / not available on dev board
#define PIN_SB_2_REC 35 #define PIN_SB_2_REC 35
#define PIN_SB_2_PLAY 36 #define PIN_SB_2_PLAY 36
// MISC/INFO PINS
#define PIN_ACTIVE -1 // TODO: if any key is played return HIGH
#define PIN_REC -1 // TODO: if any sb is recording return HIGH
#define PIN_BPM -1 // TODO: get bpm through potentiometer analog value
#define PIN_B_METRONOME -1 // TODO: button activates/deactivates bpm led output
#define PIN_L_METRONOME -1 // TODO: led blinks according to bpm value
#endif #endif

View File

@@ -235,12 +235,12 @@ uint8_t CV::_getKeyToVoltageIndex(Key k)
/*! /*!
* @param maxDurationMS maximum loop duration of recording in milliseconds * @param maxDurationMS maximum loop duration of recording in milliseconds
* @param minStepDurationMS minimum duration for a step to be recorded (prevents ultra-short steps) * @param maxStepCount maximum number of steps that can be recorded
*/ */
SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t minStepDurationMS) SequencerBlock::SequencerBlock(uint16_t maxDurationMS, uint16_t maxStepCount)
{ {
_maxDurationMS = maxDurationMS; _maxDurationMS = maxDurationMS;
_minStepDurationMS = minStepDurationMS; _maxStepCount = maxStepCount;
_stepCount = 0; _stepCount = 0;
_currentStep = 0; _currentStep = 0;
_isRecording = false; _isRecording = false;
@@ -386,7 +386,7 @@ void SequencerBlock::clear()
_lastVoltageCh1 = 0; _lastVoltageCh1 = 0;
_lastVoltageCh2 = 0; _lastVoltageCh2 = 0;
for(uint8_t i = 0; i < N_MAX_SEQUENCE_STEPS; i++) for(uint8_t i = 0; i < _MAX_SEQUENCE_STEPS; i++)
{ {
_sequence[i].voltage_ch1 = 0; _sequence[i].voltage_ch1 = 0;
_sequence[i].voltage_ch2 = 0; _sequence[i].voltage_ch2 = 0;
@@ -409,7 +409,12 @@ bool SequencerBlock::timeLimitReached()
return (elapsed >= _maxDurationMS); return (elapsed >= _maxDurationMS);
} }
uint8_t SequencerBlock::getStepCount() bool SequencerBlock::stepLimitReached()
{
return (_stepCount >= _maxStepCount);
}
uint16_t SequencerBlock::getStepCount()
{ {
return _stepCount; return _stepCount;
} }
@@ -447,21 +452,13 @@ void SequencerBlock::_finishCurrentStep()
unsigned long now = millis(); unsigned long now = millis();
uint16_t duration = now - _lastStepTime; uint16_t duration = now - _lastStepTime;
// Nur Steps mit ausreichender Dauer speichern
if(duration >= _minStepDurationMS)
{
_sequence[_stepCount - 1].duration = duration; _sequence[_stepCount - 1].duration = duration;
}
else
{
// Step war zu kurz, verwerfen
_stepCount--;
}
} }
bool SequencerBlock::_canAddStep() bool SequencerBlock::_canAddStep()
{ {
if(_stepCount >= N_MAX_SEQUENCE_STEPS) return false; if(_stepCount >= _maxStepCount) return false;
if(_stepCount >= _MAX_SEQUENCE_STEPS) return false;
if(timeLimitReached()) return false; if(timeLimitReached()) return false;
return true; return true;

View File

@@ -1,5 +1,8 @@
/* /*
* Example Code Three - Dual Channel Sequencer * Example Code Three - Dual Channel Sequencer
* TODO:
- add predefined sequence of voltage (e.g. for usage as startup sound)
- implement INFO and MISC pins form file FIRMWARE_DEF.h
*/ */
#include "FIRMWARE_DEF.h" #include "FIRMWARE_DEF.h"
#include "FIRMWARE.h" #include "FIRMWARE.h"
@@ -12,17 +15,17 @@ Keyboard keyboard(N_KEYBOARD_ROW, N_KEYBOARD_COL, pins_keyboard_row, pins_keyboa
Adafruit_MCP4728 MCP4728; Adafruit_MCP4728 MCP4728;
MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B}; MCP4728_channel_t cvMap[N_CV_GATES] = {MCP4728_CHANNEL_A, MCP4728_CHANNEL_B};
uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = { /* 83mV = 1/12V */ uint16_t keyToVoltage[N_KEYBOARD_ROW*N_KEYBOARD_COL] = { /* 83mV = 1/12V */
1*83, 5*83, 9*83, 1*83, 5*83, 9*83, /* ROW 1: B D Fis */
2*83, 6*83, 10*83, 2*83, 6*83, 10*83, /* ROW 2: H Dis G */
3*83, 7*83, 11*83, 3*83, 7*83, 11*83, /* ROW 3: C E Gis */
4*83, 8*83, 12*83 4*83, 8*83, 12*83 /* ROW 4: Cis F A' */
}; };
CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL); CV cv(&MCP4728, &Wire, N_CV_GATES, cvMap, keyToVoltage, N_KEYBOARD_ROW, N_KEYBOARD_COL);
// Sequencer mit 30s max, 50ms Mindest-Step-Dauer // Sequencer 30s max, 512 max Steps
SequencerBlock sb1(30000, 50); SequencerBlock sb1(30000, N_MAX_SEQ_STEPS);
SequencerBlock sb2(30000, 50); SequencerBlock sb2(30000, N_MAX_SEQ_STEPS);
// Button States // Button States
struct ButtonState { struct ButtonState {