158 lines
5.4 KiB
NASM
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
|
|
|