Forum: Mikrocontroller und Digitale Elektronik STM32 I2C Stop Condition wird nicht bearbeitet


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von dnfwoaifnodnfkl (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe einen STM32F103 Controller (Master) und möchte über den I2C-Bus 
mit einem Sensor (Slave) kommunizieren.

Unter anderem ist es notwendig ein einzelnes Byte von dem Sensor zu 
empfangen. Meine Funktion dafür sieht so aus:
uint8_t i2c_read(uint8_t slave_addr, uint8_t register_addr)
{
  volatile uint32_t temp;
  uint8_t buffer;
  I2C_TypeDef *I2Cx = I2C1;

  // Generate START condition and wait for EV5
  while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
  I2C_GenerateSTART(I2Cx, ENABLE);
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

  // Send slave address and wait for EV6
  slave_addr <<= (uint8_t) 1;
  I2C_Send7bitAddress(I2Cx, slave_addr, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));

  // Wait for EV8_1
  while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_TXE));

  // Send register address and wait for EV8_2
  I2C_SendData(I2Cx, register_addr);
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

   // Generate (re)start condition and wait for EV5
  I2C_GenerateSTART(I2Cx, ENABLE);

  // Send slave address and wait until ADDR = 1
  slave_addr |= (uint8_t) 0x01;
  I2C_Send7bitAddress(I2C1, slave_addr, I2C_Direction_Receiver);
  while (!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));

  // clear ACK bit
  I2Cx->CR1 &= (uint16_t) ~I2C_CR1_ACK;

  temp = I2Cx->SR1;
  temp = I2Cx->SR2;
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));
  I2Cx->CR1 |= I2C_CR1_STOP;

  // Wait until data has been received in DR register (RXNE = 1) -> EV7
  while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE));

  // Read the data
  buffer = I2C_ReceiveData(I2Cx);

  // Make sure that the STOP bit is cleared by Hardware before CR1 write access
  while (I2Cx->CR1 & I2C_CR1_STOP);

  // Enable Acknowledgement to be ready for another reception
  I2Cx->CR1 |= I2C_CR1_ACK;
  return buffer;
}

Das Problem ist jedoch, dass das Senden der Stop Condition quasi 
wirkungslos ist. Das STOP-Bit wird von der Hardware nicht gecleared, das 
BUSY und MSL Flag bleiben auch gesetzt. Im Endeffekt bleibt das Programm 
in der letzten while-Schleife hängen.

Weiß jemand was der Fehler sein könnte?

Grüße

von Mike R. (thesealion)


Bewertung
0 lesenswert
nicht lesenswert
Hast du dir die CPAL Library von ST mal angesehen?

Die I2C Funktionen der F1 er Serie sind leider etwas "missraten".

Gruß
Mike

von dnfwoaifnodnfkl (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hast du da vielleicht einen Downloadlink parat? Ich finde da irgendwie 
nichts :/ Und wieso "missraten"?

von Mike R. (thesealion)


Bewertung
0 lesenswert
nicht lesenswert
Das müssten die passenden Infos dazu sein.

http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/CD00291090.pdf

http://www.st.com/web/en/catalog/tools/PF258336

Missraten deshalb, weil die Hardware einige böse Macken hat, die man 
beachten muss. Aber das wirst du schon sehen, wenn du dir die passenden 
Dokumente ansiehst.

(Für die Suche reichte übrigens STM32F1 und CPAL ;-) )

von Mehmet K. (mkmk)


Bewertung
0 lesenswert
nicht lesenswert
Nur bei der 40x-Serie benutze ich die Hardware-I2C. Bei allen anderen 
bin ich dazu übergegangen, I2C zu Fuss zu programmieren.
Soll nicht heissen, dass es nicht geht. Ich zumindest hab's aber nicht 
geschafft.

von dnfwoaifnodnfkl (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke :)
Ich habe mir die Beispiele mal angeschaut, finde die aber nicht wirklich 
verständlich ... gibt es irgendwo ein Beispiel wo einfach nur ein I2C 
Slave vom Microcontroller gesteuert wird?

von Mike R. (thesealion)


Bewertung
0 lesenswert
nicht lesenswert
Dann hast du ziemlich oberflächlich geschaut.

Project\STM32_CPAL_Examples\STM32_CPAL_I2C\Basic_EEPROM

von dnfwoaifnodnfkl (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ja hab es mittlerweile wieder zum "laufen" bekommen mit der CPAL 
Library.
Aber: Es tritt immer noch genau das gleiche Problem auf! STOP Bit 
gesetzt sowie MSL und BUSY. Das Programm hängt sich immer noch bei der 
(einer neuen) while-Schleife auf.

Das Problem tritt nicht auf, wenn ich einen Breakpoint bei der 
while-Schleife setze oder ein Oszilloskop anschließe, weiß jmd. woran 
das liegen könnte?
void i2c_init(void)
{
  CPAL_I2C_StructInit(&I2C1_DevStructure);

  I2C1_DevStructure.CPAL_Mode = CPAL_MODE_MASTER;
  I2C1_DevStructure.CPAL_ProgModel = CPAL_PROGMODEL_DMA;
  I2C1_DevStructure.pCPAL_I2C_Struct->I2C_ClockSpeed = 50000;

  CPAL_I2C_DeInit(&I2C1_DevStructure);
  CPAL_I2C_Init(&I2C1_DevStructure);

  if (CPAL_I2C_IsDeviceReady(&I2C1_DevStructure) != CPAL_PASS)
  {
    // Device not ready/connected
  }
}

uint8_t i2c_read(uint8_t slave_addr, uint8_t register_addr)
{
  CPAL_TransferTypeDef opt;
  uint8_t buffer;

  opt.wAddr1 = slave_addr << (uint8_t) 0x01;
  opt.wAddr2 = register_addr;
  opt.wNumData = 1;
  opt.pbBuffer = &buffer;

  I2C1_DevStructure.pCPAL_TransferRx = &opt;
  CPAL_I2C_Init(&I2C1_DevStructure);

  if (CPAL_I2C_Read(&I2C1_DevStructure) != CPAL_PASS)
  {
    int i;
    ++i; // nur furs debuggen
  }

  CPAL_StateTypeDef state;
  unsigned i = 0;
  int error = 0;
  int sr1;
  int sr2;

  while (I2C1_DevStructure.CPAL_State != CPAL_STATE_READY)
  {
    if (i > 9999999) // debugging hilfe
    {
      state = I2C1_DevStructure.CPAL_State;
      error = I2C1_DevStructure.wCPAL_DevError;
      sr1 = I2C1->SR1;
      sr2 = I2C1->SR2;
    }

    ++i;
  }

  return buffer;
}


von Frank B. (f-baer)


Bewertung
0 lesenswert
nicht lesenswert
Die lokale Instanz von CPAL_TransferTypeDef ist einigermaßen ungünstig 
für die Arbeit mit der CPAL-Lib, weil dadurch der I2C-Controller 
andauernd neu initialisiert wird. Das solltest du vermeiden.
Ansonsten sind 1-Byte-Geschichten mit dem I2C-Controller des STM32 immer 
so eine Sache... Kann gehen, muss aber nicht. Gerade in Verbindung mit 
I2C-Slaves, die nicht 100% dem Standard folgen, gibt es immer wieder 
massive Probleme.
Ehrlich, wenn ich vorher geahnt hätte, WIE fehlerbehaftet die 
I2C-Peripherie von dem Teil ist, und wie oft ich das gerade brauche, 
hätte ich gleich einen anderen Controller ausgewählt.
Die CPAL-Lib hat ihre Grenzen spätestens da, wo nur ein Befehl 
übertragen wird und keine Daten, damit kommt das Teil dann meiner 
Erfahrung nach gar nicht mehr zurecht.

von dnfwoaifnodnfkl (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Dass das unperformant ist ist mir klar, mir ging es erstmal darum, ein 
funktionsfähiges Programm zu erstellen.

Aber das kanns ja nicht sein, es muss doch eine Möglichkeit geben ein 
einzelnes Byte über den I2C Bus zu empfangen. Soll ich jetzt dummy reads 
machen und das ist die Lösung oder wie?

von dgs (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die Probleme sind ST bekannt, stehen auf der Prio-Liste ganz weit oben 
und
werden schnellstmöglich in den nächsten Revisions gefixt werden.

von DerDan (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wo findet man diese Prio Liste denn,
oder ist es so, dass ST erst dann einen intern schon bekannten Bug 
zugibt, wenn man dafür genug Beweise lifert?

mfg

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.