Forum: Mikrocontroller und Digitale Elektronik I2C-Timingproblem?!


von Daniel (Gast)


Lesenswert?

Hallo zusammen,

ich versuche verzweifelt einen Drucksensor von VTI (SCP1000) per 
I2C-Interface anzusprechen. Der Sensor hängt an einem MSP430 mit 
I2C-Schnittstelle. Laut Datenblatt des Sensors sollte vor dem Auslesen 
von Druckwerten eine Routine zur Abfrage durchgeführt werden, die 
anzeigt, ob der Sensor richtig initialisiert wurde und ob 
Prüfsummenfehler im integrierten EEPROM aufgetreten sind. Also tue ich, 
wie mir gehießen.

Das Problem: Die Routine gibt beim debuggen im Einzelschrittbetrieb 
keinen Fehler zurück - also alles ok. Lasse ich den Controller 
ungezügelt auf den Bus los, krieg ich nen Fehler für eine falsche 
EEPROM-CRC zurück. Ähnliches auch, wenn ich die Startup-Routine im 
Einzelschrittbetrieb durchmache und später Werte mit vollem Takt 
auslesen oder schreiben will. Dann bleibe ich irgendwo in den 
I2C-Funktionen zum schreiben oder lesen an der Abfrage der 
Interruptflags hängen.

Jetzt drängt sich natürlich der Bustakt auf. Den hab ich aber auch schon 
variiert. Ich habe von 100kHz bis 1kHz schon alles durchgemacht. 
Pullup-Widerstände hängen auch dran: 10k, vielleicht ein bisschen hoch, 
sollten aber dennoch gehen. Den Bus kann ich mit einem Oszi mit 
Bus-Analyzer verfolgen, die Signale schauen sauber aus und es werden 
auch die Start-/Stop- und Acknowledge-Signale richtig bedient.

Ich bin vollkommen überfragt. Vielleicht fällt euch was ein?

Hier sind die wichtigsten Routinen:

In der Main-Funktion wird die Portrichtung gesetzt und der Sensor 
anschließend aus dem Power-Down-Mode genommen und die Zeit abgewartet, 
die er zur Initialisierung braucht. Solange schläft der MSP einen seiner 
Ruhezustände um Energie zu sparen. Dann wird die Initialisierungsabfrage 
aufgerufen:
1
   //Initialize Ports and Directions for specific sensor
2
    P6DIR |= SCP_PD;                //Port-pin for power-down pin on SCP as output
3
    P6OUT |= SCP_PD;                //hold PD-pin high to remain in power down
4
                                    //mode during the stabilization of the power supplies
5
6
    // Initialize Hardware:
7
    initI2C();
8
9
    //Setup timer for periodic wakeup
10
    TACTL |= (!TASSEL1 + TASSEL0);      //Timer A clock source is ACKL
11
    TACTL |= (ID1 + ID0);               //Input divider = 8
12
    TACTL |= TAIE;                      //enable timer interrupt
13
    
14
15
    for (;;){
16
      P6OUT &= ~SCP_PD;                 //release power down mode for normal operation
17
      TACCR0 = 0x01FF;                  //wait ~60ms for sensor startup time (FFh = 62,256ms / 1FFh = 125ms)
18
      START_TIMER;
19
20
      // MSP power down (LPM3: all but ACKL disabled), general interrupts enable
21
      _BIS_SR(GIE + CPUOFF + SCG1 + SCG0);
22
23
      if (!checkStartupStatus()) {      //startup fail? -> no error:
24
(...)
25
}

Die Funktion "checkStartupStatus()" im Detail:
1
/*------------------------------------------------------------------------------
2
//::FUNCTION: checkStartupStatus()
3
------------------------------------------------------------------------------*/
4
//  DESCRIPTION:
5
//  ~~~~~~~~~~~~
6
/**  \brief Checks whether start-up procedure is finished. The STATUS register
7
*           (0x07) can be read to verify that start-up procedure is finished.
8
*           If the STARTUP bit (LSB) of the STATUS register (0x07) is '0', the
9
*           start-up procedure is finished successfully. If the STARTUP bit of
10
*           the STATUS register is '1', the start-up procedure is still running.
11
*
12
*           The start-up status check includes EEPROM checksum error result
13
*           check. If the content of DATARD8 is 0x00, EEPROM checksum
14
*           calculation indicated an error and the start-up procedure is failed.
15
*           Correct EEPROM checksum calculation result is indicated by content
16
*           of 0x01 in DATARD8.
17
*
18
*    \return 0 - If start-up procedure has finished without errors
19
*            1 - If start-up procedure has failed with unfinished initialization
20
*            2 - If start-up procedure has failed with EEPROM checksum error
21
*            3 - If start-up procedure has failed with both errors
22
*/
23
/*----------------------------------------------------------------------------*/
24
25
uint8_t checkStartupStatus(void) {
26
  uint8_t success = 0;
27
28
  for (int retries = 0; retries < 6; retries++) {
29
    ((readI2C(STATUS) & 0x01) == 0 ? (success = 0) : (success = 1));
30
    if (!success)
31
      break;
32
  }
33
34
  ((readI2C(DATARD8) & 0x01) == 1 ? (success += 0) : (success += 2));
35
36
  return success;
37
}
Hier wird im Einzelschritt "success = 0" zurückgegeben, bei voller 
Geschwindigkeit "success = 2".

Die Initialisierung des I2C-Ports:
1
void initI2C(void) {
2
  P3SEL   |= 0x0A;        // Assign pins to i2c module function
3
4
  U0CTL   |= SWRST;       // hold usart in software reset
5
  U0CTL   |= SYNC;        // select "SYNC" bit and...
6
  U0CTL   |= I2C;         // ..."I2C" bit to select I2C mode
7
  U0CTL   &= ~XA;         // 7 bit addresses
8
  U0CTL   &= ~SWRST;    // Start USART1
9
10
  U0CTL   &= ~I2CEN;      // disable I2C mode for further configuration
11
  I2CTCTL &= ~I2CWORD;    // I2C data register is 8bit
12
  I2CTCTL &= ~I2CRM;      // number of bytes transmitted is controlled by I2CNDAT
13
  I2CTCTL = I2CSSEL_2;    // SMCLK as clock source. After PUC ( power up clear)
14
                          // SMCLK is sourced from DCOCLK with ~800kHz
15
  I2CPSC = 0x03;          // Set Prescaler. Divide SMCLK / 3 (Values more then 4
16
                          // are not recommended). Use I2CSCLL and I2CSCLH instead.
17
//  I2CSCLH = 0xFF;         // set i2c clock high-periode
18
//  I2CSCLL = 0xFF;         // set i2c clock low-periode
19
  U0CTL   |= I2CEN;       // I2C is now 8Bit-mode, activated and stuff from above
20
}
I2CSCLH und I2CSCLL nehme ich, um den Bustakt zu drosseln. Schaut am 
Oszi optimal aus, die High- und Low-Zeiten im Sensordatenblatt werden 
eingehalten.

Und zuletzt die Funktionen zum schreiben und lesen auf dem Bus:
1
uint8_t readI2C(uint8_t addr2) {
2
  I2CNDAT = 1;                              // number of bytes to send
3
  I2CSA = SCP1000_ADDRESS;                  // Slave Adresse
4
  U0CTL |= MST;                             // Master mode
5
  I2CTCTL |= I2CSTT+I2CTRX;                 // Start + Transmit mode (no stop bit!)
6
  while ((I2CIFG & TXRDYIFG) == 0);         // Wait for transmitter to be ready
7
  I2CDRB = addr2;                            // write register addr. to sca3000
8
  while ((I2CIFG & ARDYIFG) == 0);
9
10
  I2CNDAT = 1;                              // number of bytes to read
11
  U0CTL |= MST;                             // Master mode
12
  I2CTCTL &= ~I2CTRX;                       // RX Mode
13
  I2CTCTL |= I2CSTT + I2CSTP;               // Repeated Start + Stop
14
  while ((I2CTCTL & I2CSTP) == I2CSTP);     // Wait for Stop Condition
15
  I2CIFG = 0x00;                            // Clear I2C interrupt Flags
16
  return I2CDRB;
17
18
}
19
20
21
void writeI2C(uint8_t addr, uint8_t data) {
22
  I2CNDAT = 0x02;                           // Bytes to send (1 for addr. + 1 data byte)
23
  I2CSA = SCP1000_ADDRESS;                  // Slave Adresse
24
  U0CTL |= MST;                             // Master mode
25
  I2CTCTL |= I2CSTT+I2CSTP+I2CTRX;          // Start + Stop + Transmit mode
26
  while ((I2CIFG & TXRDYIFG) == 0);         // Wait for transmitter to be ready
27
  I2CDRB = addr;                            // write register addr. to sca3000
28
  while ((I2CIFG & TXRDYIFG) == 0);         // Wait for transmitter to be ready
29
  I2CDRB = data;                            // write data addr. to sca3000
30
//  while ((I2CTCTL & I2CSTP) == 0x02);       // Wait for Stop Condition
31
  while ((I2CTCTL & I2CSTP) == I2CSTP);       // Wait for Stop Condition
32
//  I2CIFG = 0x00;                            // Clear I2C interrupt Flags
33
}

Vielen Dank, dass ihr euch die Zeit nehmt!

Viele Grüße
Daniel

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Steht im Datenblatt des Drucksensors von VTI (SCP1000) was darüber, wie 
lange die EEPROM-CRC-Berechnung im Sensor dauert und ob eine 
Mindestwartezeit eingehalten werden muss?

Ich würde versuchsweise mal eine Wartezeit vor folgender Zeile einbauen:
  ((readI2C(DATARD8) & 0x01) == 1 ? (success += 0) : (success += 2));

von Daniel (Gast)


Lesenswert?

Der Gedanke kam mir auch und das hab ich gestern schon ausprobiert. 
Keine Wirkung. Trotzdem wollte ich es gerade nochmal machen. 
Komischerweise kommt er jetzt nur bis zur Abfrage des Registers 
"DATARD8" (also Funktion "checkStartupStatus()"
bei
"((readI2C(DATARD8) & 0x01) == 1 ?...")

Dann hängt er in der Funktion "readI2C()"
bei
"while ((I2CIFG & ARDYIFG) == 0)" fest.

von Daniel (Gast)


Lesenswert?

Halt, nee. Jetzt gehts wieder.
Entferne ich die Wartefunktion vor der Prüfsummenabfrage wird die 
Funktion richtig durchlaufen. Warte ich vorher ein paar Zyklen, bleibe 
ich an besagter Stelle hängen.

Komisch, weil gestern lief er auch mit Wartefunktion bis zum 
Rückgabewert.

Ein Kontaktproblem schließe ich aber auch aus, der Aufbau ist auf 
Lochrasterplatine gelötet und die Leitungen habe ich schon 3x 
kontrolliert und durchgeprüft. 100nF hab ich auch an den 
Versorgungsleitungen.

von Daniel (Gast)


Lesenswert?

Hab jetzt die Hardware auch nochmal neu aufgebaut. Bringt nur leider 
auch nix. Verhält sich genauso wie der alte Aufbau auf Lochraster.

Hat jemand schonmal den I2C-Bus vom MSP430 verwendet? Den Code für die 
Funktionen hab ich mit diversen Application Notes von TI verglichen - 
ich denke also, dass ich den Bus richtig bediene. Kann mich da 
wenigstens jemand bestätigen?

Danke
Daniel

von Eugen K. (kannsnet)


Lesenswert?

@Daniel
Hast du mittlerweile eine Lösung gefunden? Ich hab nämlich das selbe 
Problem mit dem SCP1000.

Gruß Eugen

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.