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?