ATmega328 DTMF Decoder

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