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


von dnfwoaifnodnfkl (Gast)


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:
1
uint8_t i2c_read(uint8_t slave_addr, uint8_t register_addr)
2
{
3
  volatile uint32_t temp;
4
  uint8_t buffer;
5
  I2C_TypeDef *I2Cx = I2C1;
6
7
  // Generate START condition and wait for EV5
8
  while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
9
  I2C_GenerateSTART(I2Cx, ENABLE);
10
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
11
12
  // Send slave address and wait for EV6
13
  slave_addr <<= (uint8_t) 1;
14
  I2C_Send7bitAddress(I2Cx, slave_addr, I2C_Direction_Transmitter);
15
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
16
17
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));
18
19
  // Wait for EV8_1
20
  while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_TXE));
21
22
  // Send register address and wait for EV8_2
23
  I2C_SendData(I2Cx, register_addr);
24
  while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
25
26
   // Generate (re)start condition and wait for EV5
27
  I2C_GenerateSTART(I2Cx, ENABLE);
28
29
  // Send slave address and wait until ADDR = 1
30
  slave_addr |= (uint8_t) 0x01;
31
  I2C_Send7bitAddress(I2C1, slave_addr, I2C_Direction_Receiver);
32
  while (!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));
33
34
  // clear ACK bit
35
  I2Cx->CR1 &= (uint16_t) ~I2C_CR1_ACK;
36
37
  temp = I2Cx->SR1;
38
  temp = I2Cx->SR2;
39
  while (I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));
40
  I2Cx->CR1 |= I2C_CR1_STOP;
41
42
  // Wait until data has been received in DR register (RXNE = 1) -> EV7
43
  while (!I2C_GetFlagStatus(I2Cx, I2C_FLAG_RXNE));
44
45
  // Read the data
46
  buffer = I2C_ReceiveData(I2Cx);
47
48
  // Make sure that the STOP bit is cleared by Hardware before CR1 write access
49
  while (I2Cx->CR1 & I2C_CR1_STOP);
50
51
  // Enable Acknowledgement to be ready for another reception
52
  I2Cx->CR1 |= I2C_CR1_ACK;
53
  return buffer;
54
}

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)


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)


Lesenswert?

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

von Mike R. (thesealion)


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)


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)


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)


Lesenswert?

Dann hast du ziemlich oberflächlich geschaut.

Project\STM32_CPAL_Examples\STM32_CPAL_I2C\Basic_EEPROM

von dnfwoaifnodnfkl (Gast)


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?
1
void i2c_init(void)
2
{
3
  CPAL_I2C_StructInit(&I2C1_DevStructure);
4
5
  I2C1_DevStructure.CPAL_Mode = CPAL_MODE_MASTER;
6
  I2C1_DevStructure.CPAL_ProgModel = CPAL_PROGMODEL_DMA;
7
  I2C1_DevStructure.pCPAL_I2C_Struct->I2C_ClockSpeed = 50000;
8
9
  CPAL_I2C_DeInit(&I2C1_DevStructure);
10
  CPAL_I2C_Init(&I2C1_DevStructure);
11
12
  if (CPAL_I2C_IsDeviceReady(&I2C1_DevStructure) != CPAL_PASS)
13
  {
14
    // Device not ready/connected
15
  }
16
}
17
18
uint8_t i2c_read(uint8_t slave_addr, uint8_t register_addr)
19
{
20
  CPAL_TransferTypeDef opt;
21
  uint8_t buffer;
22
23
  opt.wAddr1 = slave_addr << (uint8_t) 0x01;
24
  opt.wAddr2 = register_addr;
25
  opt.wNumData = 1;
26
  opt.pbBuffer = &buffer;
27
28
  I2C1_DevStructure.pCPAL_TransferRx = &opt;
29
  CPAL_I2C_Init(&I2C1_DevStructure);
30
31
  if (CPAL_I2C_Read(&I2C1_DevStructure) != CPAL_PASS)
32
  {
33
    int i;
34
    ++i; // nur furs debuggen
35
  }
36
37
  CPAL_StateTypeDef state;
38
  unsigned i = 0;
39
  int error = 0;
40
  int sr1;
41
  int sr2;
42
43
  while (I2C1_DevStructure.CPAL_State != CPAL_STATE_READY)
44
  {
45
    if (i > 9999999) // debugging hilfe
46
    {
47
      state = I2C1_DevStructure.CPAL_State;
48
      error = I2C1_DevStructure.wCPAL_DevError;
49
      sr1 = I2C1->SR1;
50
      sr2 = I2C1->SR2;
51
    }
52
53
    ++i;
54
  }
55
56
  return buffer;
57
}

von Frank B. (f-baer)


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)


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)


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)


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

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.