;Modified from multilog.asm file to build in an inintial delay. ;1/19/99 Brooks and John fix EEPROM address bug--had forgotten in original code to reset the ;eeprom ADDR pointer to the last of header locations so PIC was overwriting data at location 5 ;Brooks and Bob, 1/1/99 Happy New Year! New Code marked with !!!!! comments. ;Ran on simulator and seems to work. Need to ensure that never have 0 in either Ticks or Intervals ;and a non zero in the other. May need to run some simulations on that issue? Protect against in host? ;June 11 99 Brooks adds new EEPROM routines to DELAYLOG so that it can work with 24LC32A 4K EEPROM, ; and renames program DLOG4K ;Dec 30 99 Brooks and John add code to blink Ticks and Intervals at start of logger on Pin 28. ;Ticks and Intervals and DTicks and DIntervals are also written to last four memory locations in EEPROM. ;Both were done because we felt that the logger wasn't starting correctly 100% of the time, ; and perhaps the false start was related to improper read of EEPROM, thus 255 for Ticks and Intervals ; This code is added as subroutine BLINK, and the call comes just after the logger read of Ticks and Intvls ;----------------------------------------------------- ;DATALOGGER SOFTWARE--4K EEPROM VERSION, WITH DELAY 6/11/99 ;----------------------------------------------------- ; list p=16C73a ;Enter device name ;** Note: 1) All timing is based on a reference crystal frequency of 4MHz ;** which is equivalent to an instruction cycle time of 1 usec. ;** 2) Address and literal values are read in hexidecimal unless ;** otherwise specified. ;Output on most PORT_B pins is intended for debugging, monitoring operation. ;------------------------------------------------------ ;REGISTER DEFINITIONS ;------------------------------------------------------- ;EEPROM REGISTERS FLAG equ 20 ; Common flag bits register EEPROM equ 21 ; Bit buffer ERCODE equ 22 ; Error code (to indicate bus status) ADDR equ 23 ; Address register DATAI equ 24 ; Stored data input register DATAO equ 25 ; Stored data output register SLAVE equ 26 ; Device address (1010xxx0) TXBUF equ 27 ; TX buffer RXBUF equ 28 ; RX buffer COUNT equ 29 ; Bit counter TEMP equ 2A ; Temporary storage TEMP1 equ 2B ; More Temporary storage TEMP2 equ 2C TEMP3 equ 2D TEMP4 equ 33 ;DATALOGGER REGISTERS RTICKS equ 2E ;Ticks reset value read from EEPROM TICKS equ 2F ;Ticks working value, decrements thru time RINTRVLS equ 30 ;Intervals reset value read from EEPROM INTRVLS equ 31 ;Intervals working value, decrments thru time EBANK equ 32 ;EEPROM memory bank, 0-7 TOGGLE equ 34 ;Used to control 8sec toggle of pin 22, RB1 PINDELAY equ 35 ;Register for delay value, debouncing of start line DTICKS equ 36 ;Initial startup delay ticks, working value DINTRVLS equ 37 ;Initial startup delay intervals, working value DFLAG equ 38 ;Flag for initial delay, if >0 do initial delay routine DRTICKS equ 39 ;Reset value for DTICKS ;----------------------------------------------------------- ;PARAMETER DEFINITIONS ;----------------------------------------------------------- OK equ H'01' ;OK command code DAT equ H'02' ;DATa command code REA equ H'03' ;REAd command code INI equ H'04' ;INIntialize command code STA equ H'05' ;STArt command code STATUS equ H'03' RP0 equ H'05' TMR0 equ H'01' OPT_REG equ H'81' T0CS equ H'05' PSA equ H'03' PS2 equ H'02' PS1 equ H'01' PS0 equ H'00' INTCON equ H'0B' SSPCON equ H'13' ADCON0 equ H'1F' ADCON1 equ H'9F' ADRES equ H'1E' T0IF equ H'02' T0IE equ H'05' GIE equ H'07' F equ H'01' W equ H'00' Z equ H'02' PORT_A equ H'05' TRIS_A equ H'85' PORT_B equ H'06' TRIS_B equ H'86' PORT_C equ H'07' TRIS_C equ H'87' ;----------------------------------------------------------------------------- ; Bit Assignments ;----------------------------------------------------------------------------- ; FLAG Bits ERRORFLG equ 0 ; Error flag ; EEPROM Bits DI equ 7 ; EEPROM input DO equ 6 ; EEPROM output ; I2C Device Bits SDA equ 4 ; RB7, data in/out SCL equ 3 ; RB6, serial clock ;----------------------------------------------------------------------------- ;Setup Program Vectors ;----------------------------------------------------------------------------- org 0 ;start address 0 goto start org 0x04 ;interupt vector goto timeout org 0x50 ;----------------------------------------------------------------------------- ;BEGIN MAIN PROGRAM ;----------------------------------------------------------------------------- ;Get timing data from EEPROM, wait for start signal start ;Setup Port_B for input, loop waiting for signal on RB1, pin 22=HI bsf STATUS,RP0 ;select bank 1 movlw h'FF' ;put 11111111 in w movwf TRIS_B ;Config PORT_B as all inputs movwf TRIS_C ;configure PORT_C as all inputs movwf TRIS_A ;configure PORT_A as all inputs for A/D conversion bcf STATUS,RP0 ;select bank 0 SetDelay ;Debounce routine for start line movlw h'0F' ;load value for number of consecutive cycles that pin must be hi movwf PINDELAY ;place value in register StartCountdown btfss PORT_B,1 ;check pin goto SetDelay ;if not hi, then reset loop back decfsz PINDELAY ;if hi, then decrement register, skip out of loop if zero goto StartCountdown ;come here if pin hi, register not 0, loop back ;------------------------------------------------------------------------------------------ ;Datalogging setup: configure EEPROM and get tikcs and intervals data from it ;------------------------------------------------------------------------------------------ clrf TOGGLE movlw B'00111011' ; I2C master mode enabled movwf SSPCON clrf EBANK ;zero EEPROM bank address movlw B'10100000' ;EEPROM I2C address movwf SLAVE ;put EEPROM address in SLAVE movlw h'0C' ;RTICKS location in EEPROM, address 12 movwf ADDR ;put address in ADDR register call RDBYTE ;Input byte from EEPROM ;btfsc FLAG,ERRORFLG ;Check for error ;goto errors ;error handling routine movf DATAI,W ;Get received byte if no error movwf RTICKS ;Store number of Rticks per interval-reset value movwf TICKS ;Store ticks movlw .13 ;INTRV location in the EEPROM, addresss 13 movwf ADDR ;increment address to .13 call RDBYTE ;Input byte from EEPROM ;btfsc FLAG,ERRORFLG ;Check for error ;goto errors ;error handling routine movf DATAI,W ;Get received byte movwf RINTRVLS ;store number of Rintervals per sample-reset value movwf INTRVLS ;store ticks ;!!!!!!!!!!!!!!!!!!!!!!!!!!! New code to blink pin 28 the nmber of Ticks and Intervals call BLINK ;Subroutine to Blink and Store in EEPROM Ticks and Intervals ;!!!!!!!!!!!!!!!!!!!!!!!!!!! End of New Blink Code ;!!!!!!!!!!!!!!!!!!!!!!!!!!! New Code for Initial Delay clrf DFLAG ;Set DFLAG to zero movlw .3 ;DTICKS location in EEPROM, address 3 movwf ADDR ;put address in ADDR register call RDBYTE ;Input byte from EEPROM ;btfsc FLAG,ERRORFLG ;Check for error ;goto errors ;error handling routine movf DATAI,W ;Get received byte if no error movwf DTICKS ;Store number of Dticks per interval-reset value movwf DRTICKS ;Reset value for Dticks movlw .4 ;DINTRV location in the EEPROM, addresss 4 movwf ADDR ;increment address to .4 call RDBYTE ;Input byte from EEPROM call Delay call Delay ;btfsc FLAG,ERRORFLG ;Check for error ;goto errors ;error handling routine movf DATAI,W ;Get received byte movwf DINTRVLS ;store number of Rintervals per sample-reset value ;!!!!!!!!!!!! New Code to write DTicks and DIntervals just before last two locations in EEPROM movlw .251 ;Set up memory location, Place DTicks into EEPROM at just before last memory location movwf ADDR movlw .7 ;Place DIntervals into EEPROM just before last memory location movwf EBANK movf DTICKS, W ;Place value of DTicks into W movwf DATAO ;Put Data in EEPROM Output buffer call WRBYTE ;Write data to EEPROM call Delay call Delay incf ADDR, F ;Increment EEPROM storage location by one movf DINTRVLS, W ;Place value of DIntervals into W movwf DATAO ;Put Data in EEPROM Output buffer call WRBYTE ;Write data to EEPROM call Delay call Delay ;!!!!!!!!!!!! end of new code movlw .15 ;Last intialization storage location in EEPROM movwf ADDR ;put last EEPROM storage location in ADDR clrw ;put 0 into W register subwf DTICKS,W ;subtract, zero bit set if W =0 btfss STATUS,2 ;check zero bit, 1 if result 0 and DTICKS=0 incf DFLAG,F ;if DTICKS not 0, then incr DFLAG clrw ;clear working register W subwf DINTRVLS,W ;subtract W from DINTRVLS, result in W btfss STATUS,Z ;check zero bit, if set, result is 0, no delay set incf DFLAG,F ;if DINTRVLS not 0, then incr DFLAG--DFLAG>0 for delay ;!!!!!!!!!!!!!!!!!!!!!!!!!!end new code for Delay ;-------------------------------------------------------------------------------- ;Enter datalogging part of program ;-------------------------------------------------------------------------------- clrf FLAG ;clear EEPROM check registers clrf ERCODE bsf STATUS,RP0 ;select Page 1 clrf TRIS_B ;set PORT_B as all outputs bsf TRIS_B,7 ;reset PORT_B RB7 line to input bcf OPT_REG,T0CS ;clr bit for TMR0 internal clocking bcf OPT_REG,PSA ;clear bit to select TMR0 prescaling bsf OPT_REG,PS2 ;set bits for prescaling 1:256 bsf OPT_REG,PS1 bsf OPT_REG,PS0 bcf STATUS,RP0 ;select Page 0 bsf INTCON,GIE ;set global interupt enable bit bcf INTCON,T0IF ;clear TMR0 interupt flag bsf INTCON,T0IE ;set bit to enable TMR0 interupt clrf PORT_B ;clear PORT_B output latches clrf TMR0 ;clear timer, timer starts wait bsf PORT_B,4 bcf PORT_B,4 goto wait ;--------------------------------------------------------------------------------- ;End main program ;Begin interrupt subroutine ;--------------------------------------------------------------------------------- timeout bcf INTCON,T0IF ;clear/reset interrupt bsf INTCON,GIE ;set global interupt enable bit btfss TOGGLE,0 ;these statements toggle pin22 hi/lo each timeout bsf PORT_B,1 ;--this pin goes to connector-use to monitor operation btfsc TOGGLE,0 bcf PORT_B,1 comf TOGGLE,F ;!!!!!!!!!!!!!!! New code for initial delay clrw ;make W=0 subwf DFLAG, W ;subtract W from DFLAG, result in W btfss STATUS,Z ;check zero bit, if set DFLAG is zero, skip initial delay goto idelay ;if DFLAG not zero, goto initial delay code ;!!!!!!!!!!!!!! End of new code ;bsf PORT_B,5 ;pulse pin 26 ;bcf PORT_B,5 decfsz TICKS,F ;decrement ticks goto done ;if ticks not 0, then wait for next tick movf RTICKS,W ;if ticks 0 then reset ticks movwf TICKS ;bsf PORT_B,6 ;pulse pin 27 ;bcf PORT_B,6 decfsz INTRVLS,F ;decrement intrvls goto done ;if intrvls not 0, then wait for next tick call sample ;if intrvls 0, get data done retfie ;!!!!!!!!!!!!!!!!!!!!! New Code for Initial Delay idelay ;initial delay code decfsz DTICKS,F ;decrement DTICKS goto alldone ;if not 0 then retfie and wait for next tick movf DRTICKS,W ;if zero, then reset DTICKS to DRTICKS movwf DTICKS decfsz DINTRVLS,F ;decrement DINTRVLS goto alldone ;if DINTRVLS not 0, then return from interupt, wait for next tick clrf DFLAG ;if INTRVLS dec to 0, intitial delay done so clear DFLAG alldone retfie ;!!!!!!!!!!!!!!!!!!!! End new code for initial delay ;-------------------------------------------------------------------------------- ;End interupt subroutine ;Begin sample subroutine ;-------------------------------------------------------------------------------- ;sample routine reads in analog data, stores in EEPROM sample ;reset counters movf RTICKS,W ;n-1 8sec ticks in subintrvl, 14=2m,224=0.5hr movwf TICKS movf RINTRVLS,W ;n-1 subintervals in sampling interval movwf INTRVLS bsf STATUS, RP0 ;select memory page 1 bcf TRIS_B,7 ;Set RB7 as an output line bcf STATUS, RP0 ;select memory page 0 bsf PORT_B,7 ;turn on pin 28 the control line to sensor movlw .42 ;start 0.5 sec delay loop to allow sensor warmup movwf TEMP2 warmup call Delay decfsz TEMP2 goto warmup ;end of warmup loop for sensor warmup incfsz ADDR,F ;increment EEPROM storage location goto next ;if zero, EEPROM bank full, increment EBANK incf EBANK,F ;add 1 to EBANK movf EBANK,W ;put EBANK in W sublw .16 ;if EBANK=MAX=16, W=0 (changed from 2K version) btfsc STATUS,Z ;if EBANK=8 this bit is set goto endlog ;if EBANK=8,w=0,status,z set; end logging, mem full !!!!REVISED 1/1 next bsf STATUS,RP0 ;select page 1 movlw b'00000001' ;input channels movwf ADCON1 ;set RA3=VRef bcf STATUS,RP0 ;select page 0 bsf ADCON0,0 ;configure A/D control register bsf ADCON0,2 ; start conversion waitad btfsc ADCON0,2 ;check goto waitad ;loop until conversion done bcf PORT_B,7 ;turn off pin 28 bsf STATUS, RP0 ;select memory page 1 bsf TRIS_B,7 ;reset RB7 as an input line bcf STATUS, RP0 ;select memory page 0 movf ADRES,W ;move result to W movwf DATAO ;put data in EEPROM output buffer call WRBYTE ;write data to EEPROM call Delay call Delay ;btfsc FLAG,ERRORFLG ; Check for error ;goto errors movf ADDR,W ;make copy of ADDR in TEMP3 movwf TEMP3 movf EBANK,W ;make copy of EBANK in TEMP4 movwf TEMP4 movwf DATAO ;PUT EBANK in DATAO output buffer for EEPROM movlw .14 ;put EBANK EEPROM location in ADDR movwf ADDR clrf EBANK ;make EBANK 0--correct bank for EBANK value location call WRBYTE ;write EBANK value to location EBANK in EEPROM call Delay call Delay ;btfsc FLAG,ERRORFLG ; Check for error ;goto errors movf TEMP3,W ;get ADDR, put in DATAO output buffer movwf DATAO movlw .15 ;set EEPROM location for ADDR data movwf ADDR ;set up ADDR location in EEPROm call WRBYTE ;write ADDR data to location in EEPROM call Delay call Delay movf TEMP3,W movwf ADDR ;restore ADDR value movf TEMP4,W movwf EBANK ;restore EBANK value return ;!!!!!!!!!!!!!!!!!!!! New code 1/1 to fix sampling past the eeprom full endlog bcf STATUS,RP0 ;select Page 0 bcf INTCON,GIE ;clear global interupt enable bit, disable interrupt goto start ;!!!!!!!!!!!!!!!!!!!! end new code ;!!!!!!!!!!!!!!!!!!!! New Blink Subroutine. ;;BLINK Subroutine to blink the control line, pin 28, the number of RTicks and Tintrvls ;Ticks, the blinks are dim; Intervals, the blinks are bright ;Ticks and Intervals are also written to last 2 locations of EEPROM memory ; BLINK bcf STATUS, RP0 ;Select memory page 0 clrf PORT_B ;clear Port_B, Pin 28, for Output movf RTICKS, W ;number of 8 second ticks movwf TICKS ;Tick Counter movf RINTRVLS, W ;number of Subintervals movwf INTRVLS ;Interval Counter bsf STATUS, RP0 ;Select memory page 1 bcf TRIS_B, 7 ;Reset Port_B, Pin 28, for Output bcf STATUS, RP0 ;Select memory page 0 TickLoop bsf PORT_B, 7 ;Turn on Port_B, Pin 28 call Delay10 ;Delay for approximately 0.1 seconds bcf PORT_B, 7 ;Turn off Port_B, Pin 28 call Delay ;two calls to Delay for approximately 0.02 seconds call Delay decfsz TICKS ;Decrease Ticks by one, if not zero then loop goto TickLoop ;Loop through another blink until Ticks = 0 call Delay10 ;Delay for approximately 0.5 seconds call Delay10 call Delay10 call Delay10 IntrLoop bcf PORT_B, 7 ;Turn off Port_B, Pin 28 call Delay10 ;Delay for approximately 0.1 seconds bsf PORT_B, 7 ;Turn on Port_B, Pin 28 call Delay ;2 calls to Delay for approximately 0.02 seconds call Delay decfsz INTRVLS ;Decrease Intervals by one, if not zero then loop goto IntrLoop ;Loop through another blink until Intervals = 0 bcf PORT_B, 7 ;Turn off Port_B, Pin 28 bsf STATUS, RP0 ;Select memory page 1 bsf TRIS_B, 7 ;Reset Port_B, Pin 28, for Input bcf STATUS, RP0 ;Select memory page 0 ;Save value for ticks and intervals at last two memory locations in EEPROM. movlw .253 ;Place Ticks into EEPROM at 2nd to last memory location movwf ADDR movlw .7 ;Place Intervals into EEPROM at last memory location movwf EBANK movf TICKS, W ;Place value of Ticks into W movwf DATAO ;Put Data in EEPROM Output buffer call WRBYTE ;Write data to EEPROM call Delay call Delay incf ADDR, F ;Increment EEPROM storage location by one movf INTRVLS, W ;Place value of Intervals into W movwf DATAO ;Put Data in EEPROM Output buffer call WRBYTE ;Write data to EEPROM call Delay call Delay clrf EBANK ;Reset Ebank to zero movf RTICKS, W ;Reset TICKS and INTRVLS Counters movwf TICKS movf RINTRVLS, W movwf INTRVLS return ; ;Delay10 Subroutine to delay approximately 0.1 second. Delay10 movlw .10 movwf TEMP2 warmup10 call Delay ;delay loop for approximately 0.01 seconds decfsz TEMP2 goto warmup10 return ;----------------------------------------------------------------------------------- ;EEPROM READ/WRITE SUBROUTINES ( ;Original code from Microchip ;Modified by DB McKinney for the 24LC32A EEPROM; addressing in EBANK and ADDR ;----------------------------------------------------------------------------------- ;EBANK is the EEPROM memory bank, 0-15 no error checking! ;ADDR is address of EEPROM location ;DATAO is Data OUT register, used by WRBYTE ;DATAI is Data IN register, used by RDBYTE ;SLAVE is Device address, ;----------------------------------------------------------------------------- ; BYTE-WRITE, write one byte to EEPROM deviced ;----------------------------------------------------------------------------- ; Input : DATAO = data to be written ; EBANK = EEPROM memory bank select, 0-7 for 24LC16B ; ADDR = EEPROM data address ; SLAVE = device address (1010xxx0) ; Output : Data written to EEPROM device ;----------------------------------------------------------------------------- WRBYTE ;EEPROM CODE FOR 24LC32A EEPROM! WILL NOT WORK FOR 24LC16B! bcf STATUS,RP0 movf SLAVE,W ; Put SLAVE cntrl byte in w movwf TXBUF ; Move modified full address to xmit buffer call BSTART ; Generate START bit call TX ; Output SLAVE address bcf STATUS,RP0 movf EBANK,W ; Get high part of mem address movwf TXBUF ; Load to output buffer call TX ; Send high part of mem address bcf STATUS,RP0 movf ADDR,W ; Put low WORD address in w movwf TXBUF ; load in output buffer call TX ; Output WORD address bcf STATUS,RP0 movf DATAO,W ; Move DATA to w movwf TXBUF ; load data into buffer call TX ; Output DATA and detect acknowledgement bcf STATUS,RP0 call BSTOP ; Generate STOP bit return ;----------------------------------------------------------------------------- ; TRANSMIT 8 data bits subroutine ;----------------------------------------------------------------------------- ; Input : TXBUF ; Output : Data transmitted to EEPROM device ;----------------------------------------------------------------------------- TX bcf STATUS,RP0 movlw .8 ; Set counter for eight bits movwf COUNT TXLP bcf EEPROM,DO ; Default 0 bit out btfsc TXBUF,7 ; If shifted bit = 0, data bit = 0 bsf EEPROM,DO ; otherwise data bit = 1 call BITOUT ; Send bit bcf STATUS,RP0 rlf TXBUF ; Rotate TXBUF left skpc ; f(6) ---> f(7) bcf TXBUF,0 ; f(7) ---> carry skpnc ; carry ---> f(0) bsf TXBUF,0 decfsz COUNT ; 8 bits done? goto TXLP ; No. call BITIN ; Read acknowledge bit bcf STATUS,RP0 movlw 3 btfsc EEPROM,DI ; Check for acknowledgement call ERR ; No acknowledge from device bcf STATUS,RP0 retlw 0 ;----------------------------------------------------------------------------- ; Single bit data transmit from PIC to serial EEPROM ;----------------------------------------------------------------------------- ; Input : EEPROM register, bit DO ; Output : Bit transmitted over I2C ; Error bits set as necessary ;----------------------------------------------------------------------------- BITOUT btfss EEPROM,DO goto BIT0 bsf STATUS,RP0 bsf TRIS_C,SDA ; Output bit 0 movlw 2 bcf STATUS,RP0 btfsc PORT_C,SDA ; Check for error code 2 goto CLK1 call ERR goto CLK1 ; SDA locked low by device BIT0 bsf STATUS,RP0 bcf TRIS_C,SDA ; Output bit 0 nop ; Delay CLK1 bsf STATUS,RP0 bsf TRIS_C,SCL ; Attempt to set SCL high movlw 1 ; Error code 1 bcf STATUS,RP0 btfsc PORT_C,SCL ; SCL locked low? goto BIT2 ; No. call ERR ; Yes, set error BIT2 nop ; Timing delay nop bsf STATUS,RP0 bcf TRIS_C,SCL ; Return SCL to low bcf STATUS,RP0 retlw 0 ;----------------------------------------------------------------------------- ; BYTE-READ, read one byte from serial EEPROM device ;----------------------------------------------------------------------------- ; Input : EBANK = EEPROM memory bank 0-7 for 24LC16B ; ADDR = source address ; SLAVE = device address (1010xxx0) ; Output : DATAI = data read from serial EEPROM ;----------------------------------------------------------------------------- ; RDBYTE ;EEPROM CODE FOR 24LC32A EEPROM! WILL NOT WORK FOR 24LC16B! bcf STATUS,RP0 movf SLAVE,W ; Get SLAVE or cntl byte, put in w movwf TXBUF ; Slave into xmit buffer (R/W = 0) call BSTART ; Generate START bit call TX ; Output SLAVE address. Check ACK. bcf STATUS,RP0 movf EBANK,W ; Get high part of mem address movwf TXBUF ; put in buffer call TX ; send bcf STATUS,RP0 movf ADDR,W ; Move WORD address movwf TXBUF call TX ; Output WORD address. Check ACK. bcf STATUS,RP0 call BSTART ; START READ (if only one device is bcf STATUS,RP0 ; connected to the I2C bus) movf SLAVE,W ; get Slave or Cntrl Byte and put in w movwf TXBUF ; move to TXBUF bsf TXBUF,0 ; Specify READ mode by setting bit0 (R/W = 1) call TX ; Output SLAVE address call RX ; READ in data and acknowledge call BSTOP ; Generate STOP bit bcf STATUS,RP0 movf RXBUF,W ; Save data from buffer movwf DATAI ; to DATAI file register. return ; ;----------------------------------------------------------------------------- ; RECEIVE eight data bits subroutine ;----------------------------------------------------------------------------- ; Input : None ; Output : RXBUF = 8-bit data received ;----------------------------------------------------------------------------- ; RX bcf STATUS,RP0 movlw .8 ; 8 bits of data movwf COUNT clrf RXBUF ; RXLP rlf RXBUF ; Shift data to buffer skpc bcf RXBUF,0 ; carry ---> f(0) skpnc bsf RXBUF,0 call BITIN bcf STATUS,RP0 btfsc EEPROM,DI bsf RXBUF,0 ; Input bit =1 decfsz COUNT ; 8 bits? goto RXLP bsf EEPROM,DO ; Set acknowledge bit = 1 call BITOUT ; to STOP further input retlw 0 ; ;----------------------------------------------------------------------------- ; Single bit receive from serial EEPROM to PIC ;----------------------------------------------------------------------------- ; Input : None ; Output : Data bit received ;----------------------------------------------------------------------------- ; BITIN bsf STATUS,RP0 bsf TRIS_C,SDA ; Set SDA for input bcf STATUS,RP0 bcf EEPROM,DI bsf STATUS,RP0 bsf TRIS_C,SCL ; Clock high movlw 1 bcf STATUS,RP0 btfsc PORT_C,SCL ; Skip if SCL is high goto BIT1 call ERR BIT1 bcf STATUS,RP0 btfss PORT_C,SDA ; Read SDA pin, for ACK low goto ACKOK bsf EEPROM,DI ; DI = 1 ACKOK bsf STATUS,RP0 nop ; Delay bcf TRIS_C,SCL ; Return SCL to low bcf STATUS,RP0 retlw 0 ;----------------------------------------------------------------------------- ; DELAY, Provide a 10.78mS delay ;----------------------------------------------------------------------------- ; Input : None ; Output : None ;----------------------------------------------------------------------------- Delay bcf STATUS,RP0 movlw h'20' ; movwf TEMP1 dly1 decfsz TEMP1 goto dly1 ;Total time = ~10mS retlw 0 ;----------------------------------------------------------------------------- ; START bit generation routine ;----------------------------------------------------------------------------- ; input : none ; output : initialize bus communication ;----------------------------------------------------------------------------- ; ;Generate START bit (SCL is high while SDA goes from high to low transition) ;and check status of the serial clock. BSTART bsf STATUS,RP0 bsf TRIS_C,SDA ; Make sure SDA is high bsf TRIS_C,SCL ; Set clock high movlw 1 ; Ready error status code 1 bcf STATUS,RP0 btfss PORT_C,SCL ; Locked? call ERR ; SCL locked low by device, flag error bsf STATUS,RP0 bcf TRIS_C,SDA ; SDA goes low during SCL high nop ; Timing adjustment, 1uS @4MHz bcf TRIS_C,SCL ; Start clock train bcf STATUS,RP0 RETLW 0 ;----------------------------------------------------------------------------- ; STOP bit generation routine ;----------------------------------------------------------------------------- ; Input : None ; Output : Bus communication, STOP condition ;----------------------------------------------------------------------------- ; ;Generate STOP bit (SDA goes from low to high during SCL high state) ;and check bus conditions. BSTOP bsf STATUS,RP0 bcf TRIS_C,SDA ; Return SDA to low bsf TRIS_C,SCL ; Set SCL high nop movlw 1 ; Ready error code 1 bcf STATUS,RP0 btfss PORT_C,SCL ; High? call ERR ; No, SCL locked low by device bsf STATUS,RP0 bsf TRIS_C,SDA ; SDA goes from low to high during SCL high movlw 4 ; Ready error code 4 btfss TRIS_C,SDA ; High? call ERR ; No, SDA bus not release for STOP bcf STATUS,RP0 retlw 0 ; ;----------------------------------------------------------------------------- ; Two wire/I2C - CPU communication error status table and subroutine ;----------------------------------------------------------------------------- ; input : W-reg = error code ; output : ERCODE = error code ; FLAG(ERROR) = 1 ; ; code error status mode ; ------- ------------------------------------------------------ ; 1 : SCL locked low by device (bus is still busy) ; 2 : SDA locked low by device (bus is still busy) ; 3 : No acknowledge from device (no handshake) ; 4 : SDA bus not released for master to generate STOP bit ;----------------------------------------------------------------------------- ; ;Subroutine to identify the status of the serial clock (SCL) and serial data ;(SDA) condition according to the error status table. Codes generated are ;useful for bus/device diagnosis. ; ERR bcf STATUS,RP0 btfss FLAG,ERRORFLG ; If not first error, do not change code movwf ERCODE ; Save error code bsf FLAG,ERRORFLG ; Set error flag retlw 0 end