Forum: Mikrocontroller und Digitale Elektronik STM32 I2C bleibt hängen


von Tr1bl3 (Gast)


Lesenswert?

Hi Leute,
ich weiß es hat bereits ein paar Beiträge zu ähnlichen Problemen 
gegeben, jedoch wurden diese nicht gelöst oder die Lösung wurde nicht 
gepostet.

Ich möchte via I2C meinen Beschleunigungsensor BMA020 auslesen. 
(STM32F100-Discovery)

Ich habe auch externe Pullups an die beiden Leitungen geschalten.

Hierzu der Code:
1
#define I2C1_SLAVE_ADDRESS7  0x38    // I2C Adresse Sensor
2
#define I2C1_Own_ADDRESS7  0x00    // eigene I2C Adresse 
3
#define ClockSpeed    200000     // 200 KHz  
4
5
// Private variables 
6
I2C_InitTypeDef I2C_InitStructure;
7
GPIO_InitTypeDef GPIO_InitStructure;
8
9
void I2C_Initialisieren(void);
10
void I2C_Write(uint8_t Register_Adress, uint8_t Data);
11
uint8_t I2C_Read(uint8_t Register_Adress);
12
void I2C_Demo(void);
13
14
int main(void)       
15
{
16
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);   
17
    /* I2C1 Periph clock enable */   
18
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); 
19
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, DISABLE);
20
  
21
  I2C_Initialisieren();
22
  I2C_Write(0x48, 0x33); //Testfunktion
23
  while(1){  } 
24
}
25
26
void I2C_Initialisieren(void)
27
{
28
 
29
  //Pins konfigurieren
30
  GPIO_InitStructure.GPIO_Pin =  (GPIO_Pin_6) | (GPIO_Pin_7);     //SCL (PB6),SDA (PB7): Alternate Function, Open Drain
31
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
32
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // Open Drain, I2C bus pulled high externally  
33
  GPIO_Init(GPIOB, &GPIO_InitStructure);
34
                
35
  I2C_Cmd(I2C1, ENABLE); 
36
  
37
  I2C_DeInit(I2C1);            
38
  //Register       I2C ->Seite 539
39
  I2C_InitStructure.I2C_ClockSpeed=ClockSpeed;
40
  I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
41
  I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
42
  I2C_InitStructure.I2C_OwnAddress1=I2C1_Own_ADDRESS7;
43
  I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
44
  I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; 
45
  I2C_Init(I2C1, &I2C_InitStructure);
46
     
47
    
48
}
49
50
void I2C_Write(uint8_t Register_Adress, uint8_t Data)
51
{ 
52
  while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
53
  
54
  /* Send I2C1 START condition */
55
  I2C_GenerateSTART(I2C1, ENABLE);
56
  
57
  /* Test on I2C1 EV5 and clear it */
58
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
59
    
60
  /* Send slave Address for write */
61
  I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7<<1, I2C_Direction_Transmitter);
62
  
63
  /* Test on I2C1 EV6 and clear it */
64
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); //BLEIBT HIER HÄNGEN!!!
65
  
66
  /* Send I2C1 slave register address */
67
  I2C_SendData(I2C1, Register_Adress);
68
    
69
  /* Test on I2C1 EV8_2 and clear it */
70
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
71
  
72
  /* Send I2C1 slave Register data */
73
  I2C_SendData(I2C1, Data);
74
    
75
  /* Test on I2C1 EV8_8 and clear it */
76
  while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
77
  
78
  /* Send I2C1 STOP Condition */
79
  I2C_GenerateSTOP(I2C1, ENABLE);  
80
}

Er bleibt immer bei dieser Schleife
while(!I2C_CheckEvent(I2C1, 
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
hängen und das AF (Acknowledge Failure) Bit ist gesetzt...
Ich komme einfach nach drauf woran das liegen kann...

Ich bitte um Hilfe....
mfg T.

von holger (Gast)


Lesenswert?

>  I2C_Cmd(I2C1, ENABLE);
>
>  I2C_DeInit(I2C1);

Lustige Reihenfolge;)

von Tr1bl3 (Gast)


Lesenswert?

Haha....ups das war noch ein altes Codefragment was hineingerutscht 
ist....ist im aktuellen Programm nicht drinnen (I2C_DeInit(I2C1))...aber 
danke für den Hinweis. Nein, das Problem besteht leider weiterhin

von holger (Gast)


Lesenswert?

>ist im aktuellen Programm nicht drinnen

Toll du Volltrottel. Warum zeigst du das dann hier?
Und noch ein ein Tip: Schau mal in I2C_DeInit(I2C1);
rein was das macht. Dann verstehst du vieleicht auch das

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, 
ENABLE);
    /* I2C1 Periph clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

in void I2C_Initialisieren(void) reingehört und nicht davor.

von V. F. (10euro)


Lesenswert?

Hallo,

Schaut mal in das Datanblatt zu dem Register I2C_SR1 unter dem bit ADDR.

Dort steht: "This bit is cleared by software reading SR1 register 
followed reading SR2 [...] " -- RM0008 Seite 773 Rev 15

Die STM StdPeriph Library tut genau das in der Routine 'I2C_CheckEvent'. 
Daher wird möglicherweise der ADDR Bit in I2C_SR1 gelöscht bevor I2C_SR2 
den richtigen Wert annehmen konnte. 
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED wird daher nie mehr erreicht.

Die Lösung ist nicht die I2C_CheckEvent Routine zu benutzten! 
Stattdessen zuerst auf SR1 zu warten und dann auf SR2.

Der AF (Acknowledge Failure) Bit war bei mir auch gesetzt, aber mit der 
Methode wird der AF-Bit erst beim zweiten Aufruf gesetzt. Daher wird es 
wohl daran liegen, dass der Slave noch nicht bereit war und man schon 
wieder Daten sendet.

Insgesammt sollte das hier funktionieren:
1
do{
2
    //Clear AF bit
3
    I2C1->SR1 = ~I2C_SR1_AF;
4
        
5
    I2C_GenerateSTART(I2C1, ENABLE);
6
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
7
    I2C_Send7bitAddress(I2C1, SlaveAddress, I2C_Direction_Transmitter);
8
9
    while(!(I2C1->SR1 & I2C_SR1_TXE || I2C1->SR1 & I2C_SR1_AF)); //Warte auf einen Fehler oder das senden ist fertig. Es funktioniert auch ohne diese Zeile aber der AF bit könnte ja noch nicht gesetzt sein.
10
11
}while(I2C1->SR1 & I2C_SR1_AF); //Der Slave war wohl nicht bereit, also wiederhole...
12
13
//Achtung: hier wird mit '==' verglichen! Bitte an euren Setup anpassen!
14
while(!(I2C1->SR1 == (I2C_SR1_ADDR | I2C_SR1_TXE) ));
15
while(!(I2C1->SR2 == (I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) )); //hier wird auch ADDR gelöscht, aber das ist jetzt egal

TL;DR
alternativ das ADDR Bit ignorieren, da I2C_CheckEvent es löscht und 
darauf gewartet wird:
1
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED & ~((uint32_t)I2C_SR1_ADDR) ));

Auch wenn der Thread alt ist, hoffentlich konnte ich damit Jemandem 
weiterhelfen :)

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.