Forum: Mikrocontroller und Digitale Elektronik DS1307 und STM8S per I2C verbinden


von Dave (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin Neuling auf dem Gebiet der Mikrocontroller und versuche mich 
aktuell an einem Nachbau der Wort-Uhr. Das ganze will ich mit einem 
STM8S-Discovery Evalboard realisieren, auf das mich ein Kollege 
aufmerksam gemacht hat. Ich habe noch keine Erfahrungen mit anderen 
MCUs. Bisher bin ich mit dem Ding auch recht gut voran gekommen, trotz 
der, wie ich finde, guten FW Lib dauert es natürlich seine Zeit, sich in 
neue Gebiete einzuarbeiten.
Wie dem auch sei, nun versuche ich mit einer DS1307 RTC per I2C zu 
kommunizieren, die mir später beim Abschalten der Energiezufuhr die Zeit 
speichern und weiterzählen soll, das klappt jedoch überhaupt nicht. 
Natürlich habe ich mich über das I2C Protokoll informiert und mir einige 
SW Beispiele für die AVRs angeschaut. Wenn ich versuche, die gewonnenen 
Informationen für mich anzuwenden, klappt es jedoch überhaupt nicht.
Die RTC ist wie im Anhang zu erkennen angeschlossen (PE1 ist I2C Clock, 
PE2 I2C Data). VBat liegt erstmal auf GND, für Testzwecke verzichte ich 
darauf erst einmal. f_Master beträgt 2 Mhz. Die Software soll zum Testen 
folgendes machen:

- in der main-Funktion, vor dem Betreten der Hauptschleife, die RTC im 
Register 00h mit 0x00 beschreiben (Clock Halt Bit 0, damit der Quarz 
anschwingt)

- jetzt einmal je Sekunde das Register 00h (Sekunden) auslesen und in 
die Variable "sek" schreiben, deren Wert ich mir dann im Debugger 
angucken kann; das erfolgt in der Hauptschleife, nachdem eine 
Flag-Variable durch einen Interrupt auf 1 gesetzt wurde

SW ("Initialisierung")
1
    // I2C Config -> Output 100kHz, Input 2 Mhz, Ack on current byte, 7 bit address mode, 
2
    I2C_DeInit();
3
    I2C_Init(100000, 0xA2, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 2);
4
    I2C_Cmd(ENABLE); 
5
6
7
    I2C_GenerateSTART(ENABLE);                      // start
8
    I2C_Send7bitAddress(0xD0, I2C_DIRECTION_TX);    // address 1101000 + 0 (WRITE)
9
    I2C_SendData(0x00);                              // set register pointer 00h
10
    I2C_SendData(0x00);                              // write 0x00 to 00h (oscillator enabled)
11
    I2C_GenerateSTOP(ENABLE);                        // stop

In der Main-Schleife:
1
      if (I2C_FLAG == 1) {
2
        
3
        GPIO_WriteReverse(GPIOE, P5);
4
        
5
        I2C_AcknowledgeConfig(I2C_ACK_CURR);
6
        I2C_GenerateSTART(ENABLE);
7
        I2C_Send7bitAddress(0xD0, I2C_DIRECTION_TX);
8
        I2C_SendData(0x00);                              // set register pointer to 00h
9
        I2C_GenerateSTOP(ENABLE);
10
        
11
        I2C_GenerateSTART(ENABLE);
12
        I2C_Send7bitAddress(0xD0, I2C_DIRECTION_RX);
13
        I2C_AcknowledgeConfig(I2C_ACK_NONE);            // NAck after next byte sent
14
        sek = I2C_ReceiveData();
15
        I2C_GenerateSTOP(ENABLE);
16
        
17
        I2C_FLAG = 0;
18
      }

Ergebnis ist, dass keine Informationen von der RTC kommen, sondern immer 
0xd1, das eigentlich zuletzt gesendete byte im Data Register und damit 
in "sek" steht.

Ich habe mir beim Debuggen mal die Registerwerte angeschaut. Nach dem 
Funktionsaufruf I2C_Init... stimmen die Werte für die Control Register 1 
und 2, aus den anderen Registern werde ich jedoch nicht schlau, da 
bestimmte Bits beim Lesen dieser resettet werden. Es gibt ein Flag Bit 
für "Acknowledge Failure", das jedoch nie gesetzt ist.
Im STM8S Reference Manual steht unter anderem:
"Following the address transmission and after clearing ADDR, the master 
sends bytes from
the DR register to the SDA line via the internal shift register."
Also habe ich das Bit ADDR manuell nach dem Senden der Adresse auf 0 
gesetzt, weil die von ST definierten Funktionen dies anscheinend nicht 
tun, aber auch mit der Maßnahme ändert sich nichts.

Sonstige bisherige Maßnahmen (ohne Erfolg):
- Pullups von 4k7 auf 10k erhöht
- DS1307 ausgetauscht

Wie kann ich überprüfen, ob auf der SDA bzw. SCL überhaupt was los ist, 
also ob der STM8S überhaupt versucht, zu kommunizieren? Vorhanden ist 
leider nur ein einfaches Multimeter. Gibt es ansonsten irgendwelche 
anderen Anfänger- oder sonstige Fehler, die ich begangen habe?
Ich bin für alle Hinweise dankbar! Besonders interessant wären SW 
Beispiele für den STM8S für I2C, die ST Seite ist da leider etwas 
sparsam und ansonsten findet sich im Internet auch nichts.

MfG Dave

von Dave (Gast)


Lesenswert?

Gut, mittlerweile habe ich es durch Rumprobieren zum Laufen bekommen.
Ich habe dem STM8S Reference Manual folgend jeden notwendigen 
Registereintrag manuell gemacht und nicht auf die Funktionen der FW Lib 
zurückgegriffen.
1
u8 RTC_ReadTime(u8 adr) {
2
    if (!(I2C->SR3 & 0x02)) {            // If not busy
3
      I2C->CR2 |= 0x04;                  // Ack enabled
4
      I2C->CR2 |= 1;                     // Start condition
5
      while (!(I2C->SR1 & 0x01)) {      // Wait for SB bit set
6
        nop();
7
      }
8
      I2C->DR = 0xD0;                   // Send address 1101000 + 0 (write)
9
      while (!(I2C->SR1 & 0x02)) {      // Wait for ADDR bit set
10
        nop();
11
      }
12
      tmp = I2C->SR3;                    // Read SR3 -> clear ADDR
13
      I2C->DR = adr;                    // Write >>adr<< in DR (register pointer >>adr<<)
14
      while ((!(I2C->SR1 & 0x80)) && (!(I2C->SR1 & 0x04))) {      // Wait for BTF and TxE bit set 
15
        nop();
16
      }
17
      I2C->CR2 |= 1;                    // Re-Start 
18
      while (!(I2C->SR1 & 0x01)) {      // Wait for SB bit set
19
        nop();
20
      }
21
      I2C->DR = 0xD1;                   // Send address 1101000 + 1 (read)
22
      while (!(I2C->SR1 & 0x02)) {      // Wait for ADDR bit set
23
        nop();
24
      }
25
      tmp = I2C->SR3;                    // Read SR3 -> clear ADDR
26
      I2C->CR2 &= (~0x04);              // Ack disabled
27
      I2C->CR2 |= 0x02;                  // Stop condition
28
      while (!(I2C->SR1 & 0x40)) {      // Wait for RxNE bit set
29
        nop();
30
      }
31
      return BCD2DEC(I2C->DR);
32
    }
33
    else {
34
      return 0;
35
    }
36
  }
Die ganzen while-Schleifen gefallen mir zwar nicht, aber ohne kriege ich 
leider keine richtige Kommunikation zustande.

Ein Problem habe ich allerdings noch: Wenn ich die Zeit (Sek, Min, h) im 
Sekundentakt auslese, geht nach etwa vier einhalb Minuten die SDA 
Leitung auf low und verbleibt dort, was das "bus busy" bit setzt und 
jegliche weitere Kommunikation verhindert. Das ganze lässt sich nur 
durch einen Reset des MCU beheben. Jetzt habe ich das Intervall etwas 
verlängert (aller 5 sek) und es scheint zu funktionieren.
Was kann dafür die Ursache sein?

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.