Forum: Mikrocontroller und Digitale Elektronik Atmega TWI EEprom


von Nils (Gast)


Angehängte Dateien:

Lesenswert?

Moin,

ich versuche mich grade in die Materie von µC einzuüben und versuche 
grade den von mir geschrieben Code auszuführen.

Das Problem ist das lesen/schreiben eines EEPROM mittels Atmega.

Es handelt sich um einen Atmega16L und 24LC256m EEPROM.
Ich möchte ein Byte an eine bestimmte Adresse speichern, danach wieder 
auslesen und an einem Port ausgeben.

Dazu habe ich 2 Unterprogramme geschrieben, read und write.
Das Problem ist, dass nach schreiben und lesen im Datenregister des TWI 
immernoch das zuvor abgeschickte Controllbyte noch enthalten ist und 
nicht der erwartete zuvpor gespeicherte Wert.

Die Reihenfolge für lesen ist ja:
-Start
-Controllbyte
-Adressebyte1
-Adressebyte2
-Start
-Controllbyte
-Stop

Übersehe ich etwas?

Code im Anhang :)
-Ports als Aushänge definieren
-schreiben
-lesen
-wert an ausgang schicken
-endlosschleife

mfg,
Nils

von gtf (Gast)


Lesenswert?

Hallo Nils,
ich hatte auch mal Probleme mit TWI bis ich auf die Routinen von 
Bernhard.S gekommen bin. Die haben mir geholfen, werden auch dir helfen 
:-)

Beitrag "TWI / I2C einf. MASTER SLAVE Beispiel(Assembler) ATmega8"
/*********************************************************/
Bitte beachte das man auf einmal nur 1Byte schreiben kann, weil die 
Daten vom 24x256 beim Schreiben nicht gepuffert werden!
Während das Byte in den EEPROM gebrannt wird ist dein Bausteil(24x256) 
vom Bus getrennt! (siehe Datenblatt)

Also Ein Byte schreiben:
1) Start, SLA+W, Address High_B, Address Low_B, 1Byte(daten), Stop
2) 5ms warten
3) danach zum ersten Schritt, wenn weitere Daten da sind sonst beenden.


Lesesequenz:
Start, Address High_B, Address Low_B, RepeatedStart, SLA+R, 1Byte, 
2Byte...Stop

Hierbei fallen keine nennenswerten delays an, deswegen können mehrere 
Bytes durchgehend gelesen werden

von Nils (Gast)


Lesenswert?

Ja seinen Code habe ich auch schon unter die Finger bekommen.
Ich habe mal einen ganz einfachen Code geschrieben, der an PORTA eine 1 
bei Error schickt. Ich versuche lediglich das Startsignal zu schicken.
Pullups sind da und es ist soweit alles richtig verkabelt.

Und wie es ist, kriege ich hiermit nur einen Fehler aus, also immer 1 an 
PortA. Wieso :(?
Der Code ist wohl selbsterklärend:
1
.include "m16def.inc"
2
3
start:
4
5
ldi r16,0xFF
6
out DDRA,r16
7
8
ldi r18,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN) ;starten
9
out TWCR,r18
10
rcall warten
11
12
in r16,TWSR
13
andi r16,0xF8
14
cpi r16,START
15
brne error
16
17
noerror:
18
ldi r16,0
19
rjmp loop
20
error:
21
ldi r16,1
22
23
loop:
24
out PORTA,r16
25
rjmp loop
26
27
write:
28
29
ret
30
31
warten:
32
push r18
33
warten1:
34
in r18,TWCR
35
sbrs r18,TWINT
36
rjmp warten1
37
pop r18
38
reti

von gtf (Gast)


Lesenswert?

Zuerst würde ich nach dem Reset eine Verzögerung einfügen. Damit der 
EEPROM seine Power Up- Phase überwunden hat.
Danach prüfen ob die konstante „Start“ auch wirklich 0x08 beträgt.
Bei mir sieht’s so aus:
1
.equ  MT_Start_Condition     = $08      // A START condition has been transmitted


Wenn’s das nicht ist, dann würde ich noch einmal die Hardware prüfen.
1)  Ist SDA & SCL richtig verbunden?
2)  Wird dein EEPROM mit Strom Versorgt?

von gtf (Gast)


Lesenswert?

gtf schrieb:
> Lesesequenz:
> Start, Address High_B, Address Low_B, RepeatedStart, SLA+R, 1Byte,
> 2Byte...Stop

ooops da fehlt ja SLA+W
Korrektur:

Start, SLA+W, Address High_B, Address Low_B, RepeatedStart, SLA+R, 
1Byte,
2Byte...,Stop

von Nils (Gast)


Lesenswert?

Das habe ich doch auch soweit gemacht. ALso ich gehe davon aus, dass 
nach dem SLA+R automatisch in TWDR das byte gelesen wird? Wäre dann mein 
Code fürs lesen korrekt?
1
read:
2
ldi r18,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN) ;starten
3
out TWCR,r18
4
rcall warten
5
6
ldi r19,0b10100000            ;SLA+W senden
7
out TWDR,r19
8
ldi r18,(1<<TWINT)|(1<<TWEN)
9
out TWCR,r18
10
rcall warten
11
12
out TWDR,r21              ;HIGH_B senden        
13
ldi r18,(1<<TWINT)|(1<<TWEN)
14
out TWCR,r18
15
rcall warten
16
17
out TWDR,r22              ;LOW_B senden
18
ldi r18,(1<<TWINT)|(1<<TWEN)
19
out TWCR,r18
20
rcall warten
21
22
23
ldi r18,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)                       ;startrepeat
24
out TWCR,r18
25
rcall warten
26
27
ldi r19,0b10100001                                        ;SLA+r
28
out TWDR,r19
29
ldi r18,(1<<TWINT)|(1<<TWEN)
30
out TWCR,r18
31
rcall warten
32
33
in r16,TWDR        ;gelesene Daten kopieren
34
35
ldi r18,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN) ;stoppen
36
out TWCR,r18
37
reti

von Nils (Gast)


Lesenswert?

Ich habe eine Teilösung.
Ich führe erst an eine Adresse ein Schreibvorgang aus, dann löse ich mit 
einen Intertrupt den Lesevorgang aus. Porta zeigt die erwartete Zahl an.

Wenn ich allerdings nur einen Lesevorgang machen will funktioniert das 
nicht (PORTA bleibt 00000000).

Ich muss min. 1 Schreibvorgang ausgeführt haben um eine Leseoperstion 
durchzuführen? WIeso? ist das so?

von Nils (Gast)


Lesenswert?

Problem gelöst. Interrupt war nicht freigegeben.

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.