Introduction

The purpose of DTMF decoding is to detect sinusoidal signals in the presence of noise. There are plethora of cost effective integrated circuits on the market that do this quite well. However, there is yet another way: using a microcontroller with only a 1-bit A/D converter (i.e., a comparator).

DTMF FrequenciesDual-Tone Multi-Frequency signaling uses 8 frequencies (4 row + 4 column) to encode 16 symbols. Each keypress generates two simultaneous tones.
Row freq (Hz)1209 Hz1336 Hz1477 Hz
697 Hz123
770 Hz456
852 Hz789
941 Hz*0#

The DFT Approach

One brute-force way to detect DTMF signals is to digitize the incoming signal and compute 8 DFTs centered around the 8 DTMF composite frequencies. DFTs are preferred over FFTs because the frequencies are not equally spaced — they are logarithmically spaced.

In its simplest form:

\[ \text{DFT}(x) = \sum_{k=0}^{N} x(k) \cdot W(k) \]

where \(x(k)\) are the time samples and \(W(k)\) is the kernel function:

\[ W(k) = e^{j \cdot 2\pi f k / N} = \cos\!\left(\frac{2\pi f k}{N}\right) + j\sin\!\left(\frac{2\pi f k}{N}\right) \]

This works because of the orthogonality of sine waves:

\[ \sum_{k} \sin(f_1 \cdot k) \cdot \sin(f_2 \cdot k) = \begin{cases} \text{large} & f_1 = f_2 \\ \approx 0 & f_1 \neq f_2 \end{cases} \]

DFT with Square Waves

The orthogonality concept applies equally well to square waves. When two ±1 square waves are multiplied sample-by-sample and summed, the result is large when the frequencies match and nearly zero when they differ. Crucially, multiplying two ±1 values is equivalent to an XOR operation — extremely efficient on microcontrollers.

Example 1 — Same frequency (Σ = 25)

Example 1 — Same frequency and phase
+1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 f₁ f₂ = +25
Both waves are identical — every product is +1. Sum: Σ = +25

Example 2 — Different frequencies (Σ ≈ 1)

Example 2 — Different frequencies (f₂ = 2·f₁)
+1 +1 -1 -1 -1 -1 -1 +1 +1 +1 +1 +1 -1 -1 -1 -1 -1 +1 +1 +1 +1 +1 -1 -1 -1 f₁ f₂ = -1
Products alternate +1/−1 and nearly cancel: Σ = -1 — frequencies are distinguishable
Key insightThe multiplication of two ±1 square waves is equivalent to an exclusive OR (XOR) — a single instruction on PIC microcontrollers.
PIC Assembly — XOR-based dot product
sum_of_products    equ  0x20   ; accumulator
input_sample       equ  0x21   ; 1-bit digitized input (LS bit)
square_wave_sample equ  0x22   ; reference square wave (LS bit)

        movf    input_sample,W       ; W = input_sample
        xorwf   square_wave_sample,W ; XOR = equivalent to ±1 multiply
        skpnz                        ; skip if result != 0
         movlw  -2                   ; XOR=0 (same) → contribution +1
        addlw   1                    ; XOR=1 (diff) → contribution -1
        addwf   sum_of_products,F    ; accumulate

Quadrature

In the DFT we use both sine and cosine waves, related by a 90° phase shift. An analogously shifted square wave is needed for DTMF decoding. The reason: two waves can have the same frequency but produce a zero dot product if they are 90° out of phase:

Example 3 — Same frequency, 90° phase shift (Σ = 0)

Same frequency — 90° phase shift (quadrature)
+1 +1 -1 -1 +1 +1 -1 -1 +1 +1 -1 -1 +1 +1 -1 -1 +1 +1 -1 -1 +1 +1 -1 -1 f₁ f₂ (90°) = 0
Despite same frequency, the 90° shift causes exact cancellation: Σ = 0 — a false null. Solution: always compute two dot products (in-phase + quadrature).

To protect against this false null, always compute two dot products per tone:

Signal Strength: 1-norm

With sine/cosine DFTs, signal strength uses the 2-norm (Euclidean magnitude):

\[ \text{strength} \approx \sqrt{\,\text{Re}(\text{DFT})^2 + \text{Im}(\text{DFT})^2\,} \]

The general p-norm:

\[ \text{strength} \approx \Bigl(|\text{Re}(\text{DFT})|^p + |\text{Im}(\text{DFT})|^p\Bigr)^{1/p} \]

Setting \(p = 1\) gives the extremely simple 1-norm:

\[ \boxed{\text{strength} \approx |\text{Re}(\text{DFT})| + |\text{Im}(\text{DFT})|} \]
Why the 1-norm matters on microcontrollersThe 2-norm requires a square root — expensive on 8-bit PICs. The 1-norm replaces it with two absolute values and one addition: a massive speedup with minimal accuracy loss for DTMF detection.

Digitization: +1/−1 vs +1/0

Microcontrollers work more efficiently with 0 and 1 than with −1 and +1. The conversion:

\[ q = \frac{f + 1}{2} \qquad \Longleftrightarrow \qquad f = 2q - 1 \]

Substituting into the dot product expansion and assuming no DC component (\(\sum q_1 = \sum q_2 = N/2\)):

\[ \sum f_1 \cdot f_2 = 4\sum q_1 q_2 - N \]

Conclusion: 0/1 digitization is equivalent to ±1, introducing only a DC offset \(N\) and a scale factor of 4.

Measuring the DC Component

The DC component of a square wave equals its duty cycle times its amplitude. By simply counting high vs. low samples, the DC can be measured — no A/D converter needed.

Error Analysis

Consider the dual-tone DTMF signal with equal amplitudes:

\[ g(t) = A\cos(\omega_1 t) + A\cos(\omega_2 t) = 2A\cos\!\left(\frac{\omega_1+\omega_2}{2}t\right)\cos\!\left(\frac{\omega_1-\omega_2}{2}t\right) \]

The 1-bit digitized version is \(g_d(t) = \frac{1 + \operatorname{sign}(g(t))}{2}\). Using the identity \(\operatorname{sign}(ab) = \operatorname{sign}(a)\cdot\operatorname{sign}(b)\):

\[ \operatorname{sign}(g(t)) = \operatorname{sign}\!\left[\cos\!\left(\tfrac{\omega_1+\omega_2}{2}t\right)\right] \cdot \operatorname{sign}\!\left[\cos\!\left(\tfrac{\omega_1-\omega_2}{2}t\right)\right] \]

Each sign(cosine) is a 50% duty-cycle square wave — exactly what the 1-bit comparator produces. This validates the approach mathematically.

Note from the original articleThe complete error analysis was marked as unfinished by Dattalo. The key practical result is that the 1-norm with square waves provides sufficient SNR to reliably distinguish all 8 DTMF tones in typical telephony conditions.