$page ;***************************************************************************** ;***************** DDS DRIVER ********************************* ;***************************************************************************** ;***************************************************************************** ;***************************************************************************** ;* * ;* DRIVER MODULE * ;* * ;***************************************************************************** ;***************************************************************************** ; ; This module contains drivers for the following components: ; DDS ; Set_DDS ; Shaft Encoders (Special and Grey) ; Do_Special_Encoder ; Do_Grey_Encoder ; LCD ; Cmnd2LCD ; Data2LCD ; BusyCheck ; LCD_Init ; LCD_Clear ; ClearLCDLine1 ; ClearLCDLine2 ; BlankLCD ; UnBlankLCD ; ShowCursor ; HideCursor ; Disp_Msg ; EEPROM ; Write_EEPROM_Byte ; Erase_EEPROM_All ; Erase_EEPROM_Byte ; Init_EEPROM ; EEPROM_On ; EEPROM_Off ; EEPROM_Security_On ; EEPROM_Security_Off ; EEPROM_Disable ; EEPROM_Enable ; ;***************************************************************************** ;***************************************************************************** ; Set_DDS - This routine sends the 5-byte DDS control word (DDS_w4 through ; DDS_w0, LSB to MSB in each) to the DDS chip by serial data transfer. Set_dds: ldhx #DDS_w4 ;point to the start of the DDS programming words mov #$05,byte_count ;we'll process 5 bytes nxtbyt: mov X+,byte2send ;get the DDS word (and increment pointer H:X) mov #$08,bit_count ;we'll process 8 bits nxtbit: ror byte2send ;test next LSB for 0 or 1 bcc send0 ;send a 0 if carry clear send1: bset DDS_data,portf ;else send a one bset DDS_clk,portf ;Toggle write clock bclr DDS_clk,portf bra check send0: bclr DDS_data,portf ;Send zero bset DDS_clk,portf ;Toggle write clock bclr DDS_clk,portf check: dbnz bit_count,nxtbit ;get next DDS programming bit if not done dbnz byte_count,nxtbyt ;get next DDS programming byte if not done bset DDS_load,portf ;else done - send DDS load signal bclr DDS_load,portf rts $page ;***************************************************************************** ;************** SHAFT ENCODER DRIVER ********************************* ;***************************************************************************** ;***************************************************************************** ; Read Special Encoder - Wait here for shaft to turn. Exit with ; Z=0 if CCW ; Z=1 if CW ;***************************************************************************** ; + + ; ---- + --+- ---- ; A | + | + | | | ; | + | + | | | ; -+-- + ---- ; + + ; ---+ +--- ---- ; B +| |+ | | ; +| |+ | | ; + --- + ---- ; + + ;***************************************************************************** ;Await negative transition on either A or B shaft encoder line Do_Special_Encoder: brset ENC_A,portF,de1 ;A still high, go check B tst A_flag ;A is low ... previously low too? beq de2 ;yes, previously low so not neg-edge. Check B next. clr A_flag ;neg edge A found! Set flag to indicate it's now low bra de4 ;and go process rotation de1: mov #$FF,A_flag ;set A flag to indicate that it's (still) high de2: brclr ENC_B,portF,de3 ;B is low ... continue checking it mov #$FF,B_flag ;B is high, so set flag indicating this bra do_special_encoder ;and do all again de3: tst B_flag ;B previously low? beq do_special_encoder ;yes, nothing to process, so do all over again clr B_flag ;neg edge B found! Set flag indicate it's now low ;and continue onward to process direction ;negative edge found on A or B. Determine which direction shaft was turned. ; Direction = CW if B toggled ; Direction = CCW if A toggled de4: mov enc_new,enc_old lda portF and #$30 sta enc_new eor enc_old and #$10 ;z=1 ==> A toggled = CCW rotation = down ;z=0 ==> B toggled = CW rotation = up rts ;************************************************************************** ; Process Grey Code Encoder - Wait here for shaft to turn. Exit with ; Z=0 if CCW ; Z=1 if CW ;************************************************************************** Do_Grey_Encoder: jsr read_encoder sta temp2 ;buffer the input lda temp2 and #$30 ;isolate the encoder bits sta enc_new eor enc_old beq Do_Grey_Encoder ;no change, wait in encoder loop bclr 3,enc_old ;change detected ... which way? lda enc_old rola eor enc_new and #$10 ;b5 changed mov enc_new,enc_old ;update new/old bits rts ;----------------------------------------------------------- ; Read Grey Code Shaft Encoder -- returns contents of portF ; To deal with contact bounce on shaft encoder bits, ; 3 successive readings must be identical before returning Read_Encoder: mov portF,enc_temp ;make initial reading jsr wait1ms lda portF ;make first check sub enc_temp bne Read_Encoder ;if not the same, try again jsr wait1ms lda portF ;make 2nd check sub enc_temp bne Read_Encoder ;if not the same as 1st, try again lda enc_temp rts jsr wait1ms lda portF ;make 3rd check sub enc_temp bne Read_Encoder ;if not the same as 2nd, try again lda enc_temp rts $page ;************************************************************************** ;******************* LCD Driver ********************************* ;************************************************************************** ;------------------------------------------------------------ ;Display character in A to the LCD. LCD_rw and LCD_rs must be ;set up prior to entry. Cmnd2LCD: sta LCD_char ;temp save char to be written bclr LCD_rs,porta ;rs is low for cmnd jsr busy_check ;LCD ready for new data? clr porta mov #$FF,ddra ;setup for all outputs bclr LCD_rw,porta ;change LCD back to Write mode bclr LCD_rs,porta ;ensure that rs is low for cmnd bra write_LCD ;continue Data2LCD: sta LCD_char ;temp save char to be written bset LCD_rs,porta ;rs is hi for data jsr busy_check ;LCD ready for new data? clr porta mov #$FF,ddra ;setup for all outputs bclr LCD_rw,porta ;change LCD back to Write mode bset LCD_rs,porta ;ensure that rs is hi for data Write_LCD: lda LCD_char ;get the character and #$F0 ;deal with hi nibble sta temp1 lda porta ;get porta image and #$0F ;clear the data nibble ora temp1 ;combine with character hi nibble sta porta bset LCD_e,porta ;strobe enable jsr wait1us bclr LCD_e,porta lda LCD_char ;get character back again nsa ;get low nibble hi and #$F0 sta temp1 lda porta and #$0F ora temp1 sta porta jsr wait1us bset LCD_e,porta jsr wait1us bclr LCD_e,porta rts ;----------------------------------------------------- ;Busy_check Subroutine ; ;LCD read/write operations are slooooow, this subroutine ;polls the LCD busy flag to determine if previous operations are completed. Busy_Check: clra mov #$0F,ddra ;tristate the data pins bclr LCD_rs,porta ;set up to read busy flag bset LCD_rw,porta ;set up for Read jsr wait1us mov #$FF,LCD_timer ;init timeout counter busy: bset LCD_e,porta ;raise the Enable bit jsr wait1us mov porta,LCD_read ;read the byte bclr LCD_e,porta jsr wait1us bset LCD_e,porta ;get next nibble to keep LCD happy jsr wait1us bclr LCD_e,porta jsr wait1us dbnz LCD_timer,busy2 ;timer not zero bra not_busy ;timer=0 so exit anyway busy2: brset 7,LCD_read,busy ;check for busy flag - wait if set not_busy: rts ;----------------------------------------------------------- ; LCD_INIT ; Power on initialization of LCD. ; The LCD controller chip must be equivalent to an Hitachi 44780. LCD_Init: jsr Wait100ms mov #$30,porta ;func set bset LCD_e,porta jsr Wait64ms bclr LCD_e,porta jsr Wait1us bset LCD_e,porta jsr Wait1us mov #$30,porta ;func set bset LCD_e,porta jsr Wait32ms bclr LCD_e,porta jsr Wait1us bset LCD_e,porta jsr Wait1us mov #$30,porta ;func set bset LCD_e,porta jsr Wait32ms bclr LCD_e,porta jsr Wait1us mov #$20,porta ;set 4-bit mode bset LCD_e,porta jsr Wait16ms bclr LCD_e,porta jsr Wait1us lda #$28 ;1/16 duty cycle, 5x8 matrix jsr cmnd2LCD lda #$08 ;disp off, curs & blank off jsr cmnd2LCD lda #$01 ;clear & reset cursor jsr cmnd2LCD lda #$06 ;cursor moves right, no shift jsr cmnd2LCD lda #$0C ;display on, cursor & blink off jsr cmnd2LCD rts ;----------------------------------------------------------- ; LCD_clear -- clears the LCD display LCD_Clear: lda #$01 jsr cmnd2LCD rts ;----------------------------------------------------------- ; ClearLCDLine1 -- point to 1st char on Line 1, clear line, leave cursor at position 1 ClearLCDLine1: lda #$80 ;point to 1st char line 1 jsr Cmnd2LCD jsr wait1ms ldhx #_blank_line jsr disp_msg lda #$80 ;leave cursor at home on line 1 jsr Cmnd2LCD rts _blank_line fcb " ",0 ;----------------------------------------------------------- ; ClearLCDLine2 -- point to 1st char on Line 2, clear line, leave cursor at position 1 ClearLCDLine2: lda #$C0 ;point to 1st char line 2 jsr Cmnd2LCD jsr wait1ms ldhx #_blank_line jsr disp_msg lda #$C0 ;leave cursor at home on line 1 jsr Cmnd2LCD rts ;----------------------------------------------------------- ; BlankLCD BlankLCD: lda #8 ;Blank the LCD jsr Cmnd2LCD rts ;----------------------------------------------------------- ; UnBlankLCD UnBlankLCD: lda #12 ;UnBlank the LCD jsr Cmnd2LCD rts ;----------------------------------------------------------- ; ShowCursor -- produce a blinking cursor ShowCursor: lda #15 ;Show Cursor (blinking) jsr Cmnd2LCD jsr wait1ms rts ;----------------------------------------------------------- ; HideCursor HideCursor: lda #12 ;Hide Cursor lda Cmnd2LCD jsr wait1ms rts ;----------------------------------------------------------- ; DISP_MSG -- displays the message pointed to by H:X Disp_Msg: lda ,x beq disp_msg_end ;zero ends the string jsr data2LCD incx bra disp_msg disp_msg_end: rts $page ;************************************************************************** ;******************* EEPROM Driver ****************************** ;************************************************************************** ; ;-------------------------------------------------------------------------- ; Write_EEPROM_Byte -- The target EEPROM address H:X (in the range 800-9FF) ; is first erased, then written with the byte supplied ; in reg A. Write_EEPROM_Byte: psha ;save the data to be written jsr Erase_EEPROM_Byte ;erase the target location lda #(EERAS1|EERAS0) coma ;clear EERAS1 & EERAS0 in EECR and EECR sta EECR ora #EELAT ;set EELAT in EECR sta EECR pula ;and retrieve the data sta ,x ;Write data to the desired EEPROM address lda #EEPGM ;Set the EEPGM bit in the EECR ora EECR sta EECR jsr Wait100ms ;Wait 10ms to program the byte. lda #EEPGM ;clear EEPGM coma and EECR sta EECR jsr Wait100us ;Wait 100us for pgm voltage to fall. lda #EELAT coma ;clear EELAT and EECR sta EECR rts ;-------------------------------------------------------------------------- ; Erase_EEPROM_All -- Bulk erase all EEPROM locations (800-9FF) Erase_EEPROM_all: ldhx #$800 ;any location in EEPROM area will do bulk erase lda EECR ora #(EERAS1|EERAS0) sta EECR bra ee_1 ;-------------------------------------------------------------------------- ; Erase_EEPROM_Byte -- Erase target EEPROM address H:X (in the range 800-9FF) Erase_EEPROM_byte: lda EECR and #$EF ;clear EERAS1 (b4) ora #$08 ;set EERAS0 (b3) sta EECR ee_1: ora #EELAT ;set EELAT in EECR sta EECR sta ,x ;write any data to the target location erases lda #EEPGM ;Set the EEPGM bit in the EECR ora EECR sta EECR jsr Wait100ms ;Wait 10ms for byte erase lda #EEPGM coma ;clear EEPGM and EECR sta EECR jsr Wait100us ;Wait 100us for pgm voltage to fall. lda #EELAT coma ;clear EELAT and EECR sta EECR rts ;-------------------------------------------------------------------------- ; Init_EEPROM -- Initialize the EEPROM configuration registers ; This is a nonvolatile register setting Init_EEPROM: jsr EEPROM_On ;Turn on array for operation lda #$10 ;lower 4 bits are positions for EEPROM bank enables ldhx #EENVR jsr Write_EEPROM_Byte ;enable the EEPROM lda ,x ;puts new settings into effect lda #$80 ;set upper bit EEDIVSECD to allow the values to be modified later ldhx #EEDIVHNVR jsr Write_EEPROM_Byte ;write the high divider byte lda #172 ;divider value is 170 (based on CGMXCLK clock of 4.9152 MHz) ldhx #EEDIVLNVR jsr Write_EEPROM_Byte ;write the low divider byte rts ;-------------------------------------------------------------------------- ; EEPROM_On -- Turns on the EEPROM array for operation (default = ON) EEPROM_On: lda #EEOFF coma and EECR ;clear EEOF in EECR sta EECR rts ;-------------------------------------------------------------------------- ; EEPROM_Off -- Turns off the EEPROM array. Provides for lower power ; operation (default = ON) EEPROM_Off: lda EECR ora #EEOFF ;set EEOFF on EECR sta EECR rts ;-------------------------------------------------------------------------- ; EEPROM_Security_On -- Turns on the EEPROM array security bit ; This is a nonvolatile setting. (Initially = disabled) ; Takes effect after reset. EEPROM_Sec_On: mov EEPRTCT,temp ;set up temp to hold inverse of EEPRTCT bit com temp ; to enable clearing of bit in EENVR below ldhx #EENVR lda ,x and temp ;0=secure jsr Write_EEPROM_Byte rts ;-------------------------------------------------------------------------- ; EEPROM_Security_Off -- Turns off the EEPROM array security bit ; This is a nonvolatile setting. (Initially = disabled) ; Changes take effect after reset. EEPROM_Sec_Off: ldhx #EENVR lda ,x ora #EEPRTCT ;1=security disabled jsr Write_EEPROM_Byte lda ,x ;puts new settings into effect rts ;-------------------------------------------------------------------------- ; EEPROM_Disable -- Protects the selected EEPROM block (0,1,2,3) ; from being written or erased. Block indicated ; in corresponding bits of reg A. ; All four blocks are initially unprotected. (3:0 =0) ; This is a nonvolile setting. (Initially = disabled) ; Changes take effect after a reset. EEPROM_Disable: and #$0F ;isolate the block bits (3:0) sta temp ;temp save selected block(s) ldhx #EENVR lda ,x ora temp ;disable (protect) the selected bits/banks jsr Write_EEPROM_Byte lda ,x ;puts new seetings into effect rts ;-------------------------------------------------------------------------- ; EEPROM_Enable -- Enables the selected EEPROM block (0,1,2,3) ; to be being written or erased. Block indicated ; in corresponding bits of reg A. ; All four blocks are initially unprotected. (3:0 =0) ; This is a nonvolatile setting. (Initially = disabled) ; Changes take effect after a reset. EEPROM_Enable: and #$0F ;isolate the block bits (3:0) coma ;invert (0 means enable) sta temp ;temp save selected block(s) ldhx #EENVR lda ,x and temp ;enable (unprotect) the selected bits/banks jsr Write_EEPROM_Byte lda ,x ;puts new seetings into effect rts