;-------------------------------------------------------------------------
; LOOPAIC.ASM
; Keith Larson
; TMS320 DSP Applications
; (C) Copyright 1995,1996
; Texas Instruments Incorporated
;
; This is unsupported freeware with no implied warranties or
; liabilities.  See the disclaimer document for details
;
; LOOPAIC.ASM is a simple program which initializes and uses the TLC32040.
; The analog ADC input is either looped back to to the DAC output (RAMPEN=0)
; or a sawtooth ramp is generated at the DAC output (RAMPEN=1).
;-------------------------------------------------------------------------
          .start  "AICTEST",0x809802 ; Start assembling here
          .sect   "AICTEST"          ;
;------------------------------------
; Define constants used by program
;------------------------------------
RAMPEN    .set   0                   ; Set to 1 to generate ramp at AOUT
T0_ctrl   .set   0x808020            ; TIM0 gl control
T0_count  .set   0x808024            ; TIM0 count
T0_prd    .set   0x808028            ; TIM0 prd
S0_gctrl  .set   0x808040            ; SP 0 global control
S0_xctrl  .set   0x808042            ; SP 0 FSX/DX/CLKX port ctl
S0_rctrl  .set   0x808043            ; SP 0 FSR/DR/CLKR port ctl
S0_xdata  .set   0x808048            ; SP 0 Data transmit
S0_rdata  .set   0x80804C            ; SP 0 Data receive
TIM0_PRD  .set   2                   ; Timer diviser
TA        .set   8                   ; AIC timing register values
TB        .set   14                  ;
RA        .set   8                   ;
RB        .set   14                  ;
GIE       .set   0x2000              ; This bit in ST turns on interrupts
;------------------------------------
; Define some constant storage data
;------------------------------------
A_REG        .word  (TA<<9)+(RA<<2)+0 ; A registers
B_REG        .word  (TB<<9)+(RB<<2)+2 ; B registers
C_REG	     .word  00000011b	      ; control
S0_gctrl_val .word  0x0E970300        ; Serial port control register values
S0_xctrl_val .word  0x00000111        ;
S0_rctrl_val .word  0x00000111        ;
RAMP         .word  0                 ; RAMP count value
ADC_last     .word  0                 ; Last received ADC value
;****************************************************
; Begin main code loop here
;****************************************************
main      or    GIE,ST          ; Turn on INTS
          ldi   0xF4,IE         ; Enable XINT/RINT/INT2
          b     main            ; Do it again!
;-------------------------------
DAC2      push  ST              ; DAC Interrupt service routine
          push  R3              ;
          .if   RAMPEN          ; If RAMPEN=1 assemble this code
          ldi   @RAMP,R3        ;
          addi  256,R3          ; Add a value to RAMP
          sti   R3,@RAMP        ;
          .else                 ; Else assemble this
          ldi   @ADC_last,R3    ;
       ;  mpyi   1,R3           ; Scale up the ADC value to see distortion
          cmpi   32767,R3       ;
          ldigt  32767,R3       ;
          cmpi  -32768,R3       ;
          ldilt -32768,R3       ;
          .endif                ;
          andn  3,R3            ;
          sti   R3,@S0_xdata    ; Output the new DAC value
          pop   R3              ;
          pop   ST              ;
          reti                  ;
;-------------------------------
ADC2      push  ST              ;
          push  R3              ;
          ldi   @S0_rdata,R3    ; Sign extend the data
          lsh   16,R3  ;SEE NOTE; Present data is in lower 16 bits
          ash   -16,R3          ; >> Sample N-1 is in upper 16 bits
          sti   R3,@ADC_last    ;    If a delay is acceptable, the 'LSH 11,R3'
          pop   R3              ;    can be ommitted
          pop   ST              ;
          reti                  ;
;*****************************************************;
; The startup stub is used during initialization only ;
; and can be safely overwritten by the stack or data  ;
;*****************************************************;
          .entry   ST_STUB      ; Debugger starts here
ST_STUB   ldp   T0_ctrl         ; Use kernel data page and stack
          ldi   @stack,SP
          ldi   0,R0            ; Halt TIM0
          sti   R0,@T0_ctrl     ;
          sti   R0,@T0_count    ; Zero the count
          ldi   TIM0_PRD,R0     ; Set the period
          sti   R0,@T0_prd      ;
          ldi   0x2C1,R0        ; Restart the timer
          sti   R0,@T0_ctrl     ;
          ;---------------------
          ldi   @S0_xctrl_val,R0;
          sti   R0,@S0_xctrl    ; transmit control
          ldi   @S0_rctrl_val,R0;
          sti   R0,@S0_rctrl    ; receive control
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ; DXR data value
          ldi   @S0_gctrl_val,R0; Setup serial port
          sti   R0,@S0_gctrl    ; global control
;======================================================;
; This section of code initializes the AIC             ;
;======================================================;
AIC_INIT  LDI   0x10,IE         ; Enable only XINT interrupt
          andn  0x34,IF         ;
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ;
          RPTS  0x040           ;
          LDI   2,IOF           ; XF0=0 resets AIC
          rpts  0x40            ;
          LDI   6,IOF           ; XF0=1 runs AIC
          ;---------------------
          ldi   @C_REG,R0       ; Setup control register
          call  prog_AIC        ;
          ldi   0xfffc  ,R0     ; Program the AIC to be real slow
          call  prog_AIC        ;
          ldi   0xfffc|2,R0     ;
          call  prog_AIC        ;
          ldi   @B_REG,R0       ; Bump up the Fs to final rate
          call  prog_AIC        ; (smallest divisor should be last)
          ldi   @A_REG,R0       ;
	  call	prog_AIC	;
	  b	main		;
;-------------------------------
prog_AIC  ldi   @S0_xdata,R1    ; Use original DXR data during 2 ndy
          sti   R1,@S0_xdata    ;
          idle
          ldi   @S0_xdata,R1    ; Use original DXR data during 2 ndy
          or    3,R1            ; Request 2 ndy XMIT
          sti   R1,@S0_xdata    ;
          idle                  ;
          sti   R0,@S0_xdata    ; Send register value
          idle                  ;
          andn  3,R1            ;
          sti   R1,@S0_xdata    ; Leave with original safe value in DXR
          ;---------------------
          ldi   @S0_rdata,R0    ; Fix the receiver underrun by reading
	  rets			; the DRR before going to the main loop
stack     .word   $             ; Put stack here
;****************************************************;
; Install the XINT/RINT ISR handler directly into    ;
; the vector RAM location it will be used for        ;
;****************************************************;
          .start   "SP0VECTS",0x809FC5
          .sect    "SP0VECTS"
          B        DAC2         ; XINT0
          B        ADC2         ; RINT0
