Jan 2016
DTMF decoding using Goertzel based algo wiith fixed math algorithm
Sampling frequency 8 KHz
Sampling time 125us
Two buffer with 205 samples each
Single buffer loading time = 205 * 0.125 = 25.626ms
Time to execute Goertzel Algo on 1 buffer using integer fixed math = 2ms
Time to Scan 4 lines = 8ms without any code present (for a full 4x4 keyboard)
Max Time if "D" char pressed = 16ms
Other time free to execute anything else
And here the whole sw on the go
Real time DTMF code decoding.
Take care to the LED on the Arduino board
1234 code turns Arduino internal led on
9876 code turns it off
ADC front end using rail-to-rail OPA344
MFT frequency response
Eagle CAD draw
Goertzel coefficeint in 7bit fixed math evaluated at 8Khz sampling frequency
ATmega328 ADC specific usage
Using timer1 compare match B for ADC sampling.
[take care on arduino one timer0 should be used by delay(), millis() and micros() / time1 used by the servo library / timer2 used by tone()]
//initialize timer1 Compare Match B
void InitTimer1(void)
{
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
// Set Initial Timer counter value
TCNT1 = 0;
// prescaler set to 64
// on 16Mhz clock so 4us time period x120 = 480 us => 2083hz
// ADC sampling will be at 2Khz nice for 1Khz BW
// WARNING: OCF1B MUST BE CLEARED BY MANUALLY !! TIFR1 =(1<<OCF1B)
ICR1 = 120; // <<<== Compare match B occurs on register !!
// Make toggle PB2/OC1B pin on compare match
TCCR1A |= (1 << COM1B0); // WARNING: MUST BE CLEARED BY MANUALLY !!
// turn on CTC mode compare match B
TCCR1B |= (1 << WGM13) | (1 << WGM12); // >>>>> warning: if compb no !!
}
Clock period here:
void InitADC()
{
// Mux Analog channel 0000 => ADC0
ADMUX=0;
// Select Vref=AVcc
ADMUX |= (1<<REFS0);
// Set left adjust result
ADMUX |= (1<<ADLAR);
ADCSRA = 0;
ADCSRB = 0;
// 10-bit successive approximation ADC
// AD-auto-trigger-enable, AD-interrupt-enabled, AD-converter on, prescaler = 64
// ADC clock set to 16x10^6/64 = 250Khz => 4us (not sutable for 10bit convertion)
// so single convertion takes 13.5 ADC clock cycles = 54us
ADCSRA |= (1<<ADATE)|(1<<ADIE)|(1<<ADEN)| (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
ADCSRB |= (1<<ACME) | (1<<ADTS2) | (1<<ADTS0); //Setting compare match B as trigger source
}
Sampling simple signal:
Synthesizing code for DTMF code "1" (freq 697Hz + 1209Hz) for use with GWInstek AFG-2125 Arbitrary function generator.
Sampling_rate:16Khz
Block_size: 4096
#include <stdio.h>
#include <math.h>
#define PI 3.1415
#define DUEPI 6.2831853071795865
#define FLOATING float
#define SAMPLE int
//#define SAMPLE unsigned char
#define SAMPLING_RATE 16000.0 //8kHz
#define N 4096 //Block size
SAMPLE testData[N];
/* Synthesize some test data at a given frequency. */
void GenerateDTMF(void)
{
int n;
FLOATING step;
step = 1 / SAMPLING_RATE;
/* Generate the test data */
for (n = 0; n < N; n++)
{
testData[n] = (SAMPLE) ( (200.0 * sin( DUEPI * 697 * n * step) + 255.0 * sin( DUEPI * 1209 * n * step) )) ;
}
}
int main(void)
{
FLOATING freq;
GenerateDTMF();
printf("Start:,0,\n");
printf("Length:,%u,\n",N);
printf("Sample Rate:,%u,\n",(int)SAMPLING_RATE);
for (int i = 0; i<N; i++)
{
printf("%i,\n",testData[i]);
}
return 0;
} // END
Reading synthesized signal within gwinstek Arbitrary Waveform Editor:
And here the result generated from the AFG:
Here we find the code on github.com/qrpfun DTMF_Decoder