Forum: Mikrocontroller und Digitale Elektronik Probleme mit I2C beim STM32F103C8T6


von Pete V. (elektrohonk)


Lesenswert?

Hallo zusammen,

leider bin ich ein wenig verzweifelt.
Ich versuche seit einigen Tagen meinen I2C-Bus am STM32F103C8T6 zu 
nutzen.

Das Datenblatt habe ich mir mehrfach durchgelesen und in punkto I2C auch 
soweit verstanden.
Trotzdem bekomme ich es nicht hin, eine Kommunikation mit einem PCF8574 
aufzubauen.

Folgendes Problem besteht:

Ich initialisiere alle notwendigen Register und halte mich auch an die 
im Datenblatt angegebene Reihenfolge.
Dann setze ich das Startbit und SDA wird auch auf LOW gezogen, das 
Startbit wird dann auch nach Lesen des SR1 und anschließendem 
Beschreiben von DR korrekt zurückgesetzt.
In DR schreibe ich die Adresse des PCF8574 (ist in einem LCD-Modul 
eingebunden - A0,A1,A2 sind mit PullUps auf HIGH - daher ist die Adresse 
des Display statt 0x20 somit 0x27).

Es wäre mir eine wirklich große Hilfe, wenn mir jemand einen heißen Tipp 
geben könnte, was ich falsch mache oder vergessen habe.

Der Controller läuft mit 8MHz Quarz + PLL auf 72 MHz hochmultipliziert.
Der Vorteiler für APB1 (PCLK1) ist auf 2 --> also 36MHz am I2C1.
Die Taktfrequenz habe ich auch schon im RCC heruntergesetzt, genauso wie 
die
100kHz I2C-Takrtfrequenz auch mal auf 10kHz eingestellt waren.
Leider ohne Erfolg.

Ich habe auch schon andere I2C-Teilnehmer an den Controller 
angeschlossen - leider ohne Erfolg.

Am SDA/SCL hängen je 2k2 PullUp-Widerstände gegen 5V (PB6/PB7 sind 
5V-Tolerant)
1
void I2C_Init(void){ //I2C initialisieren
2
  
3
  #define __I2C_SCL(x) ((x)?(GPIOB->BSRR |= (1 << 6)):(GPIOB->BSRR |= (1 << (6 + 16)))) //nicht schoen, aber fuer den Test ausreichend...
4
  #define __I2C_SDA(x) ((x)?(GPIOB->BSRR |= (1 << 7)):(GPIOB->BSRR |= (1 << (7 + 16))))
5
  
6
  #define __I2C_SCL_IDR (GPIOB->IDR & (1 << 6))
7
  #define __I2C_SDA_IDR (GPIOB->IDR & (1 << 7))
8
  
9
  //Ports fuer PortB einstellen
10
  RCC->APB2ENR |= (uint32_t)(0x00000008);
11
  
12
  // +++++++++++++++++++++++++++++++++++++++++++
13
  // +++ Start Init-Seq from ST ERRATA-Sheet +++
14
  // +++++++++++++++++++++++++++++++++++++++++++
15
  
16
  //Set Up Register for GPIO 
17
  setGPIORegister(GPIOB,0x06,6); //GPIO, OpenDrain, LowSpeed
18
  setGPIORegister(GPIOB,0x06,7); //GPIO, OpenDrain, LowSpeed
19
  
20
  __I2C_SCL(true);
21
  __I2C_SDA(true);
22
  while(!__I2C_SDA_IDR && !__I2C_SCL_IDR);
23
  __I2C_SDA(false);
24
  while(__I2C_SDA_IDR);
25
  __I2C_SCL(false);
26
  while(__I2C_SCL_IDR);
27
  __I2C_SCL(true);
28
  while(!__I2C_SCL_IDR);
29
  __I2C_SDA(true);
30
  while(!__I2C_SDA_IDR);
31
  
32
  // ++++++++++++++++++++++++++++++++++++++++++
33
  // +++ Stop Init-Seq from ST ERRATA-Sheet +++
34
  // ++++++++++++++++++++++++++++++++++++++++++
35
  
36
  // +++ I2C +++
37
  RCC->APB1ENR |= (uint32_t)(0x00200000); //I2C1 aktivieren
38
  
39
  //Set Up Register for AF (I2C) [0x0E]
40
  setGPIORegister(GPIOB,0x0E,6); //AlternateFunction, OpenDrain, LowSpeed [0x0E]
41
  setGPIORegister(GPIOB,0x0E,7); //AlternateFunction, OpenDrain, LowSpeed [0x0E]
42
  
43
  I2C1->CR1 = (uint16_t)0x8000; //SoftReset des I2C
44
  I2C1->CR1 = (uint16_t)0x00; //SoftReset zuruecknehmen
45
  
46
  //Frequenz einstellen
47
  I2C1->CR2 = (uint16_t)36; //36 MHz PCLK1
48
  I2C1->CCR = (uint16_t)180; //Frequenz = 100kHz
49
  I2C1->TRISE = (uint16_t)39; // (1000ns / (1/36MHz)) + 1 = 39
50
  
51
  I2C1->CR1 = (uint16_t)0x01; //I2C aktivieren
52
  
53
  while(__I2C_BUSY); //Warten, falls Busleitungen noch nicht auf HIGH sind...
54
55
}
56
57
58
bool I2C_SendData(unsigned char Adr, unsigned char *Data, unsigned int Len){ //I2C Daten senden
59
60
  
61
  bool success = true;
62
  unsigned int x = Len;
63
  unsigned char *data = Data;
64
  
65
  //Start-Condition
66
  while(__I2C_BUSY);
67
  
68
  __I2C_START;
69
  
70
  while(!__I2C_START_SENT);
71
  I2C1->DR = (Adr << 1); //Adresse ist 0x27 -> nach dem 'Schieben' ist der Byteinhalt 0x4E
72
  
73
  while(!__I2C_ADDR_SENT); // <--- Hier bleibt das Programm haengen!! AF ist gesetzt und SCL ist auf LOW (wird nicht durch Slave auf LOW gezogen!)
74
  
75
  while(x){ //Daten senden
76
    
77
    I2C1->DR = (*data++);
78
    while(!__I2C_TX_EMPTY);
79
    
80
    x--;
81
  }
82
  
83
  //Stop-Condition
84
  __I2C_STOP;
85
  
86
  
87
  return success;
88
  
89
}
90
91
92
int main(void){
93
  
94
  I2C_Init();
95
  unsigned char data[2] = {0x01,0x08};
96
  I2C_SendData(0x27,&data,2);
97
  
98
  
99
  while(1){
100
    
101
    //Hier steht noch weiterer Code - aber die Funktion
102
    //bleibt an der markierten Stelle in I2C_SendData(...) hängen... 
103
104
    
105
  }
106
  
107
  
108
}


Das I2C-Interface scheint also immerhin zu arbeiten, da das Start-Bit ja 
generiert wird. Mit dem Oszi sehe ich auch einen Takt auf SCL - 
allerdings wird er danach auch LOW gezogen.

Ich habe übrigens nicht vor, den Code so zu lassen :)
Es geht mir im Augenblick erst einmal darum, das System ans Laufen zu
bekommen. Eine wiederverwendbare und adaptierbare Funktion wird dann 
gebaut, wenn ich die ersten Bytes erfolgreich gesendet bzw. empfangen 
habe.

Es wäre wirklich wunderbar, wenn mir die Experten in diesem Forum unter 
die Arme greifen würden.

Vielen Dank im Voraus und einen schönen Freitagabend...

Edit:
Die ERRATA - Init-Sequenz habe ich auch schon einmal komplett 
auskommentiert.
Ohne Erfolg natürlich...

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Pete V. schrieb:
> Ich versuche seit einigen Tagen meinen I2C-Bus am STM32F103C8T6 zu
> nutzen.

Da und hie frage ich mich ja, ob es Spass macht wieder mal ein (diesmal 
3-eckiges) Rad neu zu erfinden.
Zeitaufwaendig scheint es zumindest zu sein.
"Librarys sind Luxus".

leo

von Code Leser (Gast)


Lesenswert?

Pete V. schrieb:
> Es wäre wirklich wunderbar, wenn mir die Experten in diesem Forum unter
> die Arme greifen würden.

Ich könnte mir vorstellen dass deine Magic-Numbers-
Programmierung die meisten Leute abhalten wird sie nach-
zuvollziehen um einen Fehler zu finden.

... if you know what I mean ...

von Pete V (Gast)


Lesenswert?

Es geht ganz bestimmt nicht darum, etwas neu zu erfinden.

Ich möchte es verstehen - dazu sollte es doch möglich sein, ein 
funktionierenden Code zu programmieren, der an das Datenblatt angelehnt 
ist.
Den Lerneffekt, den man beim Einbinden einer fertigen Lib hat, ist nicht 
das, was mich zu Frieden stellt.


Bezüglich der MagicNumbers werde ich den Code noch umschreiben. Danke 
für den Hinweis :)

von Code Leser (Gast)


Lesenswert?

Pete V schrieb:
> Den Lerneffekt, den man beim Einbinden einer fertigen Lib hat, ist nicht
> das, was mich zu Frieden stellt.

Vielleicht hat leo auch nur das selbe gemeint wie ich,
nur in anderen Worten ....

Genormte Low-Level Calls zu nutzen ist nicht verwerflich
und ist bei weitem nicht als Verwendung einer fertigen
Lib zu betrachten.

von Code Leser (Gast)


Lesenswert?

Pete V schrieb:
> Bezüglich der MagicNumbers werde ich den Code noch umschreiben. Danke
> für den Hinweis :)

Vielleicht ist dir noch nicht geläufig wo du nachzuschauen
hast um schnell auf einen grünen Zweig zu kommen.
Für deinen Fall wäre das in der SPL die Dateien

stm32f10x_i2c.c

und

stm32f10x_i2c.h

Die bieten dir eine anständige Schnittstelle "nach unten" und
du kannst den Code der da unten verwendet wird auch kopieren
um eigenständig zu sein.

Die Dateien zu verwenden ist beileibe nicht "eine fertige Lib
benutzen".

von Pete V (Gast)


Lesenswert?

Okay, das ist ein super Hinweis - danke.
Hab mal vor ein paar Jahren mit dem LPC1768 programmiert und sonst nur 
Erfahrungen mit den einschlägigen AVRs - da ist man um jede Quelle 
dankbar :)

Das werde ich mir mal hinzufügen und dann Rückmeldung geben :)

von Pieter (Gast)


Lesenswert?

moin moin,

ich komme aus der Pascal-Ecke, aber was mir bei Deiner Initialisierung 
fehlt:
RCC->APB2ENR->AFIOEN, das Bit0 setzen...wegen der AlternateFunction

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe hier einen Beispiel-Code für dich, wie man die richtige I²C 
Schnittstelle benutzt: http://stefanfrings.de/stm32/stm32f1.html#i2c

Du siehst, dass ich hier gar nicht direkt auf die I/O Pins zugreife. Ich 
halte deine Initialisierungsroutine für unnötig komplex.

Unabhängig davon würde ich Dir empfehlen, deinen Code weiter zu 
untersuchen. Besorge Dir einen "8ch Logic Analysator" und das kostenlose 
Programm "PulseView". Damit kannst du die Signale auszeichnen und 
untersuchen. Das Programm kann sogar das I²C Protokoll dekodieren.

Das Bild, dass dieses Programm ausgibt, wird so ähnlich aussehen, wie 
das angehängte (ein funktionierendes Beispiel für einen anderen Slave). 
Damit kann ich dir besser helfen, als deinen Quelltext zu analysieren.

von Stefan F. (Gast)


Lesenswert?

Zwei Sachen fallen mir spontan auf:

1) Fehlende bzw. zu geringe Verzögerungszeiten:
1
  __I2C_SCL(true);
2
  __I2C_SDA(true);
3
  while(!__I2C_SDA_IDR && !__I2C_SCL_IDR);
4
  __I2C_SDA(false);
5
  while(__I2C_SDA_IDR);
6
  __I2C_SCL(false);
7
  while(__I2C_SCL_IDR);
8
  __I2C_SCL(true);
9
  while(!__I2C_SCL_IDR);
10
  __I2C_SDA(true);
11
  while(!__I2C_SDA_IDR);

Du fummelst hier an den beiden Signalen herum, ohne lange genug zu 
warten. Die beiden letzten Schreibzugriffe könnten letztendlich dazu 
führen, dass die Pins gleichzeitig oder fast gleichzeitig auf High 
gehen, was im I²C Protokoll nicht zulässig ist.

2) Deine Prozedur, wie du die Daten sendest und empfängst ist völlig 
falsch. Das solltest du nochmal einen Blick in das Reference-Manual und 
(ganz wichtig!) auch das Errata Dokument werden. Beim STM32 geht das 
nämlich nicht ganz so einfach, wie bei AVR. Siehe mein 
Beispiel-Quelltext, der setzt 1:1 das um, was ST in den beiden 
Dokumenten empfohlen hat.

Ich scheiße-kompliziert aber wohl nötig.

Und dann fällt mich noch etwas ein, wass ich selber herausfinden musst: 
Konfiguriere zuerst die I²C Peripherie, und erst danach die I/O Pins. 
Nur in dieser Reihenfolge starten sie gleich mit den richtigen Pegeln 
ohne die I²C Slaves zu blockieren.

von Holm T. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich habe hier einen Beispiel-Code für dich, wie man die richtige I²C
> Schnittstelle benutzt: http://stefanfrings.de/stm32/stm32f1.html#i2c
>
> Du siehst, dass ich hier gar nicht direkt auf die I/O Pins zugreife. Ich
> halte deine Initialisierungsroutine für unnötig komplex.
>
> Unabhängig davon würde ich Dir empfehlen, deinen Code weiter zu
> untersuchen. Besorge Dir einen "8ch Logic Analysator" und das kostenlose
> Programm "PulseView". Damit kannst du die Signale auszeichnen und
> untersuchen. Das Programm kann sogar das I²C Protokoll dekodieren.
>
> Das Bild, dass dieses Programm ausgibt, wird so ähnlich aussehen, wie
> das angehängte (ein funktionierendes Beispiel für einen anderen Slave).
> Damit kann ich dir besser helfen, als deinen Quelltext zu analysieren.

Anmerkung zu Pulseview:

Es gibt eine Firmware im Netz die man auf einen  STM32-Discovery laden 
kann um da Ding nachfolgend als Pulseview-kompatiblen LA zu nutzen, 
damit hab ich meinen I2C Kram, der ein Mischmasch wohl aus Stefans und 
W.S. und eigenem Code ist, debuggt. 24C08 etc klappt, LCD via 8574 ist 
gerade in Arbeit, die Kommunikation funktioniert aber problemlos.

Gruß,
Holm

von Pete V. (elektrohonk)


Lesenswert?

Stefanus F. schrieb:
> Ich habe hier einen Beispiel-Code für dich, wie man die richtige I²C
> Schnittstelle benutzt: http://stefanfrings.de/stm32/stm32f1.html#i2c

Hallo Stefan,

zuerst einmal vielen Dank für den Code.

Ich habe Deinen Code 1:1 bei mir übernommen - lediglich die Taktfrequenz 
angepasst, da meine Peripherie nicht auf 8, sondern auf 36 MHz läuft.

Leider funktioniert der Code auch nicht bei mir.
Habe dann mal probeweise die Taktfrequenz auf 9 MHz heruntergesetzt 
(Vorteiler PCLK1 auf 8 statt 2 @ 72MHz).

Das Verhalten ist genau das gleiche, wie bei meinem Programm.
Die SCL wird auf LOW gehalten und ein AF gesetzt, da wohl kein ACK vom 
Slave kommt.


Ich hänge den Slave jetzt einmal an einen Mega328p, da ich dafür eine 
funktionierende Bib hab. Vllt stimmt doch etwas nicht mit dem Slave...


Bezüglich dem LogicAnalyzer:
Ich habe mir die Woche einen bestellt, da alles andere nur Gefummele zu 
sein scheint und ich sowieso schon öfter einen gebraucht hätte.
Sollte dann im Laufe der Woche ankommen.

Das ganze Thema ist echt zeitintensiv, aber immer, wenn ich solche 
Probleme beim Programmieren habe, habe ich am Ende die wertvollsten 
Lektionen daraus ziehen können :)


@Stefan:
Du hast lesenswerte Inhalte auf Deiner Internetseite.
Werde mir das im Ganzen noch einmal genauer ansehen.

von Stefan F. (Gast)


Lesenswert?

Pete V. schrieb:
> Die SCL wird auf LOW gehalten und ein AF gesetzt, da wohl kein ACK vom
> Slave kommt.

Das ACK/NAK wird beim 9. Takt eingelesen. Wenn du nach dem Start keine 9 
Taktimpulse siehst, hast du ein Hardwareproblem außerhalb des 
Mikrocontrollers.

Probiere dann mal ohne Slave aus. Du müsstest alle 9 Takte sehen und das 
NACK (SDA=High), erst danach sollte die Übertragung abbrechen. Und zwar 
mit einem sauberen STOP Signal, gefolgt vom Ruhepegel (SDA=High und 
SCL=High).

> Das ganze Thema ist echt zeitintensiv,

Ja, I²C ist schwierig. Aber wenn es dann endlich läuft ist es sehr 
praktisch.

> Du hast lesenswerte Inhalte auf Deiner Internetseite.

Danke für das Lob. Positives Feedback treibt mich dazu an, die Seite 
weiter auszubauen.

von Pete V. (elektrohonk)


Lesenswert?

Stefanus F. schrieb:
> Das ACK/NAK wird beim 9. Takt eingelesen. Wenn du nach dem Start keine 9
> Taktimpulse siehst, hast du ein Hardwareproblem außerhalb des
> Mikrocontrollers.
>
> Probiere dann mal ohne Slave aus. Du müsstest alle 9 Takte sehen und das
> NACK (SDA=High), erst danach sollte die Übertragung abbrechen. Und zwar
> mit einem sauberen STOP Signal, gefolgt vom Ruhepegel (SDA=High und
> SCL=High).

Hallo Stefan,

also die Taktimpulse (SCL) kann ich auf dem Oszi sehen.
Ich kann sehen, dass die Taktimpulse raus gehen und auf SDA passiert 
auch etwas.
Leider muss ich noch auf meinen LogicAnalyzer warten, bis ich dazu 
genaueres sagen kann.
Also die HW des STM32 scheint auf jeden Fall grundsätzlich zu arbeiten.

Das Stop-Signal (Als Fehlerbehandlung nach "goto error") kommt auch.
In deinem Programmcode habe ich dann das "goto error" mal auskommentiert 
- die Registerinhalte mit dem AF sind auf jeden Fall genauso wie in 
meinem Programm. Der Slave gibt wohl einfach keinen ACK.

In der Zwischenzeit habe ich den Slave (I2C-LCD) an den Mega328p 
angeschlossen - es funktioniert dort einwandfrei. Hier liegt also kein 
Defekt vor...

Ich setze mal noch die Taktfrequenz von 100kHz runter auf 10kHz...
Mal schauen, ob es an der Leitungslänge liegt (ca. 10cm - sollte 
eigentlich irrelevant sein...)

: Bearbeitet durch User
von Holm T. (Gast)


Lesenswert?

Pete V. schrieb:
> Stefanus F. schrieb:
>> Das ACK/NAK wird beim 9. Takt eingelesen. Wenn du nach dem Start keine 9
>> Taktimpulse siehst, hast du ein Hardwareproblem außerhalb des
>> Mikrocontrollers.
>>
>> Probiere dann mal ohne Slave aus. Du müsstest alle 9 Takte sehen und das
>> NACK (SDA=High), erst danach sollte die Übertragung abbrechen. Und zwar
>> mit einem sauberen STOP Signal, gefolgt vom Ruhepegel (SDA=High und
>> SCL=High).
>
> Hallo Stefan,
>
> also die Taktimpulse (SCL) kann ich auf dem Oszi sehen.
> Ich kann sehen, dass die Taktimpulse raus gehen und auf SDA passiert
> auch etwas.
> Leider muss ich noch auf meinen LogicAnalyzer warten, bis ich dazu
> genaueres sagen kann.
> Also die HW des STM32 scheint auf jeden Fall grundsätzlich zu arbeiten.
>
> Das Stop-Signal (Als Fehlerbehandlung nach "goto error") kommt auch.
> In deinem Programmcode habe ich dann das "goto error" mal auskommentiert
> - die Registerinhalte mit dem AF sind auf jeden Fall genauso wie in
> meinem Programm. Der Slave gibt wohl einfach keinen ACK.
>
> In der Zwischenzeit habe ich den Slave (I2C-LCD) an den Mega328p
> angeschlossen - es funktioniert dort einwandfrei. Hier liegt also kein
> Defekt vor...
>
> Ich setze mal noch die Taktfrequenz von 100kHz runter auf 10kHz...
> Mal schauen, ob es an der Leitungslänge liegt (ca. 10cm - sollte
> eigentlich irrelevant sein...)

Meine vorgesehene Frage ob Du die richtige Adresse erwischt hast 
erübrigt sich wohl. Hast Du vernünftige Pullup Rs an SCK und SDA?
Mein LCD geht auch, bei mir war das nur eine Frage der richtigen 
Bitbelegung dieser China-I2C-zu Display Platine, die mußte ich  erst mal 
ermitteln. Das ist also ein Adapter für Standard-HD44780 Displays zu 
I2C.
Falls Du auch so ein Ding auf dem Tisch hast, probiere erst mal die 
Displaybeleuchtung mit Bit 3 (Ausgang P3 am 8574, 0x08) an und aus zu 
schalten.

Falls es irgend Jemand braucht, Zuordnung der LCD Pins zu 8574T auf der 
China Platine:

P0 -> RS
P1 -> R/W
P2 -> E
P3 -> Background Light
P4 -> DB4
P5 -> DB5
P6 -> DB6
P7 -> DB7

Die Adresse der Platine ist ohne Lötbrücken 0x4E/0x4F.

Gruß,

Holm

von Pete V. (elektrohonk)


Angehängte Dateien:

Lesenswert?

Holm T. schrieb:
> Falls es irgend Jemand braucht, Zuordnung der LCD Pins zu 8574T auf der
> China Platine:
>
> P0 -> RS
> P1 -> R/W
> P2 -> E
> P3 -> Background Light
> P4 -> DB4
> P5 -> DB5
> P6 -> DB6
> P7 -> DB7

Hallo Holm,

ich musste auch erst suchen bei der Erstinbetriebnahme.
Habe dann irgendwo den Schaltplan (siehe Anhang) gefunden.

Dass die Adresse des Displays bei den unteren Bits (A3-A0) eine 0x07 
ist, hat mich auch etwas verwirrt, da der Schaltplan ja etwas anderes 
gezeigt hat.

Das hab ich auch in der aktuellen Problematik öfter in Frage gestellt.
Aber dadurch, dass ich es gerade mit (0x27 << 1) am laufen hatte, ist es 
jetzt wieder eindeutig.

von Holm T. (Gast)


Lesenswert?

Pete V. schrieb:
> Holm T. schrieb:
>> Falls es irgend Jemand braucht, Zuordnung der LCD Pins zu 8574T auf der
>> China Platine:
>>
>> P0 -> RS
>> P1 -> R/W
>> P2 -> E
>> P3 -> Background Light
>> P4 -> DB4
>> P5 -> DB5
>> P6 -> DB6
>> P7 -> DB7
>
> Hallo Holm,
>
> ich musste auch erst suchen bei der Erstinbetriebnahme.
> Habe dann irgendwo den Schaltplan (siehe Anhang) gefunden.
>
> Dass die Adresse des Displays bei den unteren Bits (A3-A0) eine 0x07
> ist, hat mich auch etwas verwirrt, da der Schaltplan ja etwas anderes
> gezeigt hat.

Nuja, Dein Schaltplan lügt ganz einfach. Auf der Platine sind 3 
Lötbrücken..wenn die offen sind liegen halt die Eingänge vom PCV nicht 
an Masse..damit wird die Sache klar. Ich hab die Verschaltung 
ausgeklingelt, nur einen "Schaltplan" habe ich davon nicht gemalt.

>
> Das hab ich auch in der aktuellen Problematik öfter in Frage gestellt.
> Aber dadurch, dass ich es gerade mit (0x27 << 1) am laufen hatte, ist es
> jetzt wieder eindeutig.

0x27<<1 ist 0x4e...

Ich habe aber bei mir noch einen I2C Pegelwandler mit 2 Stück 2N7002 
dazwischen..sind die 3,3V am Display Dein Problem? Den 24C08 betreibe 
ich mit 3v3, das Display mit 5V.

Gruß,

Holm

von Pete V (Gast)


Lesenswert?

Den Pegelwandler mit dem FET hab ich auch gerade mal noch eingebaut.

Leider auch keine Veränderung an der aktuellen Situation...

Was kann es denn noch sein? ?

von Holm T. (Gast)


Angehängte Dateien:

Lesenswert?

Pete V schrieb:
> Den Pegelwandler mit dem FET hab ich auch gerade mal noch eingebaut.
>
> Leider auch keine Veränderung an der aktuellen Situation...
>
> Was kann es denn noch sein? ?

..ohne Logikanalyzer ist das eher schwer rauszubekommen.
Hast Du nicht so ein Discovery Board da um einen provisorischen LA zu 
mimikrieren? Ich habe diverse alte LA's da, aber das Feature von 
Pulseview Protokolle decodieren zu können hat mir mit dem 24C08 der erst 
nicht wollte sehr geholfen und man braucht ja nicht mehr als 2 Eingänge.
Die Software auf dem PC ist dann die Selbe wie für Deinen mittlerweile 
gekauften LA...

https://sysprogs.com/w/how-we-turned-8-popular-stm32-boards-into-powerful-logic-analyzers/

Gruß,

Holm

von Pete V. (elektrohonk)


Angehängte Dateien:

Lesenswert?

Leider habe ich ein solches Board nicht da.
Habe mir vor kurzem noch einen zweiten STM32 bestellt, sonst habe ich 
"nur" AVRs und PICs, sowie den LPC1768 hier.

Ich habe gerade einmal die Frequenz auf dem I2C verlangsamt, den Slave 
entfernt und eine Endlosschleife programmiert, die praktisch immer
das Start-Bit setzt und dann den Byte-Inhalt 0x4E sendet.
1
....
2
while(!success){
3
    //Start-Condition
4
    
5
    while(__I2C_BUSY);
6
    
7
    __I2C_START;
8
    
9
    while(!__I2C_START_SENT);
10
    I2C1->DR = (Adr << 1); //Adresse ist 0x27 -> nach dem 'Schieben' ist der Byteinhalt 0x4E
11
    
12
      success = true;
13
    while(!__I2C_ADDR_SENT){ 
14
      if((I2C1->SR1 & I2C_SR1_AF)){
15
        __I2C_STOP;
16
        I2C1->CR1 &=~ (I2C_CR1_PE);
17
        I2C1->CR1 |= (I2C_CR1_PE);
18
        success = false;
19
        break;
20
      }
21
    }
22
  }
23
...

Das habe ich mit dem Oszi aufgezeichnet.
Also, das was dort auf dem Bus geschieht, sieht jedenfalls gut aus.
Das gibt Mut, dass die HW tatsächlich intakt ist.

gelb = SCL
rot = SDA

von W.S. (Gast)


Lesenswert?

Pete V. schrieb:
> setGPIORegister(GPIOB,0x06,6); //GPIO, OpenDrain, LowSpeed
>   setGPIORegister(GPIOB,0x06,7); //GPIO, OpenDrain, LowSpeed
>
>   __I2C_SCL(true);
>   __I2C_SDA(true);

Du hast eine seltsame Herangehensweise.
Also, ich würde an deiner Stelle zu allererst mal folgendes machen:
Pre-Requisites:
USB anwerfen und Kommandoprogramm in die Firmware, damit du mit deinem 
µC überhaupt kommunizieren kannst. Alternativ Semihosting, ist mir aber 
nicht sympathisch.

So, und dann:
1. Die beiden Portpins aufsetzen
2. beide Portpins per Kommando mit deinen Makros ausprobieren, ob sie 
tatsächlich sich so verhalten, wie du es dir gedacht hast.
3. bei Portpins = high auch durch Zurücklesen sicherstellen, daß du den 
tatsächlichen Pin-Zustand erfaßt hast und nicht versehentlich den 
Zustand der Output-Register geliefert kriegst. Das sollte beim STM32F103 
kein Thema sein, gilt aber als Stolperfalle bei anderen µC, z.B. beim 
LPC1114. Aber Nachprüfen ist besser als dran glauben.

So, noch ein Wort zu deinen Makros: Der I2C ist eine langsame Sache, 
also braucht man auch nicht auf Hochgeschwindigkeit zu achten. Mach dir 
lieber für einen Software-I2C sowas:

void SCL_Low(void);
void SCL_High(void);
void SDA_Low(void);
void SDA_High(void);
bool Lies_SDA(void);

Der Aufruf solcher Funktionen ist ne recht sparsame Sache und die Zeit 
dafür hast du allemal. Du müßtest zusätzlich auch ne Wartefunktion 
vorsehen, um soviel Zeit durch Trampeln zu verplempern, daß die 
Geschwindigkeit von SCL nicht höher kommt als etwa 400 kHz.

Und wenn du den eingebauten I2C-Peripherie-Core benutzen willst, dann 
kannst du dir sämtliche diesbezüglichen Makros komplett sparen, denn 
dann solltest du überhaupt nicht dirkt auf SCL und SDA zugreifen. Aber 
soweit ich mich erinnere, ist gerade der I2C beim o.g. Controller ein 
eher schwieriges Kind. Ich hab deshalb auf diesem Controller schlichtweg 
nur nen Software-I2C laufen. Den hatte ich schonmal gepostet.

W.S.

von Holm T. (Gast)


Angehängte Dateien:

Lesenswert?

Pete V. schrieb:
> Leider habe ich ein solches Board nicht da.
> Habe mir vor kurzem noch einen zweiten STM32 bestellt, sonst habe ich
> "nur" AVRs und PICs, sowie den LPC1768 hier.
>
> Ich habe gerade einmal die Frequenz auf dem I2C verlangsamt, den Slave
> entfernt und eine Endlosschleife programmiert, die praktisch immer
> das Start-Bit setzt und dann den Byte-Inhalt 0x4E sendet.
>
>
1
> ....
2
> while(!success){
3
>     //Start-Condition
4
> 
5
>     while(__I2C_BUSY);
6
> 
7
>     __I2C_START;
8
> 
9
>     while(!__I2C_START_SENT);
10
>     I2C1->DR = (Adr << 1); //Adresse ist 0x27 -> nach dem 'Schieben' ist 
11
> der Byteinhalt 0x4E
12
> 
13
>       success = true;
14
>     while(!__I2C_ADDR_SENT){
15
>       if((I2C1->SR1 & I2C_SR1_AF)){
16
>         __I2C_STOP;
17
>         I2C1->CR1 &=~ (I2C_CR1_PE);
18
>         I2C1->CR1 |= (I2C_CR1_PE);
19
>         success = false;
20
>         break;
21
>       }
22
>     }
23
>   }
24
> ...
25
>
>
> Das habe ich mit dem Oszi aufgezeichnet.
> Also, das was dort auf dem Bus geschieht, sieht jedenfalls gut aus.
> Das gibt Mut, dass die HW tatsächlich intakt ist.
>
> gelb = SCL
> rot = SDA

Hab Dir mal angehangen wie das aussehen sollte... das ist die 
Kommunikation zum PCF8574T. Ich habe so lange gebraucht weil ich 
Pulseview neu bauen und erst wieder konfigurieren mußte...

Muß jetzt zum Nachbarn.

Gruß,

Holm

von Pete V. (elektrohonk)


Lesenswert?

Holm T. schrieb:
> Hab Dir mal angehangen wie das aussehen sollte... das ist die
> Kommunikation zum PCF8574T. Ich habe so lange gebraucht weil ich
> Pulseview neu bauen und erst wieder konfigurieren mußte...
>
> Muß jetzt zum Nachbarn.
>
> Gruß,
>
> Holm

Danke für die ausführliche Darstellung. Das ist sehr nett von Dir, dass 
Du Dir die Arbeit gemacht hast.
Hatte gestern mal die beiden Scopes miteinander verglichen und vom 
Signalverlauf her passte das auch.

Hatte auch gestern den Bus kurz am laufen - ich konnte auf jeden Fall im 
Sekundentakt die Hintergrundbeleuchtung des Displays ein- und 
ausschalten.
Leider ist das ganze konstrukt noch sehr instabil - das ist wohl der 
Punkt, an dem man merkt, dass der I2C auf dem Chip tatsächlich eine 
Mimose zu sein scheint.

Ich werde nun folgendes tun (um nicht noch mehr Zeit zu investieren):
Ich programmiere nun einen Soft-I2C, nutze die Pins des IC21 als GPIO 
und Route diese auch entsprechend auf dem Board, das ich gerade designe.
Wenn dann mein LogicAnalyzer kommt, steige ich noch einmal tiefer ein 
und gehe der Sache dann noch einmal auf den Grund.


Bis dahin danke ich Euch allen für Eure Hilfe.
Ich melde mich die Tage noch einmal, was die Analyse mit LA ergeben hat.
Damit der nächste, der ein ähnliches Problem hat, evtl. Abhilfe findet.

Allen einen entspannten Sonntag!

von Holm T. (Gast)


Lesenswert?

Pete V. schrieb:
> Holm T. schrieb:
>> Hab Dir mal angehangen wie das aussehen sollte... das ist die
>> Kommunikation zum PCF8574T. Ich habe so lange gebraucht weil ich
>> Pulseview neu bauen und erst wieder konfigurieren mußte...
>>
>> Muß jetzt zum Nachbarn.
>>
>> Gruß,
>>
>> Holm
>
> Danke für die ausführliche Darstellung. Das ist sehr nett von Dir, dass
> Du Dir die Arbeit gemacht hast.
> Hatte gestern mal die beiden Scopes miteinander verglichen und vom
> Signalverlauf her passte das auch.
>
> Hatte auch gestern den Bus kurz am laufen - ich konnte auf jeden Fall im
> Sekundentakt die Hintergrundbeleuchtung des Displays ein- und
> ausschalten.
> Leider ist das ganze konstrukt noch sehr instabil - das ist wohl der
> Punkt, an dem man merkt, dass der I2C auf dem Chip tatsächlich eine
> Mimose zu sein scheint.
>
> Ich werde nun folgendes tun (um nicht noch mehr Zeit zu investieren):
> Ich programmiere nun einen Soft-I2C, nutze die Pins des IC21 als GPIO
> und Route diese auch entsprechend auf dem Board, das ich gerade designe.
> Wenn dann mein LogicAnalyzer kommt, steige ich noch einmal tiefer ein
> und gehe der Sache dann noch einmal auf den Grund.
>
>
> Bis dahin danke ich Euch allen für Eure Hilfe.
> Ich melde mich die Tage noch einmal, was die Analyse mit LA ergeben hat.
> Damit der nächste, der ein ähnliches Problem hat, evtl. Abhilfe findet.
>
> Allen einen entspannten Sonntag!

Mach mal langsam, ich werde Dir die Initailisierungsteile für den I2C 
Bus und die Routinen für den EEPROM und das Display hier rein kopieren.
Ich bastele an einen Nonprofit Projekt für einen Freund, der will ne 
Teufenanzeige für einen Fahrkorb in einem alten Bergwerksschacht.
Auf dem Fotos siehst Du den Absolutwertgeber und die großen Displays für 
die Anzeige. Ich habe mir den I2C Code hier auch nur im Netz 
zusammenkopiert, der Kram benutzt die HardwareI2C Schnittstelle, IMHO 
SPI3..

Gruß,

Holm

von Holm T. (Gast)


Angehängte Dateien:

Lesenswert?

So, ich habe Dir hier mal was zusammenkopiert, wie schon gesagt ist das 
nicht Alles auf meinem Mist gewachsen. Nimm Dir raus was Du brauchst.
This is "work in progress" ..and has no warranty for nothing, may kill 
your dog ..etc.

Gruß,

Holm

von Pete V. (elektrohonk)


Lesenswert?

Hallo Holm,

tausend Dank =)

Ich habe mir die Dateien in meiner Code-Sammlung abgelegt und werde mir 
diese mal nacheinander ansehen.

Es ist immer wertvoll für mich, die Handschrift und die Umsetzungsweise 
anderer Programmierer einsehen zu dürfen.

Noch einmal vielen Dank!


Nun noch einmal zu meinem "Problem..."

Ich habe mir gerade eben einmal den Soft-I2C Code zusammengeschrieben 
und auf den Chip geladen.
Das Display ließ sich direkt ansprechen und hat alle Befehle 
entgegengenommen.
Hab dazu meine "Lib" genommen, die ich seiner Zeit mal für den AVR 
erstellt hatte und auf den ARM umgeschrieben.

Jetzt kommt das kuriose:
Nachdem ich das Display per Soft-I2C angesprochen habe, habe ich noch 
einmal den Code vom HW-I2C in den Controller geladen und siehe da.
Jetzt gehts...
Manche Dinge muss man glaube ich nicht direkt verstehen.

Räume jetzt meine Funktionen auf und dann geht's zum nächsten Schritt.

Der I2C läuft jetzt mit PCLK1 auf 36MHz und CCR auf (36M/100k), also mit 
50kHz stabil.
Hab den Controller jetzt zig mal neu gestartet, neu geflasht, etc. - der 
Bus scheint immer noch stabil zu laufen.

Danke an alle Experten.
Wenn ich eine Erklärung für dieses Phänomen habe, lasse ich es euch 
wissen!

von Stefan F. (Gast)


Lesenswert?

Pete V. schrieb:
> Nachdem ich das Display per Soft-I2C angesprochen habe, habe ich noch
> einmal den Code vom HW-I2C in den Controller geladen und siehe da.
> Jetzt gehts...
> Manche Dinge muss man glaube ich nicht direkt verstehen.

Wenn der I²C Bus blockiert, muss man manchmal die Stromversorgung vom 
Master und Slave komplett aus schalten, um da wieder raus zu kommen.

Ich habe deswegen schon mal erwägt, einen Power-Reset Knopf in meinen 
USB Hub einzubauen.

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.