;------------------------------------------------------------------
; DSKOSC.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
;-------------------------------------------------------------------
;
;This application is written to run with the DOS executable DSK_OSC.EXE
;
;STARTUP STUB
;------------
; The initialization code which is used only on startup is placed inside
; the volatile data memory array to gain back internal memory.
;
;SAMPLING RATES
;--------------
; The AIC sampling rates can be set to any combination which can still
; communicate with the DSP.  Some combinations will work as high as 130 KHz
; with substantial performance degradation.  Experimentation is required to
; find values that work best, or at all, since some will crash the
; communications entirely.
;
;HOST SYNCHRONIZATION
;--------------------
; Since the host should not disturb the ADC while data is being collected
; an interlock is used to keep the host from timing out.  This application
; uses a message box.
;
;SERIAL PORT REFRESH
;-------------------
; If the serial port is not serviced once every frame synch an underrun
; condition will occur and the port will shut down.  This is important for
; the transmit section since putting a new value in the DXR will cause the
; previous value to move to the shift register irregardless of the state
; of FSX.  Since the bit patterns are data dependent and in this case shifted
; by an unknown amount the AIC could be reprogrammed if steps are not taken
; to avoid a bad restart.  This is done by placing a zero in the transmitter
; whenever the serial port and AIC are likely to underrun.
;
; To prevent this the communications kernel is written such that the serial
; port tranmit channel is updated with zero whenever the kernel enters the
; wait for command loop 'spin0'.  When spin0 is exited (RUN command) the
; serial port is restarted with the original value.
;-------------------------------------------------------------------------
TA       .set   10     ; Default startup values
TB       .set   14     ;
RA       .set   10     ; Default startup values
RB       .set   14     ;
         .include "C3XMMRS.ASM"
;==================================================
          .start  "AICTEST",0x809900
          .sect   "AICTEST"
GIE       .set  0x2000
;=================================================================
_STOP     .set   1
_START    .set   2
;
MSG_BOX   .word  _STOP             ; 0x809900
TLVL      .word  1000              ; 0x809901
A_REG     .word  (TA<<9)+(RA<<2)+0 ; 0x809902
B_REG     .word  (TB<<9)+(RB<<2)+2 ; 0x809903
C_REG     .word  00001011b         ; 0x809904  +/- 6 V
EDGESEL   .word  0                 ; 0x809905
SAMPLES   .word  512               ; 0x809906
A_REGOLD  .word  0
B_REGOLD  .word  0
C_REGOLD  .word  0
;
OSC_DATA  .word  O_DATA
S0_gctrl_val  .word  0x0E970300 ; Runtime value XINT/RINT enabled
S0_xctrl_val  .word  0x00000111 ;
S0_rctrl_val  .word  0x00000111 ;
;-------------------------------
R_edge    ldi   R0,R2           ; Initialize post sample
          rptb  Rno_trg         ;
R_trgr    call  GETADC          ;
          cmpi  @TLVL,R2        ;
          blt   Rno_trg         ;
          cmpi  @TLVL,R0        ;
          blt   trgrd           ;
Rno_trg   ldi   R0,R2           ; decrement RC
          b     trgrd           ;
;-------------------------------
main      ldi   0x30,IE         ; Ignore the host while collecting data
          ldi   @S0_rdata,R0    ; Clear SP under/overflow
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ;
          ldi   @S0_rdata,R0    ;
          ldi   0,R0            ;
          sti   R0,@S0_xdata    ;

          ldi   25,RC           ; Preload some ADC data to flush out
          rptb  preload         ; the AIC after putting it to sleep
preload   call  GETADC          ;
          ;---------------------
          ldi   4000,RC         ; Trigger within N samples
          ldi   @EDGESEL,R2     ;
          bnz   R_edge          ;
          ;---------------------
F_edge    ldi   R0,R2           ; Initialize post sample
          rptb  Fno_trg         ;
F_trgr    call  GETADC          ;
          cmpi  @TLVL,R2        ;
          bgt   Fno_trg         ;
          cmpi  @TLVL,R0        ;
          bgt   trgrd           ;
Fno_trg   ldi   R0,R2           ; decrement RC
          ;---------------------
trgrd     ldi    RC,R4          ; Set trigger bit if no timeout has occured
          ldiu   1,R1           ; LDIU does not corrupt status
          ldiz   0,R1           ; If RC=0 no trigger event ocurred
          ;---------------------
          ldi   @OSC_DATA,AR0   ;
          ldi   @SAMPLES,RC     ; Now get samples, packed two/loop
          ash   -1,RC           ;

          subi  1,RC            ;
          lsh   16,R0           ; Save pre/post-trigger values for host side
          and   0xFFFF,R2       ; analysis.  By evaluating which is closer
          or    R0,R2           ; to the threshold the data can be pre-post
          sti   R2,*AR0++       ; shifted to steady the display

          rptb  samples         ; packing 2 ints per word
          call  GETADC          ;
          or    R1,R0           ;
          ldi   R0,R2           ;
          and   0xFFFF,R2       ;
          call  GETADC          ;
          or    R1,R0           ;
          lsh   16,R0           ;
          or    R2,R0           ;
samples   sti   R0,*AR0++       ; store to data array
          ;---------------------
          ldi   0,R0            ; The host may take some time to complete
          sti   R0,@S0_xdata    ; all tasks so use a safe DXR shut down value
          ;---------------------
          ldi   0x4,IE          ; Only service host interrupts now
          ldi   _START,R0       ;
NO_START  cmpi  @MSG_BOX,R0     ; Restart when START message is received
          bnz   NO_START        ;
          ldi   _STOP,R0        ; Set MSG box to STOP
          sti   R0,@MSG_BOX     ;
          ;---------------------
          ldi   0,R2            ;
          ldi   @A_REG   ,R0    ; Reload any new runtime parameters
          cmpi  @A_REGOLD,R0    ;
          ldinz 1,R2            ;
          sti   R0,@A_REGOLD    ;
          ;- - - - - - - - - - -
          ldi   @B_REG   ,R0    ;
          cmpi  @B_REGOLD,R0    ;
          ldinz 1,R2            ;
          sti   R0,@B_REGOLD    ;
          ;- - - - - - - - - - -
          ldi   @C_REG   ,R0    ;
          cmpi  @C_REGOLD,R0    ;
          ldinz 1,R2            ;
          sti   R0,@C_REGOLD    ;
          ;- - - - - - - - - - -
          cmpi  0,R2            ;
          bz    main            ;
          call  AIC_INIT        ; Restart with new AIC setup
          b     main            ; Do it all over again!
;***************************************************************************
RAMP      .word 0               ;
FLAGS     .word 0

GETADC    ldi   0x30,IE         ; Come here and wait for ADC interrupt
          IDLE                  ; confirmation to save power and code space
       ;  or    GIE,ST          ;
          ldi   @FLAGS,R0       ;
          tstb  0x20,R0         ;
          bz    $-3             ;
          andn  0x20,R0         ;
          sti   R0,@FLAGS       ;
          ldi   @S0_rdata,R0    ; Return sign extended ADC value
          lsh   16,R0           ;
          ash   -16,R0          ;
          rets

ADC       push  ST              ; On interrupt, set a software flag to
          push  R0              ; let the CPU know that the RINT has been
          ldi   @S0_rdata,R0    ;
          ldi   @FLAGS,R0       ;
          or    0x20,R0         ;
          sti   R0,@FLAGS       ;
          pop   R0              ;
          pop   ST              ;
          reti                  ;

DAC       push  ST              ;
          push  R1              ;
          ldi   @RAMP,R1        ; Send RAMP signal out DAC for loopback test
          subi  256,R1          ;
          lsh   17,R1           ; Decrease
          ash   -17,R1          ;
          andn  3,R1            ;
          sti   R1,@RAMP        ;
          sti   R1,@S0_xdata    ; loopback ADC->DAC
          pop   R1
          pop   ST
          reti

;--------------------------------
prog_AIC  push  R1              ;
          push  IE              ;
          ldi   0x10,IE         ;
          andn  0x30,IF         ;
          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
          pop   IE              ;
          pop   R1              ;
          rets                  ;
;======================================================;
; This section of code is called by the initialization ;
; code as well as by the main program loop.  It is     ;
; therfor assembled into the regular program RAM       ;
;======================================================;
AIC_INIT  push  R0              ;
          LDI   0x10,IE         ; Enable XINT interrupt
          andn  0x34,IF         ;
AIC_reset
          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   @S0_rdata,R0
          ldi   0,R0
          sti   R0,@S0_xdata

          ;-----------------------------
          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        ;
          pop   R0              ;
          ldi   0,R0            ; Put a safe 0 in DXR
          sti   R0,@S0_xdata    ;
          ldi   @S0_rdata,R0    ; Clear receive underrun
          rets                  ;
;-------------------------------------------
          .start "OSCDATA",0x809A00
          .sect  "OSCDATA"
O_DATA    .word  0
;*****************************************************;
; Startup stub...                                     ;
;                                                     ;
; The following section of code is used only once for ;
; initialization and can be safely overwritten by     ;
; assembling it into the stack or volatile data       ;
; storage.                                            ;
;*****************************************************;
          .entry   ST_STUB
ST_STUB   ldp   T0_ctrl         ; Use kernel data page and stack
          ldi   0,R0            ; Halt TIM0 & TIM1
          sti   R0,@T0_ctrl     ;
          sti   R0,@T1_ctrl     ;
          sti   R0,@T0_count    ; Set counts to 0
          sti   R0,@T1_count    ;
          ldi   1,R0            ; Set periods to 1
          sti   R0,@T0_prd      ;
          sti   R0,@T1_prd      ;
          ldi   0x2C1,R0        ; Restart both timers
          sti   R0,@T0_ctrl     ;
          sti   R0,@T1_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
          ;---------------------
          call  AIC_INIT        ; Initialize the AIC
          ldi   0x30,IE         ; Service both RINT/XINT
          ldi   @S0_rdata,R0    ;
     ;    ldi   0,R0            ; Put a safe 0 in DXR
     ;    sti   R0,@S0_xdata    ;
          b     main            ;

S0_dxr   .word  S0_xdata
;****************************************************;
; Install the XINT/RINT ISR handler directly into    ;
; the vector RAM location it will be used in         ;
;****************************************************;
          .start   "SP0VECTS",0x809FC5
          .sect    "SP0VECTS"
          b        DAC        ; XINT0
          b        ADC        ; RINT0
          .end

