Forum: Mikrocontroller und Digitale Elektronik EEPROM mit TWI Schnittstelle beschreiben und lesen


von Jack (Gast)


Lesenswert?

Hallo,
bekomme die TWI nicht zum Laufen. Nutze ein ATmega644P. Hab den Code aus 
dem Datenblatt. Sehe auch nichts auf dem Osci.

Bitte um Hilfe.
MFG

1
//eeprom_twi_tests:
2
int SLA_W = 0x85;
3
int DATA = 0xBC;
4
5
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //uC als Master definieren, START condition
6
while (!(TWCR & (1<<TWINT))); //warten und prüfen ob richtig gesendet
7
if ((TWSR & 0xF8) != TW_START); //Wenn anderer Wert als beim senden --> Error
8
  //error?
9
TWDR = SLA_W; //SLA_W sendet die Adresse
10
TWCR = (1<<TWINT) | (1<<TWEN); //Lösche TWINT bit im TWCR um das Senden der Adresse zu beginnen
11
while (!(TWCR & (1<<TWINT))); //Warten auf TWINT Flag, bedeutet SLA_W wurde gesendet und ACK/NACK wurde empfangen
12
if((TWSR & 0xF8) != TW_MT_SLA_ACK); //Prüfe TWI Status Register, wenn status anders als im MT_SLA_ACK -> Error 
13
  //error?
14
TWDR = DATA; //Data -> Daten in das TWDR Register geladen werden sollen
15
TWCR = (1<<TWINT) | (1<<TWEN); //Lösche TWINT bit in TWCR zum starten der Übertragung
16
while (!(TWCR & (1<<TWINT))); //Warte auf TWINT Flag, bedeutet DATA wurde gesendet und ACK/NACK wurde empfangen
17
uart_puts("zweiter error weiter");
18
if ((TWSR & 0xF8) != TW_MT_DATA_ACK); //Überprüfe Wert vom TWI Status Register
19
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition

von Stephan W. (sir_wedeck)


Lesenswert?

Hi,

den Code haste scheinbar richtig abgetippt, also muss der Fehler wo 
anders sein! Zeig mal das restliche Programm bzw. mach ein mini Prog. 
auf, damit wir es testen können.

Schaltplan wäre auch nicht schlecht, sowie der Name des EEProms das du 
ansprechen willst.

Schreibe bitte NIE LEERE! IF - Anweisungen in dein Code, das ist nicht 
gut!!!!
1
if ((TWSR & 0xF8) != TW_START) //Wenn anderer Wert als beim senden --> Error
2
  uart_puts("Keine TW-Start erhalten!");
3
....
4
if((TWSR & 0xF8) != TW_MT_SLA_ACK) //Prüfe TWI Status Register, wenn status anders als im MT_SLA_ACK -> Error 
5
  uart_puts("Keine TW_MT_SLA_ACK erhalten!");
6
....

für kleine Testprogs. ist es immer gut kleine DebugMess. zu senden! Im 
richtigen Code, werden dann aber Return-Val. verwendet!

Stephan

von Jack (Gast)


Lesenswert?

Hallo,
also ein Teil funktioniert jetzt. Am Osci scheint auch alles in Ordnung 
zu sein, das schreiben gibt mir KEINE Fehler aus, also alle ACK's werden 
erhalten
1
//eeprom_twi_tests:
2
char SLA_W = 0xA0;
3
char DATA0 = 0x00;
4
char DATA1 = 0x00;
5
char DATA2 = 0xAB;
6
char DATA3 = 0xAB;
7
8
9
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //uC als Master definieren, START condition
10
while (!(TWCR & (1<<TWINT))); //warten und prüfen ob richtig gesendet
11
if ((TWSR & 0xF8) != TW_START){ //Wenn anderer Wert als beim senden --> Error
12
  //error?
13
uart_puts("error01");
14
}
15
16
TWDR = SLA_W; //SLA_W sendet die Adresse
17
TWCR = (1<<TWINT) | (1<<TWEN);
18
while (!(TWCR & (1<<TWINT)));
19
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
20
  //error?
21
uart_puts("error02");
22
}
23
  //error?
24
TWDR = DATA0; //Data -> Daten in das TWDR Register geladen werden sollen
25
TWCR = (1<<TWINT) | (1<<TWEN);
26
while (!(TWCR & (1<<TWINT)));
27
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
28
  //error?
29
uart_puts("error03");
30
}
31
32
TWDR = DATA1;
33
TWCR = (1<<TWINT) | (1<<TWEN);
34
while (!(TWCR & (1<<TWINT)));
35
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
36
  //error?
37
uart_puts("error04");
38
}
39
40
TWDR = DATA2;
41
TWCR = (1<<TWINT) | (1<<TWEN);
42
while (!(TWCR & (1<<TWINT)));
43
44
TWDR = DATA3;
45
TWCR = (1<<TWINT) | (1<<TWEN);
46
while (!(TWCR & (1<<TWINT)));
47
48
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition
49
while (TWCR & (1<<TWINT));
50
51
PORTC &= ~(1 << DDC2);


Jetzt habe ich versucht, meine Bytes wieder auszulesen, es wird mir über 
meine USB am Terminal, der error11 und error12 ausgegeben.

Der Code sieht so aus:


SLA_W = 0xA0;
char DATA00 = 0x00;
char DATA01 = 0x00;

char SLA_R = 0xA1;

_delay_ms(2000);

TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //Start
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_START){
  //error?
uart_puts("error07");
}

TWDR = SLA_W;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
  //error?
uart_puts("error08");
}

TWDR = DATA00;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
  //error?
uart_puts("error09");
}

TWDR = DATA01;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
  //error?
uart_puts("error10");
}


TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //Start
while (!(TWCR & (1<<TWINT)));

if ((TWSR & 0xF8) != TW_START){
  //error?
uart_puts("error11");
}

TWDR = SLA_R;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
  //error?
uart_puts("error12");
}

TWCR = (1<<TWINT) | (1<<TWEN);

uart_puts(TWDR);

TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition
uart_puts(TWDR);[/c]

Ich verwende das EEPROM ST M24512.

Datenblatt: 
http://www.st.com/stonline/products/literature/ds/16459/m24512-w.pdf

Vielen dank für jeden Hinweis.
MFG

von Jack (Gast)


Lesenswert?

Hallo,
also ein Teil funktioniert jetzt. Am Osci scheint auch alles in Ordnung 
zu sein, das schreiben gibt mir KEINE Fehler aus, also alle ACK's werden 
erhalten
1
//eeprom_twi_tests:
2
char SLA_W = 0xA0;
3
char DATA0 = 0x00;
4
char DATA1 = 0x00;
5
char DATA2 = 0xAB;
6
char DATA3 = 0xAB;
7
8
9
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //uC als Master definieren, START condition
10
while (!(TWCR & (1<<TWINT))); //warten und prüfen ob richtig gesendet
11
if ((TWSR & 0xF8) != TW_START){ //Wenn anderer Wert als beim senden --> Error
12
  //error?
13
uart_puts("error01");
14
}
15
16
TWDR = SLA_W; //SLA_W sendet die Adresse
17
TWCR = (1<<TWINT) | (1<<TWEN);
18
while (!(TWCR & (1<<TWINT)));
19
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
20
  //error?
21
uart_puts("error02");
22
}
23
  //error?
24
TWDR = DATA0; //Data -> Daten in das TWDR Register geladen werden sollen
25
TWCR = (1<<TWINT) | (1<<TWEN);
26
while (!(TWCR & (1<<TWINT)));
27
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
28
  //error?
29
uart_puts("error03");
30
}
31
32
TWDR = DATA1;
33
TWCR = (1<<TWINT) | (1<<TWEN);
34
while (!(TWCR & (1<<TWINT)));
35
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
36
  //error?
37
uart_puts("error04");
38
}
39
40
TWDR = DATA2;
41
TWCR = (1<<TWINT) | (1<<TWEN);
42
while (!(TWCR & (1<<TWINT)));
43
44
TWDR = DATA3;
45
TWCR = (1<<TWINT) | (1<<TWEN);
46
while (!(TWCR & (1<<TWINT)));
47
48
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition
49
while (TWCR & (1<<TWINT));
50
51
PORTC &= ~(1 << DDC2);


Jetzt habe ich versucht, meine Bytes wieder auszulesen, es wird mir über 
meine USB am Terminal, der error11 und error12 ausgegeben.

Der Code sieht so aus:

1
SLA_W = 0xA0;
2
char DATA00 = 0x00;
3
char DATA01 = 0x00;
4
5
char SLA_R = 0xA1;
6
7
_delay_ms(2000);
8
9
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //Start
10
while (!(TWCR & (1<<TWINT)));
11
if ((TWSR & 0xF8) != TW_START){
12
  //error?
13
uart_puts("error07");
14
}
15
16
TWDR = SLA_W;
17
TWCR = (1<<TWINT) | (1<<TWEN);
18
while (!(TWCR & (1<<TWINT)));
19
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
20
  //error?
21
uart_puts("error08");
22
}
23
24
TWDR = DATA00;
25
TWCR = (1<<TWINT) | (1<<TWEN);
26
while (!(TWCR & (1<<TWINT)));
27
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
28
  //error?
29
uart_puts("error09");
30
}
31
32
TWDR = DATA01;
33
TWCR = (1<<TWINT) | (1<<TWEN);
34
while (!(TWCR & (1<<TWINT)));
35
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
36
  //error?
37
uart_puts("error10");
38
}
39
40
41
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //Start
42
while (!(TWCR & (1<<TWINT)));
43
44
if ((TWSR & 0xF8) != TW_START){
45
  //error?
46
uart_puts("error11");
47
}
48
49
TWDR = SLA_R;
50
TWCR = (1<<TWINT) | (1<<TWEN);
51
while (!(TWCR & (1<<TWINT)));
52
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
53
  //error?
54
uart_puts("error12");
55
}
56
57
TWCR = (1<<TWINT) | (1<<TWEN);
58
59
uart_puts(TWDR);
60
61
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition
62
uart_puts(TWDR);

Ich verwende das EEPROM ST M24512.

Datenblatt: 
http://www.st.com/stonline/products/literature/ds/16459/m24512-w.pdf

Vielen dank für jeden Hinweis.
MFG

von Stephan W. (sir_wedeck)


Lesenswert?

Hi
1
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //Start
2
while (!(TWCR & (1<<TWINT)));
3
4
if ((TWSR & 0xF8) != TW_START){
5
  //error?
6
uart_puts("error11");
7
}

ändere dies zu:
1
TWCR = (1<<TWINT) | (1<<TWEA) | (1<<TWEN); //Start
2
while (!(TWCR & (1<<TWINT)));
3
4
if ((TWSR & 0xF8) != TW_REP_START){
5
  //error?
6
uart_puts("error11");
7
}

gebe auch das Register: TWSR in den DebugMes. aus, kann helfen.

Stephan

von Jack (Gast)


Lesenswert?

1
//uart_puts("test");
2
3
_delay_ms(4000);
4
TWBR = ((14745600UL/100000)-16/2);
5
_delay_ms(2000);
6
PORTC |= (1 << DDC2);
7
8
//uart_puts("test2");
9
10
//eeprom_twi_tests:
11
char SLA_W = 0xA0;
12
int DATA0 = 0x00;
13
int DATA1 = 0x00;
14
int DATA2 = 0xAB;
15
int DATA3 = 0xAB;
16
17
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //uC als Master definieren, START condition
18
while (!(TWCR & (1<<TWINT))); //warten und prüfen ob richtig gesendet
19
if ((TWSR & 0xF8) != TW_START){ //Wenn anderer Wert als beim senden --> Error
20
  //error?
21
uart_puts("error01");
22
}
23
24
TWDR = SLA_W; //SLA_W sendet die Adresse
25
TWCR = (1<<TWINT) | (1<<TWEN);
26
while (!(TWCR & (1<<TWINT)));
27
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
28
  //error?
29
uart_puts("error02");
30
}
31
uart_putc(TWSR);       // DEBUG - 0x18 (alles okay)
32
33
  //error?
34
TWDR = DATA0; //Data -> Daten in das TWDR Register geladen werden sollen
35
TWCR = (1<<TWINT) | (1<<TWEN);
36
while (!(TWCR & (1<<TWINT)));
37
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
38
  //error?
39
uart_puts("error03");
40
}
41
uart_putc(TWSR);       // DEBUG - 0x28 (alles okay)
42
43
TWDR = DATA1;
44
TWCR = (1<<TWINT) | (1<<TWEN);
45
while (!(TWCR & (1<<TWINT)));
46
if ((TWSR & 0xF8) != TW_MT_DATA_ACK){
47
  //error?
48
uart_puts("error04");
49
}
50
uart_putc(TWSR);       // DEBUG - 0x28 (alles okay)
51
52
TWDR = DATA2;
53
TWCR = (1<<TWINT) | (1<<TWEN);
54
while (!(TWCR & (1<<TWINT)));
55
56
TWDR = DATA3;
57
TWCR = (1<<TWINT) | (1<<TWEN);
58
while (!(TWCR & (1<<TWINT)));
59
60
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition
61
while (TWCR & (1<<TWINT));
62
63
PORTC &= ~(1 << DDC2);
64
65
66
67
68
69
70
71
72
73
74
SLA_W = 0xA0;
75
char DATA00 = 0x00;
76
char DATA01 = 0x00;
77
78
char SLA_R = 0xA1;
79
80
_delay_ms(2000);
81
82
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //Start
83
while (!(TWCR & (1<<TWINT)));
84
if ((TWSR & 0xF8) != TW_START){
85
  //error?
86
uart_puts("error07");
87
}
88
89
TWDR = SLA_W;
90
TWCR = (1<<TWINT) | (1<<TWEN);
91
while (!(TWCR & (1<<TWINT)));
92
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
93
  //error?
94
uart_puts("error08");
95
}
96
97
TWDR = DATA00;
98
TWCR = (1<<TWINT) | (1<<TWEN);
99
while (!(TWCR & (1<<TWINT)));
100
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
101
  //error?
102
uart_puts("error09");
103
}
104
105
TWDR = DATA01;
106
TWCR = (1<<TWINT) | (1<<TWEN);
107
while (!(TWCR & (1<<TWINT)));
108
if((TWSR & 0xF8) != TW_MT_DATA_ACK){
109
  //error?
110
uart_puts("error10");
111
}
112
113
114
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //ReStart
115
while (!(TWCR & (1<<TWINT)));
116
117
if ((TWSR & 0xF8) != TW_REP_START){
118
  //error?
119
uart_puts("error11");
120
}
121
122
uart_putc(TWSR);       // DEBUG - 0x10 (A repeatet START condition has been transmitted)
123
124
TWDR = SLA_R;
125
TWCR = (1<<TWINT) | (1<<TWEN);
126
while (!(TWCR & (1<<TWINT)));
127
if((TWSR & 0xF8) != TW_MT_SLA_ACK){
128
  //error?
129
uart_puts("error12");
130
}
131
132
uart_putc(TWSR);      // Mega seltsamer 0x00 Wert
133
134
uart_putc(TWDR);
135
136
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); //Transmit Stop condition


Hab nochmal geschaunt, wenn man ein erneutes START con senden will, muss 
da ein TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //ReStart rein
TWSTA, das funktioniert schonmal, doch error12 bleibt und er gibt bei 
TWSR nur ein komisches 0x00 raus, was im Datenblatt nicht verzeichnet 
ist.

Vielen Dank für deine Hilfe.
MFG

von Stephan W. (sir_wedeck)


Lesenswert?

Hi
ich sehe zwar den Fehler gerade nicht, aber es kann kein "TW_MT_SLA_ACK" 
raus kommen!!!

Das MT steht für MasterTransmit!

ich würde diese hier erwarten:
TW_MR_SLA_ACK
TW_MR_SLA_NACK oder
TW_MR_ARB_LOST

in den seltenen Fällen auch
TW_BUS_ERROR

schau noch mal nach.

Stephan

von Jack (Gast)


Lesenswert?

Hi,
TW_MR_SLA_ACK

damit erhalte ich kein error mehr,

um jetzt weiter zu clken und die Daten erhalten zu wollen, muss ich doch 
folgendes eingeben:
1
TWCR = (1<<TWINT) | (1<<TWEN);
2
while (!(TWCR & (1<<TWINT)));
3
4
uart_putc(TWDR);

Ist das richtig so? Bekomm da nämlich noch nicht das was ich sende, also 
das 0xAB

Vielen herzlichen Dank für deine Hilfe.

von Stephan W. (sir_wedeck)


Lesenswert?

>damit erhalte ich kein error mehr,
also war der Status doch nicht NULL!
Wenn dein Terminal-Programm nur ASCII-Daten anzeigt, dann musst du deine 
DebugMess. ändern!!!!

>Ist das richtig so?
Ja, fast! Schau dir nochmal die Abfolge im DB deines EEProms an!
Da steht was zu ACK und NACK von Datenbytes.

mögliche Statuscodes vom MC überprüfen <- als TIP
TW_SR_DATA_ACK
TW_SR_DATA_NACK

Stephan

von Jack (Gast)


Lesenswert?

Er hatte zumindest Null angezeigt. Kann sein das ich was verpeilt hatte, 
muss wohl so sein :)

von Jack (Gast)


Lesenswert?

Geht jetzt, man sollte nur
1
PORTC |=(1<<DDC2);

zu beginn, mit dem hier ersetzen
1
PORTC &=~(1<<DDC2);

Falls es jemand jemals brauchen sollte.


Vielen Dank nochmal. Warst mir eine große Hilfe.

Eine Frage habe ich noch, wenn das eeprom "voll" ist, beginnt er von 
vorn richtig? Gibt es eine Art Belegt-Status oder muss man beim 
programmieren "mitrechnen"?

Mfg

von Stephan W. (sir_wedeck)


Lesenswert?

>Eine Frage habe ich noch, wenn das eeprom "voll" ist, beginnt er von
>vorn richtig? Gibt es eine Art Belegt-Status oder muss man beim
>programmieren "mitrechnen"?
ja, im EEProm wird der Adresszeiger wieder auf Null gesetzt wenn du über 
das Ende schreibst(ließt).
Einen Belegstatus gibs nicht!

so dann noch viel Spaß damit.

Stephan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.