Title "Read4K.asm 6/11/98 ;Modified from reader0.asm code for 4K 24lc32A EEPROM. Ver 1.0--June 11,1999 ;Modifications by Brooks McKinney, John Halfman, and John Rumpf list p=16c73a ;-------------------------------------------------------------------------- ;READER program ;This program uses PORT_B output to signal the datalogger to start, but also ;as a debugging output ;For HI value on Pin ; 28 RB7 start ; 27 RB6 ckdata ; 26 RB5 w/28 pulsing=sndata ; 25 RB4 cmand ; 24 RB3 setrd ; 23 RB2 intlz ; 22 RB1 (on at start command) ;-------------------------------------------------------------------------- ;----- Parameters---------------------------------------------------------- W EQU H'0000' F EQU H'0001' NOTOK equ H'00' ;NOT OK command code 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 EXI equ H'06' ;EXIt command code ;----- Register Files------------------------------------------------------ TMR0 EQU H'0001' STATUS EQU H'0003' INTCON EQU H'000B' PIR1 EQU H'000C' SSPBUF EQU H'0013' SSPCON EQU H'0014' RCSTA EQU H'0018' TXREG EQU H'0019' RCREG EQU H'001A' ;OPTION EQU H'0081' PIE1 EQU H'008C' PCON EQU H'008E' PR2 EQU H'0092' TXSTA EQU H'0098' SPBRG EQU H'0099' PORT_B EQU H'06' TRIS_B EQU H'86' PORT_C EQU H'07' TRIS_C EQU H'87' ;----- STATUS Bits -------------------------------------------------------- RP1 EQU H'0006' RP0 EQU H'0005' Z EQU H'0002' ;----- INTCON Bits -------------------------------------------------------- GIE EQU H'0007' PEIE EQU H'0006' T0IE EQU H'0005' INTE EQU H'0004' RBIE EQU H'0003' T0IF EQU H'0002' INTF EQU H'0001' RBIF EQU H'0000' ;----- PIR1 Bits ---------------------------------------------------------- ADIF EQU H'0006' RCIF EQU H'0005' TXIF EQU H'0004' SSPIF EQU H'0003' CCP1IF EQU H'0002' TMR2IF EQU H'0001' TMR1IF EQU H'0000' ;----- RCSTA Bits --------------------------------------------------------- SPEN EQU H'0007' RX9 EQU H'0006' RC9 EQU H'0006' ; Backward compatibility only NOT_RC8 EQU H'0006' ; Backward compatibility only RC8_9 EQU H'0006' ; Backward compatibility only SREN EQU H'0005' CREN EQU H'0004' FERR EQU H'0002' OERR EQU H'0001' RX9D EQU H'0000' RCD8 EQU H'0000' ; Backward compatibility only ;----- OPTION Bits -------------------------------------------------------- NOT_RBPU EQU H'0007' INTEDG EQU H'0006' T0CS EQU H'0005' T0SE EQU H'0004' PSA EQU H'0003' PS2 EQU H'0002' PS1 EQU H'0001' PS0 EQU H'0000' ;----- PIE1 Bits ---------------------------------------------------------- ADIE EQU H'0006' RCIE EQU H'0005' TXIE EQU H'0004' SSPIE EQU H'0003' CCP1IE EQU H'0002' TMR2IE EQU H'0001' TMR1IE EQU H'0000' ;----- TXSTA Bits --------------------------------------------------------- CSRC EQU H'0007' TX9 EQU H'0006' NOT_TX8 EQU H'0006' ; Backward compatibility only TX8_9 EQU H'0006' ; Backward compatibility only TXEN EQU H'0005' SYNC EQU H'0004' BRGH EQU H'0002' TRMT EQU H'0001' TX9D EQU H'0000' TXD8 EQU H'0000' ; Backward compatibility only ;------------------------------------------------------- ;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 EBANK equ 2C KOUNT equ 2D ;Serial Registers BYTEIN equ 2E ;register for incoming serial data BYTEOUT equ 2F ;register for outgoing serial data ;----------------------------------------------------------------------------- ; 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 ; RC4, data in/out SCL equ 3 ; RC3, serial clock ;----------------------------------------------------------------------------- org 00h ;Reset Vector goto start ; org 05h ;Beginning of program ;-------------------------------------------------------------------------- ;Begin Main Program ;-------------------------------------------------------------------------- start ;Set up RS232 to Host bsf STATUS,RP0 ;select bank 1 movlw 0h ;put 00000000 in w movwf TRIS_B ;Config PORT_B as all outputs movlw .25 ;2400 baud @4MHz movwf SPBRG movlw b'10100000' ;Async, Low baud rate movwf TXSTA bcf STATUS,RP0 ;select bank 0 movlw B'00111011' ; I2C master mode enabled movwf SSPCON clrf EBANK clrf ADDR movlw B'10100000' ; EEPROM I2C address movwf SLAVE movlw b'10000000' movwf PORT_B ;PIN 28 HI ;>FLOWCHART#1 call rcbyte ;Read in byte from serial port host, data in bytein movlw OK ;OK code in w subwf BYTEIN, W ;subtract, result 0 if bytein=ok btfsc STATUS, Z ;if w=0 go on, if not try again goto cont1 ;go here if bytein=ok call txnot ;send notok code back to host goto start ;loop back to try again cont1 movlw b'01000000' ;PIN 27 HI movwf PORT_B ;>FLOWCHART#2 call txok ;send OK code to host ckdat ;>FLOWCHART#3 clrf EBANK clrf ADDR call rcbyte ;wait for host DAT code; back here if NOTOK read movlw DAT ;load DAT code to w subwf BYTEIN,W ;result w=0 if rec byte is DAT ;>FLOWCHART#4 btfsc STATUS, Z ;if DAT, w=0, z is set do goto goto sndata ;go here if bytein=DAT call txnot ;if not DAT send NotOk code goto ckdat ;loop to try again sndata ;>FLOWCHART#5 clrf PORT_B ;all PORT_B Pins off, pulse 28 and 26, see below movlw B'10100000' ;EEPROM I2C address movwf PORT_B ;PIN 28 and 26 on bsf STATUS,RP0 ;select bank 1 movlw 0FFh ;Setup PORT_C as all inputs movwf TRIS_C ;configure PORT_C as all input bcf STATUS,RP0 call txok ;send ok loop1 ;>FLOWCHART#6 call rcbyte ;wait for byte, no checking what it is 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 BYTEOUT ;put byte from EEPROM in serial out buffer call txbyte ;send byte to host incfsz ADDR,F ;increment address goto loop1 ;send another unless ADDR=0 incf EBANK,F ;if ADDR=0, incrment EBANK movlw .16 ;put max EBANK in w --changed from 2K version subwf EBANK,W ;subtract W from EBANK, if 0 done btfss STATUS,Z ;if bit is set, done goto loop1 ;if bit clear, not 0, not done, read next ;>FLOWCHART#7 call rcbyte ;wait for byte to come in, no checking movlw h'00' ;put 0 in w movwf BYTEOUT ;put in output buffer call txbyte ;send to host--first of end of data markers comf BYTEOUT,F ;set BYTEOUT to h'FF' ;>FLOWCHART#8 call rcbyte ;wait for byte to come in, no checking call txbyte ;send to host, second of end of data markers ;-------------Data sent, wait for commands-------------------------------- ;Reader wait for one of three command codes: ; NOTOK = Problem with data, go back and reread ; REA = Set REAd flag in logger EEPROM ; INI = Do logger initialization ;------------------------------------------------------------------------- ; cmand clrf PORT_B ;clear PORT_B pins movlw b'00010000' ;Turn PIN 25 on movwf PORT_B ;FLOWCHART#9 call rcbyte ;wait for byte from host, data in bytein movlw REA ;REA code in w subwf BYTEIN, W ;subtract, result 0 if bytein=REA btfsc STATUS, Z ;if bytein=REA this bit set goto setread ; movlw INI ;INI code in w subwf BYTEIN, W ;subtract, result 0 if bytein=INI btfsc STATUS, Z ;if bytein=INI this bit set goto setini ; movlw DAT ;falls thru to here, put code in w movwf BYTEOUT ;move to serial out buffer ;>FLOWCHART#10 call txbyte ;send code back to host goto ckdat ;go back to chkdata, if error in code does this! setread ;>FLOWCHART#11 clrf PORT_B ;Clear PORT_B movlw b'00001000' ;PIN 24 HI clrf EBANK ;clear EBANK, select EEPROM bank 0 movlw .5 ;location of ADDR in EEPROM movwf ADDR ;put into EEPROM subroutine addr buffer movlw .1 ;value for read movwf DATAO ;put in EEPROM output buffer call WRBYTE ;write value to EEPROM call Delay movlw REA ;put code in w movwf BYTEOUT ;move to serial out buffer call txbyte ;send code back clrf ADDR goto cmand ;back for next command setini ;FLOWCHART#12 movlw INI movwf BYTEOUT call txbyte clrf PORT_B ;clear PORT_B movlw b'00000100' ;PIN 23 HI movwf PORT_B clrf EBANK ;set EEPROM bank 0 clrf ADDR ;set ADDR 0 nxtdat ;>FLOWCHART#13 call rcbyte ;get first databyte movf BYTEIN,W ;move data to w movwf DATAO ;move data to EEPROM output buffer wrtdat call WRBYTE ;write EEPROM nop ;delay for EEPROM nop call Delay ;Debug Call Delay call RDBYTE ;read back data movf DATAI,W ; movwf BYTEOUT ; subwf DATAO,W ;subtract in from out, result in w should be 0 ;>FLOWCHART#14 ;-- btfss STATUS,Z ;check, if set data is ok go to next ;-- goto wrtdat ;if z bit clear, then in not same as out, redo ;Note that this could be an infinite loop! HOST cont2 ;should time out in that case. call txbyte ;send byte back to host incfsz ADDR,F ;increment address goto nxtdat ;get another unless ADDR=0 incf EBANK,F ;if ADDR=0, incrment EBANK movlw .16 ;put max EBANK in w -- changed from 2K version subwf EBANK,W ;subtract W from EBANK, if 0 done btfss STATUS,Z ;if bit is set, done goto nxtdat ;if bit clear, not 0, not done, read next clrf ADDR ;clear ADDR ;>FLOWCHART#15 call rcbyte ;wait for STArt byte from host movlw STA ;put STArt code in w subwf BYTEIN,w ;subtract, w=0 if BYTEIN=STArt code btfss STATUS,Z ;bit set if BYTEIN=STA goto setini ;send go back to setini, sends ini code and waits clrf PORT_B movlw b'00000010' ;send RB1 high movwf PORT_B call txok ;FLOWCHART#16 xloop goto xloop ;terminal loop--turns on startpin. Manually reset processor. ;----------------------------------------------------------------------- ;END main program ;----------------------------------------------------------------------- ;SUBROUTINES ;-------------------------------------------------------------------------- ;TXOK: Send an OK code out serial port ;-------------------------------------------------------------------------- txok movlw OK ;OK code in w movwf BYTEOUT call txbyte ;send OK return ;-------------------------------------------------------------------------- ;TXNOT: Send a NOTOK code out serial port ;-------------------------------------------------------------------------- txnot movlw NOTOK ;NOTOK code in w movwf BYTEOUT call txbyte ;send NOTOK return ;-------------------------------------------------------------------------- ;RCBYTE: get one byte from serial port, result in BYTEIN ;-------------------------------------------------------------------------- rcbyte bcf RCSTA, CREN ;clear any errors movlw b'10010000' ;Enable continous reception movwf RCSTA listen btfss PIR1, RCIF ;RCIF set when byte received goto listen movlw 06h ;Mask out unwanted bits andwf RCSTA,W ;Check for errors btfsc STATUS,Z goto dataok ;No error bcf RCSTA, CREN ;Error, clear error bsf RCSTA, CREN ; goto listen ;try again dataok movf RCREG,W movwf BYTEIN bcf RCSTA, CREN ;disable receive return ;-------------------------------------------------------------------------- ;TXBYTE: send one byte out serial port ;-------------------------------------------------------------------------- txbyte bsf STATUS,RP0 ;select bank1 bsf TXSTA, TXEN ;enable send bcf STATUS,RP0 ;select bank0 movf BYTEOUT,W ;put data in w movwf TXREG ;put data in tx register and start send 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 ;----------------------------------------------------------------------------- ;NEW CODE--changed to support 24lc32 eeprom, code extracted from d32.asm; 6/4/99 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 nop ; DEBUG 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 ; Debug 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 nop ; Delay nop ; DEBUG 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 7 movwf TEMP1 clrf TEMP ;clear last location dly1 nop nop nop decfsz TEMP ;reduce count goto dly1 ;Inner loop time = 1.54mS decfsz TEMP1 goto dly1 ;Total time = 10.78mS 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 nop ; DEBUG 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 nop ; DEBUG 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 nop ;DEBUG 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