This 12-Bit Dual Dma powered Dtmf Generator program is an Stm32 F4 version of the tried and trusty Atmel AVR312 application note. We wanted for some


time now to port this program over to the Stm32 F4 to take advantage of the 12-Bit Dac and  Dma1. And the following text explains exactly how we did it!


    The AVR version uses 2*7-Bit values to represent the sine wave amplitudes both for the High and Low  frequencies, so that the sum of both of the frequency


amplitudes can fit into one byte. We chose instead to use 2*12-Bit values for both of the desired dtmf frequencies. This would normally demand a 13-Bit Dac unit 


if we were to mix the frequencies as in the app note. Since the Dac has a Dual output buffer, we decided to output the High frequency on channel 1 and the Low 


frequency on channel 2 of the Dac buffer output. They are then "mixed" together in the 8-Ohm loudspeaker to form a Dual Tone output waveform on GPIOA 


Pins 4 and 5. A simple, passive 2-Pole Low-Pass filter is used to clean up the noisy, semi-analog output waveform before sending it out to the loudspeaker. 


Ideally the inductors should have a DC resistance of less than 5 Ohms and the capacitors should be rated at 10V or more.


    Passive 2-Pole Low-Pass Filter 



    A precalculated 256 * 12-Bit SineWave table at SineHigh is first converted into its negative mirror image with an amplitude of .75 * SineHigh . This array is 


then stored into User ram starting at location SinLow. The necessary registers and peripherals are then initialised in Main as follows. The clocks for DMA 1, GPIOD, 


DAC, Timer 6 and Timer 7 are enabled as usual. GPIOD bit 15 , which is connected to the user Blue led,  is then set up as a general purpose 2 MHz output and the 


Blue led is then set to on. The DAC is initialised next.  Timer 7 is selected as the DAC Channel 2 trigger, and Timer 6 is selected as the DAC Channel 1 trigger. Both


of the Dma streams are then set up so that stream 5 handles the SineWave array at SinHigh and stream 6 takes care of the SineWave array at SinLow. Next Timers 


6 and 7 are set up as timebases to trigger both of the seperate DAC channels. And finally, the Systick clock is then initialised to generate an interrupt every 150mS.


    Some Dtmf Tones


    The Interrupt Service Routine at IsrRout simply sleeps and waits for the next Systick Interrupt. When it arrives the Next Digit Routine checks first to see if we're 
at the last digit of the telephone number to be dialled, and if so it drops through to the Ende routine. Here we switch off all the usable peripherals and clear the 
Blue led before jumping back to IsrRout to wait in vain for the next Systick interrupt, which, of course, never comes! The Ascii characters corresponding to the key 
buttons ABCD*# are then processed if necessary, and finally the Ascii characters corresponding to the key buttons 0123456789 are taken care off. Some instructions 
later in the AscChar routine, the processed value of the telephone digit is used to index into the table at ArrReg and the corresponding indexed values for both the 
High and Low frequencies are stored into the Auto Repeat Registers of Timer 6 and Timer 7. Thus by changing these values, we can change the Low and High 
frequencies to suit the digit selected. At the end of this routine we once again jump back to the IsrRout routine and wait for the next Systick interrupt. The telephone 
number to be output is stored in flash at location TelNum, and it can, of course be altered, if so desired.
   " Life is a foreign language; everyone mispronounces it. "  Christopher Morley