A waveform generator implemented on a DE1-SoC FPGA board that produces sine waves and PWM square waves at 16 selectable frequencies (10Hz to 10kHz) with 8 duty cycle presets.
- 16 Preset Frequencies: 10, 20, 50, 100, 200, 500, 700, 1k, 2k, 3k, 4k, 5k, 7k, 8k, 9k, 10k Hz
- Dual Waveforms: 64-sample sine wave and PWM square wave
- 8 Duty Cycles: 0%, 12%, 25%, 37%, 50%, 62%, 75%, 87%
- Context-Aware Display: Shows "S" + frequency (Hz) or "P" + duty cycle (%)
- Leading Zero Suppression: Clean numeric display (e.g., "S 10" not "S 00010")
- Simple DAC Interface: CS̄/WR̄ tied to GND (continuous write mode)
| Component | Specification |
|---|---|
| FPGA Board | DE1-SoC (Intel Cyclone V 5CSEMA5F31C6) |
| DAC Chip | TLC7524CN 8-bit (16-pin DIP) |
| Breadboard | Standard solderless breadboard |
| Jumper Wires | 11 wires minimum |
| Oscilloscope | For waveform verification |
| Power | USB (from DE1-SoC to PC) |
- Clone or download this repository
- Open Intel Quartus Prime
- Create new project:
- File → New Project Wizard
- Choose any location
- Project name:
fpga_function_generator - Top-level entity:
function_generator_top
- Add VHDL files: Add all 7 files from the
vhdl/folder - Set target device:
- Assignments → Device
- Select: 5CSEMA5F31C6 (NOT 5CSEBA5!)
- Assign pins (create new .qsf or manually assign):
set_location_assignment PIN_AF14 -to CLOCK_50 set_location_assignment PIN_AA14 -to KEY[0] set_location_assignment PIN_AB12 -to SW[0] set_location_assignment PIN_AC12 -to SW[1] set_location_assignment PIN_AF9 -to SW[2] set_location_assignment PIN_AF10 -to SW[3] set_location_assignment PIN_AD11 -to SW[4] set_location_assignment PIN_AD12 -to SW[5] set_location_assignment PIN_AE11 -to SW[6] set_location_assignment PIN_AC9 -to SW[7] set_location_assignment PIN_AD10 -to SW[8] set_location_assignment PIN_AE26 -to HEX0[0] set_location_assignment PIN_AE27 -to HEX0[1] set_location_assignment PIN_AE28 -to HEX0[2] set_location_assignment PIN_AG27 -to HEX0[3] set_location_assignment PIN_AF28 -to HEX0[4] set_location_assignment PIN_AG28 -to HEX0[5] set_location_assignment PIN_AH28 -to HEX0[6] [Continue for HEX1-5, GPIO_0[7:0]] - Compile: Processing → Start Compilation (wait ~5 minutes)
- Locate .sof file:
output_files/fpga_function_generator.sof
TLC7524CN (16-pin DIP)
+---v---+
OUT1|1 16| RFB (not used)
OUT2|2 15| REF ⚡ OUTPUT (to oscilloscope)
GND |3 14| VDD (+5V power)
DB7 |4 13| WR̄ (write, tie to GND)
DB6 |5 12| CS̄ (chip select, tie to GND)
DB5 |6 11| DB0
DB4 |7 10| DB1
DB3 |8 9| DB2
+-------+
| GPIO_0 | DAC Pin |
|---|---|
| +3.3V | 1 (OUT1) |
| GND | 2 (OUT2) |
| GND | 3 (GND) |
| [7] | 4 (DB7) |
| [6] | 5 (DB6) |
| [5] | 6 (DB5) |
| [4] | 7 (DB4) |
| [3] | 8 (DB3) |
| [2] | 9 (DB2) |
| [1] | 10 (DB1) |
| [0] | 11 (DB0) |
| - | 12 (CS̄) → GND on breadboard |
| - | 13 (WR̄) → GND on breadboard |
| +5V | 14 (VDD) |
| Oscilloscope | 15 (REF) ← OUTPUT |
| - | 16 (RFB) not used |
- Connect DE1-SoC board to PC via USB
- Open Quartus Programmer: Tools → Programmer
- Click "Hardware Setup" → Select USB-Blaster
- Click "Add File" → Select
output_files/fpga_function_generator.sof - Check "Program/Configure" box
- Click "Start" → Wait ~30 seconds
| Switch | Function |
|---|---|
| SW[8] | Waveform Mode: 0 = Sine, 1 = PWM |
| KEY[0] | Reset (press and release) |
| SW[3:0] | Binary | Frequency |
|---|---|---|
| 0 | 0000 | 10 Hz |
| 1 | 0001 | 20 Hz |
| 2 | 0010 | 50 Hz |
| 3 | 0011 | 100 Hz |
| 4 | 0100 | 200 Hz |
| 5 | 0101 | 500 Hz |
| 6 | 0110 | 700 Hz |
| 7 | 0111 | 1 kHz |
| 8 | 1000 | 2 kHz |
| 9 | 1001 | 3 kHz |
| 10 | 1010 | 4 kHz |
| 11 | 1011 | 5 kHz |
| 12 | 1100 | 7 kHz |
| 13 | 1101 | 8 kHz |
| 14 | 1110 | 9 kHz |
| 15 | 1111 | 10 kHz |
| SW[6:4] | Binary | Duty Cycle |
|---|---|---|
| 0 | 000 | 0% |
| 1 | 001 | 12% |
| 2 | 010 | 25% |
| 3 | 011 | 37% |
| 4 | 100 | 50% |
| 5 | 101 | 62% |
| 6 | 110 | 75% |
| 7 | 111 | 87% |
Sine Mode (SW[8] = DOWN/0):
- HEX5 shows:
S - HEX4-0 show frequency in Hz with leading zero suppression
- Examples:
- 10 Hz →
S 10 - 100 Hz →
S 100 - 1 kHz →
S 1000 - 10 kHz →
S10000
- 10 Hz →
PWM Mode (SW[8] = UP/1):
- HEX5 shows:
P - HEX4-0 show duty cycle percentage
- Examples:
- 0% →
P 0 - 50% →
P 50 - 87% →
P 87
- 0% →
(Spaces represent blank 7-segment digits due to leading zero suppression)
Setup:
- Probe: Connect to DAC Pin 15 (REF)
- Ground: Connect to breadboard ground
- Probe attenuation: 1X (not 10X)
Sine Wave Example (10 Hz):
- Settings: SW[8]=0 (Sine), SW[3:0]=0000 (10Hz)
- Horizontal: 10 ms/div (period = 100ms)
- Vertical: 500 mV/div
- Expected: 64 discrete voltage steps forming sine shape
- Amplitude: ~3.3 Vpp (0V to 3.3V)
- Frequency: 10 Hz
Sine Wave Example (1 kHz):
- Settings: SW[8]=0 (Sine), SW[3:0]=0111 (1kHz)
- Horizontal: 500 μs/div (period = 1ms)
- Expected: Smooth sine wave (steps too fast to see)
- Amplitude: ~3.3 Vpp
PWM Example (1 kHz, 50% duty):
- Settings: SW[8]=1 (PWM), SW[3:0]=0111 (1kHz), SW[6:4]=100 (50%)
- Horizontal: 500 μs/div
- Expected: Clean square wave
- High time: 500 μs (50%)
- Low time: 500 μs (50%)
- Amplitude: 0V to ~3.3V
| Parameter | Value |
|---|---|
| Device | Intel Cyclone V 5CSEMA5F31C6 (DE1-SoC) |
| Clock | 50 MHz system clock |
| Waveforms | Sine (64-sample LUT), PWM square wave |
| Frequencies | 16 presets: 10Hz - 10kHz |
| Frequency Accuracy | < 1% error |
| Sine Resolution | 64 samples/cycle (5.625° per step) |
| Duty Cycles | 8 presets: 0% - 87% |
| DAC | TLC7524CN 8-bit (multiplying mode) |
| Output Voltage | 0V to 3.3V |
| Output Signal | ~3.3 Vpp |
The design consists of 7 modular VHDL files:
function_generator_top.vhd (Top-level integration)
├── clock_divider.vhd (Programmable sample clock from 50MHz)
├── frequency_controller.vhd (SW[3:0] → clock divider ratio + frequency value)
├── sine_generator.vhd (64-sample sine LUT with FSM)
├── pwm_generator.vhd (Duty cycle counter: 8 presets)
├── waveform_selector.vhd (Mux: selects sine or PWM based on SW[8])
└── segment_display.vhd (Context-aware 7-seg controller: S/P + value)
| Module | Type | Purpose |
|---|---|---|
function_generator_top |
Top-level | I/O mapping, component instantiation |
clock_divider |
Sequential | Divides 50MHz clock to sample rate |
frequency_controller |
Combinational | Maps SW[3:0] to divider ratio and frequency |
sine_generator |
Sequential | 64-sample sine LUT, FSM to cycle through samples |
pwm_generator |
Sequential | Counter-based PWM with 8 duty cycle presets |
waveform_selector |
Combinational | 2:1 mux selects sine or PWM output |
segment_display |
Combinational | Displays "S" or "P" + numeric value with leading zero suppression |
Solutions:
- Verify CS̄ (Pin 12) and WR̄ (Pin 13) are connected to GND (breadboard)
- Check OUT1 (Pin 1) = 3.3V, OUT2 (Pin 2) = 0V
- Ensure measuring REF (Pin 15), not OUT1
- Press KEY[0] to reset
- Verify DAC powered: VDD (Pin 14) = 5V
- Check oscilloscope probe set to 1X (not 10X)
Likely causes:
- Measuring wrong pin (OUT1 instead of REF)
- OUT1 not connected to 3.3V
- CS̄/WR̄ not connected to GND
- Probe set to 10X instead of 1X
Solutions:
- Verify switch positions carefully
- Press KEY[0] to reset
- Check device is 5CSEMA5F31C6 in Quartus (not 5CSEBA5)
- Verify 7-segment encoding is ACTIVE LOW in VHDL
Solutions:
- Ensure all 7 VHDL files added to project
- Set
function_generator_topas top-level entity - Verify device: 5CSEMA5F31C6
- Check pin assignments match your GPIO_0 header
Solution: Wrong device selected - must be 5CSEMA5F31C6 (NOT 5CSEBA5)
- Smooth waveform quality (5.625° angular resolution)
- Visible 64-step staircase at low frequencies (10Hz, 20Hz)
- Matches industry standard
- Integer duty cycle divisions (8/64 = 12.5%, 16/64 = 25%, etc.)
- OUT1/OUT2 set voltage range → REF becomes output
- No WR̄ pulsing needed (tied to GND = continuous write)
- Simpler hardware, fewer control signals
- Stronger signal amplitude (3.3 Vpp vs 0.5 Vpp in standard mode)
- Shows relevant information only (frequency in Sine, duty in PWM)
- Clear mode indicator (S vs P)
- Leading zero suppression improves readability
- No wasted display space
MIT License - See LICENSE file for details
- DE1-SoC Board: Terasic Inc.
- DAC Chip: Texas Instruments TLC7524CN
- FPGA Tools: Intel Quartus Prime
⭐ If you find this project useful, please star the repository!