Signal Generation Using DDS
Signal Generation Using DDS
A technique known as Direct Digital Synthesis (DDS) will be implemented to demonstrate the use
of interrupts and DAC to generate a signal with the desired frequency.
Consider a 16-bit wide register. Its content is increased periodically (the period is given as TP) by a
factor K. Obviously the time T needed to overflow the register equals:
If we keep increasing the content of the register then the overflows will repeat at regular time
intervals, and the frequency of overflows f can be calculated as:
where fP represents the number of increases per unit of time. Such structure is easy to implement
in a microcontroller. One only needs a timer and associated interrupt function. The timer defines the
period TP, and periodically calls an interrupt function, where a variable declared as an unsigned
integer gets increased by a factor K. The frequency of overflows is linearly dependant of factor K, and
it changes for about 15.26E-6 times fP. If we select the frequency of interrupt requests from the timer
(fP) at 100 kHz, then we will be able to define the frequency of overflows linearly in steps of 1.5 Hz.
If we consider the content of the register as the output signal, then we get a sawtooth generator.
However, we can use the content of the register as a pointer to a table, which can be filled by any
waveshape during the initialization process, like for instance one period of a sinewave. If we consider
the entry from a table, pointed to by the content of the register, as the output signal, we have a
sinewave generator. The frequency of the signal can still be adjusted in small steps, and the
amplitude can be adjusted by a simple multiplication of the entry by a constant before it gets passed
to the DAC.
It does not seem rational to prepare a huge table with 65536 entries, since neighboring entries
will be very similar. We can prepare smaller table, and use only the bits from the upper part of the
register as a pointer; we intend to generate signals within the audio range from 20 Hz on, and the
factor K will be about 16 at least. The decision on the table length depends on the required precision,
and we will use a table with 4096 entries in this example. It would be possible to reduce the size of
this table to ¼ by exploiting the properties of a sinewave, but we will not do this for the reason of
simplicity. The block diagram of the hardware that could be used as a DDS generator is shown in Fig.
1.
1
Playing with STM32F407 test board – Signal generation using DDS
K
16 16
ADDER
16
TP
REGISTER
16 12 12 OUT
TABLE DAC
POINTER
2
Playing with STM32F407 test board – Signal generation using DDS
to remain within the bounds of the table by AND-ing it with the pointer to the last valid element
(4095), the rest is the same as for the first DAC.
The interrupt function takes about 500ns to execute, and the quality of the generated signal could be
much improved by increasing the frequency of interrupt requests.
#include "stm32f4xx.h"
#include "LCD2x16.c"
#include "math.h"
int main () {
// Table init
for (TablePtr = 0; TablePtr <= 4095; TablePtr++)
Table[TablePtr] = (int)(1850.0 * sin((float)TablePtr / 2048.0 * 3.14159265));
// LCD init
LCD_init(); LCD_string("f =", 0x01); LCD_string("Am=", 0x41);
// DAC set-up
RCC->APB1ENR |= 0x20000000; // Enable clock for DAC
DAC->CR |= 0x00010001; // DAC control reg, both channels ON
GPIOA->MODER |= 0x00000f00; // PA04, PA05 are analog outputs
// Timer 2 set-up
RCC->APB1ENR |= 0x0001; // Enable clock for Timer 2
TIM2->ARR = 840; // Auto Reload: 8400 == 100us -> 100kHz
TIM2->DIER |= 0x0001; // DMA/IRQ Enable Register - enable IRQ on update
TIM2->CR1 |= 0x0001; // Enable Counting
// IRQ function
void TIM2_IRQHandler(void) // IRQ function takes approx 500ns of CPU time!
{
GPIOE->ODR |= 0x0100; // PE08 up
TIM2->SR &= ~0x00000001; // clear update event flag in TIM2
TablePtr = (TablePtr + K) & 0xffff; // increase pointer and limit to 16b
DAC->DHR12R1 = (Am * Table[ TablePtr >> 4 ]) / 256 + 2048;
DAC->DHR12R2 = (Am * Table[((TablePtr >> 4) + 1024) & 4095]) / 256 + 2048;
GPIOE->ODR &= ~0x0100; // PE08 down
}
Figure 1: A listing of the program for sinewave signal generation – DDS method