Forum: Mikrocontroller und Digitale Elektronik TWI - AVR stürzt ab


von Matthis (Gast)


Lesenswert?

Hi Leute,
Brauche mal wieder eure Hilfe. Bei der benutzung der TWI meines mega32
stüzt ständig das Programm ab. Weiß nicht warum?!
Dies Programm soll eigentlich dazu dienen die Temperatur aus dem DS1621
auszulesen. Tut es auch, 10mal oder so.


#include "lcd.h"


void sendi2c(uint8_t add, uint8_t data)
{

  TWBR=11;

  TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while(!(TWCR & (1<<TWINT)));    //start i2C

  TWDR=add;
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));  //adress + write trasmitt

  TWDR=data;
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));    //data transmitt

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

uint8_t readi2c(uint8_t add, uint8_t comm)
{

  TWBR=11;

  TWCR=(1<<TWEN)|(1<<TWSTA)|(1<<TWINT);
  while(!(TWCR & (1<<TWINT)));    //start

  TWDR=add;
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));  //adress + write transmitt
  TWDR=comm;
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));    //command transmitt

  TWCR=(1<<TWEN)|(1<<TWSTA)|(1<<TWINT);
  while(!(TWCR & (1<<TWINT)));    //repared start

  TWDR=add+1;
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));  //adress + read transmitt

  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));    //data read

  TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);  //stop
  return(TWDR);
}



int main(void)
{

  lcd_init(LCD_DISP_ON);
  uint8_t high;

  while(1)
  {

  sendi2c(144,0xEE);  //start messung
  sendi2c(144,0x22);  //stop messung

  high = readi2c(144,0xAA); //Temp auslesen
  lcd_puti2(high);

  lcd_home();

  }
  return(0);
}

von T.Stütz (Gast)


Lesenswert?

Dein Programm "stuertzt" nicht ab sonder hängt in einer der
While-Schleifen endlos.
Gib doch mal vor jeder While-Schleife ein eindeutiges Signal
an LED's/Ports aus und mess mal.

Du gehst davon aus, das dein Gerät (Temperaturmesser) ständig unter
allen Umständen über die gesammte Laufzeit (Endlos) ohne Fehler sofort
sich per I2C meldet.

=> keine Endlosschleifen verwenden, besser Timeout oder Watchdog-Reset

Gruss

von peter dannegger (Gast)


Lesenswert?

Ich kämpfe auch gerade mit dem Hardware-I2C.

Für zuverlässiges Arbeiten brauchst du einen Interrupthandler, der
erstmal das TWSR auswertet und bei jedem unerwarteten Zustand das TWSTO
setzt um die interne Zustandsmaschine zurückzusetzen. Außerdem noch ein
Errorflag, damit Du die mißglückte Übertragung nochmal starten kannst.

Trotzdem kann es sein, daß sich die interne Zustandsmaschine total
verhakt. Ich habe deshalb noch einen Timeoutinterrupt, der testet, ob
ein Stop innerhalb 5ms ausgeführt werden konnte. Wenn nicht, wird mit
TWCR = 0; das I2C komplett abgeschaltet und nochmal neu initialisiert.

Ich muß das Hardware-I2C benutzen, da ich die Multimaster Funktion
benötige.
Ich muß auch absichern, daß Störungen auf dem I2C-Bus in jedem Fall
behoben werden.


Für Single-Master Anwendungen ist deshalb ein Software-I2C wesentlich
einfacher (weniger Code) und stabiler.


Peter

von Matthias (Gast)


Lesenswert?

Ja stimmt, daran hab ich gar nicht gedacht. Hab jetzt ein Timeout
eingabaut, jetzt geht es. Danke!
mfg

von Martin (Gast)


Lesenswert?

Hallo Peter!

Ich hatte gerade ein ähnliches Problem:
Ich steuere mit einem ATMEGA128 einen PCF8574 an.
Ab und zu kam es vor, dass die Stopp-Routine nicht beendet werden
konnte, nachdem ich Daten vom Baustein las. (Nach dem Schreiben auf
den Baustein gab es nie Probleme) - Trat das Problem auf, blieb die
Datenleitung unerbittlich auf low.

Erst mit deiner beschriebenen Neuinitialisierung funktionierte es.
TWCR = 0;
TWCR = Initwert;
I2C-Start();
Die Datenleitung war nach dem Start plötzlich wieder frei.
Ich kam dahinter das dieses Problem aber nicht vom ATMEGA128 kam,
sondern vom PCF8574, der die Datenleitung plötzlich nicht mehr
freigab.
Eine Genaue Untersuchung des Problems ergab, dass ich das
Acknowledge-Bit "TWEA" eingeschaltet hatte. Wenn der ATMEGA128 nun
Daten vom Baustein bekam, sendete der µC ein Ack. zurück an den
PCF8574 und das mag er anscheinend nicht. Jetzt funktioniert es super.

Verrat uns bitte, ob du dein Problem auf diese Weise lösen konntest.

Tschüss
Martin

von thkais (Gast)


Lesenswert?

@Martin:
Dein Problem ist hausgemacht. Laut I²C-Spezifikation muß der Master,
wenn er Daten liest, beim letzten Datenbyte ein nACk senden. Denn sonst
legt der Slave beim nächsten Takt, wenn eigentlich das Stop-Bit gesendet
werden soll, das erste Bit schon auf den Bus. Wenn das 0 ist, dann hängt
die Übertragung, weil ja der Master eigentlich ein Stop senden will,
dies aber nicht kann. Nur das nAck kann dies verhindern.
Liest Du nur ein einziges Datenbyte vom 8574, dann mußt Du bereits beim
ersten Datenbyte nAck senden.
Ist alles ganz logisch.
Man kann sich die komplette I²C-Spezifikation bei Philips
herunterladen, würde ich sehr empfehlen, das dürfte einige Unklarheiten
beseitigen.

von Andreas Bauer (Gast)


Lesenswert?

Hallo

Ich möchte noch eine Anmerkung machen, obwohl der Thread nicht mehr
ganz aktuell ist. Hatte vor kurzem dasselbe Problem und die Hinweise
oben haben mir sehr geholfen.

Meines Erachtens haben die AVRs einen Hardwarefehler in der
State-Machine, funktionieren jedoch im Multi-Master-Mode einwandfrei,
wenn man folgendes beachtet:

Das letzte Datenbyte muss (wie von thkais angemerkt) mit NACK bestätigt
werden. Der Slave bekommt dann keinen Interrupt mit Status TW_SR_STOP
(0xA0) mehr, sondern die Kommunikation ist mit TW_SR_DATA_NACK (0x58)
bzw. TW_SR_GEN_NACK (0x98) beendet.

Dass das allerdings laut Standard so sein soll, kann ich nach dem
Durchlesen der Philips-I2C-Spezifikation nicht nachvollziehen. Der
Slave kann zwar mit einem NACK beim letzten Datenbyte dem Master
mitteilen, dass er keine weiteren Daten empfangen möchte, wenn die
Anzahl der Datenbytes aber feststeht, muss er das aber nicht machen. In
den Beispielen sind jedenfalls beim letzten Datenbyte beide
Möglichkeiten ACK/NACK angeführt.

Andreas

von Thomas K. (thkais)


Lesenswert?

@Andreas:

"If a master-receiver is involved in a transfer, it must signal
the end of data to the slave- transmitter by not generating
an acknowledge on the last byte that was clocked out of
the slave. The slave-transmitter must release the data line
to allow the master to generate a STOP or repeated
START condition."

Seite 10 der I²C-Spezifikationen von Philips (rechts unten) Version 2.1
vom Januar 2000.

Gruß
Thomas

von Andreas Bauer (Gast)


Lesenswert?

An Thomas:

Danke für den Hinweis. Hab ich nicht gesehen. Allerdings verwende ich
den Slave-Transmitter-Modus gar nicht.

IMHO sollte als Slave-Receiver ein ACK beim letzten Byte möglich sein.
Scheint mir auch sinnvoll, damit der Master weiss, dass der Slave das
Byte bekommen hat. Der ATmega128 hängt sich da in einer
Multi-Master-Umgebung jedenfalls auf. Wenn das letzte Byte ein NACK
bekommt, läuft es zuverlässig. Wenn nur ein Master vorhanden ist,
scheint es auch mit ACK zu funktionieren.

Schöne Grüße,
Andreas

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.