Forum: Mikrocontroller und Digitale Elektronik D/A Wandler I2C Bus Problem


von Andreas F. (finki79)


Lesenswert?

Hallo,

ich habe ein Problem mit meinem I2C Bus in Verbindung mit einem D/A 
Wandler.

Dies ist mein erstes Projekt mit einem I2C Bus.

Ich verwende einen Mircochip PIC18F45K22 µC.
Über den I2C Bus versuche ich 3 ICs anzusteuern.

RTCC MCP7941
EEPROM 24AA64
D/A Wandler MCP4725 und optional DAC6571

Im ersten Versuch hab ich die PullUp Widerstände an SCL und SDA 
vergessen.
Da ging erstmal gar nix, hab ich über die Suchfunktion aber lösen 
können.
Habe an SCL und SDA jeweils ein 2,2k als PullUp eingelötet.

Die RTCC und das EEPROM funktionieren jetzt super.
Nur mit dem D/A hab ich meine Probleme.
Ich kann einfach keinen Werte für die Ausgangsspannung vorgeben.
Habe deswegen auch schon einen anderen D/A verwendet. siehe oben. Diese 
beiden D/A sind von der Pinbelegung identisch.
Den A0 Adresspin hab ich auf Masse gelegt.
VDD hängt an 5V, VSS an GND, Vout über 10k an Masse.
Ich messe dann mit dem Multimeter den Spannungsabfall über den 10k 
Widerstand.
Dieser bleibt jedoch konstant bei ca. 10mV.

Ich bekomme von D/A einfach kein ACK.
Da die anderen beiden ICs funktionieren, gehe ich davon aus, dass die 
Software an sich funktionieren sollte.
Ablauf:
Start
Byte 1 Adresse
Byte 2 MS Byte
Byte 3 LS Byte
Stop
Ohne meine Timeout Funktion hängt sich die Software auf, da ich keine 
Bereitschaft vom D/A bekomme. Die beiden anderen ICs bräuchten den 
Timeout nicht.
Beim 4725 hab ich auch die Wiederholung von Byte 2 und 3 probiert.
Jedoch alles ohne Erfolg.
Was kann man denn noch falsch machen, dass der IC einfach nicht läuft?
Ich hoffe ihr könnt mir helfen.

BOOLEAN i2c_ready(BYTE I2C_IC) {
   int1 ack;
   i2c_start(I2C_INT);              // Startbit Senden
   ack = i2c_write(I2C_INT,I2C_IC); // ControlByte senden und ACK Bit 
abfragen
   i2c_stop(I2C_INT);               // Stopbit senden
   return !ack;                     // Statusbit zurückgeben
}

int i2c_schreiben(int Bytes)
{
   i2c_error=FALSE;             // Merker I2C Fehler zurücksetzen
   i2c_timeout=0;               // Zähler I2C zurücksetzen
   while(!i2c_ready(I2C_DA_OUT[0])){if (i2c_error){break;}}  // warten 
bis IC bereit nach 250ms Fehler => Abbruch
   if (!i2c_error){             // Wenn Bus bereit
      i2c_start(I2C_INT);       // Startbit senden
      for (i=0; i<Bytes; i++){i2c_write(I2C_INT,I2C_DA_OUT[i]);} // alle 
Bytes senden
      i2c_stop(I2C_INT);        // Stopbit senden
      I2C_Bytes=0;              // Anzahl Bytes auf Null setzen (=Merker 
ob senden ja/nein)
   }
   return i2c_error;
}

#int_timer2                             // Interrupt Routine für Timer 2
void Takt_ISR()
{
   if (!Tasten_Enable){                 // wenn Taste gedrückt wurde
      if (--int_count_Tasten == 0){     // 300 ms abgelaufen - drücken 
wieder bearbeiten
         int_count_Tasten = INT_TASTER; // Zähler zurücksetzen
         Tasten_Enable = TRUE;}}        // Tasten wieder frei geben
   if (!Analog_Enable){                 // wenn Analogeingang gelesen 
wurde
      if (--int_count_Analog == 0){     // 300 ms abgelaufen - nächsten 
Analogwert lesen
         int_count_Analog = INT_ANALOG; // Zähler zurücksetzen
         Analog_Enable = TRUE;}}        // Analogeingang wieder frei 
geben
   if (!RTCC_Enable){                   // wenn Uhrzeit gelesen wurde
      if (--int_count_RTCC == 0){       // 500 ms abgelaufen - nächste 
Uhrzeit lesen
         int_count_RTCC = INT_UHRZEIT;  // Zähler zurücksetzen
         RTCC_Enable = TRUE;}}          // Uhrzeit wieder frei geben

   if(++i2c_timeout==250){i2c_error=TRUE;} // I2C Timeout
}

Edit: ich verwende den CCS Compiler und die Funktionen i2c_start(); 
i2c_stop; i2c_write sind dort vordefinierte funktionen. I2C_INT ist der 
Stream (es gibt 2 I2C Schnittstellen), ja und der D/A hängt am richten 
I2C Bus. Mit Multimeter die Widerstände nachgemessen. :)

von Klaus (Gast)


Lesenswert?

Wenn ich einen neuen I2C-Baustein in Betrieb nehme, bastel ich mir 
erstmal eine Funktion, die den Bus scannt.

Etwa so

loop über alle 128 Adressen {
   Start
   write Adresse
   Stop
   wenn ACK, Chip gefunden
}

So kann man leicht überprüfen, ob die Adressen stimmen und der Chip 
lebt.

MfG Klaus

von Andreas F. (finki79)


Lesenswert?

Hallo Klaus,

vielen Dank für den Tipp, hab ich gleich mal ausprobiert.
Erst war ich überrascht warum ich bei so viele Adressen ein ACK bekommen 
habe. Dann wars mir klar jedes IC sendet auf write und read ein ACK.

So nun hab ich folgendes zurück bekommen:

160 => EEPROM
174 => RTCC (EEPROM)
222 => RTCC (SRAM)
224 => ?? keine Ahnung wer das ist

152 => D/A keine Antwort
144 => D/A Broadcast Adresse auch keine Antwort

Jetzt bin ich etwas verwirrt. Ich habe keinen 4. IC an meinem Bus 
hängen.
Also welcher IC anwortet mit ACK bei der 4. Adresse? Dachte erst die 
Adresse vom D/A wurde falsch im Datenblatt angegeben, aber mit der 
Adresse lässt sich der Analogwert auch nicht verstellen.

von Stephan (Gast)


Lesenswert?

Hi,
pass auf, denn deine DAs haben unterschiedliche Adressen!
Warum gibs du uns eingendlich nicht die richtigen Adressen, könnte man 
besser überfliegen. I2C Adr. sind nur 7Bit oder 10Bit lang!

MCP4725
Adr: b 1100xxa bei dir ist sie (a= 0) b 1100xx0
wie die A2 + A1 stehen, hast du ja nicht gesagt.
Ergibt einen Adr.Raum von 96 - 102!

DAC6571
Adr: b 100110a bei dir ist sie (a= 0) b 1001100
Ergibt einen Adr von 76!

also schau noch mal in die Schaltung und prüfe sie!
Beim Broadcast würd ich vorsichtig sein mit Antworten. KA!

Stephan

von Andreas F. (finki79)


Lesenswert?

Hallo Stephan,

die Adressen:

MCP4725
RS Bestellnummer: 669-6290, Teilnummer: MCP4725A0T-E/CH
PIN A0 liegt an GND
Datenblatt Seite 15 müsste mit der Teilnummer die A2 und A1 "0" sein.
Adresse somit 0b11000000 = dezimal 192
Dieser IC ist gerade nicht eingelötet.

DAC6571
RS Bestellnummer: 662-1448, Teilenummer: DAC6571IDBVTG4
PIN A0 liegt an GND
Datenblatt Seite 15 gibt es 2 Adressen, IC und broadcast
0b10010000 IC            = dezimal 144
0b10011000 broadcast     = dezimal 152

hab meine Defines nicht mit angegeben:
#define I2C_W_EEPROM    0b10100000     // dezimal 160
#define I2C_W_D_A       0b11000000     // dezimal 192
#define I2C_W_D_A_2     0b10010000     // dezimal 144
#define I2C_W_RTCC_E    0b10101110     // dezimal 174
#define I2C_W_RTCC_S    0b11011110     // dezimal 222

ich hab halt in der Software die Konstanten ausgetauscht um die beiden 
D/A's anzusprechen. Aktuell ist der DAC6571 verbaut, weil der MCP4725 
nicht funktioniert hat und ich einfach nen anderen ausprobieren wollte, 
nachdem ich den IC 2x getauscht habe.
Habe dann weil der DAC6571 auch nicht auf seiner Adresse antwortet mit 
der Broadcast probiert.
Mitd er Lösung von Klaus hab ich ja auch antworten von den IC's 
bekommen.

Code:
void i2c_Adr_check()
{
   int1 ack;
   for (i=0; i<255; i++){
      i2c_start(I2C_INT);         // Startbit Senden
      ack = i2c_write(I2C_INT,i); // ControlByte senden ACK Bit abfragen
      i2c_stop(I2C_INT);          // Stopbit senden
      if (!ACK){fprintf (RS_CONTROL, "Adresse: %03u vorhanden   ",i);}
      delay_ms(10);
   }
}

aus dem Compiler Manual zu i2c_write:
This function returns the ACK Bit.
0 means ACK, 1 means NO ACK, 2 means there was a collision if in 
Multi_Master Mode.
This does not return an ACK if using i2c in slave mode

nur antwortet eben ein IC mit der ADR: 224 der gar nicht vorhanden ist.
und der D/A antwortet weder bei 144 noch bei 152.

Andi

von Stephan W. (sir_wedeck)


Lesenswert?

Hi,

>Dies ist mein erstes Projekt mit einem I2C Bus.
Bitte lerne es gleich richtig und kennzeichne deine defines für die 
Chips nicht als Adressen! (zb. I2C_W_EEPROM)
I2C Adr. sind nur 7Bit oder 10Bit lang!
1
if (!ACK)...
Das ist ein Schreibfehler hoffe ich, aber sonst ok.
Deine Funktion gibt halt W und R Kommandos an.

schreib einfach:
1
..."Adresse: %03u vorhanden   ",i>>1);}
dann bekommst du auch gleich die richtigen Adressen.

Ich setzte hier den DAC7571 ein und der lief bei mir sofort. Prüfe noch 
mal ob du nicht doch einen Kurzschluss bei dem DAC gemacht hast.

Stephan

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

Und nimm Hex, bei Dezimal sieht kein Schwein durch, welches Bit da nun 
gesetzt ist und welches nicht.

[quote]VDD hängt an 5V, VSS an GND, Vout über 10k an Masse[/quote]
Der Widerstand könnte sogar schon zu klein sein. Miss mal ohne R von OUT 
nach GND.

von Andreas F. (finki79)


Lesenswert?

Guten Morgen,

ok ich bin einfach blind gewesen.
Hab den Fehler gefunden.
Am D/A sind SCL und SDA vertauscht. Das kann also so nicht gehen :(
Jetzt mal schaun ob ich das noch drehen kann.
Danke für die anderen Tipps werde die gleich mal umsetzen.

Bleibt noch eine Frage,
ich habe den D/A nun ausgelötet, wobei mir dann die vertauschten 
Leitungen beim Nachmessen aufgefallen sind. Danach habe ich nochmal alle 
Bus Adressen geprüft.
Es bleibt noch die Adresse: 0b1110000 0x70
Diese Antwortet auch mit einem ACK, ich weiß nur nicht wer das sein 
soll.

Andi

von mr. mo (Gast)


Lesenswert?

Dann nehm ein Baustein raus, teste die Adresse und dann den nächsten. 
Bis du weiß wer es ist.

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.