Subject: 68HC11 power glove code (long)

From: [email-masked] (Ron Menelli)
Date: Thu, 24 Oct 91 16:41:38 CDT

Here's the 68HC11 power glove code. Notice that it does not include
deglitching. This is mainly because I think there is a problem in the
glove read routine, and I wanted it to be more obvious (for now). I 
haven't tried any of the other versions of the software, so I don't know
the proper behavior, but my code seems to receive a large amount of noise,
and it gets worse when you make a fist with the glove. My guess is that
there is some timing that is slightly off, and the reduced sample rate
when a fist is made makes it worse. I haven't had time to play with it,
and many people have been asking for the code, so I'll send it as is...

Please send me any comments/suggestions/corrections/flames or whatever!

-Ron Menelli
[email-masked]

------------------------cut here----------------------------------------


;/**********************************************************************
; 
;  Originally "power.c" (c) manfredo 9/91 ([email-masked])
;  Developed on an ATARI 1040ST with TC 1.1 using a logic analyzer to get
;  the correct timings.
; 
;**********************************************************************/
;/*********************************************************************
;             ported to PC compatibles by
;                Greg Alt 10/91
; 
;               [email-masked]
;            or [email-masked]
; 
;**********************************************************************/
;/*********************************************************************
;
; Substantially rewritten by Dave Stampe (c) 1991: PWRFILT.C
;  No cash, no warranty, no flames.
;  This stuff works great, so gimme credit.
;
; Goals <achieved> were:
;
;  Higher speed, smaller code.
;  Polled operation is now possible.
;  Graphics test (VGA)
;  Noise reduction added, gets rid of 99.5% of noise with NO DELAY!
;
;  This runs on a 486/25 with an i/o card. 
;  Someone should adapt it for the usual printer port adapter.
;  It was compiled with Turbo C++ 2.0 but will probably
;  work on any Turbo C directly. MSC will need library calls checked.
;
;
; [email-masked]          17/10/91
;**********************************************************************/
;
;
; 68HC11 version by Ron Menelli, 10/23/91
;
; A million thanks to the above people for taking this project as far
; as it has gone! This version runs on the MC68HC11 processor, specifically
; Motorola's MC68HC11EVB board. The assembler I used was Matt Dillon's
; DASM for the Amiga - this code will have to be converted a bit to be
; used on Motorola's freeware assembler.
;
; As it stands, this code is a direct port of Dave Stampe's code minus
; the IBM specific stuff (VGA, for example). The way this code works is
; by sending the data received from the Power Glove over the serial port
; at 9600 baud. By sending single character commands, the serial port
; action can be controlled as follows:
;
;       Send    Action
;       ====    =========
;        C      Start continuous mode - send every time the glove is read.
;               The data is sent with a certain byte preceding it as a
;               flag marking the beginning. The format I have used is:
;
;                   A0 X Y Z rot fingers keys
;
;                   ^
;                   +--- Flag character (A0 used for old time's sake!)
;
;        R      Start request mode - send the 6 byte data packet when
;               requested by user. Format is the same as above, minus
;               the flag character.
;
;        ?      In request mode, this causes the controller to report
;               the current glove data.
;
; *** Note that the deglitching code is not in this version
;
; Please send me any suggestions you have regarding improvements to this
; code!
;
; -Ron Menelli  [email-masked]
;

    PROCESSOR   68HC11          ; Needed for DAsm

    ORG         $D000           ; Jump to this address to start
                                ; This is the beginning of RAM for the EVB.
;
; Macro definitions
;

; Delay 3us (made a macro because a subroutine would be too slow)

    MAC DELAY3US

        NOP
        NOP
        NOP

    ENDM

; Set Clock = 0, Latch = 0

    MAC C0L0

        LDAB    #0
        STAB    PORTA

    ENDM

; Set Clock = 0, Latch = 1

    MAC C0L1

        LDAB    #GLATCH
        STAB    PORTA

    ENDM

; Set Clock = 1, Latch = 0

    MAC C1L0

        LDAB    #GCLOCK
        STAB    PORTA

    ENDM

; Set Clock = 1, Latch = 1

    MAC C1L1

        LDAB    #GCLOLAT
        STAB    PORTA

    ENDM

;
; RAM allocation
;

BITCNT      EQU     $0000
BYTECNT     EQU     $0001
GLOVEFLAG   EQU     $0002       ; Flag byte for continuous mode
GLOVEDATA   EQU     $0003       ; 7 byte array
UNREADY     EQU     $0009
MODEFLAG    EQU     $000A       ; Mode flag - continuous or request

;
; Port A definitions
;
; bit 0 - Data in
; bit 4 - Clock out
; bit 5 - Latch out
;

PORTA       EQU     $1000
PACTL       EQU     $1026
GDATA       EQU     $01
GCLOCK      EQU     $10
GLATCH      EQU     $20
GCLOLAT     EQU     $30

;
; Serial port definitions
;

BAUD        EQU     $102B
SCCR1       EQU     $102C
SCCR2       EQU     $102D
SCSR        EQU     $102E
SCDR        EQU     $102F

;
; Timing constants (for an 8Mhz crystal)
;

D2BYTES     EQU     30          ; 96us
D2SLOW      EQU     700         ; ~= 2100us

; Other stuff

CONTMODE    EQU     0           ; Continuous mode
REQMODE     EQU     1           ; Request mode
CONTCHAR    EQU     'C          ; Character to request cont. mode
REQCHAR     EQU     'R          ; Character to request request mode
QUERYCHAR   EQU     '?          ; Character to request a data packet
                                ; * Only valid in request mode
FLAGCHAR    EQU     $A0         ; Flag indicating beginning of packet in
                                ; continuous mode

;
; ***********************
; * Program begins here *
; ***********************
;

INIT:       LDS     #$00FF      ; Initialize stack pointer

            LDAA    #0          ; Disable pulse accumulator on port A
            STAA    PACTL

            LDAA    #$01        ; Set EVB to serial receive normally
            STAA    $4000

            LDAA    #$30        ; Set serial port for 9600 baud
                                ; (using 8 MHz XTAL)
                                ; (Set to $20 for 31.25 kbaud)
            STAA    BAUD
            LDAA    #$0C        ; Transmit & receive enable
            STAA    SCCR2

            LDAA    #FLAGCHAR   ; Set up flag character in buffer
            STAA    GLOVEFLAG

            LDAA    #CONTMODE   ; Start in request mode
            STAA    MODEFLAG

INITGLOVE:  JSR     HIRES       ; Set hi-res mode

;
; *********************
; * Main program loop *
; *********************
;

MAIN:       LDAA    #0          ; Zero the retry counter
            STAA    UNREADY
            LDX     #D2SLOW     ; Wait a while
            JSR     DELAY

CHECKRDY:   JSR     GETBYTE     ; Check to see if glove is ready
            CMPA    #$A0        ; Is it A0 (the start of the sequence?)
            BEQ     READDATA    ; Yes, read the rest of the data sequence

            INC     UNREADY     ; Increment retry counter
            BEQ     INITGLOVE   ; If 256 tries, initialize the glove again

            LDX     #D2SLOW     ; Wait and try again
            JSR     DELAY
            BRA     CHECKRDY

READDATA:   LDY     #GLOVEDATA
            JSR     GETGLOVE    ; Read glove data into buffer
            LDY     #GLOVEDATA

            LDAA    SCSR        ; Check serial port receive status
            ANDA    #$20
            BEQ     CHECKMODE

            LDAA    SCDR        ; Character received - check it

            CMPA    #QUERYCHAR  ; Is it the query character?
            BNE     NOTQRYCH    ; No - skip this
            LDAA    MODEFLAG    ; Yes - check to see what mode we're in
            CMPA    #REQMODE    ; If not in request mode, skip this
            BNE     CHECKMODE
            LDY     #GLOVEDATA  ; Send 6 bytes over the serial port
            LDAB    #6
            JSR     SENDSER     ; This does our pausing for us (6.25 ms)
            BRA     MAIN        ; No need to continue checking
            
NOTQRYCH:   CMPA    #CONTCHAR   ; Is it the cont. mode activator?
            BNE     NOTCONTCH   ; No - skip this
            LDAA    #CONTMODE   ; Yes - set continuous mode
            STAA    MODEFLAG
            BRA     CHECKMODE

NOTCONTCH:  CMPA    #REQCHAR    ; Is it the request mode activator?
            BNE     CHECKMODE   ; No - skip this
            LDAA    #REQMODE    ; Yes - set request mode
            STAA    MODEFLAG
            BRA     WAIT        ; No need to continue checking

CHECKMODE:  LDAA    MODEFLAG    ; Check the mode flag
            CMPA    #CONTMODE   ; Is it continuous mode?
            BNE     WAIT        ; No - wait and start the loop again
            LDY     #GLOVEFLAG  ; Send data (6 + Flag) over serial port
            LDAB    #7
            JSR     SENDSER     ; This provides approx. 7.29 ms of delay
                                ; at 9600 baud
            BRA     MAIN

WAIT:       LDX     #D2SLOW     ; Wait a while before continuing
            JSR     DELAY
            BRA     MAIN

;
; **************************************
; *          Delay subroutine          *
; * (Delay proportional to value in X) *
; **************************************
;

DELAY:      DEX
            BNE     DELAY
            RTS

;
; *******************
; * Set hi-res mode *
; *******************
;

HIRES:      C1L0                ; Dummy read 4 dummy bits from glove
            C1L1
            DELAY3US
            C1L0

            DELAY3US
            C0L0
            C1L0
            DELAY3US
            C0L0
            C1L0
            DELAY3US
            C0L0
            C1L0
            DELAY3US
            C0L0
            C1L0

            C1L0
            LDX     #2402       ; Delay 7212us
            JSR     DELAY

            C1L1
            LDX     #752        ; Delay 2260us
            JSR     DELAY

            LDAA    #7
            STAA    BYTECNT
            LDY     #HRCODE     ; Send the 7 byte code
BYTELOOP:   LDAA    #8
            STAA    BITCNT
            LDAA    0,Y
BITLOOP:    LSLA
            BCC     BITOFF
            C1L1
            C0L1
            C1L1
            BRA     NEXTLOOP
BITOFF:     C1L0
            C0L0
            C1L0
NEXTLOOP:   DELAY3US
            DEC     BITCNT
            BNE     BITLOOP

            LDX     #D2BYTES
            JSR     DELAY
            INY
            DEC     BYTECNT
            BNE     BYTELOOP

            LDX     #296        ; Delay 892us
            JSR     DELAY

            C1L0
            LDX     #20000      ; Delay a "long time"
            JSR     DELAY
            RTS

;
; Glove initialization bytes
;

HRCODE:     dc.b    $06,$C1,$08,$00,$02,$FF,$01

;
; *******************************************
; *        Get the 6 byte data packet       *
; * (Places data in buffer pointed to by Y) *
; *******************************************
;

GETGLOVE:   JSR     GETBYTE     ; Get each byte consecutively
            STAA    0,Y         ; and store in memory
            INY
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE
            STAA    0,Y
            INY
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE
            STAA    0,Y
            INY
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE
            STAA    0,Y
            INY
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE
            STAA    0,Y
            INY
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE
            STAA    0,Y
            LDX     #D2BYTES
            JSR     DELAY

            JSR     GETBYTE     ; Throw away last two bytes
            LDX     #D2BYTES
            JSR     DELAY
            JSR     GETBYTE
            RTS

;
; *****************************
; * Get a byte from the glove *
; *    (Returns byte in A)    *
; *****************************
;

GETBYTE:    C1L0                ; Pulse the latch line
            C1L1
            DELAY3US
            C1L0

            LDAA    #8
            STAA    BITCNT

GETLOOP:    LSLA                ; Read 8 bits sequentially
            LDAB    PORTA
            ANDB    #GDATA      ; Mask off other bits
            ABA                 ; Assemble the data byte
            C0L0
            C1L0
            DEC     BITCNT
            BNE     GETLOOP

            RTS

;
; ***********************************************
; * Send an X byte packet over the serial port  *
; * (Y contains the address of the data buffer, *
; *  B contains the number of bytes to send)    *
; ***********************************************
;

SENDSER:    LDAA    SCSR        ; Check status register for Tx ready
            ANDA    #$80
            BEQ     SENDSER     ; Try again if not ready

            LDAA    0,Y         ; Send byte to the serial port
            STAA    SCDR

            INY                 ; Move to next data byte
            DECB
            BNE     SENDSER     ; Send next byte if not done

            RTS