Lab 4 : ADC and DTMF
EEC 172: Lab #4 - ADC and DTMF
Author : Kelly Su, Tony Xiao
Intro
The objective of this lab is to program a decoder that converts DTMF sound signals to their corresponding digit buttons. Learn to use Goertzel algorithm to recognize DTMF. We will also use code from Lab 3 to obtain the letter based on frequency of button presses to be displayed on the OLED screen. We also need to incorporate a confidence determinant to filter out noise that could be similar to the frequency of a button press. Lastly, we also want to allow bidirectional texting between two CC3200 Launchpads that will be able to send characters to each other’s screens.
Background
The Adafruit electret microphone with amplifier is used to detect sound signal. In this lab, we used the microphone to detect DTMF tones, and therefore, we configured a gain of 50dB which will reduce much noise.
The voltage regulator used in this lab was the LM1086CT model. It is used as the power supply line for the OLED. A 5.0 V from the CC3200 Launchpad is used as input alongside two 10uF capacitors to produce a clean +3.3 V output so noise on the power supply line won’t corrupt the microphone’s output signal. Due to OLED generating significant noise on the power supply line, we used separate power sources for OLED and the microphone.
The Microchip ADC (Analog/Digital Converter) converts continuous analog voltage (analog signal) produced by the microphone into discrete digital signal that the CC3200 Launchpad can use to decode. It will be interfaced to the launchpad to the same SPI port as OLED.
“The Goertzel algorithm is a technique in digital signal processing (DSP) that provides a means for efficient evaluation of individual terms of the discrete Fourier transform(DFT), thus making it useful in certain practical applications, such as recognition of DTMF tones produced by the buttons pushed on a telephone keypad. The algorithm was first described by Gerald Goertzel in 1958.” [Goertzel, G. (January 1958), “An Algorithm for the Evaluation of Finite Trigonometric Series”, American Mathematical Monthly, 65 (1): 34–35, doi:10.2307/2310304 ]. In this case, it recognizes the DTMF tones produced by the button on the telephone keypad.
The DTMF (Dual-tone Multi-frequency signaling) is a dial-tone representation used for telephone signal transmission. There are 16 unique keys that are formed from the combination of two sinusoidal signals from two frequency groups. They are used in telephone calls and electronic systems.
Goals
Part I: DTMF detection and decoding
Use a buffer to collect sample data at 16kHz. Use the Goertzel algorithm to decode the buttons of the digital signal converted by the ADC from the buffer.
Part II: Code Flow
Record button pushed and calculate the confidence of that button pushed using a threshold and analyzing the previous samples decoded. Keep track of previous samples to measure confidence that button was pressed. Keep translating until there is high enough confidence that that button was pressed.
Part III: Texting
Once confidence is high enough, use Lab3’s techniques to integrate multi-tap use the UART module to display the characters on the screen.
Methods
Part I:
In this part, we configured a timer that would interrupt at a rate of 16kHz. During the interrupt we would get data from the ADC output (sound signal data) by calling readADC()
. We used SPITransfer()
function in readADC()
to receive 2 bytes from ADC, which we masked and shift to get the 10 bits of data we need. We then subtract the DC bias value and then store the data in sample_buffer array. Once we collect 410 sample data points, we set a flag, so in our main while loop knows to call the Goertzel algorithm to calculate the power value for each of the 8 frequencies used in DTMF. In the post_test()
function we find the highest values (frequencies) in the column and row, if those values are within a threshold which we get from experiment (20000 ~ 40000), we can determine which button was pressed.
Part II:
In order to make sure that the button press detected was significant and not just due to noise, we used a variable prevChar to store the previous button press. After decoding the button, we compare it with the previous decoded value and update a confidence value counter. If the confidence value is greater than 4, then we are confident that button has been pressed. If the counter value did not reach 4, we would discard the decoded values and reset the counter back to 0.
Part III:
In this part, we incorporated what we did in Lab 3. We used a timer to determine the time difference between two buttons. Once we detected a button was pressed with confidence, we check that this button press was the same or not with the previous button press as well as if the time difference is within a time range. If it is, we would increment the pointer array of the button to get the next succeeding letter. Once a different button decoded was pressed or a timer following the last button pressed timed out, we would store and print the letter out to the OLED display.
If the button pressed was *, we would remove the character from the end of the buffer and fill the corresponding position as black on the OLED.
If the button pressed was #, it will call MAP_UARTCharPut()
to send the buffer in a for loop and clear the buffer and fill the OLED screen with black. The UART Interrupt Handler is the same as we did in the Lab 3.
Discussion
We had some problems when using SPI to receive data from ADC. Initially we try to use SpiDataGet()
, but it doesn’t work since we couldn’t get the whole chunk of data through this function. Then it was suggested that we use SPITransfer and it worked. Some issues we did have during this lab was determining the confidence that was needed to make sure a button signal detected was actually a button pressed. It was also challenging to minimize the delay between reading the signals and making sure the interrupts for handling that weren’t disabled for too long. This meant that our decoding process needed to be fast and interrupts needed to be enabled again as soon as possible. We also have problem when using Timer_IF.h. Since it defines some functions that wrap basic timer function, by using them, we might call unnecessary functions. Later we were advised to use the timer functions such as timerload(). This solved our problems.
Conclusion
In this lab, we learned to use the microphone, how to use the ADC to convert analog signal to digital signal and the process in interpreting DTMF signals. We learned to use the Goertzel algorithm to convert frequency into button based on tone and how to configure more interrupts to keep polling the sound coming from the microphone. We also learned to use confidence checking before bringing out a button as being pressed to handle noise. We also learned to configure the Tx and Rx cables to have the two boards simultaneously be able to send text over to each other. We also learned how to use the oscillator to read frequency signals coming in from the microphone. Additionally, we learned to put all these together with the UART module to display the signals and send bidirectional signals from board to board through Tx/Rx communication.