;Logger code for PIC16C773 12-bit ADC ;D.B. McKinney, 6/26/02 ;Based on dlog4kb code for PIC16C73A ;Modifications noted in comments with ">>>" pointer ; ;New Data Storage scheme ;All data written to EEPROM in this version goes in two bytes, a low and a high. These will be ;reassembled into a single 12bit value in the HWS HOST code. The EEPROM addressing is set ;up as follows ; HIEADR LOEADR ; Bits 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ;Lo byte 0 n n n n n n n n n n n n n n ;Hi byte 1 n n n n n n n n n n n n n n ;Thus the low bytes are stored in locations 0-16,383 and high bytes 16,384-32,767 ;In hex the low bytes are stored in locations 0000 to 3FFF, high bytes in 4000 to 7FFF ;Using this scheme, almost the same addressing and address incrementing routines can be used, ;only the eeprom is read/written twice during each RDBYTES WRBYTES, once to the low byte location, once ;to the high byte location. ; ;A/D Conversion ;Operation similar to 8bit, but must supply +Vref on RA3 (as in 8bit) and -Vref on RA2. ;Result is put in ADRESL and ADRESL high then shifted to storage ;----------------------------------------------------- ;DATALOGGER SOFTWARE--12BIT ADC, 256K EEPROM VERSION, WITH START DELAY ;----------------------------------------------------- ; list p=16C773 ;>>>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 hexadecimal 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) LOEADR equ 23 ; >>>Lo byte of EEPROM address (ADDR in PIC16C73 code) LODATI equ 24 ; >>>Lo byte of EEPROM stored data input register LODATO equ 25 ; >>>Lo byte of EEPROM stored data output register HIDATI equ 40 ;>>>Hi byte of EEPROM stored data input register HIDATO equ 41 ;>>>Hi byte of EEPROM stored data output register SLAVE equ 26 ; EEPROM 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 HIEADR equ 32 ;>>>Bits 0-5 of EEPROM address (EBANK in PIC16C73 code) 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 DATBUF equ 42 ;>>>Buffer for read/write to EEPROM RDCNT equ 43 ;EEPROM read repetition counter ;----------------------------------------------------------- ;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' ADRESH equ H'1E' ;>>>Change from ADRES to ADRESH ADRESL equ H'9E' ;>>>Additional low byte of AD conversion 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'03' ;value for number of cycles that pin must be hi >>>changed from 0F 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 call Delay ;------------------------------------------------------------------------------------------ ;Datalogging setup: configure EEPROM and get tikcs and intervals data from it ;------------------------------------------------------------------------------------------ clrf TOGGLE movlw B'00111011' ; I2C master mode enabled movwf SSPCON clrf HIEADR ;zero high byte of EEPROM address movlw B'10100000' ;EEPROM I2C address movwf SLAVE ;put EEPROM address in SLAVE movlw h'0C' ;RTICKS location in EEPROM, address 12 movwf LOEADR ;put low byte address in register movlw h'0F' movwf RDCNT rdtcks call Delay call Delay call RDBYTES ;Input byte from EEPROM movf LODATI,W ;Get received byte incfsz W ;if ticks is read as 244, w increments to 0 goto tcksok ;ticks ok, go on decfsz RDCNT goto rdtcks ;ticks read as 255, try again Possible infinit loop here tcksok movf LODATI,W movwf RTICKS ;Store number of Rticks per interval-reset value movwf TICKS ;Store ticks movlw .13 ;INTRV location in the EEPROM, addresss 13 movwf LOEADR ;increment address to .13 movlw h'0F' movwf RDCNT rdints call Delay call Delay call RDBYTES ;Input byte from EEPROM movf LODATI,W ; incfsz W goto intsok decfsz RDCNT goto rdints intsok movf LODATI,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 LOEADR ;put address in lo byte register call RDBYTES ;Input byte from EEPROM movf LODATI,W ;Get received byte 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 LOEADR ;increment address to .4 call RDBYTES ;Input byte from EEPROM ;call Delay ;call Delay movf LODATI,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 h'FE' ;Set up memory location, Place DTicks into EEPROM at just before last memory location movwf LOEADR movlw h'7F' ;Place DIntervals into EEPROM just before last memory location movwf HIEADR movf DTICKS, W ;Place value of DTicks into W movwf LODATO ;Put Data in EEPROM Output buffer call WRBYTES ;Write data to EEPROM call Delay call Delay incf LOEADR, F ;Increment EEPROM storage location by one movf DINTRVLS, W ;Place value of DIntervals into W movwf LODATO ;Put Data in EEPROM Output buffer call WRBYTES ;Write data to EEPROM call Delay call Delay ;!!!!!!!!!!!! end of new code movlw h'0F' ;Last intialization storage location in EEPROM movwf LOEADR ;put last EEPROM storage location in LOEADR 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 ;clrf LOEADR ;Is this write over bug? 7/6 recompile and test! clrf HIEADR 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 h'2A' ;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 LOEADR,F ;increment EEPROM storage location goto nxtdat ;if zero, EEPROM bank full, increment HIEADR incf HIEADR,F ;add 1 to HIEADR nxtdat bsf STATUS,RP0 ;select page 1 movlw b'10010000' ;>>>input channels movwf ADCON1 ;>>>set RA3=+VRef, RA2=-VRef bcf STATUS,RP0 ;select page 0 bsf ADCON0,0 ;turn on converter nop ;wait for signal aquisition nop ;ditto bsf ADCON0,2 ; start conversion waitad btfsc ADCON0,2 ;check goto waitad ;loop until conversion done bcf ADCON0,0 ;turn off A/D conversion 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 bsf STATUS, RP0 ;select memory page 1 movf ADRESL,W ;move result to W bcf STATUS, RP0 ;select memorpy page 0 movwf LODATO ;put data in EEPROM output buffer movf ADRESH,W movwf HIDATO call WRBYTES ;write data to EEPROM ;call Delay ;call Delay ;btfsc FLAG,ERRORFLG ; Check for error ;goto errors movf LOEADR,W ;Make copies of eeprom address--put LOEADR in w movwf TEMP3 ;make copy of LOEADR in TEMP3 movf HIEADR,W ;put HIEADR in w movwf TEMP4 ;make copy of HIEADR in TEMP4 incfsz LOEADR,F ;increment copy of EEPROM storage location to write EOD marker goto nxtmrk ;if zero, lo byte EEPROM address full, increment HIEADR movf HIEADR,W ;put HIEADR in W sublw h'3F' ;if HIEADR=MAX=h'3F', W=0 (>>>updated from 32K version) btfsc STATUS,Z ;if HIEADR=40 this bit is set goto endlog ;if HIEADR=8,w=0,status,z set; end logging, mem full !!!!REVISED 1/1 incf HIEADR,F ;add 1 to copy of HIEADR nxtmrk movlw h'00' movwf LODATO ;put h'00' marker in low data byte movlw h'10' ;maker for hi data--this value not accessible from 12bit A/D movwf HIDATO ;put HIEADR EEPROM location in data out reg call WRBYTES ;write marker in next eeprom location ;call Delay ;call Delay ;btfsc FLAG,ERRORFLG ; Check for error ;goto errors movf TEMP3,W ;put copy of this datapoint LOEADR in w movwf LODATO ;move copy to lODATO for output to eeprom clrf HIDATO ;movf TEMP4,W ;put copy of this datapoint HIEADR in w ;movwf HIDATO ;move copy to HIDATO for output to eeprom movlw h'0F' ;set lo byte location for eeprom data in header movwf LOEADR ;temporarirly set lo byte address in header clrf HIEADR ;set top part of address for header call WRBYTES ;write last datapoint LOEADR data to header movf TEMP4,W ;put copy of this datapoint's HIEADR in w movwf LODATO ;put in LODATO for output to eeprom decf LOEADR ;point to HIEADR address in header call WRBYTES ;call Delay ;call Delay movf TEMP3, W ;restore eeprom addresses movwf LOEADR movf TEMP4, W movwf HIEADR 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 h'FE' ;Place Ticks into EEPROM at 2nd to last memory location movwf LOEADR movlw h'7F' ;Place Intervals into EEPROM at last memory location movwf HIEADR movf TICKS, W ;Place value of Ticks into W movwf LODATO ;Put Data in EEPROM Output buffer call WRBYTES ;Write data to EEPROM call Delay call Delay incf LOEADR, F ;Increment EEPROM storage location by one movf INTRVLS, W ;Place value of Intervals into W movwf LODATO ;Put Data in EEPROM Output buffer call WRBYTES ;Write data to EEPROM call Delay call Delay clrf HIEADR ;Reset HIEADR 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 24LC256 EEPROM; addressing in HIEADR and ADDR. ;See note inn program header on organization--two parallel banks, one for lo byte, one for hi ;All reads and writes are two bytes, one from each bank, address differs only in bit 6 of HIEADR ;----------------------------------------------------------------------------------- ;HIEADR is high byte of the EEPROM memory address ;LOEADR is low byte of the EEPROM memory address ;LODATO is low byte data OUT register, used by WRBYTES ;HIDATO is hi byte data OUT register, used by WRBYTES ;LODATI is low byte data IN register, used by RDBYTES ;HIDATI is hi byte data IN regsiter, used by RDBYTES ;SLAVE is Device address ;DATBUF is a register for swapping hi/lo bytes to the read/write routines ;----------------------------------------------------------------------------- ; BYTE-WRITE, write one byte to EEPROM deviced ;----------------------------------------------------------------------------- ; Input : LODATO = lo data byte to be written ; HIDATO = hi data byte to be written ; HIEADR = high byte of EEPROM memory address ; LOEADR = low byte of EEPROM memory address ; SLAVE = device address (1010xxx0) ; Output : Data written to EEPROM device ;----------------------------------------------------------------------------- WRBYTES ;EEPROM CODE FOR 24LC256 EEPROM, writes a high and low byte for each call TOPWRB bcf STATUS,RP0 ; Which byte to write, hi or lo? btfsc HIEADR,6 ; If bit 6 clear, data is low byte movf HIDATO,W ; If bit 6 set, put hi byte in w btfss HIEADR,6 ; If bit 6 is set, data is hi byte movf LODATO,W ; If bit 6 clear, data is lo byte movwf DATBUF ; Put data in buffer 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 movf HIEADR,W ; Get high byte of mem address movwf TXBUF ; Load to output buffer call TX ; Send high part of mem address movf LOEADR,W ; Get low byte of mem address movwf TXBUF ; load in output buffer call TX ; Send lo byte of mem address movf DATBUF,W ; Load data byte to w movwf TXBUF ; load data byte into buffer call TX ; Output DATA and detect acknowledgement call BSTOP ; Generate STOP bit call Delay call Delay ;call WRDONE ; poll ack to see if write is completed btfsc HIEADR,6 ; Check to see if this is lo (clear) or hi (set) byte goto ENDWRB ; if bit is set, write cycle is done bsf HIEADR,6 ; Set bit 6 for hi data byte goto TOPWRB ; Loop back to do hi data byte ENDWRB bcf HIEADR,6 ; reset bit 6 for lo byte for return to program ; Call WRDONE Call Delay Call Delay return ;----------------------------------------------------------------------------- ; WRDONE Poll eeprom to see if write cycle is done >>>added for 12bit version ; Currently link to it is commented out, see 8 lines above ;----------------------------------------------------------------------------- WRDONE 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 btfsc EEPROM,DI ; Check ack bit, LO if write done goto WRDONE ; loop back and try again 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 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 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 : LOEADR = lo byte of eeprom address ; HIEADR = hi byte of eeprom address ; LODATI = lo byte of eeprom data ; HIDATI = hi byte of eeprom data ; SLAVE = device address (1010xxx0) ; Output : LODATI = lo byte of data read from serial EEPROM ; HIDATI = hi byte of data read from serial EEPROM ;----------------------------------------------------------------------------- ; RDBYTES ;EEPROM CODE FOR 24LC256 EEPROM! TOPRDB 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 HIEADR,W ; Get high part of mem address movwf TXBUF ; put in buffer call TX ; send bcf STATUS,RP0 movf LOEADR,W ; Get lo part of mem address movwf TXBUF ; put in buffer call TX ; send 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 btfsc HIEADR,6 ; If clear, low data byte in W goto HIGHDATA ; movwf LODATI ;put result in low data byte bsf HIEADR,6 ;set bit for high data byte goto TOPRDB HIGHDATA movwf HIDATI ;put result in hi data byte bcf HIEADR,6 ;Reset to low data byte address bcf STATUS,RP0 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