Forum: Mikrocontroller und Digitale Elektronik Stm32F103 I2C Konfiguration Bare Metal


von Matthias (Gast)


Lesenswert?

Guten Abend,

folgende Konfiguration lässt mein kleines BluePill Board leider kalt:
1
  RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
2
  GPIOB->CRL |= (GPIO_CRL_CNF6_1) | GPIO_CRL_CNF6_0
3
              | (GPIO_CRL_CNF7_1) | GPIO_CRL_CNF7_0;
4
  RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
5
  
6
  
7
  I2C1->CR1  = 0x00000000;
8
  I2C1->CR2  = 0x00000000;
9
  
10
  I2C1-> CR1 |= I2C_CR1_PE;

zum Konfiguration testen habe ich ein Oszilloskop und schaue mir die 
beiden Leitungen an.

Mit
1
I2C1->CR2 &= I2C_CR1_START;

müsste ich doch eigentlich was sehen, oder?
Was habe ich im Code / Datenblatt übersehen?

von Matthias (Gast)


Lesenswert?

Der letzte Befehl lautet
1
I2C1->CR1 &= I2C_CR1_START;

von Markus M. (adrock)


Lesenswert?

Ich mag mich irren, aber musst Du den Port nicht auch auf Ausgang 
setzen, bzw. MODEy[1:0] auf irgendetwas ungleich 00? Siehe Abschnitt 
9.2.2 im RefManual.

Siehe auch Abschnitt 9.1.4:

"For bidirectional Alternate Functions, the port bit must be configured 
in Alternate Function Output mode (Push-Pull or Open-Drain). In this 
case the input driver is configured in input floating mode"

Habe allerdings mit dem F103 keine Erfahrungen...

: Bearbeitet durch User
von Matthias (Gast)


Lesenswert?

Das hat mir schonmal weitergeholfen.
1
   GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_CNF6_0
2
              | GPIO_CRL_CNF7_1 | GPIO_CRL_CNF7_0
3
              | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE6_0
4
              | GPIO_CRL_MODE7_1 | GPIO_CRL_MODE6_0;

Jetzt bekomme ich eine Pegeländerung angezeigt. Soweit so gut. Ich würde 
jedoch gerne Soweit kommen, dass ich vielleicht eine "Nullrunde" sehe. 
Also Takt und leere Datenbits. Ich hatte erwartet das das nun erscheint. 
Leider ist dem immer och nicht so. Gibt es noch wweitere Hinweise?

von Markus M. (adrock)


Lesenswert?

Kenne mich mit I2C nicht aus, aber musst Du nicht irgendeinen Wert in 
das Datenregister (DR) schreiben, damit die Übertragung beginnt?

Siehe auch Abschnitt 26.6.5 "Transmitter mode: Byte transmission starts 
automatically when a byte is written in the DR register".

Ich würde Dir mal die Application Note AN2824 ans Herz legen, dort ist 
I2C erklärt, Dein Fall in Abschnitt 1.2.1 "Master Transmitter". Darauf 
basierend könntest Du Dir dann die entsprechenden HAL Codeschnipsel 
anschauen und davon abschreiben wenn Du den HAL nicht verwenden willst.

von Lutz (Gast)


Lesenswert?

Matthias schrieb:
> I2C1->CR1 &= I2C_CR1_START;

Da stimmt was nicht.

von Stefan F. (Gast)


Lesenswert?

Matthias schrieb:
> Ich würde
> jedoch gerne Soweit kommen, dass ich vielleicht eine "Nullrunde" sehe.
> Also Takt und leere Datenbits.

Dann musst du zumindest eine Slave-Ardesse senden. Beispielcode: 
http://stefanfrings.de/stm32/stm32f1.html#i2c

Die dort gezeigte Funktion kann allerdings keine leeren Buffer senden. 
Versuche einfach, eine 0 zu senden. Wenn sich unter der angegebenen 
Adresse kein Slave angesprochen fühlt, wird die Funktion wegen dem 
fehlenden ACK abbrechen.

von Matthias (Gast)


Lesenswert?

Vielen Dank für euer Feedback.

Ich konnte die ersten Schritte mit i2c nun begehen. Der Code:
1
 
2
/*Init:*/
3
  RCC->CFGR |= RCC_CFGR_PPRE2_2;
4
  RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
5
  RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
6
    
7
  
8
  I2C1->CR1 &= ~I2C_CR1_PE;
9
  I2C1->CR2  = 0x24;
10
  I2C1->CCR |= 0x80;
11
  //I2C1->CR1  = 0x08;
12
  I2C1->TRISE |= 0x09;
13
  I2C1->CR1 |= I2C_CR1_PE;
14
15
  GPIOB->CRL |= GPIO_CRL_CNF6_1 | GPIO_CRL_CNF6_0
16
              | GPIO_CRL_CNF7_1 | GPIO_CRL_CNF7_0
17
              | GPIO_CRL_MODE6_0 | GPIO_CRL_MODE7_0
18
              | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1;

und das Senden der Adresse:
1
 
2
  I2C1->CR1 |= I2C_CR1_START;
3
  while(!(I2C1->SR1 & I2C_SR1_SB)){};
4
  I2C1->DR |= 0x07;
5
  while(!(I2C1->SR1 & I2C_SR1_ADDR)){};
6
  I2C1->SR2;


@Stefan
Ist das deine eigene Library zum Setzen von Bits, bytes, registern etc?
Und ich finde es ziemlich cool, das die Initialisierungsroutine 
generischer gehalten wurde. Ich hätte für I2C1 und I2C2 jeweils eine 
Init funktion erstellt. Naja bin halt Anfänger :D
Deswegen auch eine Frage zum Code: Ich nutze diese While schleifen zum 
pollen... Sollte man sowas eventuell über interrups lösen oder ist das 
in diesem Fall irrelevant?

von Stefan F. (Gast)


Lesenswert?

Matthias schrieb:
> Ist das deine eigene Library zum Setzen von Bits, bytes, registern etc?

Ich habe einfach nur die Hinweise aus dem Reference Manual und dem 
Errata Dokument 1:1 umgesetzt und in C Funktionen verpackt.

> Ich nutze diese While schleifen zum pollen...
> Sollte man sowas eventuell über interrups lösen oder ist das
> in diesem Fall irrelevant?

Das kommt ganz auf die Anforderungen deiner Software an. Mein 
Beispielcode kann hängen bleiben, wenn auf dem BUS eine Störung 
auftritt. Wenn deswegen dann die Waschmaschine überläuft, hat man etwas 
falsch gemacht :-)

Ich werden mich mit der Interrupt-basierten Übertragung erst befassen, 
wenn ich dafür einen guten Grund habe. Bei meinen bisherigen Anwendungen 
war das nicht nötig.

Beitrag #6327175 wurde von einem Moderator gelöscht.
Beitrag #6327190 wurde von einem Moderator gelöscht.
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.