Forum: Mikrocontroller und Digitale Elektronik I2c: Acknowledge Polling mag nicht


von Michael Z. (incunabulum)


Lesenswert?

Moin!

ich versuche gerade, einen AD5251 (digitales Potentiometer, 2 Kanäle, 
I2c Interface) zum leben zu erwecken. Im großen und ganzen funktioniert 
das auch. Mit einem Problem:

Der AD5251 hat neben der Potentiometer ein kleines EEPROM an Bord. 
Sollen dort Werte geschrieben werden, so ist laut Dokumentation 
Acknowledge Polling anzuwenden um so herauszufinden wann die 
Schreiboperation abgeschlossen ist. Im Datenblatt steht dies so:

1
To determine if the internal write cycle is complete and the i2c interface
2
is enabled, interface polling can be executed. I2c interface polling can be
3
conducted by sending a start condition followed by the slave address and the
4
write bit. If the I2c interface responds with an ACK, the write cycle is 
5
complete and the interface is ready to proceed with further operations.

Die entsprechende Schreibfunktion sieht bei mir so aus:
1
void Ad5251::setEEMEM(u08 channel, u08 value) {
2
  i2cWriteStartWait(m_i2cAddr + I2C_WRITE);
3
  i2cWriteDataByte(B8(00100000) + channel);
4
  i2cWriteDataByte(value);
5
  i2cWriteStop();
6
7
  // TODO: acknowledge polling not working!
8
  i2cWriteStartWait(m_i2cAddr + I2C_WRITE); // wait for acknowledge
9
  i2cWriteStop();
10
}

Der eigentliche Schreibvorgang funktioniert einwandfrei. Schreibe ich 
allerdings mehrere Werte hintereinander, so wird nur jeder 2. 
geschrieben, da anscheinend der AD5251 noch nicht aufnahmebereit ist. 
Mit einem kleinen Delay klappt es. Ergo mein Schluss, dass das 
Acknowledge Polling irgendwie faul ist.

Die relevante i2cWriteStartWrite() Funktion sieht bei mir wie folgt aus. 
Ist bereits mehrfach getestet und letztlich von den Atmel App Notes 
(oder Fleury?) nahezu 1:1 übernommen:
1
void i2cWriteStartWait(u08 addr) {
2
  // Send start condition; send address, transfer direction
3
  // If device busy, use ack polling to wait for ready
4
    u08   twst;
5
    while ( 1 ) {
6
      TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);  // send START condition
7
    while(!(TWCR & (1<<TWINT)));        // wait until transmission completed
8
      twst = TW_STATUS & 0xF8;            // check value of TWI Status Register.
9
                            // Mask prescaler bits.
10
    if ( (twst != TW_START) && (twst != TW_REP_START))
11
      continue;                 // failed; retry
12
13
      TWDR = addr;                  // send device address
14
      TWCR = (1<<TWINT) | (1<<TWEN);
15
      while(!(TWCR & (1<<TWINT)));         // wail until transmission completed
16
      twst = TW_STATUS & 0xF8;            // check value of TWI Status Register.
17
                            // Mask prescaler bits.
18
      if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) {
19
          TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);  // device busy, send stop condition to
20
                                // terminate write operation //
21
          while(TWCR & (1<<TWSTO));              // wait until stop condition is executed and bus released
22
          continue;
23
      }
24
      break;                        //if( twst != TW_MT_SLA_ACK) return 1;
25
     }
26
}

Mach ich das richtig? Oder wieso funktioniert das nicht wie gewünscht?

von Stephan W. (sir_wedeck)


Lesenswert?

Morgen
>Mach ich das richtig?
Nicht ganz, denn nach dem Schreiben der Daten ist das Interface 
deaktiviert und du bekommst keiner Antwort.

In deiner Funktion wird aber nur auf ein Nack reagiert und nicht auf Ack 
bzw keine Antwort. Also schreibe deine Funktion so um, das sie nach dem 
Schreiben der Daten so lange wartet bis sie ein Ack erhält. Dann ist der 
Schreibvorgang beendet.

Stephan.

Von der Geschwindigkeit her würde ich es umgekehrt machen, erst beim 
erneuten schreiben warten bis ein Ack kommt. Meine Meinung. :-)

von Michael Z. (incunabulum)


Lesenswert?

Stephan W. schrieb:
> In deiner Funktion wird aber nur auf ein Nack reagiert und nicht auf Ack
> bzw keine Antwort. Also schreibe deine Funktion so um, das sie nach dem
> Schreiben der Daten so lange wartet bis sie ein Ack erhält.

Duhh... ich wusste, dass es etwas triviales ist. Da ich die I2c 
Funktionen jetzt schon lange verwende habe ich deren Funktion für 
"gottgegeben" angenommen und hier nicht weiter intensiv nachgeforscht. 
Hät ich aber auch selber draufkommen können!

> Von der Geschwindigkeit her würde ich es umgekehrt machen, erst beim
> erneuten schreiben warten bis ein Ack kommt. Meine Meinung. :-)

Und noch ein gute Idee! Damit spare ich mir zumindest das Delay beim 
letzten Byte und kann den AVR sich mit anderen Dingen beschäftigen 
lassen.

Danke!

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.