Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC asembler i2c routines for 10 or 8 MHz

Status
Not open for further replies.

traxonja

Advanced Member level 4
Joined
Apr 6, 2004
Messages
109
Helped
2
Reputation
4
Reaction score
1
Trophy points
1,298
Activity points
1,184
bsf trisa scl high

Hello,

Does anyone have i2c routines written in asembler for pic16f84a running on 10 or 8 MHz, THAT WORK?

I am trying to get these I have here to work but it's giving me bad time. As I can remember it worked on 4 MHz but at 10 MHz I get all crazy data where reading, so, I don't even know if it writes to the chip. First I need to write some data to it, and than later on read from it byte by byte. So, random read and random write procedures will be used, not sequential.

I will use 24c16, so I need 2 byte addresing.

So, please help, I need it to finish my "SMS Alarm" sys. :wink:


Best regards,
Trax
 

Re: PIC asembler i2c routines question

Could someone tell me what's wrong with this code? (using 4 mhz xtal)

I am using eeprom: 24lc08b (04 x 256 bytes or 08 kilobits, 1024 bytes / 1 kb) and PIC16F84a. It all works fine when I use 1 byte addressing but when I try to use 2byte addresing it doesn't work :( My eeprom has 1024 bytes so I need to address every single byte and to do that I need 2byte addresing? Right?

Here is the stuff I do when PIC starts to work:

Code:
		clrf	ADR_LO		; =0
		clrf	ADR_HI		; =0

		movlw	a'm'		;
		movwf	DAT_VAL		;
		CALL	RANDOM_WRITE;

		incf	ADR_LO, 1	; ++
		movlw	a'i'		; 
		movwf	DAT_VAL		;
		CALL	RANDOM_WRITE;

		incf	ADR_LO, 1	; ++
		movlw	a'n'		; 
		movwf	DAT_VAL		;
		CALL	RANDOM_WRITE;

		incf	ADR_LO, 1	; ++
		movlw	a'a'		; 
		movwf	DAT_VAL		;
		CALL	RANDOM_WRITE;

Here is the code (i2c routines I got somewhere from the net):

Code:
;********** i2c rutava karina ***********

RANDOM_WRITE:					; write DAT_VAL to 16-bit address ADR_HI and ADR_LO
		CALL	START
	
		BCF		STATUS, C		; send address byte
		RLF		DEV_ADR, W
		IORLW	h'A0'
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        MOVF	ADR_HI, W		; send high byte of address
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        MOVF	ADR_LO, W		; send low byte of address
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        MOVF	DAT_VAL, W		; send the actual data
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        CALL	STOP 
        RETURN

RANDOM_READ:					; reads data at location specified in ADR_HI & ADR_LO
								; returns result in W .. i u I_BYTE
		CALL	START
	
		BCF		STATUS, C		; send address byte - write
		RLF		DEV_ADR, W
	    IORLW	h'A0'
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        ;MOVF	ADR_HI, W		; send high and low bytes of address
        ;MOVWF	O_BYTE
        ;CALL	OUT_BYTE
        ;CALL	NACK

        MOVF	ADR_LO, W
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        CALL	START			; note there is no STOP

        BCF		STATUS, C
		RLF		DEV_ADR, W
        IORLW	h'A1'			; R/W set to one for read operation
        MOVWF	O_BYTE
        CALL	OUT_BYTE
        CALL	NACK

        CALL	IN_BYTE			; fetch the byte
        CALL	NACK

        CALL	STOP

		;TRAX: ionako mi treba da ostane u I_BYTE! - i need it to stay in i_byte varijable
		;MOVF	I_BYTE, W		; return the byte in W		
        RETURN

; The following routines are low level I2C routines applicable to most
; interfaces with I2C devices.

IN_BYTE							; read byte on i2c bus
		CLRF	I_BYTE
		MOVLW	d'8'
		MOVWF	_N				; set index to 8	
		CALL	HIGH_SDA		; be sure SDA is configured as input
IN_BIT
		CALL	HIGH_SCL		; clock high
		BTFSS	PORTA, SDA		; test SDA bit
		GOTO	IN_ZERO
		GOTO	IN_ONE

IN_ZERO
		BCF		STATUS, C		; clear any carry
		RLF		I_BYTE, F		; i_byte = i_byte << 1 | 0
		GOTO	CONT_IN
	
IN_ONE
		BCF		STATUS, C		; clear any carry
		RLF		I_BYTE, F		
		INCF	I_BYTE, F		; i_byte = (i_byte << 1) | 1
		GOTO	CONT_IN

CONT_IN
		CALL	LOW_SCL			; bring clock low
		DECFSZ	_N, F			; decrement index
		GOTO	IN_BIT
		RETURN

;;;;;;

OUT_BYTE:						; send o_byte on I2C bus
		MOVLW	d'8'
		MOVWF	_N
OUT_BIT:
		BCF		STATUS,C		; clear carry
		RLF		O_BYTE, F		; left shift, most sig bit is now in carry
		BTFSS	STATUS, C		; if one, send a one
		GOTO	OUT_ZERO
		GOTO	OUT_ONE

OUT_ZERO:
		CALL	LOW_SDA			; SDA at zero
		CALL	CLOCK_PULSE	
		CALL	HIGH_SDA
		GOTO	OUT_CONT

OUT_ONE:
		CALL	HIGH_SDA		; SDA at logic one
		CALL	CLOCK_PULSE
		GOTO	OUT_CONT

OUT_CONT:
		DECFSZ	_N, F			; decrement index
		GOTO	OUT_BIT
		RETURN	

;;;;;;
		
NACK:							; bring SDA high and clock
		CALL	HIGH_SDA
		CALL	CLOCK_PULSE
		RETURN

ACK:
		CALL	LOW_SDA
		CALL	CLOCK_PULSE
		RETURN

START:				
		CALL	LOW_SCL
		CALL	HIGH_SDA
		CALL	HIGH_SCL
		CALL	LOW_SDA			; bring SDA low while SCL is high
		CALL	LOW_SCL
		RETURN

STOP:
		CALL	LOW_SCL
		CALL	LOW_SDA
		CALL	HIGH_SCL
		CALL	HIGH_SDA		; bring SDA high while SCL is high
		CALL	LOW_SCL
		RETURN

CLOCK_PULSE:					; SCL momentarily to logic one
		CALL	HIGH_SCL
		CALL	LOW_SCL
		RETURN		

HIGH_SDA:						; high impedance by making SDA an input
		BSF		STATUS, RP0		; bank 1
		BSF		TRISA, SDA		; make SDA pin an input
		BCF 	STATUS, RP0		; back to bank 0
		CALL	DELAY_SHORT
		RETURN

LOW_SDA:
		BCF 	PORTA, SDA	
		BSF 	STATUS, RP0		; bank 1
		BCF 	TRISA, SDA		; make SDA pin an output
		BCF 	STATUS, RP0		; back to bank 0
		CALL 	DELAY_SHORT
		RETURN

HIGH_SCL:
		BSF 	STATUS, RP0		; bank 1
		BSF 	TRISA, SCL		; make SCL pin an input
		BCF 	STATUS, RP0		; back to bank 0
		CALL 	DELAY_SHORT
		RETURN

LOW_SCL:
		BCF 	PORTA, SCL
		BSF 	STATUS, RP0		; bank 1
		BCF 	TRISA, SCL		; make SCL pin an output
		BCF 	STATUS, RP0		; back to bank 0
		CALL 	DELAY_SHORT
		RETURN

;**** Pauze i2c

DELAY_SHORT:					; provides nominal 25 usec delay
		MOVLW 	d'5'
		MOVWF 	LOOP2
DELAY_SHORT_1:
		NOP
		DECFSZ 	LOOP2, F
		GOTO 	DELAY_SHORT_1
		RETURN 	

DELAY_LONG:
		MOVLW	d'250'			; 250 msec delay
DELAY_N_MS:
		MOVWF	LOOP1
OUTTER:
		MOVLW	d'110'			; close to 1.0 msec delay when set to .110
		MOVWF 	LOOP2
INNER:
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		DECFSZ	LOOP2, F		; decrement and leave result in LOOP2 
								; skip next statement if zero
		GOTO 	INNER
		DECFSZ 	LOOP1, F
		GOTO 	OUTTER
		RETURN


When I read the locations I've written I get the last byte that I wrote :x

When I comment the lines that work with ADR_HI everything works nice! But... I need the whole 1kb of the eeprom :roll:

I don't know what to do, i'm going CrAZy[/list]
 

hello,

I'm reading microchip's datasheets on 24xx08 and 24xx56 devices.. it seems that the 24xx08 does not accept two bytes of address data. however the 24xx56 device accepts them :)

they don't mentione anything about two-byte addresses in the 24xx08 datasheets. they mentione data "pages" that are to be selected in the first "control" byte :)

crazy stuph.

so, the .asm routine i've posted above actually work, but my chip doesn't support this kind of operation :(

never mind, i'll use the xx65 one.

it's been very nice talking to myself here, hope it's ok with mod.

best regards,
trax
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top