please dont rip this site

PIC Microcontoller Input / Output Method

for I2C

by Andrew D. Vassallo [snurple@hotmail.com]

Here are some bit-banged I^2C routines that should be easy to understand. They are fairly optimized, with near-minimum instruction count allowable for 4MHz operation.

Tested/bulletproof at 4MHz. Bank switching is provided. Routines exit with Bank 0 selected.

;------------------------------------------------------------------------
;
; I^2C master send/receive routines for 24Cxx EEPROM memory chips
; by Andrew D. Vassallo
;
; email: snurple@hotmail.com
;
; Timing set for 4MHz clock, 4.7K pullup resistors to SDA and SCL lines.
; Checks provided for failed ACK during EEPROM write access.
; Optimized for speed and clarity of function.
; Full comments provided.
; Bank switching correct.
;
;------------------------------------------------------------------------

;------ NOTE: Locate all variables in Bank 1!!
CBLOCK
	GenCount	; generic counter/temp register (use with caution)
	Mem_Loc		; EEPROM memory address to be accessed
	Data_Buf	; byte read from EEPROM is stored in this register
	OutputByte	; used for holding byte to be output to EEPROM
	flags		; flag bit register
ENDC


;------ Define port pins: RB2=SDA=data, RB1=SCL=clock
;------ Pins are connected via 4.7K pullup resistors for passive control
;------ Any port pins can be used.
#define	SDA	TRISB, 2
#define	SCL	TRISB, 1


;------ The memory address is predefined as Mem_Loc coming in to this routine to read from EPROM.
;------ Note that using the 24Cxx requires an address for bits <1:3> for control bytes.  For a one-
;------ memory circuit used here, just use address 000.  This routine uses "random addressing."
;------ This code has been optimized for speed at 4MHz, assuming Temperature is between -40 and +85 deg. C.
;
; Call with: EEPROM address in Mem_Loc
; Returns with: byte in Data_Buf
ReadEPROM
		bcf	STATUS, RP0
		movf	PORTB, 0		; for EEPROM operation,
		andlw	0xF9			; load zero into RB1 and RB2
		movwf	PORTB			; for passive control of bus
		bsf	STATUS, RP0		; select Bank 1 for TRISB access (passive SCL/SDA control)
		bsf	SDA			; let SDA line get pulled high
		bsf	SCL			; let SCL line get pulled high
		bcf	SDA			; START - data line low
		movlw	0xA0			; send "dummy" write (10100000) to set address
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine		; NOTE: MUST USE "RETURN" FROM THERE
		movf	Mem_Loc, 0
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine
		bcf	SCL			; pull clock line low in preparation for 2nd START bit
		nop
		bsf	SDA			; pull data line high - data transition during clock low
		bsf	SCL			; pull clock line high to begin generating START
		bcf	SDA			; 2nd START - data line low
		movlw	0xA1			; request data read from EPROM (read=10100001)
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine
;------ Note that Byte_Out leaves with SDA line freed to allow slave to send data in to master.
		call	Byte_In
		movf	Data_Buf, 0		; put result into W register for returning to CALL
		bcf	SCL			; extra cycle for SDA line to be freed from EPROM
		nop
		bcf	SDA			; ensure SDA line low before generating STOP
		bsf	SCL			; pull clock high for STOP
		bsf	SDA			; STOP - data line high
		bcf	STATUS, RP0		; leave with Bank 0 active as default
		return

;------ Save each byte as it's written (not page write mode).
;------ We can speed this up to ~1.5ms for fast page write capable EEPROMs, but in case we want to
;------ use another slower memory chip, the default is 10ms delay per write.
;
; Call with:  EEPROM address in Mem_Loc, byte to be sent in Data_Buf
; Returns with:  nothing returned
WriteEPROM
		bcf	STATUS, RP0
		movf	PORTB, 0		; for EEPROM operation,
		andlw	0xF9			; load zero into RB1 and RB2
		movwf	PORTB			; for passive control of bus
		bsf	STATUS, RP0		; select Bank 1 for TRISB access (passive SCL/SDA control)
		bsf	SDA			; ensure SDA line is high
		bsf	SCL			; pull clock high
		bcf	SDA			; START - data line low
		movlw	0xA0			; send write (10100000) to set address
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine		; NOTE: MUST USE "RETURN" FROM THERE
		movf	Mem_Loc, 0
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine
		movf	Data_Buf, 0		; move data to be sent to W
		call	Byte_Out
		btfsc	flags, 0
		goto	Error_Routine
		bcf	SCL			; extra cycle for SDA line to be freed from EPROM
		nop
		bcf	SDA			; ensure SDA line low before generating STOP
		bsf	SCL			; pull clock high for STOP
		bsf	SDA			; STOP - data line high
		call	Delay10ms		; 10ms delay max. required for EPROM write cycle
		bcf	STATUS, RP0		; leave with Bank 0 active by default
		return

;------ This routine reads one byte of data from the EPROM into Data_Buf
Byte_In
		clrf	Data_Buf
		movlw	0x08			; 8 bits to receive
		movwf	GenCount
ControlIn
		rlf	Data_Buf, 1		; shift bits into buffer
		bcf	SCL			; pull clock line low
		nop
		bsf	SCL			; pull clock high to read bit
		bcf	STATUS, RP0		; select Bank 0 to read PORTB bits directly!
		btfss	SDA			; test bit from EPROM (if bit=clear, skip because Data_Buf is clear)
		goto	$+3
		bsf	STATUS, RP0		; select Bank 1 to access variables
		bsf	Data_Buf, 0		; read bit into 0 first, then eventually shift to 7
		bsf	STATUS, RP0		; select Bank 1 to access variables
		decfsz	GenCount, 1
		goto	ControlIn
		return

;------ This routine sends out the byte in the W register and then waits for ACK from EPROM (256us timeout period)
Byte_Out
		movwf	OutputByte
		movlw	0x08			; 8 bits to send
		movwf	GenCount
		rrf	OutputByte, 1		; shift right in preparation for next loop
ControlOut
		rlf	OutputByte, 1		; shift bits out of buffer
		bcf	SCL			; pull clock line low
		nop
		btfsc	OutputByte, 7		; send current "bit 7"
		goto	BitHigh
		bcf	SDA
		goto	ClockOut
BitHigh		
		bsf	SDA
ClockOut	
		bsf	SCL			; pull clock high after sending bit
		decfsz	GenCount, 1
		goto	ControlOut
		bcf	SCL			; pull clock low for ACK change
		bsf	SDA			; free up SDA line for slave to generate ACK
		nop
		nop
		nop				; wait for slave to pull down ACK
		bsf	SCL			; pull clock high for ACK read
		clrf	GenCount		; reuse this register as a timeout counter (to 256us) to test for ACK
WaitForACK
		bsf	STATUS, RP0		; select Bank1 for GenCount access
		incf	GenCount, 1		; increase timeout counter each time ACK is not received
		btfsc	STATUS, Z
		goto	No_ACK_Rec
		bcf	STATUS, RP0		; select Bank0 to test SDA PORTB input directly!
		btfsc	SDA			; test pin. If clear, EEPROM is pulling SDA low for ACK
		goto	WaitForACK		; ...otherwise, continue to wait
		bsf	STATUS, RP0		; select Bank1 as default during these routines
		bcf	flags, 0		; clear flag bit (ACK received)
		return


;------ No ACK received from slave (must use "return" from here)
;; Typically, set a flag bit to indicate failed write and check for it upon return.
No_ACK_Rec
		bsf	flags, 0		; set flag bit
		return				; returns to Byte_Out routine (Bank 1 selected)


;------ No ACK received from slave.  This is the error handler.
Error_Routine
; Output error message, etc. here
		bcf	STATUS, RP0		; select Bank0 as default before returning home
		return				; returns to INITIAL calling routine


Delay10ms
	movlw	0x0A
	movwf	GenCount
Delay_Start
	nop
	movlw 0x07			; 249 cycles * 4us per cycle + 5us = 1.000ms
Delay
	addlw 0x01
	btfss STATUS, Z
	goto Delay
	decfsz GenCount, 1
	goto Delay_Start
	return

  

PICList post "IIC Routines - giving, not needing"

Questions:

Interested:

Comments:


file: /Techref/microchip/i2c-dv.htm, 11KB, , updated: 2013/11/25 14:51, local time: 2024/11/17 17:33, owner: ADV--A41,
TOP NEW HELP FIND: 
3.140.188.185:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://linistepper.com/techref/microchip/i2c-dv.htm"> PIC Microcontoller Input / Output Methods for I2C</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.


Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?