I2C problem. (pic + I2C eeprom)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

I2C problem. (pic + I2C eeprom)

Inlägg av Rocky_AL »

Har under gårdagen kodat en assemblerkod till en pic16f628a som har till uppgift att skicka och ta emot data från ett externt eeprom (M24C64-WBN6 8Kx8).
Problemet är att det inte verkar fungera alls, får bara tillbaka 0xFF. Antingen är det fel på skrivrutinen eller läsrutinen. Lägger upp hela koden. Jag har provat att lägga till lite kod till funktionen "ACK" som efter klockpulsen (SCL = från 1 till 0) kollar om SDA är låg eller inte och den var inte låg en enda gång under hela skriv eller läsningen (obs denna kodbit är borta i denna koden). Så det verkar vara något knas med skrivningen, om jag nu inte har missförstått hur man kollar om man fått ack eller inte.

Många kakor till den som klarar ut felet.

Kod: Markera allt

	list      p=16F628A           ; list directive to define processor
	#include <p16F628A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file


;Config
	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _HS_OSC

;Interupt
INT   CODE 0x0004
	goto Intr

;Reset
RST   CODE     0x0000
	goto     Init

;Variablar
	UDATA


;Delade variablar
	UDATA_SHR
	COUNT1				RES 1
	COUNT2				RES 1
	COUNT3				RES 1
	TEMP				RES 1
	EEPROM_ADR_H		RES 1
	EEPROM_ADR_L		RES 1
	EEPROM_DEV			RES 1
	EEPROM_DATA			RES 1


	Intr CODE
Intr
	retfie

	CODE
Init
;Define
	#Define		PORT_SDA		PORTA,0
	#Define		PORT_SCL		PORTA,1
	#Define		TRIS_SDA		TRISA,0
	#Define		TRIS_SCL		TRISA,1

;Stänger av analoga funktioner
	BANKSEL PORTA
	clrf PORTA
	BANKSEL CMCON
	movlw 0x07
	movwf CMCON

;Sätter variablar
	clrf COUNT1
	clrf COUNT2
	clrf COUNT3
	clrf TEMP
	clrf EEPROM_ADR_H
	clrf EEPROM_ADR_L
	clrf EEPROM_DEV
	clrf EEPROM_DATA

;Sätter portar
	BANKSEL TRISA
	clrf TRISA
	clrf TRISB
	BANKSEL PORTA
	clrf PORTA
	clrf PORTB

;Testloop, skickar ett värde till eepromet och läser sedan av samma värde från eepromet och lägger på PORTB
Start
	movlw 0x45
	movwf EEPROM_ADR_H
	movlw 0x3A
	movwf EEPROM_ADR_L
	movlw .0
	movwf EEPROM_DEV
	movlw b'10010110'
	call Rand_write

	movlw 0x45
	movwf EEPROM_ADR_H
	movlw 0x3A
	movwf EEPROM_ADR_L
	movlw .0
	movwf EEPROM_DEV
	movlw b'10010110'
	call Rand_read

	BANKSEL PORTB
	movf TEMP,W
	movwf PORTB
hej
	goto hej

Rand_read ;Läser innehållet på adressen EEPROM_ADR_H/EEPROM_ADR_L från minne nr. EEPROM_DEV och sparar i W-reg
	call EEPROM_Start ;Utför start condition
	bcf STATUS,C ;skapa första byten (1010ABC0) A,B,C är EEPROM_DEV, sista nollan är för write
	rlf EEPROM_DEV,F
	movlw b'10100000'
	addwf EEPROM_DEV,W
	call Send_byte ;skickar första byten
	call ACK ;acknowledge
	movf EEPROM_ADR_H,W ;skickar adressbitar 15-8
	call Send_byte
	call ACK
	movf EEPROM_ADR_L,W ;skickar adressbitar 7-0
	call Send_byte
	call ACK
	call EEPROM_Start
	bsf STATUS,C ;skapa första byten (1010ABC1) A,B,C är EEPROM_DEV, sista ettan är för read
	rlf EEPROM_DEV,F
	movlw b'10100000'
	addwf EEPROM_DEV,W
	call Send_byte ;Skickar device select
	call ACK
	call Read_byte
	call NOACK
	call EEPROM_Stop
	return

Read_byte ;Läser en byte och sparar i W-reg
	movlw .8
	movwf COUNT3 ;loopvariabel
Read_byte_0
	call SDA_H ;Gör SDA till en input
	call SCL_H
	BANKSEL PORTA
	btfss PORT_SDA
	goto Read_0
	goto Read_1
Read_0
	bcf STATUS,C
	rlf TEMP,F
	goto Read_count
Read_1
	bsf STATUS,C
	rlf TEMP,F
	goto Read_count
Read_count
                call SCL_L
	decfsz COUNT3,F ;kör loopen 8 gånger för att läsa en byte
	goto Read_byte_0
	movf TEMP,W ;loopen är klar, sparar svaret i W-reg
	return

Rand_write ;Skriver innehållet i W-reg på adress EEPROM_ADR_H/EEPROM_ADR_L till minne nr. EEPROM_DEV
	movwf EEPROM_DATA ;sparar W-reg i en temporär variabel.
	call EEPROM_Start ;Utför start condition
	bcf STATUS,C ;skapa första byten (1010ABC0) A,B,C är EEPROM_DEV, sista nollan är för write
	rlf EEPROM_DEV,F
	movlw b'10100000'
	addwf EEPROM_DEV,W
	call Send_byte ;skickar första byten
	call ACK ;acknowledge
	movf EEPROM_ADR_H,W ;skickar adressbitar 15-8
	call Send_byte
	call ACK
	movf EEPROM_ADR_L,W ;skickar adressbitar 7-0
	call Send_byte
	call ACK
	movf EEPROM_DATA,W ;skickar databyten
	call Send_byte
	call ACK
	call Delay_long ;väntar 10ms för intern writecykel
	return

Send_byte ;Skickar innehållet i W-reg till det externa eepromet
	movwf TEMP
	movlw .8
	movwf COUNT3 ;loopvariabel
Send_byte_0
	rlf TEMP,F ;flyttar ut högsta byten och kollar om den är 1 eller 0
	btfss STATUS,C
	goto Send_0
	goto Send_1
Send_0 ;klocka ut en nolla till eepromet
	call SDA_L
	call SCL_H
	call SCL_L
	goto Send_count
Send_1 ;klocka ut en nolla till eepromet
	call SDA_H
	call SCL_H
	call SCL_L
	goto Send_count
Send_count
	decfsz COUNT3,F ;kör loopen 8 gånger för att skicka en byte
	goto Send_byte_0
	return

EEPROM_Start ;SDA 1-0 medan SCL = 1
	call SCL_L ;Säkerhetsåtgärd ifall SCL råkar vara 1
	call SDA_H
	call SCL_H
	call SDA_L
	call SCL_L
	return

EEPROM_Stop ;SDA 0-1 medan SCL = 1
	call SDA_L
	call SCL_H
	call SDA_H
	call SCL_L
	return

SDA_H ;SDA = input
	BANKSEL TRISA
	bsf TRIS_SDA
	call Delay_short
	return

SDA_L ;SDA = output (0)
	BANKSEL PORTA
	bcf PORT_SDA
	BANKSEL TRISA
	bcf TRIS_SDA
	call Delay_short
	return

SCL_H ;SCL = input
	BANKSEL TRISA
	bsf TRIS_SCL
	call Delay_short
	return

SCL_L ;SDA = output (0)
	BANKSEL PORTA
	bcf PORT_SCL
	BANKSEL TRISA
	bcf TRIS_SCL
	call Delay_short
	return

ACK ;klockar ut en acknowledge
	call SDA_H
	call SCL_H
	call SCL_L
	return


NOACK ;klockar ut en acknowledge
	call SDA_L
	call SCL_H
	call SCL_L
	return



Delay_short
			;46 cycles
	movlw	0x2F
	movwf	COUNT1
Delay_short_0
	decfsz	COUNT1, f
	goto	Delay_short_0

			;4 cycles (including call)
	return


Delay_long
			;249993 cycles
	movlw	0x4E
	movwf	COUNT1
	movlw	0xC4
	movwf	COUNT2
Delay_long_0
	decfsz	COUNT1, f
	goto	$+2
	decfsz	COUNT2, f
	goto	Delay_long_0

			;3 cycles
	goto	$+1
	nop

			;4 cycles (including call)
	return

	end
Senast redigerad av Rocky_AL 21 september 2008, 23:14:11, redigerad totalt 2 gånger.
sodjan
EF Sponsor
Inlägg: 43249
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Det löser kanske inte problemet med din 628A, men har du
funderat på att använda än modell med hårdvarustöd för I2C ?
T.ex F88 (somma pinout som 628A).
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

Kollat som hastigast...
du verkar trixa med bara TRIS för klockpulsen
Om du inte har extern pull up så måste du se till att din clock blir
"1".
Är dålig på PIC och intern pull up.. men har du kollat att det
verkligen blir någon klockpuls

Swech
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Glömde säga att jag har pull-up motstånd på både SDA och SCL (10kΩ), så när jag sätter portarna till input så blir det "1". Har kollat med oscilloskop men det är analogt så man hinner knapt se något, men man hinner helt klart se lite fyrkantsvågor. Skulle vara jättelätt att se vad felet var om man hade ett digitalt oscilloskop eftersom man kan studera vågorna i efterhand, synd bara att de ska kosta så mycket.

Och jag vill kunna använda dessa funktioner på picar utan inbyggt I2C. Dessutom kan man alltid välja portar fritt om man gör egna funktioner.

edit: Om någon har färdig assemblerkod för detta så skulle även det lösa problemet. picen körs i 20MHz.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

kör inte så fort då :D
Det går att köra riktigt långsamt med i2c också....
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

När är det man ska kolla om man får ett ack egentligen? Jag vet att det är klockpuls nr. 9 man ska få ett ack, men under vilken del?

1. Innan klockpuls nr. 9 går från Låg till hög
2. När klockpuls nr. 9 är på stadig hög nivå.
3. Efter klockpuls nr. 9 har gått från hög till låg nivå.

Jag antar att picen (master) ska sätta SDA som input och sedan läsa av värdet på SDA. Om den är noll så har man fått ett ack, om den är ett så har man inte fått ett ack (förutsatt att man har pull-up). Rätta mig om jag har fel.
Användarvisningsbild
Icecap
Inlägg: 26636
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Jag har testat att göra en IIC i mjukvara, det var egentligen inte så speciellt besvärligt men jag ogillar den buss generellt.

ACK får man vid att slaven HÅLLER SCL låg till den är klar, mastern ger alltså "som vanligt" en SCL och släpper den och kollar när den blir hög.

Ibland går det fort och då hinner slaven släppa innan/samtidig som mastern.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Vänta nu, ska inte slaven hålla SDA låg och inte SCL. SCL är ju klockpulsen.
Användarvisningsbild
Icecap
Inlägg: 26636
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Oj... just det. Ett tag sedan jag pillade med IIC...
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Blir bara mer och mer förvirrad med det här, jag hhittar verkligen inget fel i koden, men det vägrar fungera.
Användarvisningsbild
Marta
EF Sponsor
Inlägg: 7461
Blev medlem: 30 mars 2005, 01:19:59
Ort: Landskrona
Kontakt:

Inlägg av Marta »

För att testa med ett vanligt scope så gör Du ett speciellt testprogram som skickar den sekvens som skall testas om oc om igen med så hög hastighet som det är möjligt så Du får en stabil bild. Om det behövs så pulsa en extra utgång varje gång sekvensen startar så scopet kan triggas stabilt. Sedan ka Du bläddra igenom förloppet med fördröjd tidbas. Har Du ingen DTB så flytta triggpulsgenereringen. Denna metod fungerar oftast mycket bra.
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

kan detta vara något?

To read starting at a particular address in the EEPROM, a combined message is used. After a START, the master first writes that chip's bus address with the direction bit clear ("write") and then the two bytes of EEPROM data address. It then sends a (repeated) START and the EEPROM's bus address with the direction bit set ("read"). The EEPROM will then respond with the data bytes beginning at the specified EEPROM data address -- a combined message, first a write then a read.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Inlägg av Rocky_AL »

Precis så min rand_read fungerar. Det jobbigaste med allt detta är att jag inte kan veta om det är läs eller skrivfunktionen som är fel.
Ingen som har färdig kod eller kan prova att först använda min skrivfunktion och sedan använda en redan fungerande läsfunktion för att se om något har hänt?
Stranne
Inlägg: 48
Blev medlem: 28 maj 2008, 09:52:31
Ort: Stockholm

Inlägg av Stranne »

Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Inlägg av Swech »

Har du valt rätt ID på EE minnet? Den har väl 3 pinnar för detta...
Skriv svar