************************************************************************ * QuickCam Interface code for the 68HC11 using a BOTBoard2 * by Tom Dickens 8/30/2000 * ************************************************************************ * Scratch RAM ************************************************************************ TEMP_A EQU $00 TEMP_B EQU $01 RECEIVED_COMMAND EQU $02 RECEIVED_PARAM EQU $03 WORDS_TO_GET EQU $04 WORDS_TO_GET2 EQU $05 ************************************************************************ * Constants ************************************************************************ SCSR_IND EQU $2E SCDR_IND EQU $2F ************************************************************************ * Start of the code ************************************************************************ org $b600 ldaa #$E5 staa $103c ; set into expanded mode ldaa #$12 staa RECEIVED_COMMAND ldaa #$34 staa RECEIVED_PARAM jmp $2000 ; jump to external EEPROM org $2000 ldx #$8000 ldaa #0 Zero_RAM: staa 0,x inx bne Zero_RAM lds #$ffff jsr Init_Term jsr Reset_QCam Top: *** ldx #string_0 *** jsr send_string ldaa #23 ; GetVersion Command ldab #1 ; Black level jsr Send_Command *** ldx #string_1 *** jsr send_string *** ldaa RECEIVED_COMMAND *** jsr send_hex *** ldx #string_2 *** jsr send_string *** ldaa RECEIVED_PARAM *** jsr send_hex *** ldx #string_3 *** jsr send_string ldx #string_Pict jsr send_string ldx #$8000 jsr get_picture ldx #$8000 jsr term_picture bra Top string_0: fcc 'Sending a GetVersion to the QuickCam.' fcb $0a, $0d, $00 string_1: fcc 'The command received was <$' fcb $00 string_2: fcc '>, parameter was <$' fcb $00 string_3: fcc '>.' fcb $0A, $0D, $0A, $0D, $00 string_Pict: * < ESC > put curcor to top-left, CIT manual, page 5-33. fcb $1b, $5b, '1, ';, 'H, $00 ************************************************************************ * Reset QCam ************************************************************************ Reset_QCam: psha ldaa #%00000100 staa $4000 jsr Delay5mS ldaa #%00000000 staa $4000 jsr Delay5mS ldaa #%00000100 staa $4000 jsr Delay5mS ldab #104 jsr Set_Contrast ; defalut value of 104 jsr Do_AutoAdjust_Offset pula rts ************************************************************************ * Send Command * Inputs: A register is the command. * B register is the parameter for the command. ************************************************************************ Send_Command: pshx staa TEMP_A stab TEMP_B ldaa #%00000100 staa $4000 * Send Command ldaa TEMP_A staa $5000 ldaa #%00000110 ; PCA set high staa $4000 *** ldx #wait_HC *** jsr send_string Wait_CR_HighC: ldab $4000 ; wait for CamRdy to go high andb #%10000000 beq Wait_CR_HighC ldaa $4000 anda #$0F ; look at the bottom nybble lsla lsla lsla lsla ; A = A * 16, bottom nybble to top nybble ldab #%00000100 ; PCA set low stab $4000 *** ldx #wait_LC *** jsr send_string Wait_CR_LowC: ldab $4000 andb #%10000000 bne Wait_CR_LowC ldab $4000 andb #$0F ; look at bottom nybble aba ; A = A + B, this should be the command we sent staa RECEIVED_COMMAND * Send Parameter ldaa TEMP_B staa $5000 ldaa #%00000110 ; PCA set high staa $4000 *** ldx #wait_HP *** jsr send_string Wait_CR_HighP: ldab $4000 ; wait for CamRdy to go high andb #%10000000 beq Wait_CR_HighP ldaa $4000 anda #$0F ; look at the bottom nybble lsla lsla lsla lsla ; A = A * 16, bottom nybble to top nybble ldab #%00000100 ; PCA set low stab $4000 *** ldx #wait_LP *** jsr send_string Wait_CR_LowP: ldab $4000 andb #%10000000 bne Wait_CR_LowP ldab $4000 andb #$0F ; look at bottom nybble aba ; A = A + B, this should be the param we sent staa RECEIVED_PARAM ldaa TEMP_A ldab TEMP_B pulx rts wait_HC: fcc 'Before wait_CR_HighC.' fcb $0a, $0d, $00 wait_LC: fcc 'Before wait_CR_LowC.' fcb $0a, $0d, $00 wait_HP: fcc 'Before wait_CR_HighP.' fcb $0a, $0d, $00 wait_LP: fcc 'Before wait_CR_LowP.' fcb $0a, $0d, $00 ************************************************************************ * send string * input: X points to a null-terminated ASCII string ************************************************************************ send_string: psha pshx more_string: ldaa 0,x beq end_of_string bsr write_byte inx bra more_string end_of_string: pulx pula rts ************************************************************************ * send_hex: * Input: A, to be written out as a 2-digit ASCII hex number ************************************************************************ send_hex: psha anda #$F0 lsra lsra lsra lsra ; look at top nybble in bottom position bsr send_hex_1 pula psha anda #$0F bsr send_hex_1 pula rts ************************************************************************ send_hex_1: psha cmpa #9 bgt Hex_Number adda #'0 bra Over_Hex Hex_Number: adda #'A-10 Over_Hex: bsr write_byte pula rts ************************************************************************ * write_byte: * Input: A is the ASCII byte to write. ************************************************************************ write_byte: pshx ldx #$1000 write_wait: brclr SCSR_IND,x %10000000 write_wait ; check Transmit-empty staa SCDR_IND,x pulx rts ************************************************************************ ************************************************************************ *======================================================================= * Init_Term: Configure Serial port for pcbug11 communications: *======================================================================= Init_Term: ldx #$1000 clr $2c,x ; Set 8-bits, wake on Idle ldd #$3008 ; boot-loader loads #$302c staa $2b,x ; 9600 BAUD stab $2d,x ; No interrupts, enable transmitter rts ************************************************************************ * get picture * Inputs: X is the RAM location for the image. * * page 30: The following steps are necessary to get video data... * 1) Decide what region of the CCD image to get * 2) Choose a desired image depth (4 or 6 bits) * 3) Choose a data bus mode (4 or 12) * 4) Choose a transfer mode: 1:1, 2:1, or 4:1 * 5) Compute number of transfers per line based on 1 - 4 above * 6) Setup frame, depth, bus mode, and transfer mode * 7) Get the video data * ************************************************************************ get_picture: psha pshb ldab #20 jsr Set_Top ldab #20 jsr Set_Left ldab #24 jsr Set_NumV * * number of transfers per line. We want 78 pixels, 4-bits deep, at 1:1 * 78 * 4 / 24 = 13.0 transfers. * ldab #13 jsr Set_NumH ldd #13*24 std WORDS_TO_GET * * get video frame: bit 0=0 for nybble, 1 for byte bus * bit 1=0 for 4-bits deep, 1 for 6-bits deep * bits 3&2 = 00 for 1:1, 01 for 2:1, 10 for 4:1, 11 -na- * bit 4=0 for normal, 1 for test pattern * bits 5-7 unused * ldab #%00000001 ldab #%00001101 jsr Get_Video pulb pula rts ************************************************************************ * term picture * * assuming 24 x 78 for now ************************************************************************ term_picture: pshx pshy psha pshb ldy #24 Term_LoopY: ldaa #78 Term_LoopA: psha ldab 0,x ; get image pixel from RAM inx pshx ldx #GRAY_SCALE ; look up ASCII-gray character abx ldaa 0,x pulx bsr write_byte pula ; the characters-per-line counter deca bne Term_LoopA * end of line. Return and form-feed. dey beq End_Of_Loop ldaa #') bsr write_byte ldaa #$0a bsr write_byte ldaa #$0d bsr write_byte bra Term_LoopY End_Of_Loop: pulb pula puly pulx rts GRAY_SCALE: * 0123456789012345 * fcc '0123456789ABCDEF' fcc '.,:;-+=*|lI!HOB0' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' fcc 'abcdefghijklmnopqrstuvwxyz' ************************************************************************ * set top * Inputs: B is the top parameter. ************************************************************************ Set_Top: psha ldaa #13 jsr Send_Command pula rts ************************************************************************ * set left * Inputs: B is the left parameter divided by 2. ************************************************************************ Set_Left: psha ldaa #15 jsr Send_Command pula rts ************************************************************************ * set num V * Inputs: B is the number-of-lines-to-transfer parameter * if transfer mode is other than 1:1, this parameter * MUST take this into account. ************************************************************************ Set_NumV: psha ldaa #17 jsr Send_Command pula rts ************************************************************************ * set num H * Inputs: B is the number of transfers per line parameter ************************************************************************ Set_NumH: psha ldaa #19 jsr Send_Command pula rts ************************************************************************ * set exposure * Inputs: B is the exposure parameter ************************************************************************ Set_Exposure: psha ldaa #11 jsr Send_Command pula rts ************************************************************************ * set contrast * Inputs: B is the contrast parameter * suggested value = 104 ************************************************************************ Set_Contrast: psha ldaa #25 jsr Send_Command pula rts ************************************************************************ * do auto-adjust offset contrast * Inputs: -none- * This takes some time, during this time Get_Offset * will return $FF. ************************************************************************ Do_AutoAdjust_Offset: psha pshx ldaa #27 jsr Send_Command Offset_Wait: jsr Get_Offset ldx #string_o1 jsr send_string jsr send_hex ; send value in reg A ldx #string_o2 jsr send_string cmpa #$FF beq Offset_Wait pulx pula rts string_o1: fcc 'Value from Get_Offset was <$' fcb $00 string_o2: fcc '>.' fcb $0A, $0D, $00 ************************************************************************ * Get Offset * Inputs: -none- * Outputs: A register, the current offset value from the QCam. ************************************************************************ Get_Offset: pshb ldaa #33 ldab #0 jsr Send_Command ldaa RECEIVED_PARAM pulb rts ************************************************************************ * get video * Inputs: B is the video-parameter parameter * X points to RAM for the image ************************************************************************ Get_Video: pshx pshy psha pshb ldaa #7 jsr Send_Command jsr Port_Turnaround ldaa #%00000111 staa $4000 * wait for CR2 to go high Wait_CR2_HighVL_top: ldab $6000 ; wait for CamRdy2 to go high andb #%10000000 beq Wait_CR2_HighVL_top Video_Loop: * set PCA high ******* do this at the bottom of the loop to be sure the data is ready *** ldaa #%00000111 *** staa $4000 * wait for CR2 to go high ********** based on the slowness of the HC11, we ASSUME that it is high ***** ***Wait_CR2_HighVL: *** ldab $6000 ; wait for CamRdy2 to go high *** andb #%10000000 *** beq Wait_CR2_HighVL * read 12-bits of video data & store video data to RAM *** ldaa $5000 *** ldab $6000 ldd $5fff ; get both bytes in 5 clocks, not 8 staa TEMP_A anda #$0F staa 0,x inx * set PCA low * do it now to be sure the data is ready for next time ldaa #%00000101 staa $4000 ldaa TEMP_A lsra lsra lsra lsra *** anda #$0F ; not needed with the 4 lsr's *** staa 0,x andb #$0F *** stab 0,x std 0,x ; get both bytes in 5 clocks, not 8 inx inx * wait for CR2 to go low ********** based on the slowness of the HC11, we ASSUME that it is low ***** ***Wait_CR2_LowVL: *** ldab $6000 ; wait for CamRdy2 to go low *** andb #%10000000 *** bne Wait_CR2_LowVL * read 12-bits of video data & store video data to RAM *** ldaa $5000 *** ldab $6000 ldd $5fff staa TEMP_A anda #$0F staa 0,x inx * set PCA high * do it now to be sure the data is ready for next time ldaa #%00000111 staa $4000 ldaa TEMP_A lsra lsra lsra lsra andb #$0F std 0,x inx inx * decrement WORDS_TO_GET ldy WORDS_TO_GET dey sty WORDS_TO_GET * if WORDS_TO_GET > 0, do it again bne Video_Loop * Put PCA high for > 3 uS to signal end-of-frame ldaa #%00000111 staa $4000 jsr Delay_3uS * go back into nybble mode ldaa #%00000100 staa $4000 pulb pula puly pulx rts ************************************************************************ * port turnaround ************************************************************************ Port_Turnaround: psha ldaa #%00000101 staa $4000 * * do the port turnaround handshale * ldaa #%00000111 ; set PCA high staa $4000 Wait_CR_HighPT: ldaa $4000 ; wait for CamRdy to go high anda #%10000000 beq Wait_CR_HighPT ldaa #%00000101 ; set PCA low staa $4000 Wait_CR_LowPT: ldaa $4000 anda #%10000000 bne Wait_CR_LowPT pula rts ************************************************************************ * delay 3 uS * the jsr takes 6 clocks, the RTS takes 5, which is 11 * 500 nS * which equals 5.5 uS. We don't need to do anything else... ************************************************************************ Delay_3uS: rts *======================================================================= * Delay 5 mS: * Input: -none- * Output: -none- * Action: Delay a specific amount of time, then return. * The delay clock cycles = 35 + Y * ( 10 + X * 6 ) = 9999 * 9999 * 500 nS = 5 mS. *======================================================================= * ; the JSR was 6 clocks Delay5mS: pshx ; 4 clocks pshy ; 5 clocks ldy #94+1 ; 4 clocks DelayY: ldx #14+1 ; 3 clocks ----+ 10 + 6 X DelayX: dex ; 3 clocks + 6 | bne DelayX ; 3 clocks + | dey ; 4 clocks | bne DelayY ; 3 clocks ----+ puly ; 6 clocks pulx ; 5 clocks rts ; 5 clocks *======================================================================= * Delay100mS *======================================================================= Delay100mS: psha ldaa #200 Loop100: bsr Delay5mS deca bne Loop100 pula rts *======================================================================= * Delay1S *======================================================================= Delay1S: psha ldaa #10 Loop1: bsr Delay100mS deca bne Loop1 pula rts