# Make a DAC with a microcontroller's PWM timer

Many embedded-microcontroller applications require generation of analog signals. An integrated or stand-alone DAC fills the role. However, you can often use PWM signals for generating the required analog signals. You can use PWM signals to create both dc and ac analog signals. This Design Idea shows how to use a PWM timer to simultaneously create a sinusoid, a ramp, and a dc voltage. A PWM signal is a digital signal with fixed frequency but varying duty cycle. If the duty cycle of the PWM signal varies with time and you filter the PWM signal, the output of the filter is an analog signal (Figure 1). If you build a PWM DAC in this manner, its resolution is equivalent to the resolution of the PWM signal you use to create the DAC. The PWM output signal requires a frequency that is equivalent to the update rate of the DAC, because each change in PWM duty cycle is the equivalent of one DAC sample. The frequency the PWM timer requires depends on the required PWM signal frequency and the desired resolution. The required frequency is FCLOCK=FPWM×2n, where FCLOCK is the required PWM-timer frequency, FPWM is the PWM-signal frequency, and n is the desired DAC resolution in bits.

Figure 2 depicts a circuit that delivers a 250-Hz sine wave, a 125-Hz ramp, and a dc signal. The desired sampling rate is 8 kHz (32 samples for each sine-wave cycle (16× oversampled), and 64 samples for each ramp cycle (32× oversampled)). These figures result in a required PWM-signal frequency of 8 kHz and a required PWM clock frequency of 2.048 MHz. It is usually best for the PWM signal frequency to be much higher than the desired bandwidth of the signals to be produced. Generally, the higher the PWM frequency, the lower the order of filter required and the easier it is to build a suitable filter. This design uses Timer B of the MSP430 in 16-bit mode and in "up" mode, in which the counter counts up to the contents of capture/compare register 0 (CCR0) and then restarts at zero. CCR0 is loaded with 255, thereby giving the counter an effective 8-bit length. You can find this register and others in a DAC demonstration program for the MSP430 microcontroller. Click here to download the program.

CCR1 and output TB1 produce the sine wave. CCR2 and TB2 generate the ramp, and CCR3 and TB3 yield the dc value. For each output, the output mode is the reset/set mode. In this mode, each output resets when the counter reaches the respective CCRx value and sets when the counter reaches the CCR0 value. This scheme provides positive pulses equivalent to the value in CCRx on each respective output. If you use the timer in 8-bit mode, the reset/set output mode is unavailable for the PWM outputs because the reset/set mode requires CCR0. The timer's clock rate is 2.048 MHz. Figure 3 shows the sine and ramp waveforms. The sine wave in this example uses 32 samples per cycle. The sample values are in a table at the beginning of the program. A pointer points to the next value in the sine table, so that, at the end of each PWM cycle, the new value of the sine wave is written to the capture/compare register of the PWM timer.

The ramp in this example does not require a table of data values. Rather, the ramp simply increments the duty cycle for each cycle of the PWM signal until it reaches the maximum and then starts over at the minimum duty cycle. This gradual increase in PWM-signal duty cycle results in a ramp voltage when the signal passes through a filter. You control the dc level by simply setting and not changing the value of the PWM-signal duty cycle. The dc level is directly proportional to the duty cycle of the PWM signal. Figure 2 shows the reconstruction filters used for each signal in this example. The filter for the ac signals is a simple two-pole, stacked-RC filter, which is simple and has no active components. This type of filter necessitates a higher sampling rate than would be required if the filter had a higher order. With the type of filter shown in Figure 2, you should use at least a 16× oversampling rate.

The filter yields its best response when R2>>R1. Also, setting the cutoff frequency too close to the bandwidth edge causes a fair amount of attenuation. To reduce the amount of attenuation in the filter, set the cutoff frequency above the bandwidth edge but much lower than the frequency of the PWM signal. The filter for the dc value serves for charge storage rather than ac-signal filtering. Therefore, it uses a simple, single-pole RC filter. Figure 4 shows the software flow for the DAC. After a reset, the routine stops the watchdog timer, configures the output ports, and sets up the clock system. Next, the software calls a delay to allow the 32,768-Hz crystal to stabilize to calibrate the DCO (digitally controlled oscillator).

Next, the routine calls the calibration routine to set the operating frequency to 2.048 MHz. After the DCO calibration, the program sets up Timer_B, CCR1 and CCR2 for PWM generation and then starts the timer. Finally, the MSP430 goes into low-power mode 0 (LPM0) to conserve power. The CPU wakes up to handle each CCIFG0 interrupt from the PWM timer and then re-enters LPM0. (See references 1, 2, and 3 for more information on the DCO and the MSP430 family.)

di2968.txt
;*****************************************************************************
;
; "Make a DAC with a microcontroller's PWM timer," EDN, September 5, 2002, pg 110
;
;
; THIS PROGRAM IS PROVIDED "AS IS". TI MAKES NO WARRANTIES OR
; REPRESENTATIONS, EITHER EXPRESS, IMPLIED OR STATUTORY,
; INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
; FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR
; COMPLETENESS OF RESPONSES, RESULTS AND LACK OF NEGLIGENCE.
; TI DISCLAIMS ANY WARRANTY OF TITLE, QUIET ENJOYMENT, QUIET
; POSSESSION, AND NON-INFRINGEMENT OF ANY THIRD PARTY
; INTELLECTUAL PROPERTY RIGHTS WITH REGARD TO THE PROGRAM OR
; YOUR USE OF THE PROGRAM.
;
; IN NO EVENT SHALL TI BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
; CONSEQUENTIAL OR INDIRECT DAMAGES, HOWEVER CAUSED, ON ANY
; THEORY OF LIABILITY AND WHETHER OR NOT TI HAS BEEN ADVISED
; OF THE POSSIBILITY OF SUCH DAMAGES, ARISING IN ANY WAY OUT
; OF THIS AGREEMENT, THE PROGRAM, OR YOUR USE OF THE PROGRAM.
; EXCLUDED DAMAGES INCLUDE, BUT ARE NOT LIMITED TO, COST OF
; REMOVAL OR REINSTALLATION, COMPUTER TIME, LABOR COSTS, LOSS
; OF GOODWILL, LOSS OF PROFITS, LOSS OF SAVINGS, OR LOSS OF
; USE OR INTERRUPTION OF BUSINESS. IN NO EVENT WILL TI'S
; AGGREGATE LIABILITY UNDER THIS AGREEMENT OR ARISING OUT OF
; YOUR USE OF THE PROGRAM EXCEED FIVE HUNDRED DOLLARS
; (U.S.\$500).
;
; Unless otherwise stated, the Program written and copyrighted
; by Texas Instruments is distributed as "freeware".  You may,
; only under TI's copyright in the Program, use and modify the
; Program without any charge or restriction.  You may
; distribute to third parties, provided that you transfer a
; copy of this license to the third party and the third party
; agrees to these terms by its first use of the Program. You
; must reproduce the copyright notice and any other legend of
; ownership on each copy or partial copy, of the Program.
;
; You acknowledge and agree that the Program contains
; information and is protected by copyright laws,
; well as other intellectual property laws.  To protect TI's
; rights in the Program, you agree not to decompile, reverse
; engineer, disassemble or otherwise translate any object code
; versions of the Program to a human-readable form.  You agree
; that in no event will you alter, remove or destroy any
; copyright notice included in the Program.  TI reserves all
; rights not specifically granted under this license. Except
; as specifically provided herein, nothing in this agreement
; shall be construed as conferring by implication, estoppel,
; or otherwise, upon you, any license or other right under any
;
; You may not use the Program in non-TI devices.

NAME        PWMDAC
;****************************************************************************
;  PWM DAC Demonstratin Program
;  Generate a 250Hz sine wave using PWM timer Timer_B.
;
;  Description: This program demonstrates the usage of a PWM timer together
;  with external filters to implement a DAC.  The program shows how to
;  create a 250Hz sine wave, a 125Hz ramp, and a DC level with Timer_B.
;  Timer_A could also be used in the same manner.  A sine table holds the
;  sample values for the sinusoid.  To create the ramp, the PWM value is
;  simply incremented. The DC level is created by storing charge on an
;  RC network using a PWM output to provide the charge.  The value of the DC
;  voltage directly corresponds to the duty cycele of the PWM signal.  After
;  initialization, the CPU is put into LPM0.  It remains there until the
;  CCIFG0 interrupt from Timer_B wakes it up.  In the Timer_B ISR, the next
;  value for the sinusoid is loaded into CCR1 and the ramp value is incremented
;  and loded into CCR2. Upon return form the ISR, the CPU goes back into LPM0.
;
;  Mike Mitchell
;  MSP430 Applications
;  Texas Instruments, Inc
;
;****************************************************************************
#include    "MSP430X14x.H"                  ; Include Standard Defs

Delta       EQU     250                     ; Delta = Target DCO/8192
; Target DCO frequency = 2.048MHz
; This value is used in the
; software FLL routine to
; calibrate the DCO frequency
; using the 32768Hz oscillator
; as a reference.  For more
; information on stabilizing
; the DCO or the FLL routine
; see the application report
; titled "Controlling the DCO
; frequency of the MSP430x11x"
; Literature number SLAA074
;-----------------------------------------------------------------------------
RSEG    CODE
;-----------------------------------------------------------------------------
Sine_Tab    DW      255                     ; Sine Table.  These are the count
DW      254                     ; values in decimal that will
DW      246                     ; go into TBCCR1 to change the
DW      234                     ; PWM duty cycle.
DW      219                     ; Must use words instead of bytes
DW      199                     ; because must move words into
DW      177                     ; TB registers.
DW      153                     ; Don't use a '0' as a sample value
DW      128                     ; The timer will glitch.
DW      103
DW      79
DW      57
DW      37
DW      22
DW      10
DW      2
DW      1
DW      2
DW      10
DW      22
DW      37
DW      57
DW      79
DW      103
DW      128
DW      153
DW      177
DW      199
DW      219
DW      234
DW      246
DW      255
;-----------------   Code Starts Here   --------------------------------------
RESET       mov     #09FEh,SP               ; Initialize stackpointer

StopWDT     mov     #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT

SetupP4     bis.b   #00Eh,&P4SEL            ; Select TB1, TB2, TB3 instead of
bis.b   #00Eh,&P4DIR            ; P4.x, and set as outputs

SetupBC     mov.b   #0A6h,&BCSCTL1          ; ACLK is divided by 4. RSEL=6,
; no division for MCLK or SMCLK,
; DCO sources MCLK and SMCLK.
; XT2 is off.
; NOTE: To determine the value of
; Rsel for a desired DCO frequency,
; refer to the DCO table in the
; datasheet.

call    #Delay                  ; Delay for crystal stabilization.
; Need to put a delay here because
; the 32768Hz crystal is used as
; a reference to stabilize the DCO
; frequency.  Therefore, the 32768
; crystal needs to be stable.

call    #SW_FLL                 ; Call the routine to Stabilize
; the DCO clock.

call    #TB_SETUP               ; Setup Timer_B for PWM generation

clr     R15                     ; R15 and R14 used as pointers
clr     R14                     ; to the sine table and to hold the
; ramp value after the DCO is
; stabilized

eint                            ; Enable interrupts

bis     #LPM0,SR                ; Put CPU to sleep.
; This is the end of the program
; except for handling the CCIFG0
; interrupt, which is where the
; PWM values are updated.
;-----------------------------------------------------------------------------
Delay;      Software delay for crystal stabilization
;-----------------------------------------------------------------------------
mov     #0004h,R15
L1          mov     #0FFFFh,R14             ; This should ideally be about a sec.
L2          dec     R14                     ;
jnz     L2                      ;
;
dec     R15                     ;
jnz     L1                      ;
ret                             ;
;
;-----------------------------------------------------------------------------
SW_FLL;    Subroutine: Stabilizes DCO frequency.
; This routine uses the 32768Hz crystal oscillator as a reference
; frequency to stabilize and trim the DCO oscillator to the desired
; frequency of 2.048MHz.
;-----------------------------------------------------------------------------
clr     R15                     ;
Setup_TA    mov     #TASSEL1+TACLR,&TACTL   ; SMCLK clocks TA
Setup_CC2   mov     #CCIS0+CM0+CAP,&CCTL2   ; Define CCR2,CAP,ACLK
bis     #MC1,&TACTL             ; Start timer_A: Continous Mode
Test_DCO    bit     #CCIFG,&CCTL2           ; Test capture flag
jz      Test_DCO                ;
bic     #CCIFG,&CCTL2           ; Clear capture flag
;
AdjDCO      mov     &CCR2,R14               ; R14 = captured SMCLK
sub     R15,R14                 ; R14 = capture difference
mov     &CCR2,R15               ; R15 = captured SMCLK
cmp     #Delta,R14              ; Delta = SMCLK/(32768/4)
jlo     IncDCO                  ;
jeq     DoneFLL                 ;
DecDCO      dec.b   &DCOCTL                 ;
jmp     Test_DCO                ;
IncDCO      inc.b   &DCOCTL                 ;
jmp     Test_DCO                ;
DoneFLL     clr     &CCTL2                  ; Stop CCR2
clr     &TACTL                  ; Stop timer_A
ret                             ; Return from subroutine
;-----------------------------------------------------------------------------
TB_SETUP;    Subroutine: Setup Timer_B for PWM generation
;-----------------------------------------------------------------------------
mov     #TBSSEL1+TBCLR,&TBCTL   ; SMCLK clocks TB.
mov     #CCIE,&TBCCTL0          ; Set CCR0 in compare mode, enable
; it's interrupt
mov     #0FFh,&TBCCR0           ; Put 255d in CCR0.  This will set
; the period of the PWM output to
; 256 counts(8-bits).  This gives
; an 8-bit DAC.
mov     #02E0h,&TBCCTL1         ; Set CCRx in compare mode, disable
mov     #02E0h,&TBCCTL2         ; interrupt, set outmode to '7' which
mov     #02E0h,&TBCCTL3         ; is reset/set.  EQU0 sets the output
; EQU1 will reset it. Set the load
; condition for the compare latch
; to be when the counter counts to
; 0.
mov     #Sine_Tab,&TBCCR1       ; Load first sample value into CCR1
mov     #01h,R14                ; Load inital ramp value into R14.
mov     #0AAh,&TBCCR3           ; This is for the DC value.  It will
; result in a voltage of approximately
; 2/3 Vcc because #0AAh is 2/3 of
; #0FFh.
bis     #MC0,&TBCTL             ; Start timer_B in up mode

ret
;-----------------------------------------------------------------------------
TB_ISR;    Timer_B ISR: changes the value in the CCR1 and CCR2 registers to
;          vary the PWM for the sinusoid and the ramp.  The CCR3 value is left
;          unchanged for the DC signal.
;-----------------------------------------------------------------------------
incd   R15                      ; Increment the pointer R15 to
; to point to next word of sine
; table.  Must increment by 2
; because the sine table is words
; not bytes.
and     #03Fh,R15               ; ANDing with 03Fh gives an
; effective modulo 32 counter for
; pointing to each value in the
; sine table
mov    Sine_Tab(R15),&TBCCR1    ; Move new sine value to CCR1

add    #04h,R14                 ; Increment ramp value.
; Changing the step size in R14
; will change the frequency of
; the ramp.
and    #0FFh,R14                ; And off unwanted bits
mov    R14,&TBCCR2              ; Move new ramp value to CCR2

reti                            ; return with interrupts enabled
;---------------------------------------------------------------------------
COMMON  INTVEC                  ; MSP430x14x interrupt vectors
;---------------------------------------------------------------------------
ORG     TIMERB0_VECTOR
DW      TB_ISR                  ; CCIFG0 interrupt
ORG     RESET_VECTOR
DW      RESET                   ; POR, ext. Reset, Watchdog
END 

• 0
点赞
• 0
评论
• 0
收藏
• 一键三连
• 扫一扫，分享海报