PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme mit 24C65



Sauerbruch
16.04.2011, 11:26
Liebe Experten,

seit ein paar Tagen mache ich erste Experimente mit externen EEPROMs, und habe mir hierzu einen 24C65 gekauft.

Um mit dieser neuen Materie vertraut zu werden, wollte ich als erstes einfach nur ein einziges Byte an einem bestimmten Speicherplatz ablegen, es anschließend wieder auslesen und auf einem LCD anzeigen.

Mein Code hierfür sieht so aus:


$regfile = "m8def.dat"
$crystal = 1000000

Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.6 , Db5 = Portd.5 , Db6 = Portb.7 , Db7 = Portb.6 , E = Portd.7 , Rs = Portb.0
Initlcd
Cursor = Off
Cls

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

Dim Z As Byte

Do

Cls
Locate 1 , 1
Lcd "Schreiben:"
Waitms 500

I2cstart
I2cwbyte &B10100000 '24C65, A2-A0 = 0, Schreiben
I2cwbyte &B00000000 'H-byte Speicheradresse
I2cwbyte &B00000010 'L-Byte Speicheradresse
I2cwbyte 5
I2cstop

Locate 1 , 1
Lcd "Lesen:"
Waitms 500

I2cstart
I2cwbyte &B10100000 '24C65, A2-A0 = 0, Schreiben
I2cwbyte &B00000000 'H-byte Speicheradresse
I2cwbyte &B00000010 'L-Byte Speicheradresse
I2cstart
I2cwbyte 10100001 '24C65, A2-A0 = 0, Lesen
I2crbyte , Z , Nack
I2cstop

Cls
Locate 1 , 1
Lcd Z
Wait 1

Loop

Allerdings läuft alles in extremster Zeitlupe ab - Zwischen den LCD-Meldungen "Lesen" und "Schreiben" vergehen Minuten (!), und für die ausgelesene Variable Z wird 255 angezeigt (obwohl der Wert "5" in den Speicher geschrieben werden soll).

Die Taktfrequenz stimmt, ich habe versuchsweise mal eine LED-Blinksequenz mit 1Hz vor die Do-Loop-Schleife gesetzt, die läuft korrekt ab.

Beim 24C65 habe ich die Adresseingänge A2-A0 auf GND gelegt, und die SDA-Leitung über 2k2 auf +5V. Interessanterweise sehe ich mit dem Oszi keinerlei "Traffic" auf den SDA- und SCL-Leitungen. Ich habe SDA und SCL auch schon mal auf andere Ports des Mega8 gelegt - genau das gleiche. Das DDR-Register des SCL-Ausganges habe ich auch versuchsweise mal auf 1 gesetzt (obwohl das ja mit "I2CINIT" schon erledigt sein sollte) - ebenfalls ohne Erfolg.

Hat jemand irgendeine Idee, was ich falsch mache??

mat-sche
17.04.2011, 08:59
Moin!

Ich habe erfolgreich einen TWI EEprom so angesteuert:




$regfile = "m32def.dat"
$crystal = 14745600
$baud = 9600
$hwstack = 228
$swstack = 228
$framesize = 128
$lib "i2c_twi.lbx" 'TWI-Lib für Hardware I2C

Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7 , E = Portc.3 , Rs = Portc.2 ' Pinbelegung "LCD-Port)"
Config Lcd = 16 * 2
'(----------------- LCD Display an Port c =>Conector SV9 ------------------------
Config Lcdpin = Pin , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2 , E = Portc.6 , Rs = Portc.7 ' Pinbelegung "LCD-Port)"
' SV9 6 5 4 3 7 8 ' Pinbelegung SV9 Board
Config Lcd = 20 * 4
Cursor Off Noblink
')
'------------------ DS1820 on pinA 0 (pull up)----------------------------------

Config 1wire = Portd.4 '

Declare Sub Read1820
Declare Sub Crcit
Declare Sub Temperature

Dim Bd(9) As Byte
Dim I As Byte , Tmp As Byte
Dim Crc As Byte
Dim T As Integer , Temp As Single
Dim V As Byte , A As Word
'

'----------------- Config TWI --------------------------------------------
Config Twi = 400000 ' Init TWBR und TWSR
' TWI gleich einschalten, das macht Bascom ansonsten erst beim I2CStart !
Twcr = &B00000100 ' nur TWEN setzen
'----------------- Eeprom Anschlüße --------------------------------------------
Config Sda = Portc.1 'SDA und SCL als Hardware-TWI definieren
Config Scl = Portc.0
Portb.2 = 1 'Pullups für Taster ein
Portb.3 = 1
Const E_prom_w = &HA0 'Epromadresse 160 (A1/2/3 auf GND) schreiben
Const E_prom_r = &HA1 'Epromadresse 160+1 für schreiben der Daten

'EEprom 24C32,24C128, 24C256 haben im Gegensatz zu den 24C16'er einen Adressraum von zwei Byte.
'Weil grösserer Speicherbereich im EEprom vorhanden ist Darum muss man den Adressbereich in High und Low Adressbereich
'trennen. (Zuerst High-Adressbereich schreiben und dann Low-Adressbereich)
Dim E_ah As Byte 'höherwertiges Byte der SpeicherAdresse (Adresse=Word)
Dim E_al As Byte 'niederwertiges Byte der SpeicherAdresse (Adresse=Word)
Dim E_addr As Word 'SpeicherAdresse EEprom
Dim E_dat_r As Byte 'Daten der zu lesenen Daten aus EEprom
Dim E_dat_w As Byte 'Daten der zu schreibenen Daten ins EEprom
Dim Temperature As Single
Dim Storetemp(4) As Byte At Temperature Overlay 'Maske: weise die 4Byte aus dem Single(Temperature) dem
'Storetemp(1-4) zu

Declare Sub E_write(byval E_addr As Word , E_dat_w As Byte) 'Sub zum schreiben in EEprom mit Übergabe einer Kopie der Variable (Eaddr/E_dat_w)
Declare Sub E_read(byval E_addr As Word , E_dat_r As Byte) 'Sub zum lesen aus EEprom
Declare Sub 24lc256_test


'------------------ Startbildschirm --------------------------------------------




Cls 'clear the LCD display
Locate 1 , 1
Lcd "Speicherung 1xTemp." 'display this at the 1.line

Locate 2 , 1 'display this at the 2. line
Lcd " im EEprom 24c65 "

Locate 3 , 1 'display this at the 3.line
Lcd "Taster S7 speichern"

Locate 2 , 1 'display this at the 4.line
Lcd "Taster S8 auslesen"

Wait 5
Cls
'------------------ Hauptprogramm ----------------------------------------------
Do
Temperature

If Pinb.3 = 0 Then Call 24lc256_test
If Pinb.2 = 0 Then

Cls
Locate 2 , 1
Lcd Storetemp(1) ; " " ; Storetemp(2) ; " " ; Storetemp(3) ; " " ; Storetemp(4) ; ""; 'Anzeige der 4 einzelnen Bytes aus dem Overlay der Temperatur
Locate 3 , 1
Call E_read(&H10 , E_dat_r) 'Aufruf der Subroutine zum lesen der einzelnen Bytes
Call E_read(&H11 , E_dat_r) 'E_read(&H10 , E_dat_r)
Call E_read(&H12 , E_dat_r) ' &H10 - zu lesende Adresse aus EEprom
Call E_read(&H13 , E_dat_r) ' E_dat_r - Daten aus dem Speicherort
Lcd "Speicherwert= " ; Temperature ; "" 'Anzeige der Temperature zusammengesetzt aus dem Overlay: Storetemp(4)
Locate 2 , 1 : Lcd "Read i2c error= " ; Err 'Err: Daten korrekt gesendet? 0=i.o.; 1=bad
End If




Loop

End


'////////////////// Subroutinen ////////////////////////////////////////////////
Sub Temperature ' actual measuring

1wwrite &HCC : 1wwrite &H44 ' start measure
Waitms 300 ' wait for end of conversion
Read1820
Deflcdchar 0 , 6 , 9 , 9 , 6 , 32 , 32 , 32 , 32 ' replace ? with number (0-7) ' read 9 bytes
Locate 1 , 1 : Lcd "Temp= "
' sensor present, check CRC
Locate 1 , 7 : Lcd Fusing(temp , "#.##") ; Chr(0) ; "C"

End Sub

'//////////////////////////////////////////////////////////////////////////////
Sub Read1820 ' reads sensor ans calculate
' T for 0.1 C
1wreset ' reset the bus
1wwrite &HCC ' read internal RAM
1wwrite &HBE ' read 9 data bytest
Bd(1) = 1wread(9) ' read bytes in array
1wreset ' reset the bus


T = Makeint(bd(1) , Bd(2))
T = T / 2
Temp = Bd(8) - Bd(7)
Temp = Temp / Bd(8)
Temp = T + Temp
Temp = Temp - 0.25

End Sub
'///////////////////////////////////////////////////////////////////////////////'
Sub 24lc256_test


Temperature = Temp
Call E_write(&H10 , Storetemp(1)) 'Call I2C Routine zum schreiben und übergebe dabei die Adresse
Call E_write(&H11 , Storetemp(2)) ' im EEprom und den Wert der zu speichern ist
Call E_write(&H12 , Storetemp(3))
Call E_write(&H13 , Storetemp(4))

End Sub
'///////////////////////////////////////////////////////////////////////////////
' Routine to write the 24C65

Sub E_write(byval E_addr As Word , E_dat_w As Byte )
E_ah = High(e_addr) 'E_ah = EEprom high Adressbyte der jeweiligen Word-Adresse (H&10)
E_al = Low(e_addr) 'E_ah = EEprom low Adressbyte der jeweiligen Word-Adresse (H&10)
I2cstart 'Start I2C
I2cwbyte E_prom_w 'Sende Slave Adresse
I2cwbyte E_ah 'Sende Speicheradresse High
I2cwbyte E_al 'Sende Speicheradresse Low
I2cwbyte E_dat_w 'Sende Daten Werte
I2cstop 'Stop I2C
Waitms 10
End Sub

'///////////////////////////////////////////////////////////////////////////////
' Routine to read the 24C65

Sub E_read(byval E_addr As Word , E_dat_r As Byte)
E_ah = High(e_addr)
E_al = Low(e_addr)
I2cstart
I2cwbyte E_prom_w
I2cwbyte E_ah
I2cwbyte E_al
I2cstart
I2cwbyte E_prom_r
I2crbyte E_dat_r , Nack
I2cstop '
End Sub


probier es mal damit.
Gruß MAT

Michael
17.04.2011, 13:39
Hallo Sauerbruch,


Beim 24C65 habe ich die Adresseingänge A2-A0 auf GND gelegt, und die SDA-Leitung über 2k2 auf +5V.
Bei mir funktioniert I2C nur, wenn auch die SCL Leitung einen Pullup bekommt.

Vermutlich stört auch das zusätzliche Komma:
I2crbyte , Z , Nack

Gruß, Michael

Sauerbruch
17.04.2011, 14:18
Bei mir funktioniert I2C nur, wenn auch die SCL Leitung einen Pullup bekommt.

Oh Mann - wie findet man denn sowas heraus?

In allen mir bekannten Quellen ist immer nur der PullUp für SDA erwähnt...

Aber das war die Lösung - jetzt bleibt das Programm schon mal nicht mehr in den I2C-Sequenzen hängen, ich sehe saubere Signale auf beiden Leitungen, und kann mich jetzt weiteren Feinheiten wie dem 2. Komma zuwenden :-)

Besten Dank für den Tipp!

Daniel