Forum: Mikrocontroller und Digitale Elektronik I2C-Bus mit STM32F100 bleibt stecken (AF, BERR)


von David K. (dave_k)


Lesenswert?

Hallo liebe Community,

Ich versuche schon seit einigen Tagen eine Kommunikation zwischen dem 
STM32F100 Discovery Board und dem Gyrosensor L3G4200D mittels I2C-Bus 
aufzubauen. Jedoch scheiterte ich bis jetzt. Daher bitte ich um 
dringende Hilfe.

Ich verwende das Modul PmodGYRO von Digilent, um das testen zu 
vereinfachen.

Zur Verdrahtung:
STM32 - PmodGYRO
PB6   -  J2_1   (SCL)
PB7   -  J2_3   (SDA)
GND   -  J2_5
3V3   -  J2_7

Die CS-Leitung ist bereits mit einem Pull-Up Widerstand auf Versorgung 
gesetzt und die SDO/SA0 auch - somit ist die Slave-Adresse: 1101001b

Zum Code:

1
#include "stm32f10x.h"
2
3
//Konfig fuer Firmware Lib:
4
#include "Firmware Lib\stm32f10x_conf.h"
5
6
void rcc_config (void)
7
{
8
        /* Enable AlternativFunktion */
9
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
10
  /* Enable GPIOB */
11
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
12
  
13
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
14
}
15
16
/*=============================================================*/
17
18
void I2C_config(void){
19
  
20
GPIO_InitTypeDef GPIO_InitStructure;
21
NVIC_InitTypeDef NVIC_InitStructure;
22
I2C_InitTypeDef I2C_InitStructure;
23
24
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
25
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
26
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
27
GPIO_Init(GPIOB, &GPIO_InitStructure);
28
 
29
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
30
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
31
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
32
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
33
NVIC_Init(&NVIC_InitStructure);
34
 
35
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
36
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
37
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
38
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
39
NVIC_Init(&NVIC_InitStructure);
40
 
41
I2C_DeInit(I2C1);
42
  
43
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
44
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
45
I2C_InitStructure.I2C_ClockSpeed = 100000;
46
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
47
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
48
I2C_InitStructure.I2C_OwnAddress1 = 0;
49
I2C_Init(I2C1, &I2C_InitStructure);
50
 
51
I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE);
52
I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
53
I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE);
54
55
I2C_Cmd(I2C1, ENABLE);
56
}
57
58
59
/*===============*/
60
61
I2C_TypeDef * I2C_Module = I2C1;
62
volatile uint8_t deviceAddress;
63
volatile uint8_t i2cBusyFlag=0;
64
volatile uint8_t dataByte0;
65
volatile uint8_t receivedDataByte0;
66
volatile uint8_t i2cDirectionWrite;
67
68
void i2c_writeByte(uint8_t address, uint8_t byte)
69
{
70
  while(i2cBusyFlag){}
71
  while(I2C_GetFlagStatus(I2C_Module,I2C_FLAG_BUSY)){}
72
  
73
  deviceAddress = address;
74
  dataByte0 = byte;
75
  i2cDirectionWrite = 1;
76
  i2cBusyFlag = 1;
77
  I2C_GenerateSTART(I2C_Module, ENABLE);
78
}
79
80
81
void i2c_readByte(uint8_t address)
82
{
83
  while(i2cBusyFlag){}
84
  while(I2C_GetFlagStatus(I2C_Module,I2C_FLAG_BUSY)){}
85
86
  deviceAddress = address;
87
  i2cDirectionWrite = 0;
88
  i2cBusyFlag = 1;
89
  I2C_AcknowledgeConfig(I2C_Module, ENABLE);
90
  I2C_GenerateSTART(I2C_Module, ENABLE);
91
}
92
93
94
// ISR
95
void i2c_handleEventInterrupt(void){
96
  
97
if(I2C_GetFlagStatus(I2C_Module, I2C_FLAG_SB) == SET)
98
  {
99
    if(i2cDirectionWrite){
100
      // STM32 Transmitter
101
    I2C_Send7bitAddress(I2C_Module, deviceAddress << 1, I2C_Direction_Transmitter);   // !!DAS SCHICKT ER NOCH WEG
102
103
    }else{
104
      // STM32 Receiver
105
      I2C_Send7bitAddress(I2C_Module, deviceAddress << 1, I2C_Direction_Receiver);
106
      I2C_AcknowledgeConfig(I2C_Module, DISABLE);
107
      I2C_GenerateSTOP(I2C_Module, ENABLE);    
108
    }
109
  }
110
  
111
else if(I2C_GetFlagStatus(I2C_Module, I2C_FLAG_ADDR) == SET || I2C_GetFlagStatus(I2C_Module, I2C_FLAG_BTF) == SET)
112
  {
113
    I2C_ReadRegister(I2C_Module, I2C_Register_SR1);
114
    I2C_ReadRegister(I2C_Module, I2C_Register_SR2);
115
    
116
    if(i2cDirectionWrite==1)
117
    {
118
      // STM32 Transmitter
119
        I2C_SendData(I2C_Module, dataByte0);
120
        i2cBusyFlag = 0;
121
        i2cDirectionWrite=0;
122
     }  
123
     else
124
     {
125
        I2C_GenerateSTOP(I2C_Module, ENABLE);
126
        i2cBusyFlag = 0;
127
      }
128
   }
129
   
130
else if(I2C_GetFlagStatus(I2C_Module, I2C_FLAG_RXNE) == SET){
131
    // STM32 Receiver
132
    I2C_ReadRegister(I2C_Module, I2C_Register_SR1);
133
    I2C_ReadRegister(I2C_Module, I2C_Register_SR2);
134
135
     receivedDataByte0 = I2C_ReceiveData(I2C_Module);
136
     i2cBusyFlag = 0;
137
  }
138
}
139
140
141
142
// ISR
143
void i2c_handleErrorInterrupt(void){
144
  I2C_GenerateSTOP(I2C_Module, ENABLE);
145
  i2cBusyFlag = 0;
146
 
147
  I2C_ReadRegister(I2C_Module, I2C_Register_SR1);
148
  I2C_ReadRegister(I2C_Module, I2C_Register_SR2);
149
  I2C_ClearFlag(I2C_Module, I2C_FLAG_AF);
150
  I2C_ClearFlag(I2C_Module, I2C_FLAG_ARLO);
151
  I2C_ClearFlag(I2C_Module, I2C_FLAG_BERR);
152
  I2C_GenerateSTOP(I2C_Module, DISABLE);
153
}
154
155
156
void I2C1_EV_IRQHandler(void){
157
  i2c_handleEventInterrupt();
158
}
159
 
160
void I2C1_ER_IRQHandler(void){
161
  i2c_handleErrorInterrupt();
162
}
163
164
165
166
void read (uint8_t gyro, uint8_t SUB)
167
{ 
168
  i2c_writeByte(gyro, SUB);   //Schreiben - welches Register gelesen werden soll
169
  
170
  i2c_readByte(gyro);       //Lesen - Byte vom Register auslesen
171
}
172
  
173
  
174
/*======================== MAIN =======================*/
175
int main (void)
176
{
177
  rcc_config();
178
  I2C_config();
179
180
        read (0x69,0x0F);  //Test - Anfrage: Who_am_i
181
182
  while(1)
183
  {}
184
}

Im Prinzip sollte es ja so ausschauen, dass er nach dem Generieren des 
Starts das SB-Flag gesetzt wird (was auch getan wird) und er in seine 
Event-ISR springt und die Adresse wegschickt. Das funktioniert auch 
alles gut.
Nur dann wartet er (BUSY-Flag ist gesetzt) und auf einmal ist das 
AF-Flag oder das BERR-Flag gesetzt (in letzter Zeit bleibt setzt er nur 
mehr das AF-Flag) und er springt in die Error-ISR.

Im Bestfall sollte er ja bei erfolgreicher Übermittlung der Adresse 
nochmal in die Event-ISR springen und das ADDR-Flag bzw. das BTF-Flag 
gesetzt sein. Dann kann er die Registeradresse, die ich lesen will, 
abschicken.
Nach dem muss nochmales ein Start-Signal  ausgelöst werden, aber nun mit 
dem Zeichen, dass der STM32 lesen will (readByte-Funktion) 
(I2C_Direction_Receiver).
Dann sollte der Gyrosensor aktiv werden und das Byte schicken und somit 
das RXNE-Flag setzten. Dadurch wird wieder die Event-ISR ausgelöst und 
das Byte eingelesen.
So sollte es sein oder irr ich mich?

Kurz gesagt, er bleibt nach dem Abschicken der Adresse immer hängen und 
setzt das AF- oder BERR-Flag.
Ich bitte, um dringende Hilfe.
Vielen vielen Dank im Voraus

von Jim M. (turboj)


Lesenswert?

Hast Du auch Pullups an SDA und SCL? Ohne diese tut I²C nicht.

von David K. (dave_k)


Lesenswert?

Vielen Dank für die Antwort, im Prinzip dachte ich, dass das eh vom STM 
32 generiert wird, da dieser vor jedem Pin Pullup Widerstände hat. Aber 
ein echt guter Hinweis, wenn ich wieder vorm Schreibtisch sitze, probier 
ichs gleich aus.
An der Software kann es nicht liegen?

von Martin (Gast)


Lesenswert?

Das ist zwar jetzt schon etwas älter, aber es könnte vielleicht noch 
jemand interessieren, der das hier liest.
Ich denke, das Problem liegt darin, dass das Interrupt Flag nicht 
zurückgesetzt wurde. Somit führt er die ISR einmal aus und kommt dann 
nicht mehr rein, das sie durch das Flag gesperrt ist.

von David K. (dave_k)


Lesenswert?

vielen dank für die Antwort.

Guter Ansatz mit dem Flag, aber die werden bei dem Aufruf der Registern 
zurückgesetzt.
Ich muss sagen, ich bin bei dieser Variante nicht weitergekommen. Ich 
hab das ganze ohne Interrupts gelöst. Ist zwar von der 
Prozessorauslastung nicht ideal, aber einfacherer und kontrollierter.

Aja, übrigens haben damals die Pull-up-Widerstände auch gefehlt :)
Hat aber leider auch mit denen nicht funktioniert.

von Michael (Gast)


Lesenswert?

Wie sieht denn dein Programm aus?
Wo hast du die Firmware Lib für I2C her?
Ich muss mich komplett neu in den I2C Bus einarbeiten. Einen guten Tipp 
für mich?

Ich soll binnen 1 Woche als Studiprojekt zwei Sensoren, die über einen 
I2C Bus an STM32F100RB angeschlossen sind, auswerten und die Auswertung 
auf einem Display ausgeben. Die Auswertung und die Ausgabe ist nicht das 
Problem. Aber alleine schon eine funktionsfähige I2C Konfiguration zu 
schreiben..

Wäre nett, wenn mir jemand weiterhelfen könnte.

von David K. (dave_k)


Lesenswert?

Grüß dich,

Arbeitest du mit der Std-Lib. (Funktion wie in meinen ersten Code) oder 
mit der HAL-Lib.?

Ist das Display ein alphanumerisches? Da könnt ich dir einen fertigen 
Code geben

LG

von Michael (Gast)


Lesenswert?

Wenn dann würde ich mit der STD Lib arbeiten.
Display ist alphanummerisch. Habe damit aber schon Erfahrung.

Ist folgendes erlaubt?
USART3 darf nicht auf Remap sein, oder?

void Init_GPIOs(void)
{
  /* Enable the AFIO, GPIO_A and B  */
   RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
   RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
   RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;

  /* Enable the I2C1 and I2C2 function */
  RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
  RCC->APB1ENR |= RCC_APB1ENR_I2C2EN;

  //Enable SWD, but Disable JTAG and UART3 is PC10,PC11
  AFIO->MAPR=AFIO_MAPR_SWJ_CFG_JTAGDISABLE|AFIO_MAPR_USART3_REMAP_PARTIALR 
EMAP  ;

  GPIOB->CRL   = 0x33333333;                  // B0..B7 Output PP
  GPIOB->CRH   = 0x33333333;                  // B8..B15 Output PP
  GPIOC->CRL   = 0x33333333;                  // C0..C7 Output PP
  GPIOD->CRL   = 0x44444448;                  // D2 Keys Input with 
Pullup

  // Enable additonal pins on board
  GPIOA->CRH   = 0x344334b3;                  // A9 Alternate 
Function_PP, A10 Input Floating
                        // A8, A11, A12 and A15 are connected to LEDs
  GPIOC->CRH   = 0x44884b44;                  // C12,C13 Keys (Input 
with PullUps),
                        // C10 Alternate Function_PP, C11 Input Floating
  GPIOC->ODR   = 0x3C00;

}

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.