For a first, experiment, I connected it up to an Arduino Uno, with the top 6 bits on pins 8-13 (port B) and the bottom three on pins 5-7 (port D). It's fastest to drive the ports directly, rather than using digitalWrite. The code is below. It has multiple options in it: sampled triangle and sine waves, and a square wave, using a delay to get the frequency approximately right; and a version which drives the ports as fast as possible.
The results are remarkably good. Here are example triangle and sine waves at about 10kHz:
For square waves, they still look OK at 100kHz:
The fastest square (-ish) wave I could get was about 250kHz:
In the speed test version, I could get it up to around 2.63MHz, though of course the signal is nothing like a square wave at the point:
By ignoring the lower order bits on port D, I pushed it up to 4.17MHz, with the waveform looking not much different to above.
Note that this isn't a practical design for a real DAC. It works in these experiments because the scope doesn't put much load on it. In a real design, you would put some buffering such as an opamp on the output, and also use resistors with tighter tolerances and more exact values
Here's the code. XMOS version to follow in another post.
#define NSAMPLES 64 short samples[NSAMPLES]; long max_value = 511; double freq = 400000; // Approximate, due to rounding and overheads #define PI 3.14156 void setup() { // Use pins 5 to 13 (low to high bit) DDRD = 0xe0; // Pins 5-7 DDRB = 0x3f; // Pins 8-13 for (int i = 0; i < NSAMPLES; ++i) { // Triangle //samples[i] = (max_value * i)/NSAMPLES; // Sine samples[i] = (short)(max_value * (1 + sin((float)i * 2 * PI / NSAMPLES))/2); } } void set(unsigned short n) { PORTD = (n & 0x07) << 5; PORTB = (n & 0x1f8) >> 3; } // True for a sampled waveform, false for a square wave. bool sampled = false; // Set for max speed square wave. #define MAXSPEED void loop() { #ifdef MAXSPEED while (1) { PORTD = 0; PORTB = 0; PORTD = 0xe0; PORTB = 0x3f; } #else if (sampled) { int delay_us = (int)((1000000.0/freq)/NSAMPLES); while (1) { for (int i = 0; i < NSAMPLES; ++i) { set(samples[i]); delayMicroseconds(delay_us); } } } else { int delay_us = (int)((1000000.0/freq)/2); while (1) { set(0); delayMicroseconds(delay_us); set(max_value); delayMicroseconds(delay_us); } } #endif }
No comments:
Post a Comment