; AD1986.ASM
;
; ROBERT OESTLING, 2006-10-12
; WWW.ROBOS.ORG
; ROBERT@ROBOS.ORG, ROSTLING@KTH.SE
;
;   SPECIFICATIONS
;   --------------
; CRYSTAL FREQUENCY:  3.6864 MHZ
; BAUD RATE:          57.600 KBPS
; BITS PER FRAME:     6
; SAMPLES PER SECOND: 2400
;
;   OUTPUT FORMAT
;   -------------
; LEAST SIGNIFICANT FRAME:  MSB [X X X X X 0] LSB  (EVEN)
; MOST SIGNIFICANT FRAME:   MSB [X X X X X 1] LSB  (ODD)
;
; A DROPPED FRAME WILL THUS RESULT IN TWO EVEN OR TWO ODD FRAMES IN A ROW,
; AND THE ENTIRE SAMPLE CAN BE DISCARDED
;
; PIN LAYOUT:
;            ______
;    VDD    | 1  8 |    VSS
;    XTAL1  | 2  7 |    A/D INPUT
;    XTAL2  | 3  6 |    RS232 TX (OUTPUT)
;           | 4  5 |    RS232 RX (INPUT) -- NOT CURRENTLY USED
;            ------


PROCESSOR PIC12F675
INCLUDE "p12f675.inc"

    __CONFIG _XT_OSC & _WDT_OFF & _MCLRE_OFF
    RADIX DEC

SAMPLEH EQU 0X20                ; HIGH 2 BITS OF SAMPLE
SAMPLEL EQU 0X21                ; LOW 8 BITS OF SAMPLE

    ORG 0
    GOTO RESET
    ORG 4
    GOTO INTERRUPT

RESET

    MOVLW 0X02                  ; INITIALIZE GP1 (RS232 TX) TO 1 (INACTIVE)
    MOVWF GPIO
    MOVLW 0X81                  ; START UP A/D AND CONNECT IT TO AN0, ALSO
    MOVWF ADCON0                ; WRITE A RIGHT-ALIGNED SAMPLE
    MOVLW 0X07                  ; TURN COMPARATOR OFF
    MOVWF CMCON

    CLRWDT                      ; NEEDED TO SWITCH PRESCALER FUNCTION
    BSF STATUS,RP0
    MOVLW 0X80                  ; USE INTERNAL CLOCK, WITH 1:2 PRESCALER
    MOVWF OPTION_REG
    MOVLW 0XFD                  ; GP1 = OUTPUT, ALL OTHERS ARE INPUTS
    MOVWF TRISIO
    MOVLW 0X11                  ; SELECT A/D CONVERSION CLOCK AND MAKE AD0
    MOVWF ANSEL                 ; AN ANALOG INPUT
    BCF STATUS,RP0

    CLRF SAMPLEH
    CLRF SAMPLEL                ; INITAL SAMPLE = 0

    BSF INTCON,T0IE             ; ACTIVATE TIMER 0 INTERRUPT
    BSF INTCON,GIE              ; ENABLE INTERRUPTS
WAIT
    GOTO WAIT                   ; ETERNAL LOOP, WAITING FOR TIMER INTERRUPT


; NOTE THAT SINCE THE ONLY NON-INTERRUPT WORK DONE IS A DUMMY LOOP, THERE IS
; NO NEED TO SAVE ANY REGISTERS
INTERRUPT
    NOP
    MOVLW 0X43                  ; 1536 CYCLES UNTIL NEXT SAMPLE, MINUS THESE
    MOVWF TMR0                  ; INSTRUCTIONS AND INTERRUPT LATENCY

    BSF ADCON0,GO               ; START SAMPLING

    BCF STATUS,C                ; MAKE LSB OF NEXT FRAME 0
    RLF SAMPLEL
    RLF SAMPLEH
    CALL TX_SAMPLE              ; TRANSMIT FIRST PART OF OLD SAMPLE
    CALL DELAY_60               ; STOP BIT + PAUSE BETWEEN FRAMES
    BSF STATUS,C                ; MAKE LSB OF NEXT FRAME 1
    RLF SAMPLEL
    CALL TX_SAMPLE              ; TRANSMIT SECOND PART OF OLD SAMPLE

    BSF STATUS,RP0
    MOVF ADRESL,W               ; SAVE NEW SAMPLE
    BCF STATUS,RP0
    MOVWF SAMPLEL
    MOVF ADRESH,W
    MOVWF SAMPLEH

    BCF INTCON,T0IF             ; CLEAR TIMER INTERRUPT FLAG

    RETFIE                      ; RETURN FROM INTERRUPT


; TRANSMIT THE SAMPLE IN SAMPLEH:SAMPLEL TO GP1, USING RS232
; THE ROUTINE RETURNS WHILE THE STOP BIT IS IN BEING TRANSMITTED, THE CALLER
; SHOULD MAKE SURE THAT SUFFICIENT TIME ELAPSES BEFORE NEXT START BIT
; INSTRUCTION CYCLES (INCLUDING CALL/RETURN): 117
;
; NOTE: THE CODE ASSUMES EXCLUSIVE USE OF THE GPIO OUTPUTS -- MIGHT WANT TO
; MODIFY IT IN CASE ANOTHER OUTPUT IS USE
TX_SAMPLE
    BCF GPIO,1          ;       START BIT

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    RRF SAMPLEH         ; 1
    RRF SAMPLEL         ; 2     GET LSB TO CARRY
    MOVF GPIO,W         ; 3
    BTFSS STATUS,C      ; 4     INPUT BIT 0?
    ANDLW 0XFD          ; 5     THEN CLEAR OUTPUT BIT
    BTFSC STATUS,C      ; 6     INPUT BIT 1?
    IORLW 0X02          ; 7     THEN SET OUTPUT BIT
    CALL DELAY_8        ; 15
    MOVWF GPIO          ; 16

    CALL DELAY_8        ; 8
    CALL DELAY_7        ; 15
    BSF GPIO,1          ; 16    STOP BIT

    RETURN

DELAY_60:
    CALL DELAY_8
    CALL DELAY_8
    CALL DELAY_8
    CALL DELAY_8
    CALL DELAY_8
    CALL DELAY_8
    CALL DELAY_8
    RETURN

; WAIT 8 INSTRUCTION CYCLES (INCLUDING CALL/RETURN)
DELAY_8:
    NOP
DELAY_7:
    NOP
    NOP
    NOP
    RETURN

    END


