Harmonic Motion
• FPGA-driven stepper synth

Overview

Project converting precise motion into musical tone. Timing and motor control on an FPGA;
input, interface, and I/O on a microcontroller.

  • Goals: 5 “voices” across 5 motors; microstepping sound amplification with resonance chamber development
  • Tech: Verilog modules, UART and MIDI protocols, C++ firmware
  • Status:
    FPGA single-motor control via on-board switches and Arduino-based key input driving a single
    motor are working; integration of MIDI and multi-voice expansion is in progress.

Digital simulation of a single voice motor control
Digital simulation of a single “voice”.

FPGA Verilog / pulse engine logic screenshot
FPGA pulse engine / state-machine code for motor control.

3D model of piano-style keyboard for stepper synth
3D CAD model of the keyboard module for user input.

FPGA board, Arduino, stepper driver, and motor wired together
Current prototype: FPGA, Arduino, drivers, and stepper motor wired together.

Small Code Sample

// Ramp setup
void serviceRamps() {
  unsigned long now = millis();

  for (int i = 0; i < NUM_MOTORS; i++) {
    if (!motors[i].running) continue;
    if (motors[i].currentNote < 0) continue;
    if (motors[i].currentFreq >= motors[i].targetFreq) continue;

    if (now - motors[i].rampStartMS >= RAMP_TICK_MS) {
      motors[i].rampStartMS = now;
      motors[i].currentFreq += FREQ_RAMP_STEP;

      if (motors[i].currentFreq > motors[i].targetFreq) {
        motors[i].currentFreq = motors[i].targetFreq;
      }

      if (motors[i].currentFreq > 0) {
        motors[i].stepPeriodUs = 1000000UL / motors[i].currentFreq;
      } else {
        motors[i].stepPeriodUs = 0;
      }
    }
  }
}

// Dealing with microstepping and more ramping
void serviceSteps() {
  unsigned long nowUs = micros();

  for (int i = 0; i < NUM_MOTORS; i++) {
    if (!motors[i].running) continue;
    if (motors[i].stepPeriodUs == 0) continue;

    if ((long)(nowUs - motors[i].nextStepUs) >= 0) {
      motors[i].stepLevel = !motors[i].stepLevel;
      digitalWrite(STEP_PINS[i], motors[i].stepLevel);

      unsigned long halfPeriod = motors[i].stepPeriodUs / 2;
      motors[i].nextStepUs = nowUs + halfPeriod;
    }
  }
}

// Clearing motor when key is released
void releaseKeyFromMotors(int keyIndex) {
  for (int i = 0; i < NUM_MOTORS; i++) {
    if (motors[i].assignedKey == keyIndex) {
      stopMotor(i);
    }
  }
}

Gantt Chart as of 11/14/25


Gantt chart screenshot

Excel snapshot of project Gantt chart (schedule and milestones).

Team Members

Ben Hopper

Ben Hopper
Project Lead / Embedded Systems

MIDI encode/decode logic, Arduino firmware, hardware integration, and overall coordination.

Vincent Perlowin

Vincent Perlowin
FPGA Specialist

FPGA integration, pulse engines, Verilog modules, and MIDI decoding logic.

Dr. Kim

Dr. Kim
Faculty Advisor

Guides technical decisions, project scope, and academic direction.