Friday, February 22, 2019

DTMF Board with BU8872

Objective

I wanted to create an Arduino shield with a BU8872 DTMF chip on it so that I can decode DTMF from an audio source with an Arduino sketch.  Since the chip itself was only available in a surface-mount SSOP-16 form factor, I elected to do the entire board with surface mount components.

Schematic


I followed the recommended schematic in the datasheet.  I'm routing the audio input into the A5 pin on the arduino header.  This was done just in case I wanted to attempt audio decoding natively on the Arduino.  The three digital pins map to D5,6,7 on the Arduino.  I found a surface-mounted crystal that should work with the chip as well.


Board Layout

The layout was pretty straightforward.  Because I was hand-etching this board, I elected to place components on the back of the board.  This was to ease the soldering of the traces to the header pins.  In a stacking header, the bottom of the shield is the pin side, and the top has the plastic female sockets.  It would be difficult to solder under those plastic sockets to establish the connection, so I put everything on the bottom of the board.

Note, I used a ground plane on this board, but the traces bisected the board.  Though not pictured in this board layout, after assembling the board, I bridged a few traces with 1206 Zero ohm resistors to jumper the ground connection around so that I had a full ground plane.  



Finished board

The finished board is pictured here.  As mentioned above, you can see the two 1206 zero ohm resistors bridging the long traces, assuring that the ground plane has conductivity across the entire board.  In a future revision, I'll formally put pads on the board layout to document their placement.


Test Setup

You can see the board sandwiched on the arduino to the right.  There is a logging shield on top, then the DTMF shield, and finally, an Arduino Leonardo underneath.  I actually tested this using a VHF receiver module, and transmitting from an HT to send the tones. 




Coding challenges

The code for this board is fairly straightforward.  I only ran into one vexing issue  The "DST" pin is supposed to drop cleanly after the DTMF audio tone is dropped.  In practice, there seems to be some "jitter" where the DST pin oscillates between 0 and 1 at the end of the tone.  The datasheet has a little RC filter which might have compensated for that, but I really didn't understand how to calculate appropriate values for the filter components.  In a future board, I'll probably design in the filter, and if I don't want it, I can always jumper it with 0 ohm resistors.  Anyway, the code snip below is very simple, and demonstrates what I had to do to get around the jitter issue on the DST pin.

The Code


#define EST_PIN 5
#define ACK_PIN 6
#define SD_PIN  7
#define EST_JITTER    40         // Number of consecutive reads of EST that must be "off" before assuming tone is over

int ReadDTMF()
{
  int i, dtmf;

  dtmf = 0;
  // Iterate for the 4 bits of data we need to get from the BU8872
  for (i = 0; i <4; i++) {
    digitalWrite(ACK_PIN, 1);               // Pull ACK high
    delayMicroseconds(10);                  // Wait a bit
    dtmf += (digitalRead(SD_PIN) << i);     // Read the value from the SD pin, shifted appropriately and add to the rest
    digitalWrite(ACK_PIN, 0);               // Pull ACK low
    delayMicroseconds(10);                  // Wait a bit 
  }
  return(dtmf);
}

void setup() 
{
  
  Serial.begin(115200);
  while(!Serial);         // Arduino Leonardo issue - wait for the serial port
  Serial.println("Starting");
  Serial.flush();
  pinMode(EST_PIN, INPUT);
  pinMode(ACK_PIN, OUTPUT);
  pinMode(SD_PIN, INPUT);
 // When powered up, the BU8872 is awakened by sending 4 pulses on the ACK pin.  
 // A ReadDTMF will do the trick. We just ignore the result.
  int ignored = ReadDTMF();    
}

void loop() 
{
    int dtmf;
    int i;

    // If we have a DTMF tone, grab it
    if (digitalRead(EST_PIN)) {
       dtmf = ReadDTMF();
       Serial.print("Got DTMF code: ");  Serial.println(dtmf);

      // We have jitter on the EST pin.  Make sure it is clear for several consecutive milliseconds before assuming the tone is over.
      i = 0;
      while (i < EST_JITTER) {
         if (digitalRead(EST_PIN)) {    
            i = 0;    // If the pin jitters high, restart our count
         } else {
            i++;
         }
         delay(1);
      }    
      Serial.println("RST Clear");
    }
}

Sample Output


Future Enhancements

  1. Add the RC filter to the output section.
  2. Test RC filter values to see if the jitter can be eliminated.
  3. Put placeholders in the schematic and board layout for the ground plane jumpers.
  4. Add a trim pot on the audio input line.
  5. Bonus points: Add a test mode to the board and analog pin that puts a peak detector circuit on the pin (or maybe a separate one) and uses the ADC to calculate the RMS voltages of the input audio, to facilitate adjusting the input audio volume.

Bill of Materials

RefID     Digi-Key Description QTY
C1, C2 445-1270-1-ND CAP CER 12PF 50V 5% NP0 0603 2

C3

445-1316-1-ND

CAP CER 0.1uF 25V 10% X7R 0603

1
C5 399-6049-1-ND CAP ALUM 10UF 20% 63V SMD 1
Q1 BU8872FS-E2CT-ND IC DTMF RCVR FOR PHN SSOP-A16 TR 1
Y1 CTX1023CT-ND CRYSTAL 4.194304MHZ 12PF SMD 1