ENGR 478 Embedded Systems Term Project
Digital piano on the STM32 NUCLEO-L476RG
A register-level embedded piano built with four push buttons, three speaker outputs, SysTick sound timing, EXTI button interrupts, and two ADC potentiometer controls.
Real-time signal path
Buttons select chords. Potentiometers control volume and octave.
Hardware Setup
Simple hardware, clear pin responsibilities
The hardware is intentionally small so the software behavior can be measured and explained clearly.
Push Buttons
PC0, PC1, PC2, and PC3 are inputs with pull-up resistors. Each press or release creates an EXTI interrupt.
Speaker Outputs
PA5, PA6, and PA7 are GPIO outputs. SysTick updates these pins to create the sound waveform.
Volume Knob
PA0 is an ADC input connected to a 10 kOhm potentiometer. It controls the duty time of the sound output.
Octave Knob
PA1 is an ADC input connected to a 10 kOhm potentiometer. It moves the selected note lower or higher.
| Pin | Direction | Project Use |
|---|---|---|
| PA5 | Output | Speaker output 1 |
| PA6 | Output | Speaker output 2 |
| PA7 | Output | Speaker output 3 |
| PC0-PC3 | Input | Push buttons through EXTI |
| PA0 | Analog input | Volume potentiometer |
| PA1 | Analog input | Octave potentiometer |
Software Flow
Main logic and interrupts are separated
The program initializes GPIO, SysTick, EXTI, and ADC. After setup, the main loop waits
with __WFI(). Button changes are handled by EXTI interrupts, while sound
timing runs from the SysTick interrupt at 20 kHz.
- Main loop reads ADC values every 20 ms.
- EXTI interrupt updates the active button state.
- SysTick interrupt drives PA5, PA6, and PA7.
- Shared variables connect the modules without using HAL.
Chord Table
Each button selects a three-note chord
The software maps each button to a chord table, then the SysTick sound engine outputs the selected tones.
C Major
C - E - G
G Major
G - B - D
A Minor
A - C - E
F Major
F - A - C
Demo Plan
What the project demonstrates
The live demo is organized around the main embedded concepts used in the project.
Button Response
Press each button and show that a different chord is selected.
Release Behavior
Release the button and show that the sound stops cleanly.
Volume Control
Turn the PA0 potentiometer and show the sound level changing.
Octave Control
Turn the PA1 potentiometer and show the pitch moving lower and higher.
Testing
Measured with Analog Discovery 2
The project was tested by checking the speaker output pins, button press and release behavior, ADC volume control, and ADC octave control. The measured values show that the generated tones closely match the expected musical frequencies.
AD2 Volume Readings
Volume changes while pitch stays stable
These measurements were taken while playing the SW1 C major chord. The frequencies stay nearly constant while the positive duty cycle decreases, which shows that PA0 changes loudness without changing the note pitch.
| Volume Setting | PA5 Frequency / Duty | PA6 Frequency / Duty | PA7 Frequency / Duty |
|---|---|---|---|
| High | 263.85 Hz / 48.582% | 334.45 Hz / 48.188% | 385.85 Hz / 48.006% |
| Medium | 263.85 Hz / 26.253% | 334.36 Hz / 26.525% | 385.73 Hz / 26.840% |
| Low | 264.03 Hz / 1.254% | 334.45 Hz / 1.589% | 385.73 Hz / 1.736% |
AD2 Octave Readings
Octave knob shifts the chord frequency
These measurements show the PA1 octave potentiometer moving the same SW1 C major chord down, back to normal, and up. Each octave step approximately doubles or halves the frequency.
| Octave Setting | PA5 | PA6 | PA7 |
|---|---|---|---|
| Lower Octave | 132.06 Hz | 167.29 Hz | 193.05 Hz |
| Middle Octave | 264.29 Hz | 334.54 Hz | 386.10 Hz |
| Higher Octave | 528.54 Hz | 669.27 Hz | 772.63 Hz |
Firmware
How the code is organized
The project is split into small C files so each peripheral has a clear job and the full program is easy to explain.
main.c
Starts the board setup, reads the two ADC knobs, checks the active button, and calls the sound functions.
button.c
Sets PC0-PC3 as button inputs, uses EXTI interrupts, and debounces button press and release changes.
Systick_timer.c
Runs the 20 kHz sound timing, loads chord frequencies, changes volume duty time, and counts milliseconds.
ADC.c
Reads PA0 and PA1, smooths the knob values, and converts them into volume and octave settings.