Forum: Compiler & IDEs I2C EEPROM


von Kai (Gast)


Lesenswert?

Hallo,

kann mir jemand helfen ?
ich möchte empfangene messewerte in ein serielles EEPROM reinschreiben 
und diese dann später
über die serielle Schnittstelle an ein PC-Programm übermitteln.

Mein primäres Problem ist die empfangene Messwerte in ein serielles 
EEPROM zu schreiben und
zu lesen. Nicht in das interne EEPROM des Prozessors.
Ich weis nur soviel das es mit dem I2C Bus funktioniert muss.
Gehe ich richtig in der Annahme das ich 2 Portpins (freiwählbar)benötige 
für SDA und SCL ?
Wie realisiere ich das in einem C programm ?

Kann mir jemand bei meinem problem helfen.
Im voraus besten Dank

von Peter Fleury (Gast)


Lesenswert?

siehe FAQ:
Gibt es irgendwo I2C-Funktionen für avr-gcc?
Fertige I2C-Routinen findet man z.B. auf 
http://www.mysunrise.ch/users/pfleury/avr-software.html.

von kitesurfer1404 (Gast)


Lesenswert?

Moin moin!

Ich grabe mal diesen alten Beitrag aus, anstatt einen neuen zu eröffnen.

Nachdem ich an der I2C Ansteuerung der Chipkarte von Reichelt 
gescheitert bin, habe ich mir erstmal EEPROM im DIP8 Gehäuse 
vorgenommen. Leider ebenfalls ohne Erfolg.

Ich habe breits eine selbstgeschriebene Routine, die Atmel Aplication 
Note (avr300.asm) und die im Anhang befindliche Datei i2c.inc getestet. 
Ich glaub, die kam auch aus diesem Forum. Habe die Übersicht inzwischen 
verloren.

Als Controller nutze ich einen Mega8 (interner Oszi 1Mhz), der eeprom 
ist ein M24C64. Im Anhang ist ebenfalls ein Schaltplan, wie das Ding am 
Mega8 dran hängt. Allerdings nutze ich PIN 4 und 5 vom Port B.

An Port D hängen ein paar LEDs.

Das soll passieren:
  LEDs immer abwechselnd schalten (1: ein, 2: aus, 3: ein ...)
  Daten in den EEPROM schreiben (neues "LED-Muster")
  Daten aus EEPROM lesen
  LEDs schalten.

Das passiert:
  LEDs blitzen kurz auf, gehen aus, bleiben aus.

Die Routine "i2cread" gibt für SRAMDAT immer 0x00 zurück. es wird, wie 
es scheint, nichts gelesen. Oder zuvor nichts geschrieben, das kann ich 
leider nicht feststellen.

Alle Verdindungen und Kontakte wurden geprüft.
Wenn ich das Lesen aus dem Speicher und Ausgeben an Port D in die 
Schleife verlege, zeigt das Oszilloskop am SDA Pin am Speicher lustiges 
Gewackel, was bestimmt Daten sind ;-) Der SCL Pin liegt dauerhaft auf 
low.

Vielleicht hat ja jemand ein funktionierendes Programm in asm (oder auch 
schon hex) das ich ausprobieren kann oder entsprechend anpassen kann.

Ich hoffe, ihr könnt mir weiterhelfen. Schonmal vielen Dank im Voraus.


von Frank J. (frajo)


Lesenswert?

> Als Controller nutze ich einen Mega8 (interner Oszi 1Mhz), der eeprom
> ist ein M24C64. Im Anhang ist ebenfalls ein Schaltplan, wie das Ding am
> Mega8 dran hängt. Allerdings nutze ich PIN 4 und 5 vom Port B.

Der Mega8 hat eine Hardware TWI(I2C) die an den Pins PC4(SDA) und 
PC5(SCL) angeschlassen ist. Wenn Du andere Portpins verwendest, mußt Du 
das gesammte I2C Protokoll selbst programmieren (Software I2C). Einfach 
ist es aber den eingebauten (und bezahlten) Hardware I2C des Mega8 zu 
verwenden.

von kitesurfer1404 (Gast)


Lesenswert?

Das Hardware TWI hab ich schon getestet... Leider auch ohne Erfolg. Hast 
du da Code für, den ich verwenden kann? Dann würd ich das nochmal 
testen.

In der i2c.inc sind die entsprechenden Software I2C Routinen drin.

von Frank J. (frajo)


Lesenswert?

Wenn Du den Hardware TWI verwendest, kannst Du so vorgehen. Die 
Leitungen SDA und SCL müssen über je einen Widerstand von ca. 4,7KOhm an 
die Versorgungsspannung gelegt werden.
Zuerst mußt Du die Baudrate einstellen:
1
TWBR = (F_CPU / 100000UL - 16) / 2;  // TWI Baudrate 100KHz
F_CPU sollte im makefile eingetragen sein.
Jede Übertragung beginnt mit einer Startcondition und endet mit einer 
Stopcondition. Dafür machst Du zwei Funktionen. Etwa so:
1
void TwiStart(void) {
2
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition
3
  while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission
4
}
5
6
void TwiStop(void {
7
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
8
}
Außerdem brauchst Du noch eine Funktion zum Senden und eine zum 
Emfangen:
1
void TwiSend(uint8_t DataByte, uint8_t ackno) {
2
  TWDR = DataByte;
3
  if(ackno == 1) TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
4
  else TWCR = _BV(TWINT) | _BV(TWEN); // clear interrupt to start transmission
5
  while ((TWCR & _BV(TWINT)) == 0) ; // wait for transmission
6
}
7
8
uint8_t TwiReceive(uint8_t ackno) {
9
  uint8_t DataByte;
10
  if(ackno == 1) TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
11
  else TWCR = _BV(TWINT) | _BV(TWEN);  // clear interrupt to start transmission
12
  while ((TWCR & _BV(TWINT)) == 0) ;   // wait for transmission
13
  DataByte = TWDR;
14
  return DataByte;
15
}
Mit dem Parameter ackno steuerst Du ob ein Acknowledge erwartet wird 
oder nicht. Bei nur einem Byte und beim letzten emfangenen oder 
gesendeten Byte ist ackno 0(Null).
Jeder I2C Chip hat eine Basisadresse welche Du im Datenblatt findest. 
Mein 24C256 hat 0xA0 und er braucht eine 16Bit Adresse.
1
#define TWI_SLA_EE  0xA0
Um nun auf den Speicher zu schreiben oder zu lesen kombinierst Du die 
obigen Funktionen wie erforderlich:
1
void MemByteWrite(uint16_t addr, uint8_t wert) {
2
  TwiStart();
3
  TwiSend(TWI_SLA_EE | TW_WRITE, 0);
4
  TwiSend(addr >> 8, 0);
5
  TwiSend(addr, 0);
6
  TwiSend(wert, 0);
7
  TwiStop();
8
}
9
10
uint8_t MemByteRead(uint16_t addr) {
11
  TwiStart();
12
  TwiSend(TWI_SLA_EE | TW_WRITE, 0);
13
  TwiSend(addr >> 8, 0);
14
  TwiSend(addr, 0);
15
  TwiStart();
16
  TwiSend(TWI_SLA_EE | TW_READ ,0);
17
  uint8_t wert = TwiReceive(0);
18
  TwiStop();
19
  return wert;
20
}
Um zugriff auf die Symbole TW_WRITE und TW_READ zu erhalten mußt Du die 
twi.h aus dem compat Verzeichnis includieren:
1
#include <compat/twi.h>

Nun zu ackno. Wen mehr als ein Byte gelesen oder geschrieben werden 
sollen geht das etwa so:
1
uint16_t MemWordRead(uint16_t addr) {
2
  TwiStart();
3
  TwiSend(TWI_SLA_EE | TW_WRITE, 0);
4
  TwiSend(addr >> 8, 0);
5
  TwiSend(addr, 0);
6
  TwiStart();
7
  TwiSend(TWI_SLA_EE | TW_READ ,0);
8
  uint16_t wert = TwiReceive(1);
9
  wert <<= 8;
10
  wert += TwiReceive(0);
11
  TwiStop();
12
  return wert;
13
}
Hoffe das hilft etwas. Achtung! Es wird hier keine Fehlerbehandlung 
vorgenommen. Nach jeder Operation kannst Du den Erfolg oder Misserfolg 
durch zuweisen von TW_STATUS auswerten:
1
 uint8_t twst = TW_STATUS;

Gruß
Frank.

von Frank J. (frajo)


Lesenswert?

Falls Dein Speicher einen WP(write protect) Anschluss hat, muss der an 
Masse. Ebenso die drei(?) Adressleitungen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Für die 24Cxx-EEPROMs gibt's in der avr-libc auch Beispielcode für
Hardware-TWI.

von Frank J. (frajo)


Lesenswert?

Oh, sehe gerade das die twi.h nun im util Verzeichnis liegt. Also 
richtig:
1
#include <util/twi.h>

  

von kitesurfer1404 (Gast)


Lesenswert?

muss mich erstmal in C für avr einarbeiten und gucken wie ich das auf 
meiner linux maschine zum laufen bekomme...

vielen dank schonmal!

von Frank J. (frajo)


Lesenswert?

Sieh mal hier:
Beitrag "avr-gcc toolchain unter puppy linux"
Geht bei mir sogar unter PuppyLinux.

von Johannes (Gast)


Lesenswert?

hallo,

habe was ähnliches damit gemacht:

http://www.myavr.de/shop/artikel.php?artID=65

... also die I2C leitungen sind am m8 festgelegt C6 und C7 für 
hardware-TWI
frei wählbar wirds nur wenn du mit soft-TWI arbeitest, das twi-protokoll 
ist aber nicht so simpel wie uart oder spi ob die win-avr bibliotheken 
soft-TWI her geben bezweifle ich... Wenn du aber das hardware-TWI nimmst 
solltes du es mit den TWI-bibliotheken hin bekommmen... habs sie selber 
aber noch nicht benutzt, ich habs mit dem code-wizard vom myavr-workpad 
gemacht.


J.

von kitesurfer1404 (Gast)


Lesenswert?

magst du mir die TWI-bibliotheken mal schicken?
mit der software kann ich leider nichts anfangen... bin linux user...

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.