Hi,
this might perhaps be interesting for some guys working on audio projects.
It is a testtone-generator which can do logarithmic frequency sweeps. If you have a 2-channel oscilloscope, then the second channel ist used for trigger and to display a logarithmic frequency grid, which is very handy to see the frequency response. See attachment for an example 80Hz to 10kHz.
In addition to a constant tone and two different sweeps there is a mode to test for compression. The volume of a 400Hz signal is modulated: low-high-low. This is interesting for Guitar Amps or effects.
It took me a while to get a high sample rate for good looking 20kHz. There is some compromise: At low frequency, the precision of the frequencies is not so good and there are some stops of the output between bursts of clear signal.
/*Potentiometer at A0 for selection of 4 different functions:
1. 400Hz constant Test Tone
2. Sweep for Guitar 80…10000Hz
3. Compresstest 400Hz; 1/4=>1=>1/4 Amplitude
4. Sweep for general use 20Hz … 20kHz
NF Output at A14, 12 bit
Grid Output with 2bit-Dac using digital outputs at 15 and 16 Trigger full 3.3V, Grid 0…1,65V
LED Pin 13 indicates Poti Mode
*/
The hardware is pretty simple.
Suggestions for additional modes?
Enjoy!
Christof
this might perhaps be interesting for some guys working on audio projects.
It is a testtone-generator which can do logarithmic frequency sweeps. If you have a 2-channel oscilloscope, then the second channel ist used for trigger and to display a logarithmic frequency grid, which is very handy to see the frequency response. See attachment for an example 80Hz to 10kHz.
In addition to a constant tone and two different sweeps there is a mode to test for compression. The volume of a 400Hz signal is modulated: low-high-low. This is interesting for Guitar Amps or effects.
It took me a while to get a high sample rate for good looking 20kHz. There is some compromise: At low frequency, the precision of the frequencies is not so good and there are some stops of the output between bursts of clear signal.
/*Potentiometer at A0 for selection of 4 different functions:
1. 400Hz constant Test Tone
2. Sweep for Guitar 80…10000Hz
3. Compresstest 400Hz; 1/4=>1=>1/4 Amplitude
4. Sweep for general use 20Hz … 20kHz
NF Output at A14, 12 bit
Grid Output with 2bit-Dac using digital outputs at 15 and 16 Trigger full 3.3V, Grid 0…1,65V
LED Pin 13 indicates Poti Mode
*/
Code:
#define VERSION "TeensyDac_J"
// for Teensy 3.2 09.05.2019 CWE
/*Potentiometer at A0 for selection of functions:
1. 400Hz constant Test Tone
2. Sweep for Guitar 80…10000Hz
3. Compresstest 400Hz; 1/4=>1=>1/4 Amplitude
4. Sweep for general use 20Hz … 20kHz
NF Output at A14, 12 bit
Grid Output with 2bit-Dac using digital outputs at 15 and 16 Trigger full 3.3V, Grid 0…1,65V
LED Pin 13 indicates Poti Mode
*/
#include <math.h>
float phase = 0.0;
float twopi = 3.14159 * 2;
elapsedMicros usec = 0;
const int ledPin = 13;
// #define gridPin A22
#define gridP1 15
#define gridP2 16
#define dacPin A14 //A21 for 3.5
#define potiPin A0 // For selection of modes
# define BUFLEN 16384
void startblink(int n)
{
int i;
for(i=0; i<n; i++)
{
digitalWrite(ledPin, HIGH); // set the LED on
delay(150); // wait for a second
digitalWrite(ledPin, LOW); // set the LED off
delay(150); // wait for a second
}
}
int bufmax;
short int buffer[BUFLEN+1];
void fillbuffer()
{
int i=0;
while(phase < twopi)
{
float val = sin(phase) * 2047.0; //+ 2050.0; // 0.1/1.17 f. 1000mV RMS
//float val = 100.0/950.0*sin(phase) * 2000.0 + 2050.0; // f. 100mV RMS
buffer[i]= (int)val;
phase = phase + twopi/(BUFLEN);
i++;
}
float val = sin(phase) * 2047.0; //+ 2050.0;
buffer[i]= (int)val;
}
unsigned long timeu;
float freq= 200.0;
float tcyc= 2.0;
float fsteps[30]= {10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, \
200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, \
2000.0, 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 10000.0,20000.0};
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(gridP1, OUTPUT);
pinMode(gridP2, OUTPUT);
// pinMode(gridPin, OUTPUT);
digitalWrite(gridP1, 0);
digitalWrite(gridP2, 0);
analogWriteResolution(12);
//analogWrite(gridPin, 0);
analogWrite(dacPin, 2048);
startblink(10);
Serial.begin(115200);
fillbuffer();
Serial.println(VERSION);
Serial.println("Buffer gefuellt.");
//startblink();
}
float frmin;
float frmax;
float twidth; //us
void loop() {
int poti= analogRead(potiPin)*5/1024 + 1;
Serial.println(poti);
startblink(poti);
if(poti==1) // Constant 400Hz
{
frmin= 400.0;
frmax= 400.1;
twidth= 2000000.0; //us
sweep_C();
}
if(poti==2) // Spweep for Guitar
{
frmin= 80.0;
frmax= 10000.0;
twidth= 2000000.0; //us
sweep_C();
}
if(poti==3) // Compresstest 400Hz
{
comp_B();
}
if(poti==4) // Spweep for Audio
{
frmin= 20.0;
frmax= 20000.0;
twidth= 2000000.0; //us
sweep_C();
}
//while(1);
}
int iold=0, iakt, ifrequenz, imode=1, ifakt, irepeats=100, ideltat;
unsigned long oldu, aktu;
float frfaktor;
void fastsample(void)
{
// ifrequenz=20000;
ifakt= ifrequenz*BUFLEN/(1000000/4);
iakt=0;
oldu=micros()/4;
for(int i=0; i<irepeats; i++)
{
do
{
if(imode==1) analogWrite(dacPin, 2048 + buffer[iakt]);
else analogWrite(dacPin, 2048 + buffer[iakt]/4);
aktu=micros()/4;
iakt+=(aktu-oldu)*ifakt;
oldu=aktu;
} while(iakt<BUFLEN);
iakt-=BUFLEN;
}
analogWrite(dacPin, 2048);
}
void comp_B() // Compressortest
{
ifrequenz=400;
imode = 0;
irepeats= 266;
fastsample();
imode=1;
//analogWrite(gridPin, 4095); //Trigger
digitalWrite(gridP1, 1);
digitalWrite(gridP2, 1);
fastsample();
imode=0;
//analogWrite(gridPin, 0); //Trigger
digitalWrite(gridP2, 0);
digitalWrite(gridP1, 0);
fastsample();
}
void sweep_C()
{
int fstep=0;
unsigned long int tistart;
int gridstat;
float ffaktor= (log10(frmax)-log10(frmin))/twidth;
float log10frmin= log10(frmin);
freq= frmin;
//analogWrite(gridPin, 4095); //Trigger
digitalWrite(gridP1, 1);
digitalWrite(gridP2, 1);
gridstat=1;
tistart= micros();
oldu= tistart;
imode=1;
iakt=0;
iold=0;
while(freq<frmax)
{
//frfaktor= freq*BUFLEN/1000000.0;
//Serial.println(freq);
ifrequenz=freq;
while(freq>=fsteps[fstep]) // Next grid line
{
if(gridstat<1)
{
//analogWrite(gridPin, 2048);
digitalWrite(gridP1, 1);
digitalWrite(gridP2, 0);
gridstat=1;
}
else
{
//analogWrite(gridPin, 0);
digitalWrite(gridP1, 0);
digitalWrite(gridP2, 0);
gridstat=0;
}
//Serial.println("Grid");
fstep++;
}
// fastsample();
if(freq<100.0) irepeats= 1;
else if(freq<1000.0) irepeats= 5;
else if(freq<5000.0) irepeats= 10;
else if(freq<10000.0) irepeats= 30;
else irepeats=100;
fastsample();
float fhelp= ffaktor*(micros()-tistart);
fhelp += log10frmin;
freq= pow(10,fhelp);
}
//analogWrite(gridPin, 0);
digitalWrite(gridP1, 0);
digitalWrite(gridP2, 0);
gridstat=0;
imode=0;
analogWrite(dacPin,2048);
delay(1000);
}
The hardware is pretty simple.
Suggestions for additional modes?
Enjoy!
Christof
Attachments
Last edited: