Files
paolo.iocco e51d00d234
2023-03-09 10:05:56 +00:00

158 lines
5.4 KiB
NASM

;***********************************************************************
; compact I2C eeprom access code V1.0
; (C) Mike Harrison 1998
; example code for PIC12C508
;------------------------------------------------------- workspace
cnt equ 08 ; byte count register
flags equ 09 ; flags and bit count :
read equ 0 ; 1 to read bytes, 0 to write
addr equ 1 ; 0 to send eeprom address byte
rden equ 2 ; 1 to enable read next cycle
; b5-7 used as bit counter
temp equ 0a ; read/write data byte
eeadr equ 0b ; eeprom address
iiport equ gpio ; port address
sclbit equ 4 ; SCL port pin (no pullup required)
sdabit equ 5 ; SDA port pin (10K pullup to Vdd required)
lotris equ b'00101' ; TRIS setting with SCL and SDA outputs, other bits as required by application
hitris equ lotris+(1<<sdabit)
; calling examples :
;to read 3 bytes from eeprom addr 10..12 to registers 14..16
; movlw 10
; movwf eeadr
; readee 3,14
;to write 5 bytes from registers 19..1d to eeprom address 0
; clrf eeadr
; writeee 5,19
;--------------------------------------------------- calling macros
; to simplify parameter set-up, you can call the code using the following macros
readee macro bytes,address
; usage : readee <no. of bytes to read>, <RAM address to read to>
movlw address-3 ; FSR offset due to unconditional increment
movwf fsr
movlw 0ef - bytes ; 2 writes (control, address) + n+1 reads (control,data)
call do_iic
endm
writeee macro bytes,address
; usage : writeee <no. of bytes to write>, <RAM address to write from>
movlw address-1
movwf fsr
movlw 0e0 - (bytes <<4) ; n+2 writes (control,address,data), no reads
call do_iic
endm
;-----------------------------------------------------------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, but eeprom write cache may limit this
movwf cnt
retry_iic
clrf flags ; initialise flags and bit count
phaseloop
movlw hitris
tris iiport ; ensure SDA high
bsf iiport,sclbit ; SCL high
bcf iiport,sdabit ; ensure SDA o/p reg low
movlw lotris
goto $+1 ; ensure Tsu:sta - can be omitted in fast mode
tris iiport ; sda low - start condition
movlw iiadr ; IIC control byte (write)
btfsc flags,rden
movlw iiadr+1 ; .. or read control byte if read pending
movwf temp ; IIC control byte
bcf iiport,sclbit ; scl low - code above ensures Thd:sta
byteloop ;
; start of byte read/write section
movlw lotris
btfss flags,read ; set SDA high (tri-state) if reading
btfsc temp,7 ; set SDA low only if writing and data bit = 0
movlw hitris ; (sda o/p register bit will be low)
tris iiport
goto $+1 ; wait set-up time
bsf iiport,sclbit ; clock high (may set SDA o/p reg bit high)
clc ; used later - done here for timing
movlw 0ff^(1<<sclbit)^(1<<sdabit) ; mask to clear SDA and SCL, " "
btfsc iiport,sdabit ; test SDA input for read
sec
andwf iiport ; SCL low, SDA o/p reg bit low
rlf temp ; shift read data in or write data out
movlw 020
addwf flags ; increment bitcount in b5-7
skpc
goto byteloop ; do 8 bits
movlw 0f0
xorwf cnt,w ; last byte of read ? Z set if so
movlw lotris ; ack low if reading to send ack to eeprom
skpz ; ..but no ack on last byte of read
btfss flags,read ;
movlw hitris ; ack high for write to test ack from eeprom
tris iiport
bsf iiport,sclbit ; clock high to get or send ack bit
goto $+1 ; wait ack pull-up time
movlw 0ff^(1<<sclbit)^(1<<sdabit) ; SDA/SCL low mask, done here to add delay
skpz ; last byte of read - skip retry
btfss iiport,sdabit ; read ack bit state
goto no_retry_iic
goto retry_iic ; retry if ack high (will be forced low on reads, except last byte)
no_retry _iic
andwf iiport ; set scl and sda o/p register bit low
;..................... end of byte read/write section
movf temp,w
btfsc flags,read
movwf indf ; store data if reading
movf indf,w ; get write data
incf fsr ; increment RAM pointer
btfss flags,addr
movf eeadr,w ; load eeprom address if not disabled
movwf temp ; byte to send next loop - address or data
bsf flags,addr ; disable address flag
btfsc flags,rden ; read mode pending?
bsf flags,read ; set read mode
movlw 010
addwf cnt ; increment byte counter in B4..7
skpnz
goto done ; both nibbles zero - all done
skpc ; c set if b7-4 now clear - write phase done
goto byteloop
bsf flags,rden ; set 'read pending' flag
swapf cnt ; load byte counter with read byte count
goto phaseloop ; do second phase of command
done
; do stop condition
movlw lotris ; (SDA o/p bit will be low)
tris iiport ; set SDA low
bsf iiport,sclbit ; scl high
goto $+1 ; ensure Tsu:sto
goto $+1 ; both these can be omitted for fast mode
movlw hitris
tris iiport ; sda high
retlw 0