PIC12CE518/519 EEPROM routines

PIC 12CE51X EEPROM routines

This code below is based on Mike Harrison's subroutines published on PICLIST.
The original code is slightly modified for PIC 12CE51X devices with internal EEPROM.




;====== 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

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

;====== delay macros ===========
tdelay	macro	tcycle
	local	cnt2=tcycle/2
	if	tcycle<0
	error	"Negative delay"
	if	tcycle%2
	while	cnt2
	goto	$+1
cnt2	set	cnt2-1

udelay	macro	_tenthmicrosec,_consumedtcycles
	local	mill40=40000000
	IF	_tenthmicrosec > _consumedtcycles*mill40/FOSC
	tdelay	(FOSC*_tenthmicrosec+mill40-1)/mill40-_consumedtcycles

;====== I/O pins ===============

#define	DATA		gpio,6 	; in/out
#define	CLOCK		gpio,7 	; in/out

;====== Clock frequency ========

#define	FOSC		1843200	; customize this

;====== RAM area ===============
eebuf				; eeprom tmp buffer
eecnt				; eeprom byte counter
eeflags				; eeprom flags and bit counter
eeadr				; eeprom address

; 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	; 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
	clrf	eeflags			; initialise flags and bit count
	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
	bsf	CLOCK			; set SCL high
	clrc				; used later - done here for timing
	btfsc	DATA			; test SDA input for read
	bcf	CLOCK
	rlf	eebuf			; shift read data in or write data out
	movlw	0x20
	addwf	eeflags			; increment bitcount in b5-7
	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
	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)

	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
	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