Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

DTMF decoding on pic24

Status
Not open for further replies.

neddie

Full Member level 5
Joined
Feb 23, 2010
Messages
251
Helped
41
Reputation
82
Reaction score
35
Trophy points
1,308
Location
South Africa
Activity points
3,026
Hi to all.
I'm trying to do DTMF decoding on a pic24.
I've found a project that implements a Goertzel algorithm on a pic16:
ProjectProto: Goertzel Algorithm for PIC16F , and it follows the code described here
Goertzel algorithm - Wikipedia, the free encyclopedia
, so I'm using it a base to start from.

When I run it on a pic24 , I just get garbage out(constantly changing numbers , ranging from 0 to 300000+)
. I'm currently just trying to detect 1 tone , to get things going. I'm sampeling a sine wave 2V pk-pk on AN6 of the micro.I'm using 12 bit, not 8 , but the size of the variables should handle the change.

Some of the relevant code below. I'm sure I've missed or messed up something :0(

Code:
#define ISR __attribute__((__interrupt__,auto_psv))

#define SAMPLING_RATE       2003
#define MAX_BINS            6
#define GOERTZEL_N          96
#define pi          3.141592654
#define threshold     1000
#define true        1
#define false       0

const double freqs[ MAX_BINS] = { 83, 110, 147, 196, 247, 330 };

unsigned int  sample_count = 0;
unsigned char samples[GOERTZEL_N];
unsigned char sample_complete = false;
double      prev1[ MAX_BINS ];
double      prev2[ MAX_BINS ];
double     magnitude[ MAX_BINS ];
double      coeffs[ MAX_BINS ] ;



void initialise(void);
void calc_coeffs();

/***************************************************************
 *      MAIN FUNCTION
 ***************************************************************/
int main(void)
{
  int i;
    double val;
	initialise();
	calc_coeffs();


	while(1)
	{
	  if(sample_complete == true)
	      {
	        for(i = 0; i < MAX_BINS; i++) {
	          prev2[i] = 0.0;
	          prev1[i] = 0.0;
	        }
	        for(sample_count=0; sample_count < GOERTZEL_N; sample_count ++)
	        {
	          //Goertzel Algorithm
	          for ( i = 0; i < MAX_BINS; i++ )
	          {
	            val = coeffs[i] * prev1[i] - prev2[i] + (double)samples[sample_count];
	            prev2[i] = prev1[i];
	            prev1[i] = val;
	          }
	        }
	          for ( i=0; i<MAX_BINS; i++ ) {
	          magnitude[i] = (prev1[i] * prev1[i]) + (prev2[i] * prev2[i]) - (coeffs[i] * prev1[i] * prev2[i]);
	        }
	        
	        sample_complete = false;
	        sample_count = 0;
	        TMR5 = 0;
	        IFS1bits.T5IF = 0;
	        IEC1bits.T5IE= 1; // enable TMR0 interrupt, start storing samples
	      }
	}

}

/***************************************************************
 *       TIMER 5 INTERRUPT 125us
 ***************************************************************/

void ISR  _T5Interrupt(void)
{
  IFS1bits.T5IF = 0;              //Clear Flag

  AD1CON1bits.SAMP = 1;          //start sample
  
  while(AD1CON1bits.DONE == 0)
   {
    	  AD1CON1bits.DONE = 0;
    	  samples[sample_count++] = ADC1BUF0; // Read 10 -bit ADC result
    	     if (sample_count == GOERTZEL_N)
    	     {
    	       IEC1bits.T5IE= 0;          
    	       sample_complete = true;
    	     }
	      AD1CON1bits.SAMP = 0;
   }

}



void calc_coeffs()
{
  unsigned int k, n;
  for(n = 0; n < MAX_BINS; n++)
  {
    k = (unsigned int)(0.5 + (double)GOERTZEL_N * freqs[n] / SAMPLING_RATE);
    coeffs[n] = 2.0 * cos(2.0 * pi * (double)k/GOERTZEL_N);
  }
}


Any help would be appreciated.
Cheers
Ned
 

Without referring to the algorithm, some hardware issue: did you put an RC low-pass filter close to AN6 pin, to filter out noise above half the sampling rate?
 

No , there is no hardware filter at all , at the moment. The input is coming from a signal generator though ,
so I'm assuming it's clean. I assume noise etc would show up as spurious values , not complete garbage.
Then again I'm new to any dort of dsp type stuff , so I could be completely wrong :0)
One bug in the above code unsigned : char samples[GOERTZEL_N]; should be unsigned int.
Made no difference to the output though :0(
 

If it is coaxed all the way from the generator to near the input pin, I guess no much noise.
Just to debug it, and to make sure it is not a sampling or noise issue, I would suggest uploading the samples from the PIC to a PC, put in Excel sheet and draw the waveform, to see if it makes sense (including correct frequency, according to the sample rate).
 

This is a dump from the watch window. The numbers look so wrong....


Update Address Symbol Name Value Hex Decimal Char

0920 magnitude
0920 [0] 1.096290e+007
0924 [1] 7906304.
0928 [2] 3870930.
092C [3] 1464181.
0930 [4] 260074.8
0934 [5] 185062.6
0938 coeffs
0938 [0] 1.944740
093C [1] 1.902113
0940 [2] 1.782013
0944 [3] 1.618034
0948 [4] 1.414214
094C [5] 1.044997
 

How about a dump of the unsigned char samples[GOERTZEL_N] ?
 

here you go:

0850 samples "yyyyyyyÒÒÒÒÒÒÒ[[[[[[[ÌÌÌÌÌÌÌ;;;;;;;¹¹¹¹¹¹¹]]]]]]]3333333LLLLLLL›››››››¨¨¨"
0850 [0] 'y' 121
0851 [1] 'y' 121
0852 [2] 'y' 121
0853 [3] 'y' 121
0854 [4] 'y' 121
0855 [5] 'y' 121
0856 [6] 'y' 121
0857 [7] '.' 210
0858 [8] '.' 210
0859 [9] '.' 210
085A [10] '.' 210
085B [11] '.' 210
085C [12] '.' 210
085D [13] '.' 210
085E [14] '[' 91
085F [15] '[' 91
0860 [16] '[' 91
0861 [17] '[' 91
0862 [18] '[' 91
0863 [19] '[' 91
0864 [20] '[' 91
0865 [21] '.' 204
0866 [22] '.' 204
0867 [23] '.' 204
0868 [24] '.' 204
0869 [25] '.' 204
086A [26] '.' 204
086B [27] '.' 204
086C [28] ';' 59
086D [29] ';' 59
086E [30] ';' 59
086F [31] ';' 59
0870 [32] ';' 59
0871 [33] ';' 59
0872 [34] ';' 59
0873 [35] '.' 185
0874 [36] '.' 185
0875 [37] '.' 185
0876 [38] '.' 185
0877 [39] '.' 185
0878 [40] '.' 185
0879 [41] '.' 185
087A [42] ']' 93
087B [43] ']' 93
087C [44] ']' 93
087D [45] ']' 93
087E [46] ']' 93
087F [47] ']' 93
0880 [48] ']' 93
0881 [49] '3' 51
0882 [50] '3' 51
0883 [51] '3' 51
0884 [52] '3' 51
0885 [53] '3' 51
0886 [54] '3' 51
0887 [55] '3' 51
0888 [56] 'L' 76
0889 [57] 'L' 76
088A [58] 'L' 76
088B [59] 'L' 76
088C [60] 'L' 76
088D [61] 'L' 76
088E [62] 'L' 76
088F [63] '.' 155
0890 [64] '.' 155
0891 [65] '.' 155
0892 [66] '.' 155
0893 [67] '.' 155
0894 [68] '.' 155
0895 [69] '.' 155
0896 [70] '.' 23
0897 [71] '.' 23
0898 [72] '.' 23
0899 [73] '.' 23
089A [74] '.' 23
089B [75] '.' 23
089C [76] '.' 23
089D [77] '.' 168
089E [78] '.' 168
089F [79] '.' 168

---------- Post added at 09:35 ---------- Previous post was at 07:59 ----------

Hi to all.
I've managed to get it working , looking for only 1 frequency. I found my problem. It was between keyboard and chair :0(
I had my timer isr all cocked. It was sampleing all over the place , hence the wild values.
I am however still getting very large values. My threshold is set at 416000000 !!! while detecting a 500hz tone.
Detect bandwith is from 499Hz to 501Hz.Seems pretty good , but I've never done this sort of stuff before
so I'm not sure what the norm is.
I'm doing 320 samples at 8Khz.(Sampling for 40mS) Does this seem right? Still worried about the large values!!
I'll post the code below. It's been modified to look for only 1 tone , but I'll go back to looking for DTMF once I'm happy with the results
of this. Any pointers and help is really appreciated.

Code:
#define ISR __attribute__((__interrupt__,auto_psv))

#define SAMPLING_RATE       8000
#define MAX_BINS            1
#define GOERTZEL_N          320
#define pi					3.141592654
#define threshold			416000000
#define true				1
#define false				0

double freqs = 500;

volatile unsigned int  sample_count = 0;
volatile unsigned int samples[GOERTZEL_N];
volatile unsigned char sample_complete = false;
double     prev1;
double     prev2;
double     magnitude;
volatile double    coeffs ;

void initialise(void);
void calc_coeffs();

/***************************************************************
 *      MAIN FUNCTION
 ***************************************************************/
int main(void)
{
  int i;
  double val;
  initialise();
  calc_coeffs();

  while(1)
  {
    if(sample_complete == true)
    {
      prev2 = 0.0;
      prev1 = 0.0;

      for(sample_count=0; sample_count < GOERTZEL_N; sample_count ++)
      {
        //Goertzel Algorithm
        val = coeffs * prev1 - prev2 + (double)samples[sample_count];
        prev2 = prev1;
        prev1 = val;
      }

      magnitude = (prev1 * prev1) + (prev2 * prev2) - (coeffs * prev1 * prev2);

      sample_complete = false;
      
      if(magnitude > threshold)
      {
        printf("%f\r\n",magnitude);
        SIG_LEV_RED = 1;
      }
      else
      {
          SIG_LEV_RED = 0;
      }
        
      sample_count = 0;
      TMR5 = 0;
      IFS1bits.T5IF = 0;
      IEC1bits.T5IE= 1; 
     
    }
  }
}


/***************************************************************
 *       TIMER 5 INTERRUPT 125us
 ***************************************************************/

void ISR  _T5Interrupt(void)
{
  IFS1bits.T5IF = 0;              //Clear Flag
  STATUS_LED = !STATUS_LED;
  AD1CON1bits.SAMP = 1;          //start sample

  while(AD1CON1bits.DONE == 0);
  AD1CON1bits.SAMP = 0;
  samples[sample_count++] = ADC1BUF0; // Read 10 -bit ADC result
  if (sample_count == GOERTZEL_N)
  {
    IEC1bits.T5IE= 0;
    sample_complete = true;
  }
}


void calc_coeffs()
{
  unsigned int k, n;
  static double temp1,temp2,temp3;

 
    k = (unsigned int)(0.5 + (double)GOERTZEL_N * freqs / SAMPLING_RATE);
    //coeffs = 2.0 * cos(2.0 * pi * (double)k/GOERTZEL_N);
    temp1 = (double)k/GOERTZEL_N;
    temp2 = temp1*2*pi;
    coeffs = cos(temp2);
    
    coeffs*=2;
  
}

void SetupAD(void)
{

 AD1CON1bits.ADSIDL = 0;            //Dont Stop in idle mode
 AD1CON1bits.ASAM = 0;

 AD1CON1bits.SSRC2 = 1;             //Set to autoconvert.
 AD1CON1bits.SSRC1 = 1;
 AD1CON1bits.SSRC0 = 1;

 AD1CON2bits.CSCNA = 0;           //Do not scan inputs

 AD1CON2bits.VCFG2 = 0;           //Vr+ = Vdd , VR- = Vss
 AD1CON2bits.VCFG1 = 0;
 AD1CON2bits.VCFG0 = 0;


 AD1CON3bits.ADRC = 0;             //Use system clock

 AD1CON3bits.SAMC4 = 0;
 AD1CON3bits.SAMC3 = 0;
 AD1CON3bits.SAMC2 = 1;
 AD1CON3bits.SAMC1 = 1;
 AD1CON3bits.SAMC0 = 1;

 AD1CON3bits.ADCS7 = 0;
 AD1CON3bits.ADCS6 = 0;
 AD1CON3bits.ADCS5 = 0;
 AD1CON3bits.ADCS4 = 0;
 AD1CON3bits.ADCS3 = 0;
 AD1CON3bits.ADCS2 = 0;
 AD1CON3bits.ADCS1 = 0;
 AD1CON3bits.ADCS0 = 1;

 AD1PCFGbits.PCFG6 = 0;     //AN6

 AD1CHSbits.CH0SA3 = 0;
 AD1CHSbits.CH0SA2 = 1;
 AD1CHSbits.CH0SA1 = 1;
 AD1CHSbits.CH0SA0 = 0;


 AD1CON3 = 0x1F02;

 //AD1CSSL = 0x00;                  //Scan channel 0-4 and 11
 AD1CON1bits.SAMP = 0;
AD1CON1bits.ADON = 1;              //AD convertor is on
AD1CON1bits.SAMP = 1;

//AD1CHS0 = 0;


}
/*******************************************************
 * SETUP TIMER 5 62.5uS
 *******************************************************/
void SetupTimer5(void)
{
    INTCON1 = 0;
    T5CONbits.TON = 1;          //Turn on timer
    T5CONbits.TSIDL = 1;        //Stop in IDLE
    T5CONbits.TCKPS1 = 0;       //No prescalar
    T5CONbits.TCKPS0 = 0;
    PR5 = (16000000/SAMPLING_RATE);                //Set period register for 8KHz interrupt rate
    IEC1bits.T5IE= 1;           //Enable interrupt

}
 
Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top