Table of Contents
- What Is a Function Generator?
- PWM-Based Approach: Simple but Limited
- R-2R Ladder DAC: 8-Bit Output from Digital Pins
- MCP4725 I2C DAC: True 12-Bit Analogue Output
- Waveform Mathematics: Sine, Square, Triangle, Sawtooth
- Frequency Control with Potentiometer
- Arduino Due: Built-in DAC for Best Performance
- Frequently Asked Questions
- Conclusion
What Is a Function Generator?
An arduino function generator DAC creates electronic waveforms (sine, square, triangle, sawtooth) at adjustable frequencies. It is an essential test instrument for electronics work — generating signals for testing amplifiers, filters, speakers, and communication circuits. A commercial function generator costs ₹5,000-20,000, while an Arduino-based version costs under ₹500 in components.
The key component is a Digital-to-Analogue Converter (DAC) that converts digital values from the Arduino into analogue voltage levels. By rapidly cycling through calculated voltage values, the Arduino creates a smooth analogue waveform.
PWM-Based Approach: Simple but Limited
The simplest approach uses Arduino’s PWM output with an RC low-pass filter to smooth the signal into an analogue waveform:
// PWM sine wave generator
// Pin 9 -> 10K resistor -> output
// -> 100nF cap to GND
const byte sineTable[256] = {
128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173,
176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215,
218,220,222,224,226,228,230,232,234,235,237,239,240,242,243,244,
246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255,
255,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247,
246,244,243,242,240,239,237,235,234,232,230,228,226,224,222,220,
218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179,
176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131,
128,124,121,118,115,112,109,106,103,100,97,93,90,88,85,82,
79,76,73,70,67,65,62,59,57,54,52,49,47,44,42,40,
37,35,33,31,29,27,25,23,21,20,18,16,15,13,12,11,
9,8,7,6,5,4,3,3,2,1,1,0,0,0,0,0,
0,0,0,0,0,0,1,1,2,3,3,4,5,6,7,8,
9,11,12,13,15,16,18,20,21,23,25,27,29,31,33,35,
37,40,42,44,47,49,52,54,57,59,62,65,67,70,73,76,
79,82,85,88,90,93,97,100,103,106,109,112,115,118,121,124
};
volatile byte index = 0;
void setup() {
pinMode(9, OUTPUT);
// Timer1 for precise sample rate
noInterrupts();
TCCR1A = 0; TCCR1B = 0; TCNT1 = 0;
OCR1A = 199; // 16MHz / 8 / 200 = 10 kHz sample rate
TCCR1B = (1<<WGM12) | (1<<CS11); // CTC, prescaler 8
TIMSK1 = (1<<OCIE1A);
interrupts();
}
ISR(TIMER1_COMPA_vect) {
analogWrite(9, sineTable[index++]);
}
void loop() {}
// Output: ~39 Hz sine wave (10000 / 256 = 39 Hz)
The PWM frequency is 490 Hz on pin 9, which limits the output quality. The RC filter must remove the 490 Hz carrier while passing the desired signal. This works for sub-100 Hz signals but produces distortion at higher frequencies.
R-2R Ladder DAC: 8-Bit Output from Digital Pins
An R-2R resistor ladder connected to 8 digital pins creates a true 8-bit DAC with no filtering needed. Use 16 resistors (8x 10K and 8x 20K) arranged in a ladder network. Writing an 8-bit value to PORTD sets all 8 pins simultaneously, producing an instant voltage change.
// R-2R DAC on pins 0-7 (PORTD)
ISR(TIMER1_COMPA_vect) {
PORTD = sineTable[index++]; // All 8 bits update simultaneously
}
// Much faster than analogWrite - can reach 100+ kHz output
The R-2R approach is faster than PWM because there is no filter delay. The output changes instantly with each sample, enabling output frequencies up to 20 kHz or more.
MCP4725 I2C DAC: True 12-Bit Analogue Output
#include <Wire.h>
#define MCP4725_ADDR 0x60
void writeMCP4725(uint16_t value) {
Wire.beginTransmission(MCP4725_ADDR);
Wire.write((value >> 8) & 0x0F); // Upper 4 bits
Wire.write(value & 0xFF); // Lower 8 bits
Wire.endTransmission();
}
const uint16_t sineTable12[100] = { /* 12-bit sine values */ };
// Pre-calculate: for i in range(100): int(2047 + 2047 * sin(2*pi*i/100))
void loop() {
for (int i = 0; i 30 Hz with 100 samples
}
The MCP4725 provides 12-bit resolution (4096 voltage levels) for smooth, low-distortion waveforms. However, I2C communication limits the update rate to about 3 kSPS at 400 kHz, capping output frequency at a few hundred Hz with acceptable quality.
Waveform Mathematics: Sine, Square, Triangle, Sawtooth
// Generate different waveform tables
void generateSine(int* table, int size, int amplitude) {
for (int i = 0; i < size; i++)
table[i] = amplitude/2 + (amplitude/2) * sin(2*PI*i/size);
}
void generateSquare(int* table, int size, int amplitude) {
for (int i = 0; i < size; i++)
table[i] = (i < size/2) ? amplitude : 0;
}
void generateTriangle(int* table, int size, int amplitude) {
for (int i = 0; i < size; i++) {
if (i < size/2) table[i] = amplitude * 2 * i / size;
else table[i] = amplitude * 2 * (size - i) / size;
}
}
void generateSawtooth(int* table, int size, int amplitude) {
for (int i = 0; i < size; i++)
table[i] = amplitude * i / size;
}
Frequency Control with Potentiometer
Read a potentiometer on A0 and map its value to the timer compare register, changing the sample rate and thus the output frequency. A 10K potentiometer gives you smooth, continuous frequency adjustment.
Arduino Due: Built-in DAC for Best Performance
The Arduino Due has two built-in 12-bit DACs that update at up to 1 MSPS. This enables function generation up to approximately 100 kHz with good waveform quality — far beyond what the Uno can achieve. If you need a serious Arduino-based function generator, the Due is the platform to use.
Frequently Asked Questions
What is the maximum output frequency?
With PWM + filter: ~100 Hz usable. With R-2R DAC: ~20 kHz. With MCP4725: ~500 Hz. With Arduino Due DAC: ~100 kHz. With AD9833 DDS module: 12.5 MHz.
Can I generate two frequencies simultaneously?
On the Due, yes — it has two independent DACs. On the Uno, you would need two R-2R DACs or two PWM outputs with separate filters.
How do I verify my function generator output?
Use the Arduino oscilloscope project (from the previous article) on a second Arduino, or use the Serial Plotter by feeding the DAC output back into an analog input.
Conclusion
An Arduino function generator is a practical test instrument for any electronics workspace. Start with the PWM approach for simplicity, upgrade to an R-2R ladder for better performance, or use an MCP4725 DAC for clean 12-bit output. For the best results, the Arduino Due’s built-in DAC provides professional-quality waveform generation.
Add comment