Forum: Mikrocontroller und Digitale Elektronik I2C an STM32 Discovery


von Rüd (Gast)


Lesenswert?

Hallo,

habe ein Problem mit dem STM32 Discovery Board. Ic hversuche den I2C zum 
laufen zu bringen, habe im Forum auch schon den folgenden Artikel 
gefunden Beitrag "SRF02 per I2C an STM32 Discovery"

Dieser entspricht meiner Programmierung eigentlich schon.

Letzendliche möchte ich den folgenden Sensor auslesen:
http://www.bosch-sensortec.com/content/language1/downloads/BST-BMA150-DS000-07.pdf

Wenn ich den Code allerdings laufen lassen und an PB6 mit dem Oszi messe 
bekomme ich nicht einmal den Takt zum Laufen.

Kann mir da bitte einer helfen?

Grüße Rüd
1
 
2
// Includes 
3
#include "stm32f10x.h"
4
#include "STM32vldiscovery.h"
5
#include "stdio.h"
6
#include "stdlib.h"
7
#include "string.h"
8
#include "stm32f10x_i2c.h"
9
10
11
// Private define 
12
//I2C
13
#define I2C1_SLAVE_ADDRESS7  0x38    // I2C Adresse Sensor
14
#define I2C1_Own_ADDRESS7  0x30    // I2C Adresse µC
15
#define ClockSpeed    200000     // 200 KHz  
16
17
// Private variables 
18
I2C_InitTypeDef I2C_InitStructure;
19
GPIO_InitTypeDef GPIO_InitStructure;
20
21
// Private function prototypes 
22
//I2C Protokoll
23
void I2C_Initialisieren(void);
24
void I2C_Write(uint8_t Register_Adress, uint8_t Data);
25
uint8_t I2C_Read(uint8_t Register_Adress);
26
void I2C_Demo(void);
27
28
/* Hauptprogramm -------------------------------------------------------------*/
29
30
int main(void)        //S.936 
31
32
{
33
 // uint8_t i=0;                  //Zählvariable for Schleife
34
35
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
36
                         RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
37
                         RCC_APB2Periph_GPIOE | RCC_APB2Periph_USART1|
38
       RCC_APB2Periph_AFIO  |  RCC_APB2ENR_AFIOEN   ,
39
                         ENABLE)    
40
41
42
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
43
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
44
  GPIO_Init(GPIOA, &GPIO_InitStructure);   
45
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
46
  GPIO_Init(GPIOC, &GPIO_InitStructure);   
47
  GPIO_Init(GPIOD, &GPIO_InitStructure);     
48
  GPIO_Init(GPIOE, &GPIO_InitStructure);
49
  
50
  I2C_Initialisieren();
51
  I2C_Demo();
52
53
  while(1){  } 
54
}
55
56
57
58
59
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%____I2C Bus_____%%%%%%%%%%%%%%%%%%%
60
void I2C_Initialisieren(void){
61
62
//Pins konfigurieren
63
GPIO_InitStructure.GPIO_Pin =  (GPIO_Pin_6) | (GPIO_Pin_7);     
64
                 //SCL (PB6),SDA (PB7): Alternate Function, Open Drain
65
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
66
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; 
67
                 // Open Drain, I2C bus pulled high externally
68
  
69
GPIO_Init(GPIOB, &GPIO_InitStructure);
70
              
71
I2C_Cmd(I2C1, ENABLE);      //Enable I2C1  
72
            
73
//Register       I2C ->Seite 539
74
I2C_InitStructure.I2C_ClockSpeed=ClockSpeed;
75
I2C_InitStructure.I2C_Mode=I2C_Mode_I2C;
76
I2C_InitStructure.I2C_DutyCycle=I2C_DutyCycle_2;
77
I2C_InitStructure.I2C_OwnAddress1=I2C1_Own_ADDRESS7;
78
I2C_InitStructure.I2C_Ack=I2C_Ack_Enable;
79
  I2C_InitStructure.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
80
  
81
I2C_Init(I2C1, &I2C_InitStructure);
82
83
}
84
85
void I2C_Write(uint8_t Register_Adress, uint8_t Data){
86
 
87
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
88
89
/* Send I2C1 START condition */
90
I2C_GenerateSTART(I2C1, ENABLE);
91
92
/* Test on I2C1 EV5 and clear it */
93
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
94
  
95
/* Send slave Address for write */
96
I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
97
98
/* Test on I2C1 EV6 and clear it */
99
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
100
101
/* Send I2C1 slave register address */
102
I2C_SendData(I2C1, Register_Adress);
103
  
104
/* Test on I2C1 EV8_2 and clear it */
105
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
106
107
/* Send I2C1 slave Register data */
108
I2C_SendData(I2C1, Data);
109
  
110
/* Test on I2C1 EV8_8 and clear it */
111
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
112
113
/* Send I2C1 STOP Condition */
114
I2C_GenerateSTOP(I2C1, ENABLE);  
115
}
116
117
uint8_t I2C_Read(uint8_t Register_Adress){ 
118
  
119
uint8_t I2C_ReceivedData=0;
120
/*!< While the bus is busy */
121
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))   ;
122
 
123
/*!< Send START condition */
124
I2C_GenerateSTART(I2C1, ENABLE);
125
 
126
/*!< Test on EV5 and clear it */
127
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
128
  
129
/*!< Send EEPROM address for write */
130
I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Transmitter);
131
132
/*!< Test on EV6 and clear it */
133
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
134
   
135
//send the reg select COMMAND byte
136
I2C_SendData(I2C1, Register_Adress);   
137
 
138
/*!< Test on EV8 and clear it */
139
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
140
 
141
//send START condition a second time
142
I2C_GenerateSTART(I2C1, ENABLE);
143
 
144
/*!< Test on EV5 and clear it */
145
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
146
 
147
/*!< Send EEPROM address for read */
148
I2C_Send7bitAddress(I2C1, I2C1_SLAVE_ADDRESS7, I2C_Direction_Receiver);
149
 
150
/*!< Test on EV6 and clear it */
151
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
152
153
//    /*!< Test on EV7 and clear it */
154
if(I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) 
155
{ 
156
/*!< Read a byte from the EEPROM */
157
I2C_ReceivedData = I2C_ReceiveData(I2C1);
158
}
159
160
/*!< Disable Acknowledgement */
161
I2C_AcknowledgeConfig(I2C1, DISABLE);
162
     
163
/*!< Send STOP Condition */
164
I2C_GenerateSTOP(I2C1, ENABLE);
165
166
/*!< Enable Acknowledgement to be ready for another reception */
167
I2C_AcknowledgeConfig(I2C1, ENABLE);
168
169
return I2C_ReceivedData;
170
}
171
172
void I2C_Demo(void){
173
174
uint8_t I2C_Data=0x00;    
175
uint8_t I2C_Register_Adress=0x0b;  
176
177
I2C_Data=I2C_Read(I2C_Register_Adress);
178
}

von Jean P. (fubu1000)


Lesenswert?

Hi,
1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
2
                         RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD |
3
                         RCC_APB2Periph_GPIOE | RCC_APB2Periph_USART1|
4
                         RCC_APB2Periph_AFIO  |  /*RCC_APB2ENR_AFIOEN,*/
5
                         RCC_APB1Periph_I2C1,
6
                         ENABLE);

Gruß

von Rüd (Gast)


Lesenswert?

Hallo,
danke für die Hilfe erstmal.
habe es jetzt mal so versucht wie du geschrieben hast und einmal so:
1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
2
                         RCC_APB2Periph_GPIOC  , ENABLE);   
3
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1   , ENABLE);
Habe also alles raus geschmissen was ich später nicht brauche. Leider 
beide Varianten ohne Erfolg

Hast du noch ne Idee?

Gruß Rüd

von Rüd (Gast)


Lesenswert?

Hat denn wirklich keiner nen Tipp für mich?

Habe jetzt im Netz schon mehrfach Code gefunden, der insgesamt immer 
sehr ähnlich ist. Leider ist nirgendwo ein funktionsfähiger Code zu 
finden...

Bitte um Hilfe.

Ist wichtig.

Gruß Rüd

von Gebhard R. (Firma: Raich Gerätebau & Entwicklung) (geb)


Lesenswert?

I2C braucht keinen Clock?? Lade dir mal die UM0427 von der ST HP 
herunter,da sind für alles Beispiele drin.

Grüsse

von Rüd (Gast)


Lesenswert?

Wer sagt denn, dass kein Clock notwendig ist? Die SCK-Leitung überträgt 
den Takt und den bekomm ich nicht zum laufen. Warum auch immer...

von Gebhard R. (Firma: Raich Gerätebau & Entwicklung) (geb)


Lesenswert?

Ich meinte, dass du den Versorgungs-Clock für I2C nicht einschaltest.

Grüsse

von Rüd (Gast)


Lesenswert?

1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1   , ENABLE);

Ist er doch oder was meinst du genau?

Gruß

von frame (Gast)


Lesenswert?

Da bist du nicht der Erste, der am Cortex-M3 I2C verzweifelt...

Es gibt da noch eine "brute force" Alternative - bit banging.
Da macht du mit 2 GPIOs (im OpenDrain-Mode) alle Signale selbst.

Läuft bei mir problemlos, wobei der Code dafür größtenteils schon
vorhanden war. Ich mußte nur den direkten Hardwarezugriff anpassen.

Der Nachteil: das Timing ist mit busy-waits realisiert.

von Rüd (Gast)


Lesenswert?

Lösung gefunden. Die Slave Address braucht noch ne Null mehr am Ende für 
das RW  Bit, dann klappt es


Gruß Rüd

von (prx) A. K. (prx)


Lesenswert?

Empfehlung: Erst I2C initialisieren, dann die betreffenden Pins 
aktivieren. Gibt sonst einen Low-Puls auf beiden Leitungen, der manche 
I2C-Peripherie irritiert.

von grottfl (Gast)


Lesenswert?

Rüd schrieb:
> Lösung gefunden. Die Slave Address braucht noch ne Null mehr am Ende für
> das RW  Bit,

Hi Rüd,
bin auch an diesem Punkt angekommen,
wärest Du so nett DAS etwas genauer zu beschreiben?
Wohin soll die "Null" ?

von MM (Gast)


Lesenswert?

Hallo zusammen!
Das Thema ist zwar schon älter aber vielleicht ist es für den einen oder 
anderen brauchbar.
Das gleiche Problem hatte ich auch bei einem Oled Display (ssd1306 
128x32), mit dem Arduino hat die Adresse 0x3C (0011 1100) funktioniert, 
beim STM32F411 (Discovery) musst man noch eine Null hinzufügen(von 
rechts), konkret in meinem Fall war das dann 0x78 (0111 1000).

LG

von Johannes S. (Gast)


Lesenswert?

Das liegt aber nicht am F4, sondern daran ob die Routinen eine 7 oder 8 
Bit Adresse haben möchten. Das ist nicht einheitlich.

von Stefan F. (Gast)


Lesenswert?

Außerdem würde man bei beiden Adressen ein Taktsignal sehen können.

von MM (Gast)


Lesenswert?

ich bin noch in den Kinderschuhen was STM32 betrifft. :)

Meine Frage auf die Antworten von  Johannes S. und Stefan ⛄ F. wäre, 
gibt es eine Application note die auf das Thema und generel I2C eingeht 
(in erster Linie für den STM32F411)?

von Stefan F. (Gast)


Lesenswert?

MM schrieb:
> gibt es eine Application note

Vermutlich nicht. Alle nötigen Infos stehen aber im
Reference Manual: 
https://www.st.com/resource/en/reference_manual/dm00119316-stm32f411xce-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
und Errata Sheet: 
https://www.st.com/resource/en/errata_sheet/dm00137034-stm32f411xc-and-stm32f411xe-device-limitations-stmicroelectronics.pdf

Ungünstigerweise benutzt du womöglich die Cube HAL Bibliothek, dann 
musst du deren Dokumentation zusätzlich lesen.

von Johannes S. (Gast)


Lesenswert?

MM schrieb:
> gibt es eine Application note die auf das Thema und generel I2C eingeht
> (in erster Linie für den STM32F411)?

I2C wurde von Philips entwickelt, entsprechend findet man da die 
Original Spezifikationen:
https://www.nxp.com/docs/en/user-guide/UM10204.pdf  (siehe S. 13)

Das 7/8 Bit Problem gibt es schon seitdem es Controller und Bibliotheken 
dafür gibt, ich habe nach dem 'Fehler' schon bei MCS51 danach gesucht.
Die Adresse ist 7 Bit, das 8. (LSB) bestimmt Read oder Write. Man kann 
also die Adresse in 8 bit angeben, dann muss die Sende/Empfangsroutine 
nur das untere Bit passend setzen. Bei einer 7 Bit Adresse muss erst 
einmal nach links geschoben werden. Das sollte einfach dokumentiert sein 
in welcher Form die Adresse erwartet wird.

von MM (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ungünstigerweise benutzt du womöglich die Cube HAL Bibliothek, dann
> musst du deren Dokumentation zusätzlich lesen.

Ja, die benutzte ich! Bis jetzt hab ich mich je nach dem was ich brauche 
eingelesen. Wenn man die ausdrucken würde bräuchte man vermutlich einen 
Waffenschein. :)

Jetzt habe ich weitere Abend Lektüre.
Danke für die Antworten!

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.