Digital Sawtooth Signal Generation with MSP430


Sawtooth signals have various applications for example FMCW radars, audio applications, CRT screens, etc. By using an operational amplifier, a voltage comparator, and a transistor switch you can create your own sawtooth signal. The idea behind this analog circuit is to charging a capacitor linearly and rapidly discharging it. However, it is pretty difficult to get a rapid falling edge from an analog circuit, so the circuit with those component creates an asymmetrical  triangular wave.

Analog Sawtooth Signal at 10 kHz

Analog Sawtooth Signal at 10 kHz

To overcome this problem, you can create a digital sawtooth generator that falls to zero (or to the offset you set) in no time. What you need is a digital-to-analog converter (DAC) and a controlling unit, in this case an MSP430G2553. Most DAC ICs use serial SPI or I2C interface and this reduces the speed dramatically because you are sending whole DAC count bit by bit. What if you need a sawtooth signal around a MHz, or more? For this purpose, there are parallel input high-speed DAC ICs which can give update rates up to 2.5 GSPS. In this application, I used a 10-bit 165 MSPS digital to analog converter, DAC900, to produce a 10 kHz sawtooth signal.

The signal is continuously increasing, and then roll back to zero. Therefore, it is easy to figure out what kind of parallel input to give to the DAC, a binary counter. When it reaches its maximum value, it rolls back to zero. Now, we need to calculate the maximum number of steps to fit in 100us (10kHz).

MSP430G2553 has a DCO at maximum of 16MHz, but this is the speed of the CPU clock, not the frequency of counting, since each instruction takes several cpu cycles, effective counting frequency will be reduced. One other point is that C is a high level language and its instructions take longer than Assembly instructions. Therefore, coding with Assembly will be a more effective solution.  Let us first calculate the counting frequency with full resolution, 10-bits. For this, we need to use an 11-bit counter so we can use the LSB as the DAC clock. If use the LSB as the clock, its period will determine our counting frequency.

10 bit resolution means 1024 DAC steps. If we divide 100us to 1024 we will get 97ns counting/clock period, requiring a bit more than 10MHz. This is unfortunately is not possible to get as a clock frequency because to count with two ports (since one port has 8 DIO pins, we need two of them to make a 11-bit counter), two nested loops and a comparison function is required. This will load the CPU and slow it down. I tried this method, and got maximum of 822kHz of counting frequency. Then how about counting with this frequency, and reducing the number of steps? 822kHz gives us 1.22us of count period, which means 90 steps for 100us! If we used only one port, we would have 8-bit counter and 7-bit resolution, giving us 128 steps. In that case I got approximately 1.6MHz count, which results in 80us to reach to the top value with 128 steps. This is not a big problem because we can slow down our DCO and get the required frequency. In order to use 128 steps to get 100us period, required clock frequency is 1.28MHz (Not CPU clock but the DAC clock). This value can be reached by appropriate DCO setting, which you will see in the following Assembly code[1].


; MSP430 Assembler Code Template for use with TI Code Composer Studio;
            .cdecls C,LIST,"msp430.h"       ; Include device header file

            .text                           ; Assemble into program memory
            .retain                         ; Override ELF conditional linking
                                            ; and retain current section
            .retainrefs                     ; Additionally retain any sections
                                            ; that have references to current
                                            ; section
RESET       mov.w   #__STACK_END,SP         ; Initialize stackpointer
StopWDT     mov.w   #WDTPW|WDTHOLD,&WDTCTL  ; Stop watchdog timer

                                            ; Main loop here
;DCO settings to ~1.28MHz
DcoSetng	clr.b 	&DCOCTL ; Select lowest DCOx
			bis.b 	#DCO2,&DCOCTL 

SetupP1     bis.b   #255,&P1DIR
Mainloop    inc     &P1OUT
            jmp     Mainloop

;           Stack Pointer definition
            .global __STACK_END
            .sect 	.stack

;           Interrupt Vectors
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET

With this settings our counter is ready to use and the following figure is the capture of the clock output:

Clock output from MSP430

Clock output from MSP430

Having our counter, now we need to connect it to the DAC. I directly used the basic connection instructions given in the datasheet of the DAC900. To read a value from oscilloscope, I connected a 100 ohm resistor between the current output pin and ground.

DAC900 Connections [2]

DAC900 Connections [2]

Here is the realization of this circuit on breadboard:

MSP430 and DAC900 Connections

MSP430 and DAC900 Connections

DAC900 does not come with DIP packages, so I got one SOIC-28, and soldered it on my homemade SOIC-to-DIP converter circuit. You can buy one of those coverters. I must admit that I am quite shocked about the price because similar products cost $2 in Turkey…

In the following two figures you can see the results:

Sawtooth Signal Obtained from the DAC

Sawtooth Signal Obtained from the DAC


A Close-up to the Falling Edge of the Sawtooth

A Close-up to the Falling Edge of the Sawtooth

You can see the rising is noisy due to the long thin cables, but a more important problem is that there isn’t the smooth increase of the ramp as I got in the analog circuit. However, the greatest advantage of this circuit is the real rapid falling edge.

To solve the problem with discrete increase of the ramp, I used an FPGA board, and created a sawtooth with 1250 steps. It gave much better results, and I will post that later…

Please feel free to contact me about any problems, suggestions, etc…

Thank you




[1] This code is taken from TI’s example codes for CCS and modified.




Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s