DTMFgen not working

I have a Nano (328P) set up to connect to an Ooma Telo VOIP box to dial a number. I'm using the DTMFgen.h library which uses an R-2R ladder on Port D. The code generates tones which are similar to legit DTMF samples, but to my ear not exactly the same. The Ooma terminates dial tone when the DTMF output starts, so the tones apparently are loud enough, but after completing the 10 digits, I get fast busy immediately, and the call isn't initiated.

https://github.com/dilshan/dtmfgen

The method used in the library does not produce exactly the right frequencies, and no adjustment is made to make the higher tone louder than the lower tone (which may or may not matter). But the author says his code has worked with a variety of devices, including the MT8880 decoder chip, so it's possible the Ooma is a bit too picky.

Anyway, I just wondered if anyone here as any experience with DTMFgen, or if anyone could suggest things to try to get it to work.

My schematic is what's shown in the library, with the ouput feeding into a 600/600 1:1 transformer that's connected to the line. When I listen in on another extension, everything sounds fine, so I think everything is working electronically, but maybe the Ooma doesn't like the waveform.

#include "dtmfgen.h"

// Create new instance of DTMF generator.
DTMFGenerator dtmf;

char number[] = "3034997111";  // WWV time service
unsigned char ledPin = 13;

void setup()
{
  pinMode(ledPin, OUTPUT);
  delay(3000);
  // Generate DTMF tone with 500ms duration.
  digitalWrite(ledPin, HIGH);
  for (int i = 0; i < 10; i++) {
    dtmf.generate(number[i], 500);
    delay(500);
  }

  digitalWrite(ledPin, LOW);
}

void loop()
{
}

Are you using 1% resistors?

No. But I'm having trouble understanding how that would affect something like DTMF.

To clarify, my resistors are different from the author's in that mine are 1K/2K, whereas his are 1K/2.2K, which to me is a far cry from R-2R. I thought I would be making things better, but maybe that's what lets his work while mine doesn't. I'll have to try his values.

Also, at the LS end of the ladder, he has the resistor to ground being R, whereas mine is 2R as seen is all the documentation I've seen. Again, I "fixed" his error, but maybe not for the better.

Anyway, if none of these resistor differences get it working for me, I don't think 1% would make much difference.

To be specific about the frequencies, here's a table comparing the nominal frequencies to those produced by DTMFgen:

Frequencies

Nominal  DTMFgen

697      700   
770      750   
852      850   
941      950   

1209     1200  
1336     1350  
1477     1500  
1633     1650

There is no schematic shown in the link. There is a wiring diagram. A schematic would make the project much more understandable.

Being curious about this project, I did find a similar project with an actual schematic. It is located here.

Yes, you will notice the resistor "errors" I pointed out in post #3. I went back and tried his version, but it didn't make any difference.

Then I fired up my Goertzel DTMF decoder on another Nano, and fed the output of DTMFgen into it. Of all the 16 keys, it had major problems with "4", but did pretty well with the others. I'm going to try to adjust what's supposed to be 770, but is actually being transmitted as 750. The code steps through the wave table 15 positions at a time for that frequency, but perhaps I can step 16 every other cycle, and get it closer to 770. No guarantee that it will work, but I think it's worth a try.

I implemented the change to DMTFgen so those frequencies that are farthest away from nominal have their step function alternate between two adjacent integers on each interrupt. That fixed all the issues I had with my Goertzel decoder, which now decodes every key on the first try.

But the bad news is that it still doesn't work with the Ooma Telo. I don't know why. The Telo may just be too picky. Anyway, I think I'm dead in the water with DTMFgen. I don't know what else to try to get it to work.

Would be interesting if someone could look at the output on a spectrum analyzer. Using different value resistors, or low tolerance resistors, might affect the harmonic content.

A quick google search seems to show that the frequencies should be within 1.5% of the nominal frequency. A few of the frequencies from the library are definitely outside that range. The detector should always reject a signal that is 3.5% off the nominal frequency, but between 1.5% and 3.5% seems to be unspecified, possibly a detector is allowed to detect that frequency, but not required to.

1.5%? Hell, my Nano's 16MHz resonator probably isn't that close, LOL.

I guess I'm having trouble with the library author's claims about how well it works. At the moment, I'm batting zero.

The error I get from the Telo is the same as what happens when I dial from a regular phone but don't complete the dialing - dialing 9 digits instead of 10. It waits a while, then gives me fast busy. So it seems it's decoding at least one transmission as a valid key, but not all.

I have a writeup that shows using two digital outputs, like D8 and D9, each producing a 50% square wave at the right frequencies. Then each output goes through two opamp stages to convert the output to a sine wave, then they are mixed in another opamp. But the thing is, I don't know if it's possible to produce all eight oddball DTMF frequencles with the timers available in the 328P. Five of the eight are odd numbers.

I guess I'll have to go with playing back wav files from the SD card.

I did more experimenting with the R-2R circuit, but still didn't get anywhere. So I wonder if I have a more fundamental problem. I'm driving the secondary of the 600/600 1:1 transformer through a series capacitor. The primary is connected to the line in the same way. I've been trying to get the AC amplitude on the phone line when I generate DTMF to be the same as the amplitude produced by a real telephone when it dials. Does that sound right? Or does the transformer mess things up for some reason?

The waveform I produce is a lot noisier than what a phone produces, so I figure that's the problem. I've been trying the "1" key, which by chance actually produces the frequencies within specs, but the noise will have to be dealt with whether I do R-2R, PWM, or play back a wav file of the tones off SD. Either way, I've got to convert digital output to analog, so getting the filter(s) right may be the key.

I am having trouble finding a PWM dialer sketch.

The article below describes the various serious pitfalls with R/2R ladders. Generally, better than 1% accuracy is required, and load impedance is extremely important.

I've just been playing with this problem more out of curiosity and have just created a DTMF generator sketch/library which has a more or less a 100% success rate with the earlier DTMF decoder sketch I once created discussed in your previous thread at: Using Goertzel protocol for DTMF and other decoding

Now, the main trick is that it uses an MCU with a built-in 8 bit DAC, namely an ATtiny1614 of which I panic bought a stack during the Corona lockdown period and am slowly working through them.

I'll say that it is "inspired" by the DTMF generator library at GitHub - dilshan/dtmfgen: Library to generate DTMF tones only using Arduino Uno., and I've learned a few tricks from it but, apart from that the code is new. Further, there are significant differences. For example, the whole resistor ladder is dropped and the sine table has a better resolution because it takes advantage in the symmetry of the sine wave and holds a table for quadrant 1 only. Also, since the hardware architecture is different ( AVR v. tinyAVR 1 series) the low level configuration of the timers etc. is different. With common grounds, I connect the output of the generator via a 10k resistor directly to the input of the decoder.

There is some light "polishing" necessary before I publish it but, if you are prepared to go that route and acquire one of these chips, then you can have a "pre-release" version of this code.

If you have enough resistors of the same value, the R/2R network can be constructed using only a single value resistor, using either series resistors in the 2R leg or parallel resistors in the R leg. My personal experience has been that a group of resistors purchases from a single manufacturer lot will be very close in value to each other, even for low tolerance parts.

Yes indeed. That occurred to me too, although I was just thinking of doing a half wave. But I don't see how you keep the output centered on 128, unless your fancy ATtiny does that for you automatically. So I was having trouble finding any increased resolution. So are you using a 256-byte table then for just the first quadrant? Yes, I would very much like to see your code.

By the way, I need to check something. I found a version of PWM DTMF dialer code based on app note AVR314.pdf, called "ArduinoDTMF". It includes an adjustment to make the lower frequency about 25% lower level than the higher one, which I think is part of the spec since higher frequencies attenuate more over the phone line. Anyway here's his ISR:

//**************************************************************************
// Timer overflow interrupt service routine for DTMF sine wave
//**************************************************************************
ISR (TIMER2_OVF_vect)
{
	if (x_SWb) { // dual tone
		// move Pointer about step width ahead
		i_CurSinValA += x_SWa;
		i_CurSinValB += x_SWb;
		// normalize Temp-Pointer
		i_TmpSinValA  =  (char)(((i_CurSinValA+4) >> 3)&(0x007F));
		i_TmpSinValB  =  (char)(((i_CurSinValB+4) >> 3)&(0x007F));
		// calculate PWM value: high frequency value + 3/4 low frequency value
// I think this is wrong:
		OCR2B = (auc_SinParam[i_TmpSinValA] + (auc_SinParam[i_TmpSinValB]-(auc_SinParam[i_TmpSinValB]>>2)));

		} else { // single tone

		i_CurSinValA += x_SWa;
		i_TmpSinValA  =  (char)(((i_CurSinValA+4) >> 3)&(0x007F));
		OCR2B = auc_SinParam[i_TmpSinValA];
	}
}

But I don't think the way he did that is right. The wave is centered at 128. So if you want to reduce the amplitude of the lower frequency, you have to reduce its table value if it's over 128 (by 1/4 of THAT difference), or add to its table value if it's under 128. Am I thinking wrong about it?

Does the ATtiny1614 come in DIP? :slight_smile:

Yes, I understand. I'm just having trouble with the fact that even with non-matched resistors, it works perfectly with my Goertzel decoder, but it doesn't work at all with my VOIP box head end. So I think you're correct that some other solution is going to be better, if I find one at all. They used to make DTMF dialer ICs, but it seems they aren't made anymore, and old ones are very expensive.

That is just a simple mapping in code. A sine wave has an amplitude of -1 to +1 and when that is mapped to 0 to 255, then it is automatically centered on ~128.

This is my table for quadrant 1. It may still have some rough edges on it. Incidentally, with the ATtiny1614 constants are automatically kept in flash storage so there is no explicit use of PROGMEM.

uint16_t DTMFGenerator::getSinDeg( uint16_t degrees ) {

  // degrees must be 0 to 360
  // returns a function of sin depending on the selected bit width. For example,
  // for 8 bits, the return value is between 0 and 127

  static constexpr  uint32_t sinQ1[91] = {  // Quadrant 1, sin(degrees) * 2^16
    0,   1143,   2287,   3429,   4571,   5711,   6850,   7986,   9120,   10252,
    11380,   12504,   13625,   14742,   15854,   16961,   18064,   19160,   20251,
    21336,   22414,   23486,   24550,   25606,   26655,   27696,   28729,   29752,
    30767,   31772,   32768,   33753,   34728,   35693,   36647,   37589,   38521,
    39440,   40347,   41243,   42125,   42995,   43852,   44695,   45525,   46340,
    47142,   47929,   48702,   49460,   50203,   50931,   51643,   52339,   53019,
    53683,   54331,   54963,   55577,   56175,   56755,   57319,   57864,   58393,
    58903,   59395,   59870,   60326,   60763,   61183,   61583,   61965,   62328,
    62672,   62997,   63302,   63589,   63856,   64103,   64331,   64540,   64729,
    64898,   65047,   65176,   65286,   65376,   65446,   65496,   65526,   65535
  } ;


  int32_t sin16bit = 0 ;  // bad name !
  uint32_t rv = 0 ;

  if ( degrees <= 90 )  sin16bit = sinQ1[degrees]  ;
  else if ( degrees >  90 && degrees <= 180 )  sin16bit = sinQ1[180 - degrees]  ;
  else if ( degrees > 180 && degrees <= 270 )  sin16bit = -sinQ1[degrees - 180]  ;
  else if ( degrees > 270 && degrees <= 360 )  sin16bit = -sinQ1[360 - degrees]  ;

  rv = sin16bit + 65536 ;

  switch ( dacBitWidth ) {
    case BIT8  : rv >>= 10 ; break ;
    case BIT10 : rv >>= 8  ; break ;
    case BIT12 : rv >>= 6  ; break ;
    case BIT14 : rv >>= 4  ; break ;
    case BIT16 : rv >>= 2  ; break ;
  }
  return rv ;
}


No, but could even be hand soldered onto a 14 pin break out board using a kerosene blow torch and bar solder.

I'd have to look at that whole application note to understand what he is doing to be able to comment on it but, in principle, adjusting the amplitude for the lower frequencies, say a 25% decrease, is quite straight forward if all you are doing is transferring the amplitude to a DAC register, but ensuring it is scaled to the correct bit width. Something like: amplitudeTotal = amplitudeHigh + 0.75*amplitudeLow

I just don't understand what you've done. In all the examples I've found, the table entries are the voltage levels that are sent out. I don't know what you're doing with degrees and sine.

That table/function is only part of the whole thing and was simply to demonstrate how, from the first quadrant of a sine wave, the full sine wave could be derived.

In principle, to generate a DTMF tone, you are summing the amplitudes of two sine waves at every sampling interval. At each sampling interval each wave has advanced a number of degrees depending on the frequency of the wave. If, for example, the sampling interval is 8000sps and the wave frequency is 1000Hz then it will advance 45 degrees per sampling interval. In order to calculate the voltage to be sent to the DAC, a look up at each sampling interval is made into the sine table using the number of degrees to which each wave has advanced. You then have two amplitudes read from the sine table, one for each wave. These amplitudes are scaled and added together to fit the DAC. For an 8 bit DAC this means sending it a number between 0 and 255 and the DAC emits a corresponding voltage between 0 volts and the reference voltage, say 5 volts. This repeats for each sampling interval until the burst period for the DTMF tone has been reached, say after 100ms.
This is not fundamentally different from the library you have been using but of course with out a resistor ladder.
When I've tidied up the code and added sufficient comments I'll publish it.

Ok, I understand.

I found a 328P version of the AVR314 app note software.

https://github.com/KC7MMI/AVR314-DTMF-Generator-for-Arduino

It looks pretty straightforward. I'll try to test it today - if I can figure out how to filter the output properly.