Notes:
readee
and writeee
macros
are replaced by movef
and movfe
those
have more "PIC like" mnemonics and argument order.
iic_stop
after power on reset.
;====== EEPROM macros ========== movef macro _eeaddr,_file,_len movlw _eeaddr movwf eeadr movlw _file-3 ; FSR offset due to unconditional increment movwf fsr movlw 0xef - _len ; 2 writes (control, address) + n+1 reads (control,data) call do_iic endm movfe macro _file,_eeaddr local _len=1 movlw _eeaddr movwf eeadr movlw _file-1 movwf fsr movlw 0xe0 - (_len<<4); 1+2 writes (control,address,data), no reads call do_iic endm ;====== delay macros =========== tdelay macro tcycle local cnt2=tcycle/2 if tcycle<0 error "Negative delay" endif if tcycle%2 nop endif while cnt2 goto $+1 cnt2 set cnt2-1 endw endm udelay macro _tenthmicrosec,_consumedtcycles local mill40=40000000 IF _tenthmicrosec > _consumedtcycles*mill40/FOSC tdelay (FOSC*_tenthmicrosec+mill40-1)/mill40-_consumedtcycles ENDIF endm ;====== I/O pins =============== #define DATA gpio,6 ; in/out #define CLOCK gpio,7 ; in/out ;====== Clock frequency ======== #define FOSC 1843200 ; customize this ;====== RAM area =============== cblock eebuf ; eeprom tmp buffer eecnt ; eeprom byte counter eeflags ; eeprom flags and bit counter eeadr ; eeprom address endc ;*********************************************************************** ; Mike Harrison's code with minor modifications. read equ 0x0 ; 1 to read bytes, 0 to write addr equ 0x1 ; 0 to send eeprom address byte rden equ 0x2 ; 1 to enable read next cycle ; b5-7 used as bit counter iiadr equ 0xa0 ; I2C device address ;-----------------------------------------------------------do_iic do_iic ; read/write byte(s) to I2C EEPROM ; W & FSR to be setup as follows : ; read : EF - nbytes FSR = RAM address-1 ; write : E0 - (nbytes<<4) FSR = RAM address-3 ; eeadr holds eeprom address (preserved on exit) ; on exit, FSR points to the byte after the last one read/written ; nbytes can be up to 14 on read but only 1 on write movwf eecnt retry_iic clrf eeflags ; initialise flags and bit count phaseloop bsf DATA ; SDA high bsf CLOCK ; SCL high movlw iiadr ; IIC control byte (write) (used later) udelay 47,2 ; ensure Tsu:sta (4.7 us) bcf DATA ; sda low - start condition btfsc eeflags,rden movlw iiadr+1 ; .. or read control byte if read pending movwf eebuf ; IIC control byte bcf CLOCK ; scl low - code above ensures Thd:sta (4.0 us) byteloop ; start of byte read/write section bsf DATA ; release SDA btfsc eeflags,read ; we are reading? goto dataset ; yes, leave SDA high btfss eebuf,7 ; if we write data bit=0? bcf DATA ; yes, pull down DATA dataset bsf CLOCK ; set SCL high clrc ; used later - done here for timing btfsc DATA ; test SDA input for read setc bcf CLOCK rlf eebuf ; shift read data in or write data out movlw 0x20 addwf eeflags ; increment bitcount in b5-7 skpc goto byteloop ; do 8 bits movlw 0xf0 xorwf eecnt,w ; last byte of read ? Z set if so bsf DATA btfss eeflags,read ; ack low if reading EEPROM... goto ackset skpz ; ...except on last byte bcf DATA ; pull down sda, no retry ackset bsf CLOCK ; clock high to get or send ack bit skpnz ; last byte of read? goto no_retry_iic ; yes - skip ack test btfsc DATA ; read ack bit state goto retry_iic ; retry if ack high (will be forced low on reads, except last byte) no_retry_iic bcf CLOCK bcf DATA ;..................... end of byte read/write section movf eebuf,w btfsc eeflags,read movwf indf ; store data if reading movf indf,w ; get write data incf fsr ; increment RAM pointer btfss eeflags,addr movf eeadr,w ; load eeprom address if not disabled movwf eebuf ; byte to send next loop - address or data bsf eeflags,addr ; disable address flag btfsc eeflags,rden ; read mode pending? bsf eeflags,read ; set read mode movlw 0x10 addwf eecnt ; increment byte counter in B4..7 skpnz goto iic_stop ; both nibbles zero - all done skpc ; c set if b7-4 now clear - write phase done goto byteloop bsf eeflags,rden ; set 'read pending' flag swapf eecnt ; load byte counter with read byte count goto phaseloop ; do second phase of command ; *** CALL iic_stop after POR *** iic_stop ; do stop condition bcf DATA ; set SDA low bsf CLOCK ; scl high udelay 40,1 ; ensure Tsu:sto bsf DATA retlw 0