STM32 I2C Stop Condition wird nicht bearbeitet

Gast #4049829
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
#4049889
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 ;-) )
Gast #4051137
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
}
#4051160
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren