mikrocontroller.net

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


Autor: Dave (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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")
    // I2C Config -> Output 100kHz, Input 2 Mhz, Ack on current byte, 7 bit address mode, 
    I2C_DeInit();
    I2C_Init(100000, 0xA2, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 2);
    I2C_Cmd(ENABLE); 


    I2C_GenerateSTART(ENABLE);                      // start
    I2C_Send7bitAddress(0xD0, I2C_DIRECTION_TX);    // address 1101000 + 0 (WRITE)
    I2C_SendData(0x00);                              // set register pointer 00h
    I2C_SendData(0x00);                              // write 0x00 to 00h (oscillator enabled)
    I2C_GenerateSTOP(ENABLE);                        // stop

In der Main-Schleife:
      if (I2C_FLAG == 1) {
        
        GPIO_WriteReverse(GPIOE, P5);
        
        I2C_AcknowledgeConfig(I2C_ACK_CURR);
        I2C_GenerateSTART(ENABLE);
        I2C_Send7bitAddress(0xD0, I2C_DIRECTION_TX);
        I2C_SendData(0x00);                              // set register pointer to 00h
        I2C_GenerateSTOP(ENABLE);
        
        I2C_GenerateSTART(ENABLE);
        I2C_Send7bitAddress(0xD0, I2C_DIRECTION_RX);
        I2C_AcknowledgeConfig(I2C_ACK_NONE);            // NAck after next byte sent
        sek = I2C_ReceiveData();
        I2C_GenerateSTOP(ENABLE);
        
        I2C_FLAG = 0;
      } 

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

Autor: Dave (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
u8 RTC_ReadTime(u8 adr) {
    if (!(I2C->SR3 & 0x02)) {            // If not busy
      I2C->CR2 |= 0x04;                  // Ack enabled
      I2C->CR2 |= 1;                     // Start condition
      while (!(I2C->SR1 & 0x01)) {      // Wait for SB bit set
        nop();
      }
      I2C->DR = 0xD0;                   // Send address 1101000 + 0 (write)
      while (!(I2C->SR1 & 0x02)) {      // Wait for ADDR bit set
        nop();
      }
      tmp = I2C->SR3;                    // Read SR3 -> clear ADDR
      I2C->DR = adr;                    // Write >>adr<< in DR (register pointer >>adr<<)
      while ((!(I2C->SR1 & 0x80)) && (!(I2C->SR1 & 0x04))) {      // Wait for BTF and TxE bit set 
        nop();
      }
      I2C->CR2 |= 1;                    // Re-Start 
      while (!(I2C->SR1 & 0x01)) {      // Wait for SB bit set
        nop();
      }
      I2C->DR = 0xD1;                   // Send address 1101000 + 1 (read)
      while (!(I2C->SR1 & 0x02)) {      // Wait for ADDR bit set
        nop();
      }
      tmp = I2C->SR3;                    // Read SR3 -> clear ADDR
      I2C->CR2 &= (~0x04);              // Ack disabled
      I2C->CR2 |= 0x02;                  // Stop condition
      while (!(I2C->SR1 & 0x40)) {      // Wait for RxNE bit set
        nop();
      }
      return BCD2DEC(I2C->DR);
    }
    else {
      return 0;
    }
  }
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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.