PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I²C Eeprom 24LC16



Furtion
02.07.2007, 20:46
Hi,

ich habe wieder mal meine porbleme mit dem I²C Bus und Eeproms.
Ich habe hier mal ein bischen Code für den 24LC16 aber der funktionirt
nicht.



$regfile = "2313def.dat" ' specify the used micro
$crystal = 1000000 ' used crystal frequency
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space

Declare Sub Write_eeprom
Declare Sub Read_eeprom

Config Sda = Portd.1
Config Scl = Portd.0
Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portb.0 , Db6 = Portb.1 , Db7 = Portb.2 , E = Portb.3 , Rs = Portb.4
Dim I As Bit
Config Lcd = 16 * 2 'configure lcd screen
Dim Addres As Byte
Dim Wert As Byte 'clear the LCD display
Dim Lesen As Byte
Cls
Do


Cls

Locate 1 , 1
Lcd Chr(122) 'display this at the top line

If I = 0 Then
Addres = 1
Wert = 122
Call Write_eeprom
I = 1
Wert = 0
End If

If I = 1 Then
Call Read_eeprom
Locate 2 , 1
Lcd Chr(lesen)
End If



Loop


End





Sub Write_eeprom(byval Addres As Byte , Byval Block As Byte , Byval Wert As Byte)
I2cstart 'start condition
Waitms 1
I2cwbyte &B10100000 ' Bausteinadresse
Waitms 1
I2cwbyte Addres ' Adresse im IC
Waitms 1
I2cwbyte Wert ' Byte schreiben
Waitms 1
I2cstop ' Stopbedingung
Waitms 10 ' int. Schreibzeit abwarten
End Sub


Sub Read_eeprom(byval Addres As Byte , Byval Block As Byte , Byval Lesen As Byte)
I2cstart 'start condition
Waitms 1
I2cwbyte &B10100001 ' Bausteinadresse
Waitms 1
I2crbyte Lesen
Waitms 1
I2cstop ' Stopbedingung
Waitms 10 ' int. Schreibzeit abwarten
End Sub

Verbesserungsvorschläge sind wilkommen

linux_80
02.07.2007, 22:05
Hall,

das mit den Subs haut so nicht hin,
oben bei Declare muss die gleiche Zeile wie unten in der Zeile beim beginn der Sub stehen, mit allen Argumenten usw.
Die Argumente müssen dann auch beim Aufrufe mitgegeben werden !



Declare Sub Write_eeprom(byval Addres As Byte , Byval Block As Byte , Byval Wert As Byte)


Call Write_eeprom (Addres, Block , Wert )



Beim Read ist es evtl. auch besser eine Function zu machen, um den Wert zurückzugeben.

Hier hab ich die Tage in 'nem Thread auch irgendwo ein ähnliches Beispiel gelesen, musst mal suchen.

Furtion
03.07.2007, 17:09
Hi,

ich habe mal den Code modivieziert. Funktuniert aber auch nicht:




$regfile = "2313def.dat" ' specify the used micro
$crystal = 1000000 ' used crystal frequency
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space


Declare Sub Read_eeprom(byval Lesen As Byte)

Declare Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)

Config Sda = Portd.1
Config Scl = Portd.0
Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portb.0 , Db6 = Portb.1 , Db7 = Portb.2 , E = Portb.3 , Rs = Portb.4
Dim I As Bit
Config Lcd = 16 * 2 'configure lcd screen
Dim Addres As Byte
Dim Wert As Byte 'clear the LCD display
Dim Lesen As Byte
Cls
Waitms 1000
Addres = 1
Wert = 122

Locate 1 , 2
Lcd Chr(121)
Waitms 1000
Call Write_eeprom(addres , Wert )
I = 1
Wert = 0



Do



Locate 1 , 1
Lcd Chr(122) 'display this at the top line


If I = 1 Then
Call Read_eeprom(lesen)
Locate 2 , 1
Lcd "I = " ; Lesen
Locate 2 , 6
Lcd Chr(113)
Waitms 1000
Cls
End If



Loop


End





Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
Locate 1 , 3
Lcd Chr(122)
I2cstart 'start condition
Waitms 1
I2cwbyte &B10101110 ' Bausteinadresse
Waitms 1
I2cwbyte &B11111111 ' Adresse im IC
Waitms 1
I2cwbyte Wert ' Byte schreiben
Waitms 1
I2cstop ' Stopbedingung
Waitms 10
Locate 1 , 4
Lcd Chr(122) ' int. Schreibzeit abwarten
End Sub


Sub Read_eeprom(byval Lesen As Byte)
Locate 1 , 5
Lcd Chr(122)
I2cstart 'start condition
Waitms 1
I2cwbyte &B10100001 ' Bausteinadresse
Waitms 1
I2crbyte Lesen
Waitms 1
I2cstop ' Stopbedingung
Waitms 10
Locate 1 , 6
Lcd Chr(122) ' int. Schreibzeit abwarten
End Sub



Meine Fragen wären noch:

Sind 22k gegen Plus in Ordnung?
Gibt es ein Unterscheid zwischen Hard und Software I²C?

linux_80
03.07.2007, 19:26
Was benutzt Du genau für einen AVR, einen Tiny oder AT90 ?
Beim AT90 passt das $regfile, für den Tiny nicht !

Die haben beide kein TWI onboard, also bleibt erstmal nur Soft-I2C.
Der Tiny hat USI, das kann auch so tun wie I2C, beim AT90 bleibt nur die Softwarelösung.

Ich hab hier mal eine Lib gebaut, die das USI verwendet, dazu muss man aber auch die vorgesehen Ports verwenden !
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=26774

In Sachen Pullups wird sonst gerne etwas um die 10k verwendet, hab auch schon 4k7 gesehen, mit den 22k sollte es aber erstmal auch gehen.

Das mit dem Read haut so immer noch nicht hin, Du bekommst so den Wert nicht wieder ins Hauptprogramm !
Mach mal einen Function draus:



Declare Function Read_eeprom(byval Lesen As Byte) As Byte

und in der Function am ende:

Read_eeprom = Lesen
' oder gleich
I2crbyte Read_eeprom

Furtion
03.07.2007, 20:11
Hi,

also ich habe mal das mit der Funktion asprobiert, funktioniert aber auch nicht
Ich denke es liebt an der Verbindung. Also ich habe ein Atiny2313 und
benzute zurzeit nur das:

'Config Sda = Portd.1
'Config Scl = Portd.0

Ich denke mal das das falsch ist oder leige ich da falsch?

linux_80
03.07.2007, 21:23
Wenn Du den Tiny hast, musst Du eine andere Datei bei $regfile angeben, denn diese ist für den AT90 !
$regfile = "ATtiny2313.DAT"

Wenn Du Soft-I2C verwendest, ist es egal wo Du die anschliesst, das muss halt mit den Configs zusammenpassen.

Zeig mal wie das Programm jetzt ausschaut.

Furtion
04.07.2007, 13:32
Hi,

hat dieses Congig was mit dem Usi zu tun, da ich die Lib nicht verwede.

Hier mal das neue Prog mit der Funktion:




$regfile = "Attiny2313.dat" ' specify the used micro
$crystal = 1000000 ' used crystal frequency
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space
Waitms 1000
'$lib "i2c_usi.lbx"




Declare Function Read_eeprom(byval Lesen As Byte) As Byte
Declare Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
'Declare Sub Read_eeprom(byval Lesen As Byte )

Config Sda = Portd.1
Config Scl = Portd.0

'Config Scl = Portb.7 ' Ports fuer I2C-Bus
'Config Sda = Portb.5

Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portb.0 , Db6 = Portb.1 , Db7 = Portb.2 , E = Portb.3 , Rs = Portb.4
Dim I As Bit
Config Lcd = 16 * 2 'configure lcd screen
Dim Addres As Byte
Dim Wert As Byte 'clear the LCD display
Dim Lesen As Byte
Dim Read_eeprom As Byte 'clear the LCD display
I2cinit
Cls
Waitms 1000
Addres = 1
Wert = 122

Locate 1 , 2
Lcd Chr(121)
Waitms 1000
Call Write_eeprom(addres , Wert )


I = 1
Wert = 0



Do



Locate 1 , 1
Lcd Chr(122) 'display this at the top line


If I = 1 Then

Lesen = Read_eeprom(lesen)
Locate 1 , 5
Lcd Chr(122)
Locate 2 , 1
Lcd "I = " ; Lesen
Locate 2 , 6
Lcd Chr(113)
Waitms 1000
Cls
End If



Loop


End





Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
Locate 1 , 3
Lcd Chr(122)
I2cstart 'start condition
Waitms 1
I2cwbyte &B10101110 ' Bausteinadresse
Waitms 1
I2cwbyte &B11111111 ' Adresse im IC
Waitms 1
I2cwbyte Wert ' Byte schreiben
Waitms 1
I2cstop ' Stopbedingung
Waitms 10
Locate 1 , 4
Lcd Chr(122) ' int. Schreibzeit abwarten
End Sub

Function Read_eeprom(byval Lesen As Byte )
I2cstart 'start condition
Waitms 1
I2cwbyte &B10100001 ' Bausteinadresse
Waitms 1
I2crbyte Read_eeprom
Waitms 1
I2cstop ' Stopbedingung
Waitms 10
Lesen = Read_eeprom
End Function Read_eeprom

Furtion
04.07.2007, 13:45
Hi,

also ich habe hier noch mal die Lese/Schreib Vorgänge aus dem Datenblatt.
Nur das ich keinen Denkfehler in der Interpretation habe:

Lesen:

I2cstart 'start condition
Waitms 1
I2cwbyte &B10100001 ' Bausteinadresse
Waitms 1
I2crbyte Read_eeprom
Waitms 1
I2cstop ' Stopbedingung
Waitms 10


Schreiben:

I2cstart 'start condition
Waitms 1
I2cwbyte &B10101110 ' Bausteinadresse
Waitms 1
I2cwbyte &B11111111 ' Adresse im IC
Waitms 1
I2cwbyte Wert ' Byte schreiben
Waitms 1
I2cstop ' Stopbedingung
Waitms 10

linux_80
04.07.2007, 17:50
Hi,

mach mal die ganzen Wait's raus (zwischen I2cstart und stop), da schläft ja jeder Slave ein in der Zeit :-)

Das USI musst Du nicht verwenden, aber wenn Du es doch willst, musst Du auch die richtigen Ports dafür verwenden !
Du hast aber schon PortD.0 und 1 angeben, da ist kein USI, deshalb geht das nur per Software-I2C, ist aber kein Problem.

Wie läuft das jetzt, tut sich schon was ?

Furtion
04.07.2007, 18:38
Hi,

also es passiert nicht (außer das I immer 0 ist).

Wenn ich Read_eeprom aber auf 5 setze bleibt es 5. Daruas müsste
folgen, dass der Befehl "I2crbyte Read_eeprom" nichts bringt an Daten,
weder eine 0 noch was anderes(meine Überlegung wäre nämlich, was ist,
wenn das Byte zu wenigt ist( das Eeprom liefert mehr Daten als max. 255)).

Kann es sein, das ich einfach einen Befehl wie I2cinit vergessen habe?

Furtion
04.07.2007, 19:04
Hi,

ich habe mal so ein bisschen im DB:
http://www.kr.tuwien.ac.at/staff/egly/arachnae2/part_1/electron/datsheet/24lc16.pdf
gestöbert und mir ist eingefallen, dass in der Schrieb Sub:

1*Controllbyte(1010, Blockbytes 111, 0 für Schreiben) 1* (Word Addres)
1* Data.


Beim Lesen aber nur:

1*Controllbyte(1010, Blockbytes 111, 1 für Lesen) , 1* Data.

Also fehlt beim Lesen die Word Addres. Wenn das Eeprom den ganzen
Block ausgibt sind das mehr als 1 Byte.

Zusätzlich was bedeutet dieses "NACK" am ende des :
I2crbyte Lesen , Nack

Hier noch mal was aus der Wiki:
https://www.roboternetz.de/wissen/index.php/Bascom_und_I2C_EEprom

linux_80
04.07.2007, 21:46
Vergleich mal den Teil zum Auslesen, es muss erst die (Speicher-)Adresse dem Slave per Write übergeben werden, danach ein Restart, und dann erst kann man das Byte lesen. Da war ich auch nicht ganz bei der Sache, hab das übersehen. :-k :-b
Übernimm mal das Beispiel vom lesen in die Function.

Das NACK bedeuted hier, das dies das letzte Byte ist, und danach ein Stop kommt, man könnte hier auch weiter lesen (mit ACK), und mehr Bytes holen als nur eins. Die EEproms zählen die Adresse normalweise selber weiter.

linux_80
04.07.2007, 23:02
So,
in Sachen Read funktionierts so:


Declare Function Read_eeprom(byval Adress As Byte) As Byte

'...
Lesen = Read_eeprom(addres)
'...

Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
I2cstart 'start condition
I2cwbyte &HA0 ' Bausteinadresse
I2cwbyte Addres ' Adresse im IC
I2cwbyte Wert ' Byte schreiben
I2cstop ' Stopbedingung
End Sub

Function Read_eeprom(byval Adress As Byte )
I2cstart 'Start I2C
I2cwbyte &HA0 'sende Slave Adresse
I2cwbyte Adress 'sende Speicheradresse

I2cstart 'Start I2C
I2cwbyte &HA1 'sende Slave Adresse +1 für lesen
I2crbyte Read_eeprom , Nack 'lese Adresse vom EEprom
I2cstop 'Stop I2C
End Function Read_eeprom

Auch auf die I2C-Slaveadresse achten, ob die zu der Einstellung des 2416 passt.

Nach dem schreiben eines Wertes, ist das EEprom für ein paar ms nicht erreichbar weil es das Byte erst ins EEprom schreibt, hierfür erstmal ins DB schauen wie lange das ist, können ca. 5ms sein.
Das bedeuted, wenn man sofort nachdem man einen Wert ans EEprom übergeben hat gleich wieder etwas davon lesen will, muss man erst warten. Macht man sowieso was anderes, was länger dauert als diese Zeit, braucht man natürlich nicht extra zu warten.

Furtion
06.07.2007, 19:02
Hi,

die Freude ist groß es funzelt !!!

Erst mal danke der Chip ließt den Wert wunderbar aus.

Hier mal der Code, wenn jemand sich noch einmal mit dem Teil auseinander
setzt:




$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space
Waitms 1000
'$lib "i2c_usi.lbx"



Declare Function Read_eeprom(byval Adress As Byte) As Byte
Declare Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
'Declare Sub Read_eeprom(byval Lesen As Byte )

Config Sda = Portd.1
Config Scl = Portd.0

'Config Scl = Portb.7 ' Ports fuer I2C-Bus
'Config Sda = Portb.5

Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portb.0 , Db6 = Portb.1 , Db7 = Portb.2 , E = Portb.3 , Rs = Portb.4
Dim I As Bit
Config Lcd = 16 * 2 'configure lcd screen
Dim Addres As Byte
Dim Wert As Byte 'clear the LCD display
Dim Lesen As Byte
Dim Read_eeprom As Byte 'clear the LCD display
I2cinit
Cls
Waitms 1000
Addres = 1
Wert = 122

Locate 1 , 2
Lcd Chr(121)
Waitms 1000
Call Write_eeprom(addres , Wert )


I = 1
Wert = 0



Do



Locate 1 , 1
Lcd Chr(122) 'display this at the top line


If I = 1 Then

Lesen = Read_eeprom(addres)
Locate 1 , 5
Lcd Chr(122)
Locate 2 , 1
Lcd "I = " ; Lesen
Locate 2 , 6
Lcd Chr(113)
Waitms 1000
Cls
End If



Loop


End




Sub Write_eeprom(byval Addres As Byte , Byval Wert As Byte)
Locate 1 , 3
Lcd Chr(122)

I2cstart 'start condition
I2cwbyte &HA0 ' Bausteinadresse
I2cwbyte Addres ' Adresse im IC
I2cwbyte Wert ' Byte schreiben
I2cstop ' Stopbedingung
Waitms 10
Locate 1 , 4
Lcd Chr(122) ' int. Schreibzeit abwarten


End Sub

Function Read_eeprom(byval Adress As Byte )
I2cstart 'Start I2C
I2cwbyte &HA0 'sende Slave Adresse
I2cwbyte Adress 'sende Speicheradresse

I2cstart 'Start I2C
I2cwbyte &HA1 'sende Slave Adresse +1 für lesen
I2crbyte Read_eeprom , Nack 'lese Adresse vom EEprom
I2cstop
Waitms 10
Locate 2 , 1
Lcd "I = " ; Read_eeprom
Waitms 1000
'Stop I2C
End Function Read_eeprom




Eine Frage wäre noch, wie man 2 gleiche Eeproms ansteuert, an einem
Dart geht ja nicht, weil jedes Eeprom denkt es sei gemeint und in beiden
steht das gleiche.

Geht es villeicht mit:

Config Sda = Portd.1 #1
Config Scl = Portd.0 #1

Config Sda = Portd.3 #2
Config Scl = Portd.2 #2

I2cstart #1

Wie bei dem Soft-Uart oder gibt es da was anders?

linux_80
06.07.2007, 19:28
Wenn Du mehr gleiche ansprechen willst, musst Du nur die Adresse am EEprom einstellen (Jumper, oder fest verkabeln), wenn nix eingestellt ist, haben die die Adresse $A0.

Man kann 8 von diesen am Bus betreiben. Edit: (Stimmt nicht beim 24C16 !! siehe übernächsten Beitrag !)

Das ist der Vorteil von I2C, man braucht nur einen Anschluss am µC, da es ein Bus ist, alle Slaves kommen an diese beiden Leitungen, les mal die Artikel dazu im Wiki durch, und das Datenblatt der 2416 usw.

Furtion
06.07.2007, 19:35
Hi,

hat das was mit den A0,A1 und A2 Eingängen zu tun?

PS: Das ist mein 250 Beitrag^^

linux_80
06.07.2007, 21:26
Es hat mit den A wie Adresseingänge zu tun, aber Du musst ins DB schauen, ob das bei deinem EEprom auch geht (das richtige DB des Herstellers, nicht irgendeins [-X ).
Die 24C16 die ich hier habe, da geht es nicht, die haben keine Adressleitungen nach aussen !
Das heisst dann, man kannnur eins dieser Bausteine am I2C anschliessen !

Da das 24C16 2KByte hat, werden die unteren 3 Bit der I2C-Slaveadresse als die oberen 3 Bits der Speicheradresse im EEprom angesehen !
So ist es möglich mit der Slaveadresse die 8 Blöcke des EEproms anzusprechen.

PS:
mein 1965. Beitrag, obwohl wir fast gleichlang im RN eingetragen sind ;-)

Furtion
06.07.2007, 21:40
Hi,

also wenn man die nach ausengeführten Addres eingänge A0-A2 nicht
nehmen kann, und die anderen ( 1010 (Blockadresse) 0) für die Block-
addresse sind, was soll man dann nehmen um die irgenwie voneinander
zu unterschieden?


PS:

Nun ist das mein 252ter Eintrag^^

Furtion
06.07.2007, 21:44
Hi,

aber was ist, wenn man einmal den Soft und ein mal den Hard I2c nimmt,
dann könte man das doch irgendwie hinbiegen oder?

linux_80
06.07.2007, 21:54
Du willst also unbedingt mehrere solcher am AVR haben :-)
Dann könnte es mit Hard- und SoftI2C im Prinzip gehen, ich weiss aber nicht ob das Bascom so kann, eher nicht :-k
Denn die Ports werden beim compilieren von Bascom Fest ins Programm eingesetzt und können nicht so einfach geändert werden. Man müsste sich eigene Libs schreiben, die das unterstützen.

Oder Du nimmst grössere EEproms, die das können, zB. 24C32, aber dann hat man schon von vornherein mehr Platz in einem davon. Hiervon kann man dann 8 am I2C-Bus betreiben.

Furtion
20.07.2007, 17:22
Hi,

ich habe mir nun ein 24LC64 Eeprom gekauft.
Strucktur: 8kbits * 8
Speicherkapazität: 64kbits, 8 Byte
(http://www.farnell.com/datasheets/64540.pdf)

Meine Frage wäre, wenn man die A2, A1 und A0 gegen MAsse schaltet,
muss man dann in der Addresse 1 oder 0 angeben

linux_80
20.07.2007, 19:22
Hallo,
wenn Du die Adresseingänge auf Low legst, muss das beim senden der Adresse auch Low sein.

Also 10100000 -> $A0 ist die Schreibadresse

Steht auch in dem von Dir angegebenen Datenblatt.

Timo_AVR
20.07.2007, 21:48
Hallo, vielleicht kann mir hier jemand helfen...

ich hab ein ATMega32/ 8Mhz und ein 24C64A die Adresse des EEProm A0, A1, A2 liegen auf Masse (&HA0) Pullup von 10K liegen gegen 5V an Scl = Portc.0 und Sda = Portc.1 .
Zum testen benutze ich das Beispielprogramm
https://www.roboternetz.de/wissen/index.php/Bascom_und_I2C_EEprom
Ich gebe es auf ein Terminalprogramm aus anstatt auf das Display.

Beim Lesen bekomme ich aber nur die Werte 255
könnte mir jemand sagen was ich da Falsch mache?
Würde mich sehr freuen über eine Antwort.

Schönes Wochenende
Timo

linux_80
20.07.2007, 23:22
Hallo,

wenn nur 255 zurückkommt, sieht es so aus, als wenn sich der Slave nicht meldet.
Da Bascom nur das SoftwareI2C verwendet, und auch keine Abfrage enthalten ist, ob sich der Slave nach dem Start mit Adresse gemeldet hat, wird einfach irgendwas eingelesen, und das ist jeweils eine 255 !

Es sollte nach jedem senden eines Bytes die Variable ERR geprüft werden ob die 0 ist, nur dann kann man mit dem nächsten Byte weitermachen, ansonsten mit Stop die Übertragung beeenden.

Könnte so aussehen:

I2cstart
I2cwbyte Slaveadr
If Err = 0 Then
I2cwbyte &HEE
I2cwbyte &HE1
' ... usw.
End If
I2cstop


Das hilft noch nicht beim Problem, deswegen evtl. mal die Schaltung noch gernauer beschreiben, wie schauts mit GND aus usw.

Timo_AVR
20.07.2007, 23:54
Danke für die schnelle antwort.... hab den Fehler gefunden.
Bei dem Bausatz von Pollin ist der 24CXX Pin 7 WP (Write Protect) auf 5V verdrahtet... nun hab ich den Pin 7 des 24C64A umgebogen und nun gehts.

Danke nochmal.
Schönes Wochenende

Furtion
21.07.2007, 07:47
Hi,

sorry ich habe es im Datenblatt nicht gefunden.

linux_80
21.07.2007, 10:33
Was !
Nach was hast Du gesucht ?
Probiers mal mit Kapitel 3.6 Device Addressing