Forum: Mikrocontroller und Digitale Elektronik I2C Adresse stimmt nicht


von Benjamin M. (berkutta)


Angehängte Dateien:

Lesenswert?

Langsam weiss ich echt nicht mehr weiter. Ich versuche einen I2C Sensor 
auf der Adresse 0xB8 anzusprechen. Habe mir dazu mal ein reines 
Testprogramm geschrieben welches nicht mehr als die Adresse ansprechen 
sollte. Jedoch kommt wenn ich das mit dem Oszi ansehe immer die Adresse 
um ein Bit nach Rechts geschoben vor. Sprich 0x5C. Ich habe jedoch 
absolut keine Ahnung wie das zustande kommt.
1
#define F_CPU 16000000UL
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
7
void f_i2c_start()
8
{
9
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
10
  
11
  while (!(TWCR & (1<<TWINT)));  
12
}
13
14
void f_i2c_commit()
15
{
16
  TWCR = (1<<TWINT)|(1<<TWEN);
17
  
18
  while (!(TWCR & (1<<TWINT)));
19
}
20
21
int main(void)
22
{
23
  TWBR = 55;
24
25
  while(1)
26
    {
27
    
28
    f_i2c_start();
29
    
30
    TWDR = 0xB8;
31
  
32
    f_i2c_commit();    
33
    
34
    }
35
}

von Lutz (Gast)


Lesenswert?

I2c hat 7 bit Adressen? Das LSB (8te bit) sagt schreiben oder lesen.

von holger (Gast)


Lesenswert?

0x5C ist die 7 Bit I2C Adresse. Das achte (unterste) Bit ist
das R/W Bit. Also alles in Ordnung.

von Benjamin M. (berkutta)


Angehängte Dateien:

Lesenswert?

ok, stimmt. Hatte da irgendwie einen Hänger. Danke.

Mein Vorhaben funktioniert jedoch irgendwie immernoch nicht so ganz. 
Mein Ziel ist es ein Feuchte/Temperatur Sensor AM2321B anzusprechen. 
Dafür möchte ich den Atmega 8 nutzen. Ich habe mich dabei relativ 
strikte ans Datenblatt unter 
http://akizukidenshi.com/download/ds/aosong/AM2321_e.pdf gehalten. Das 
Procedure welches ich hier "nachspielen" möchte findet sich auf Seite 
17-18. Kennzeichnet als Step one - Step three. Programm sieht wie folgt 
aus:
1
 
2
3
#define F_CPU 16000000UL
4
5
6
#include <avr/io.h>
7
#include <util/delay.h>
8
9
10
void f_i2c_start()
11
{
12
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
13
  
14
  while (!(TWCR & (1<<TWINT)));  
15
}
16
17
void f_i2c_stop()
18
{
19
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);  
20
}
21
22
void f_i2c_commit()
23
{
24
  TWCR = (1<<TWINT)|(1<<TWEN);
25
  
26
  while (!(TWCR & (1<<TWINT)));
27
}
28
29
char f_i2c_write(char data)
30
{
31
  TWDR = data;
32
  
33
  f_i2c_commit();  
34
}
35
36
int main(void)
37
{
38
  
39
  
40
  //Set Clock Rate of I2C Bus. In this Case about 10k
41
  TWBR = 65;
42
43
  /*
44
  f_i2c_start();
45
    
46
  f_i2c_write(0b10010000);
47
  */
48
    
49
  while(1)
50
      {
51
    
52
    f_i2c_start();
53
      
54
    TWDR = 0b10111000;
55
      
56
    f_i2c_commit();
57
    
58
    _delay_us(900);
59
    
60
    f_i2c_stop();  
61
    
62
    
63
    
64
    f_i2c_start();
65
      
66
    TWDR = 0b10111000;
67
      
68
    f_i2c_commit();
69
      
70
    TWDR = 0x03;
71
      
72
    f_i2c_commit();
73
    
74
    TWDR = 0x00;
75
    
76
    f_i2c_commit();    
77
    
78
    TWDR = 0x04;
79
    
80
    f_i2c_commit();
81
          
82
    f_i2c_stop();
83
84
85
86
    f_i2c_start();
87
  
88
    TWDR = 0b10111001;
89
  
90
    f_i2c_commit();
91
  
92
    _delay_us(50);
93
  
94
    f_i2c_commit();
95
  
96
    f_i2c_commit();  
97
  
98
    f_i2c_stop();    
99
    
100
101
      }
102
}
103
104
Code sieht noch relativ wild aus. Kann das ganze jedoch nicht in "schlaue" Funktionen packen ehe ich weiss wie ich das ganze korrekt mach bezüglich I2C :)
105
106
Ich hoffe jemand kennt sich mit dem Teil aus und kann mir damit etwas Starthilfe geben.

von holger (Gast)


Lesenswert?

>etwas Starthilfe geben.

Du bekommst kein ACK von deinem Sensor.
Die Vermutung liegt nahe das etwas falsch angeschlossen ist.

von holger (Gast)


Lesenswert?

Im zweiten Bild sieht man das die Clock Leitung vorne und hinten
auf Low liegt. Das sieht sehr falsch aus für I2C.

von Wolfgang (Gast)


Lesenswert?

holger schrieb:
> Die Vermutung liegt nahe das etwas falsch angeschlossen ist.

Oder der Sensor ist nicht im I2C-Kommunikationsmodus.

von Benjamin M. (berkutta)


Lesenswert?

An einen Verdrahtungsfehler denke ich momentan eher nicht. I2C auf dem 
Atmega 8 läuft, das haben vorherige Tests mit einem PCF8591 bewiesen. 
Die Belegung des nun verwendeten Sensors habe ich sowohl mit dem 
Lieferanten als auch mit dem Datenblatt abgeglichen, beides identisch 
und selbstverständlich auch so verdrahtet in meiner Schaltung. Im Single 
Line Mode sollte er ja nicht sein da ich SCL nicht an Ground geklemmt 
habe.

von Richard S. (rscheff)


Lesenswert?

Laut dem i2c programm mit dem man auf embedded linux den am2321 
ausliest, braucht der sensor beim lesen 8 slots:


st_am2321 am2321() {
  int fd;
  int ret;
  int retry_cnt;
  unsigned char data[8];

  /* open I2C device */
  fd = open( I2C_DEVICE, O_RDWR );
  if ( fd < 0 ) {
    perror( "am2321(1)" );
    exit( 1 );
  }

  /* set address of I2C device in 7 bits */
  ret = ioctl( fd, I2C_SLAVE, AM2321_ADDR );
  if ( ret < 0 ) {
    perror( "am2321(2)" );
    exit( 2 );
  }

 retry_cnt = 0;
 retry:

  /* wake I2C device up */
  write( fd, NULL, 0);

  /* write measurement request */
  data[0] = 0x03; data[1] = 0x00; data[2] = 0x04;
  ret = write( fd, data, 3 );
  if ( ret < 0 && retry_cnt++ < 5 ) {
    fprintf( stderr, "am2321: retry\n" );
    udelay( 1000 );
    goto retry;
  }
  if ( ret < 0 ) {
    perror( "am2321(3)" );
    exit( 3 );
  }

  /* wait for having measured */
  udelay( 1500 );

  /* read measured result */
  memset( data, 0x00, 8 );
  ret = read( fd, data, 8 );
  if ( ret < 0 ) {
    perror( "am2321(4)" );
    exit( 4 );
  }

  /* close I2C device */
  close( fd );

  return __st_am2321( data );
}

Eventuell ist im Am2321 nicht die vollständige i2c state machine 
implementiert, und wenn du zyklich zu wenige daten abfragst, kommst du 
aus dem tritt mit dem was der sensor an CLK erwartet, und du ihm 
mitteilen will?

Auch würde ich keine blinden while schleifen nutzen - ein I2c slave kann 
CLK low halten, bzw wenn ein slave ein SCLK verpasst, kann sich der I2c 
bus aufhängen (bekanntes problem), daher würde ich wohl immer einen 
counter mitlaufen lassen (von oben nach null, geht schneller auf AVR) 
und nach jedem byte auf eventuelle timeouts achten...

Wie dem auch sei, im Osci trace fehlt aber von den 2 read bytes jede 
Spur - nachdem ich keine hardware i2c im avr genutzt habe (und zu faul 
bin, die doku zu lesen), sicher dass man da nicht in den registern 
irgendwas von schreibend (und ACK bit lesen) auf lesen (und ACK / NACK 
schreiben) umstellen muß?

In meinem Falle hab ich den AM2321 einfach an den AT91SAM9G25 auf einen 
I2C Port gehängt, und er lief sofort ohne probleme... Allerdings mit 
vorgefertigter Software, da ich faul bin - wozu das Rad neu erfinden :)

von Wolfgang (Gast)


Lesenswert?

Benjamin M. schrieb:
> I2C auf dem Atmega 8 läuft, das haben vorherige Tests mit einem
> PCF8591 bewiesen.

Vielleicht reagiert der PCF8591 auf deine komischen SCL-Ruhepegel anders 
als der AM2321B. Nach Datenblatt soll SCL vor START und nach STOP auf 
High-Pegel liegen.

von Iqadratcverdrahter (Gast)


Lesenswert?

Das scheint das Problem des fehlenden Stopps zu sein. Laut SPEC muss das 
ein slave können. Manche können es aber nicht.

von Oliver (Gast)


Lesenswert?

Ganz blöde Frage für Zwischendurch: Die Pull-Up sind vorhanden?

von Benjamin M. (berkutta)


Lesenswert?

Jap, 10k auf 5V für SCL und SDA

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Benjamin M. schrieb:
> DSO_1.png

Nach wie vor kein ACK vom I2C Slave. Entweder hat der Sensor Mucken oder 
er befindet sich in einem anderen Modus.
Setzt ihn vor dem ersten Ansprechen mal zurück nach der bewährten 'I2C 
Bus hängt' Prozedur - beschrieben im Philips I2C Grundlagen Blatt und 
bei Atmel im USI Abschnitt. (9-mal clocken, dabei SDA beobachten usw.)

von Klaus (Gast)


Lesenswert?

Wolfgang schrieb:
> Nach Datenblatt soll SCL vor START und nach STOP auf
> High-Pegel liegen.

Nicht nur nach Datenblatt, auch nach der I2C Spec. Ein Master darf nur 
auf den Bus gehen, wenn dieser Idle ist. Und das heißt SCL und SDA high.

Iqadratcverdrahter schrieb:
> Das scheint das Problem des fehlenden Stopps zu sein. Laut SPEC muss das
> ein slave können. Manche können es aber nicht.

Das können schon alle. Aber, wenn eine der Leitungen (durch was auch 
immer) auf low klemmt, kann man kein Stop erzeugen. Da kann man das Bit 
"gib Stop auf den Bus" im Master so oft setzen, wie man will. Die 
Signalfolge eines Stops wird nicht entstehen.

MfG Klaus

von R. M. (rmax)


Lesenswert?

@Benjamin:

Ich habe hier einen AM2320 vor mir, der bis auf die Lage der Pins 
(untere Schmalseite vs. Rückseite des Gehäuses) mit dem AM2321B 
identisch zu sein scheint.

Wenn ich das schleche Englisch der Datenblätter richtig deute, soll man 
zwischen dem STOP von Step 2 und dem START von Step 3 nochmal mindestens 
1,5ms warten, was Dein Programm nicht macht. Damit klappt es bei mir.

Beim Verhalten meines Exemplars sind mir folgende Unterschiede zum 
Datenblatt aufgefallen:

Jenseits der Meßwerte liefern fast alle Register beim Lesen eine 0. 
Einzige Ausnahme ist der Wert 0xfd im Register 0x1d. Außerdem führt der 
Versuch, das letzte Register (0x1f) zu lesen zum Fehlercode 0x81 (Read 
an illegal address), obwohl das laut Datenblatt noch existieren müßte.

Falls Dein Sensor inzwischen läuft oder Du ihn mit dem o.g. Delay zum 
Laufen bekommst, würde mich interessieren, ob bei Dir die anderen 
Register sinnvollere Werte liefern.

von Benjamin M. (berkutta)


Lesenswert?

@Max:

Habe mich mit dem Sensor in der Zwischenzeit nicht mehr Beschäftigt. 
Schaue ich mir aber sonst mal an wenn ich Zeit habe und den ganzen Kram 
wieder zusammenbekomme. Kann jedoch nichts garantieren.

von R. M. (rmax)


Lesenswert?

Falls es Dir was nützt, kann ich mein Testprogramm hier reinhängen.

Es ist für den ATmega32U4 und implementiert ein USB-CDC-Device. Bei 
jeder fallenden Flanke an PE2 (die User-Taste auf dem Olimex AVR-T32U4) 
gibt es über die virtuelle serielle Schnittstelle einen Registerdump 
aus.

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.