Forum: Mikrocontroller und Digitale Elektronik I2C SW - bitte ein Bit Problem


von funny (Gast)


Lesenswert?

Hallo,

vielleicht könnt ihr mir helfen. So langsam bin ich mit meinem Latein am 
Ende.

Beim lesen der einzelen Bit eines CMPS03 Kompass Sensors bekomme ich 
immer high, ergo 0xFF als Wert.

Die Routine ist aus dem Keil Buch von Baldischweiler. Prozessor ist ein. 
8051, Compiler ist Keil C51.

Im Protokollanalyzer (Intronix Logicport)stimmt alles, es kommen auch 
Werte vom Sensor auf dem Bus. (siehe Anhang)

Also Adressierung stimmt.

Anderer Sensor und anderer Prozessor bringen das gleiche.

Ich hab echt keine Ideen mehr.

Wäre nett wenn euch was einfällt.

DANKE







Code der Leseroutine:
/*
***************************************************
*
*               I2C Library
*
*        For Keil C, with features of bus fault
*        detection, no acknowledgement feature,
*        and I2C busy feature.
****************************************************
*/
uchar Si2c_in( bit btACK )
{
   I2CWAIT2;
  SSDA = 1;   // Freigabe vom BUS
  SSCL = 1; I2CWAIT3;
  sbtD7 = SSDA;         // Lesen des Bit 7 (MSB)

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
   sbtD6 = SSDA;         // Lesen des Bit 6

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD5 = SSDA;          // Lesen des Bit 5

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD4 = SSDA;         // Lesen des Bit 4

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD3 = SSDA;          // Lesen des Bit 3

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD2 = SSDA;         // Lesen des Bit 2

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD1 = SSDA;          // Lesen des Bit 1

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD0 = SSDA;         // Lesen des Bit 0 (LSB)

  SSCL = 0; I2CWAIT4;


  SSDA = btACK;          // ACK/NACK vom Master

  SSCL = 1; I2CWAIT3;       // ACK-Takt
  SSCL = 0; I2CWAIT4;

  return(ucI2CVal);
}

von holger (Gast)


Lesenswert?

Du sammelst sbtD7..0 ein und gibst ucI2CVal zurück.
Hängen die irgendwie zusammen ? Das ist mit dem
Code leider nicht zu sehen.

von funny (Gast)


Lesenswert?

ja, das sieht so aus:


unsigned char bdata ucI2CVal;
sbit sbtD0 = ucI2CVal ^0;
sbit sbtD1 = ucI2CVal ^1;
sbit sbtD2 = ucI2CVal ^2;
sbit sbtD3 = ucI2CVal ^3;
sbit sbtD4 = ucI2CVal ^4;
sbit sbtD5 = ucI2CVal ^5;
sbit sbtD6 = ucI2CVal ^6;
sbit sbtD7 = ucI2CVal ^7;

sbit  SSCL = P0 ^1;
sbit  SSDA = P1 ^6;

von Matthias (Gast)


Lesenswert?

Musst uns mehr Input geben. Welcher 8051 genauer? Taktfrequenz? I2C- 
Taktfrequenz? Möglichst das komplette Programm als Anhang.

von winne (Gast)


Lesenswert?

hm

Hier ist timing extrem wichtig im Zweifel länger warten(langsamer 
takten).

Am besten Signalsequenzen kontrollieren.

Das du zuvor die richtige Adresse senden und vielleicht noch ein 
register setzen musst ist dir bekannt?

Hast du die Initsequenz des Kompasschips durchgezogen?

von Peter D. (peda)


Lesenswert?

Du mußt schon die komplette I2C-Sequenz posten, nicht nur einen Brocken 
einfach so hinwerfen.

Hier mal ein Beispielcode:

http://home.tiscali.de/peterd/appl/soft/c51/eeprom/index.htm


Peter

P.S.:
Man darf unter C auch Schleifen verwenden.
Copy&Paste-Code hat die Eigenschaft, sehr fehleranfällig zu sein. Und 
speicherfressend ist er sowieso.

von funny (Gast)


Lesenswert?

Hallo Matthias,

deine Vermutung geht Richtung Timing, aber Timing ist okay, siehe 
Protokoll Analyzer.
Ich kann ja den Sensor ansprechen, er leifert auch korrekte Daten auf 
dem Bus, uzu sehen am Analyzer Protokoll.

Mehr Input:
-Taktfrequenz I2C 100 Khz, siehe Diagramm.
-M8051EW, 16 MHz

Aus irgendeinem Grund ist der eine PIN immer high. Der bekommt einfach 
LOW nicht mit, im Gegensatz zum Analyzer.

Entweder stimmt für ihn der Pegel nicht oder der läuft nur als output 
und lässt sich nicht abfragen.
Die Pullups sind extern mit 4,7K beschaltet, Prozessor läuft mit 3,3 
Volt.





Code Complete



/*
***************************************************
*
*               I2C Library
*
*        For Keil C, with features of bus fault
*        detection, no acknowledgement feature,
*        and I2C busy feature.
****************************************************
*/
uchar Si2c_in( bit btACK )
{
   I2CWAIT2;
  SSDA = 1;   // Freigabe vom BUS
  SSCL = 1; I2CWAIT3;
  sbtD7 = SSDA;         // Lesen des Bit 7 (MSB)

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
   sbtD6 = SSDA;         // Lesen des Bit 6

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD5 = SSDA;          // Lesen des Bit 5

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD4 = SSDA;         // Lesen des Bit 4

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD3 = SSDA;          // Lesen des Bit 3

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD2 = SSDA;         // Lesen des Bit 2

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD1 = SSDA;          // Lesen des Bit 1

  SSCL = 0; I2CWAIT4;
  SSCL = 1; I2CWAIT3;
  sbtD0 = SSDA;         // Lesen des Bit 0 (LSB)

  SSCL = 0; I2CWAIT4;


  SSDA = btACK;          // ACK/NACK vom Master

  SSCL = 1; I2CWAIT3;       // ACK-Takt
  SSCL = 0; I2CWAIT4;

  return(ucI2CVal);
}


bit Si2c_out( unsigned char ucValue )
{
   unsigned char ucErr = I2C_OK;
   ucI2CVal = ucValue;

   SSDA = sbtD7;                     // Senden des MSB
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD6;                     // Senden des Bit 6
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD5;                     // Senden des Bit 5
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD4;                     // Senden des Bit 4
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD3;                     // Senden des Bit 3
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD2;                     // Senden des Bit 2
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD1;                     // Senden des Bit 1
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;
   SSDA = sbtD0;                     // Senden des Bit 0
   SSCL = 1; I2CWAIT1; SSCL = 0; I2CWAIT2;

   SSDA = 1;       // Datenfreigabe fuer ACK-Signal
   SSCL = 1; I2CWAIT1;  // ACK-Takt

   if (SSDA)
      ucErr = I2C_ACK_E;

   SSCL = 0; I2CWAIT2;

   //SSDA = 0;

   return ucErr;
}


bit Si2c_stop(void)
{
  SSCL = 1;
  I2CWAIT1;
  SSDA = 1;
  I2CWAIT1;
  return ~SSDA;    // 1 = Error, SDA not high
}


void Si2c_start(void)
{
  SSDA = 1;
  SSCL = 1;
  I2CWAIT2;

  SSDA = 0;
  I2CWAIT2;
  SSCL = 0;
  I2CWAIT2;

}


void _waitnop(unsigned char nops)
{
  uchar i;
  for(i=0; i<nops ;i++)  // o,4uS = 1 NOP
  {
  _nop_();
  _nop_();
  }
}



//---------------------------------------------------------------------- 
--------
// Header file
//---------------------------------------------------------------------- 
--------
#define I2CWAIT1 _waitnop(3)
#define I2CWAIT2 _waitnop(3)
#define I2CWAIT3 _waitnop(3)
#define I2CWAIT4 _waitnop(3)

#define ACK  0
#define NACK 1

unsigned char bdata ucI2CVal;
sbit sbtD0 = ucI2CVal ^0;
sbit sbtD1 = ucI2CVal ^1;
sbit sbtD2 = ucI2CVal ^2;
sbit sbtD3 = ucI2CVal ^3;
sbit sbtD4 = ucI2CVal ^4;
sbit sbtD5 = ucI2CVal ^5;
sbit sbtD6 = ucI2CVal ^6;
sbit sbtD7 = ucI2CVal ^7;

sbit  SSCL = P0 ^1;
sbit  SSDA = P1 ^6;

unsigned char Si2c_in( bit btACK );
bit Si2c_out( unsigned char ucValue);
bit Si2c_stop(void);
void Si2c_start(void);

extern void _waitnop(unsigned char nops);

von funny (Gast)


Lesenswert?

Hallo Peter,

ich vermute, dass der PIN immer high ist,und das Problem nicht in der 
eigentlichen I2C Geschichte liegt und hab mein Posting daher auf die 
vermutete Fehlerquelle beschränkt. Beim 8051 kann der PIN doch gelesen 
und geschrieben werden ?
Bzgl. Schleife, hat mich bei den NOPS im Quellcode auch gestört und hab 
das Cut&Paste dort auch schon ersetzt. Ich geb zu, dein Code ist da 
eleganter als der vom Kollegen :)

von funny (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

das mit dem Dateinanhang hat wohl nicht geklappt. Ich beziehe mich die 
ganze Zeit auf das hochgeladene Protokoll vom Analayzer und sehe gerade, 
da ist nichts. (Bitte den Dateianhang vor dem Absenden noch einmal 
auswählen!  -  werlesen kann hat Vorteile). Ich hängs nochmal an.

von Matthias (Gast)


Lesenswert?

Timing nochmal prüfen.
Dein µC ist eine 2-State-Maschine, also ein Turbo-8051. Der ist 6x 
schneller als ein Klassik. Das hast Du hoffentlich bedacht. Die 16MHz 
wären dann einer Taktfrequenz von 96MHz gleichzusetzen.

> for(i=0; i<nops ;i++)  // o,4uS = 1 NOP
0.4us würde dann nicht stimmen, sondern 0,125us pro NOP

von funny (Gast)


Lesenswert?

Die Impulsbreite beträgt 5,5 uSec (siehe auch Hardcopy Analyzer), 
absichtlich schon etwas über der 4,7 uSec Spec. Stimmt die 0,4 für ein 
einzelnes NOP im REM sind falsch.
Der Sensor versteht ja auch meine gesendeten Daten und liefert mir laut 
Analyzer die korrekten Daten zurück. Nur der der SDA Pin der ja beim 
Schreiben auch korrekt arbeitet liefert beim Lesen einfach nur immer 
High.
Stimmt der Pegel evtl. für den Prozessorpin nicht ? Aber für den 
Analyzer ist die Schwelle ja auch okay ?
Die Ports sind bei allen  8051 ja problemlos und ohne zutun 
bidirektional, oder habe ich da was übersehen ?

RATLOS !

von Matthias (Gast)


Lesenswert?

> Die Ports sind bei allen  8051 ja problemlos und ohne zutun
> bidirektional, oder habe ich da was übersehen ?

Nicht ganz. Beim Klassik-8051 musst Du um was von einen PIN einzulesen 
vorher das Ausgangslatch auch 1 setzen. Sonst liest Du immer 0.

SDA = 1; // Portlatch vor lesen auf 1 setzen
input = SDA; //liest nun 1 oder 0, jenachmdem was am PIN anliegt

Bei solch speziellen µC wie Du hast kann das aber anders sein. Da musst 
Du genauestens das Datenblatt lesen. Bei der 2Cycle 8051-Serie P89LPC9xx 
von NXP muß man z.B. auch vorher festlegen, ob der Portpin Ein- oder 
Ausgang sein soll.

Ansonsten nimm mal eine normale Varibale beim Einlesen, oder hier meine 
Routine:
1
#define  ACK      0
2
#define  NACK      1
3
4
// ********************************************************************
5
// I2C-Bus
6
// Read: 1 Byte schreiben
7
// Übergabe: acknow - ACK (weiteres Zeichen anfordern)
8
//                    NACK (letztes Zeichen)
9
// ********************************************************************
10
byte I2C_read(byte acknow) {
11
byte empfdat, i;
12
  empfdat = 0;
13
  SDA = 1; // Portpin SDA für Empfang vorbereiten
14
  SCL = 0;
15
  for (i = 1; i <= 8; i++) { // 8 Bit seriell empfangen
16
    SCL = 1; SCL = 1; SCL = 1; SCL = 1;
17
    empfdat <<= 1;
18
    empfdat |= SDA;
19
    SCL = 0;
20
  }
21
  SDA = acknow; // ACK-Bit senden
22
  SCL = 0;
23
  SCL = 1; SCL = 1; SCL = 1; SCL = 1;
24
  if (acknow == NACK) SDA = 1; // nächster Zyklus ist Reset
25
  SCL = 0; SCL = 0;
26
  SDA = 1;
27
  return empfdat;
28
}

Musst aber bestimmt noch paar waits einfügen.

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.