; 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 
; copyrighted material, trade secrets and other TI proprietary 
; information and is protected by copyright laws, 
; international copyright treaties, and trade secret laws, as 
; 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 
; TI patents, copyrights or trade secrets.
;
; 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
;  November, 2000
;
;****************************************************************************  
#include    "MSP430X24x1.H"                 ; Include Standard Defs

Delta       EQU     125                     ; 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     #20FEh,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.  This is only required in applications that
           ; need a specific DCO frequency and for MSP430 devices that do not
           ; have an FLL module.  See the MSP430x3xx and MSP430x1xx Family 
           ; User's Guides (literature numbers SLAU012 and SLAU049 repsecitvely)
           ; for more information on the clock systems employed on MSP430 devices
           ;
           ; The routine works by counting how many DCO clock cycles are inside
           ; of one ACLK cycle (actually 1/4 ACLK cycle because ACLK is divided
           ; by 4).  Timer_A is used to determine the number of DCO clocks and
           ; this value is then compared to the target value (Delta).  If the
           ; number is too high, the DCO is decremented.  If the number is too
           ; low, the DCO is incremented. The comparison is then made again.  
           ; This process is repeated until the target value is reached.  When
           ; the target value is obtained, the DCO is oscillating at the desired
           ; frequency.  See the application report "Controlling the DCO
           ; Frequency of the MSP430x11x devices", literature number SLAA074,
           ; for more application information related to controlling the DCO.
           ;
           ; This routine is run only once in this example, but in an
           ; application it would likely need to be run on a periodic 
           ; basis to make sure the DCO remained calibrated.  
;----------------------------------------------------------------------------- 
            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                 ;
            cmp.b   #0,&DCOCTL
            jnz     Test_DCO
            inc.b   &BCSCTL1
            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 