Forum: Compiler & IDEs Probleme mit i2c


von Ein Fest a. (einfest_a)


Lesenswert?

Hallo,
ich versuche mit einem ATmega32 einen HYT 221 
(Feuchte-/Temperatursensor) über i2c anzusprechen/ auszulesen.

Das ist das erste Mal, dass ich etwas mit i2c mache, bin also völlig 
unerfahren.

Da das für die erste Frage reichen sollte, und um es übersichtlich zu 
halten, poste ich erst mal nur den Teil, bei dem das erste Problem 
auftritt.

Ich benutze die i2c lib von Peter Fleury.

Leider bleibt das Programm schon beim setzen der „start condition“ 
hängen. Und zwar in der Zeile:
1
while(!(TWCR & (1<<TWINT)));
Hat jemand eine Idee was da schief läuft?
Grüße,
Tobi

Komlette Methode "i2c_start":
1
/*************************************************************************  
2
  Issues a start condition and sends address and transfer direction.
3
  return 0 = device accessible, 1= failed to access device
4
*************************************************************************/
5
unsigned char i2c_start(unsigned char address)
6
{
7
    uint8_t   twst;
8
9
  // send START condition
10
  TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
11
12
  // wait until transmission completed
13
  while(!(TWCR & (1<<TWINT))); //<-- hier bleibt mein Programm Hängen
14
15
  // check value of TWI Status Register. Mask prescaler bits.
16
17
  twst = TW_STATUS & 0xF8;
18
19
  if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
20
  
21
  // send device address
22
  TWDR = address;
23
  TWCR = (1<<TWINT) | (1<<TWEN);
24
25
  // wail until transmission completed and ACK/NACK has been received
26
  while(!(TWCR & (1<<TWINT)));
27
28
  // check value of TWI Status Register. Mask prescaler bits.
29
  twst = TW_STATUS & 0xF8;
30
  if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
31
32
  return 0;
33
}

von Timmo H. (masterfx)


Lesenswert?

Ansich ist die Funktion richtig so. Benutze sie 1:1 ohne Probleme.

Es gibt eigentlich nur drei Möglichkeiten, wenn sie hängen bleibt:
1. Falscher I2C-Clock (meist zu schnell)
2. Fehler in der Schaltung
3. I2C-Adresse nicht nach links geschiftet (ist wohl der häufigste 
Fehler, da die Adresse nur 7-Bit lang ist und in den Datenblättern 
"ungeshiftet" dargestellt wird).

Wenn im Datenblatt also steht dass die Adresse des ICs "0x0100100" (also 
0x48) dann darf man sich senden "i2c_start(0x48+I2C_READ);" sondern 
"i2c_start(0x90+I2C_READ);

Achja und die untersten/das unterste Bit der Adresse kann ja oftmals 
noch über Adress-Pins verändert werden (je nach Sensor, bei manchen 
gehts auch gar nicht)

Deine Init sieht dann vermutlich so aus
1
void i2c_init(void)
2
{
3
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
4
  
5
  TWSR = 0;                         /* no prescaler */
6
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
7
8
}/* i2c_init */

Und nicht vergessen F_CPU zu setzen.

von Ein Fest a. (einfest_a)


Lesenswert?

Vielen Dank für die Antwort!

Punkt 3. habe ich bedacht. Ich werde mir die Punkte 1 und 2 noch mal 
genau angucken.

Eigentlich wird ja bis zu der betreffenden Zeile der Slave noch garnicht 
direkt angesprochen. Also bleiben so wie so nur die Punkte 1 und 2.
Ich werde mir bei der nächsten Bestellung nochmal einen neuen uC 
bestellen. Vielleicht ist ja der Kanal aus irgendeinem Grund defekt.

Grüße

von Ein Fest a. (einfest_a)


Lesenswert?

Hallo,

ich habe es noch mal probiert, ohne ein angeschlossenes i2c Gerät. 
Trotzdem bleibt er an besagter Stelle hängen.

Ich denke mal, der uC ist defekt????

Oder gibt es noch andere Möglichkeiten?

Hier nochmal meine Init: Ist ja komplett geklaut...und mein Quarz macht 
12.288MHz
1
#include <inttypes.h>
2
#include <compat/twi.h>
3
#include "i2cmaster.h"
4
#include "rtc.h"
5
6
7
/* define CPU frequency in Mhz here if not defined in Makefile */
8
#ifndef F_CPU
9
#define F_CPU 12288000UL
10
#endif
11
12
/* I2C clock in Hz */
13
#define SCL_CLOCK  100000L
14
15
    
16
/*************************************************************************
17
 Initialization of the I2C bus interface. Need to be called only once
18
*************************************************************************/
19
void i2c_init(void)
20
{
21
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
22
  
23
  TWSR = 0;                         /* no prescaler */
24
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
25
  TWDR = 0xFF;                                 // Default content = SDA released.
26
  TWCR |= (1<<TWEN);                            // Enable TWI-interface and release TWI pins.
27
         //(0<<TWIE)|(0<<TWINT)|                 // Disable Interupt.
28
         //(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|      // No Signal requests.
29
         //(0<<TWWC);
30
31
}/* i2c_init */

von Timmo H. (masterfx)


Lesenswert?

Wie sieht deine Schalung aus? 4,7k Pullups dran? µC defekt halte ich für 
relativ unwahrscheinlich.
Zeig mal die Schaltung und den ganzen Quellcode!

von Ein Fest a. (einfest_a)


Lesenswert?

Hallo,

hier die Ausschnitte aus meinem Programm, die mit dem i2c zu tun haben:
Wie gesagt, ich nutze die i2c lib von Peter Fleury, die poste ich jetzt 
nicht komplett...die Header fehlen auch und das ganz Unwichtige habe ich 
aus der Main gestrichen.
Ich habe mir die Signale von SDA und SCL mit dem OSZI angeschaut. Falls 
sinnvoll, kann ich gerne Bilder Posten.
Die Signale sahen recht vernünftig aus. Nur der geringe Pegel von SDA 
hat mich etwas gewundert. (nur 1,5 V bei 5V VCC; SCL ist sauber auf 5V)
Wie schon vermutet, ist der Controller also wohl doch nicht im Eimer.
Zu den Wiederständen: Ich hatte bisher 10k angeschlossen und habe es 
jetzt nochmal mit 5k versucht...leider ohne Erfolg. Kondensatoren sind 
nicht im Bus.
Die Verbindung zwischen uC und Sensor ist mit normalen Einzeladern 
verdrahtet. Dafür aber auch nur ca. 5cm lang. (Testboard)


***i2c_hyd_temp***
1
#include <avr/io.h>
2
#include "i2cmaster.h"
3
#include "i2c_hyd_temp.h"
4
#include "rtc.h"
5
#define ADR_HYD 0x50
6
7
//volatile unsigned char TempCurrent;
8
//volatile unsigned char RLFCurrent;
9
10
11
_Bool getSensVal(void)
12
{
13
  int receive[4];  //receive-array
14
  int RLF_raw;
15
  int Temp_raw;
16
  
17
  i2c_start(ADR_HYD+I2C_SEND);
18
  
19
  //delay einfügen? TODO: schauen ob warten notwendig evtl. wait_i2c(1); implementieren
20
  time_out_i2c = 0;
21
  while(time_out_i2c < 150){} //150ms warten (versuch bei debugging)
22
  
23
  
24
  i2c_start(ADR_HYD+I2C_READ);
25
  
26
  receive[0] = i2c_readAck();
27
  if (receive[0] &= 0x40 == 0)
28
  {
29
    
30
    receive[1] = i2c_readAck();
31
    receive[2] = i2c_readAck();
32
    receive[3] = i2c_readNak();
33
    i2c_stop();
34
    
35
    RLF_raw = (receive[1] & (receive[0] << 8));
36
    RLFCurrent = (RLF_raw  >> 2)/163.83;
37
    Temp_raw = (receive[3] & (receive[2] << 8));
38
    TempCurrent = (Temp_raw >> 2)/99.2909-40;
39
    return TRUE;
40
    
41
    
42
    
43
  }  
44
  else
45
  {
46
    i2c_stop();
47
    return FALSE;
48
  }    
49
  
50
}

Da ich erst heute ein Display integriert habe, wird in dieser Version 
nur über LEDs angezeigt, ob der Messwert (i2c) ungleich oder gleich null 
ist.
***main***
1
#include <avr/io.h>
2
#include "rtc.h"
3
#include <avr/interrupt.h>
4
#include "i2c_hyd_temp.h"
5
#include "i2cmaster.h"
6
7
8
//#define fosc 12288000UL
9
10
#ifndef F_CPU
11
#define F_CPU    12288000UL
12
#endif
13
14
15
int main(void)
16
{
17
  
18
  init_Timers();
19
  i2c_init();
20
  sei();
21
  unsigned char sekAlt = 0;
22
  DDRD = (1<<PD0) | (1<<PD1) | (1<<PD5);
23
    while(1)
24
    {      
25
    if (Uhrzeit.Sekunden > sekAlt)
26
        {
27
      /*
28
      if (!getSensVal())
29
      {
30
        sekAlt++;
31
      } 
32
      else
33
      {
34
        */
35
        sekAlt = sekAlt+3;
36
      //}
37
    
38
      getSensVal();//für debugging
39
      
40
        
41
      if (TempCurrent  == 0)
42
      {
43
        PORTD |= (1<<PD0);//für debugging 
44
      } 
45
      else
46
      {
47
        PORTD |= (1<<PD1);//für debugging
48
      }
49
        
50
    }
51
        
52
  }
53
  return 1;
54
}

von Timmo H. (masterfx)


Lesenswert?

Ein Fest a. schrieb:
> Die Signale sahen recht vernünftig aus. Nur der geringe Pegel von SDA
> hat mich etwas gewundert. (nur 1,5 V bei 5V VCC; SCL ist sauber auf 5V)
Dann stimmt da wohl was an der Hardware nicht. Vielleicht hast du den 
falschen Pin für SDA erwischt oder so. Wie sieht der Pegel denn aus, 
wenn du das IC abklemmst?
Vielleicht hast du auch irgendwo einen Kurzschluss. Da würde ich erstmal 
genau drüber schauen, den 1,5V kann nicht sein. Vielleicht hast du den 
IC auch gar nicht richtig mit Spannung versorgt, dann kann sowas auch 
passieren.
Ob nun 10k oder 4,7k ist dann auch egal. 4,7k ist so der Standardwert, 
vorallem wenn du mit einem schnellen I2C Clock arbeitest, sollte man den 
Pullup nicht zu hochohmig machen (was aber ja bei dir nicht der Fall 
ist)

von Ein Fest a. (einfest_a)


Lesenswert?

Hallo,
vielen Dank für die Antwort!
Ich bin erst jetzt dazu gekommen, mir die Schaltung nochmal anzugucken. 
Die Verdrahtung stimmt definitiv.
Wenn ich die Pins SCL und SDA komplett offen habe, lässt sich kein 
vernünftiges Signal messen, nur ein paar Störungen.
Wenn ich keinen Slave angeschlossen habe, nur die Widerstände, messe ich 
an beiden Pins dauerhaft VCC. (Was dann ja auch nicht verwunderlich 
ist.)
Wenn der Sensor nur an die Versorgungsspannung angeschlossen ist, messe 
ich an SCL VCC(5V) und an SDA ca. 0.5V.
Ich habe danach den Sensor wieder angeschlossen, und Die Signale wieder 
gemessen, wie im letzten Beitrag beschrieben.
Also sollte ich es doch mal mit einem neuen uC und evtl . auch neuen 
Sensor versuchen?

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.