Hallo,
verwendet wird ein STM32F107 als Master (mit HAL), angeschlossen sind
mehrere Slaves in Form von ATXMega. Das ganze mit I2C verbunden (Fast
Mode mit 400 kHz, kein Clock Stretching, Pullups mit 1k).
Manchmal tritt das Problem auf, dass der Slave noch Daten senden will,
aber der Master keinen Takt mehr zur Verfügung stellt.
Wenn ich merke das der Fehler auftritt, dann erzeuge ich einen
künstlichen Takt am Master. Im Debugger funktioniert das einwandfrei.
Aber im normalen Betrieb nicht.
Hier mal der Code:
1
/* check if SDA is low, then toggle SCL to release the data line */
Wenn ich in der ersten Zeile dieser Funktion einen Breakpoint setze,
einen beim Verlassen der Funktion und von einem Breakpoint zum nächsten
springe, dann sind danach beide Leitungen vom I2C high und die
Kommunikation funktioniert wieder. Ohne Breakpoint hingegen bleibt SDA
low.
Ich kann leider auch nicht sagen ob im normalen Betrieb der manuelle
Clock funktioniert, da ich zwar mitm Oszi drauf schauen kann, aber ich
muss schon viel Traffic am Bus erzeugen, damit der Fehler auftritt.
Jemand eine Idee?
Ich würde gerne prüfen, ob die beiden Bus-Leitungen jeweils einen
angemessenen Pull-Up Widerstand haben und ob die GND Leitungen der
Busteilnehmer miteinander verbunden sind.
Hast du es mal mit niedriger Geschwindigkeit versucht, nur so zum
Vergleich?
Stefan ⛄ F. schrieb:> Ich würde gerne prüfen, ob die beiden Bus-Leitungen jeweils einen> angemessenen Pull-Up Widerstand haben und ob die GND Leitungen der> Busteilnehmer miteinander verbunden sind.
GND der beiden ist verbunden (nachgemessen mit Multimeter im
ausgeschalteten Zustand).
Wie überprüfe ich am besten die Pullups?
Stefan ⛄ F. schrieb:> Hast du es mal mit niedriger Geschwindigkeit versucht, nur so zum> Vergleich?
Leider nein und auch nicht möglich, da ich keinen Zugriff auf die
Firmware der ATXmegas habe und die Firmware keine Möglichkeit bietet,
die Frequenz zu ändern.
Casio schrieb:> for(uint_fast8_t i=0; i<16; i++)> {> HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);> HAL_Delay(1);> }
vielleicht wird der Teil oder auch nur das HAL_Delay durch irgendwelche
Compileroptionen wegoptimiert (im Debug natürlich nicht)
Optimierungen schrieb:> vielleicht wird der Teil oder auch nur das HAL_Delay durch irgendwelche> Compileroptionen wegoptimiert (im Debug natürlich nicht)
Ne, des dachte ich auch. Aber auch wenn ich es im Debugger laufen
lassen, ohne Breakpoints, dann funktioniert der Teil auch nicht.
Außerdem habe ich im Compiler "Optimize for Debug" aktiviert.
Casio schrieb:> Wie überprüfe ich am besten die Pullups?
Auch in ausgeschaltetem Zustand messen. Von SDA nach VCC sollten es 1
bis 3,3kΩ sein. Gleiches gilt für SCL.
> GND der beiden ist verbunden> verwendet wird ein STM32F107 als Master (mit HAL), angeschlossen sind> mehrere Slaves in Form von ATXMega.
Hast du jetzt mehrere Slaves, oder nicht?
>> Hast du es mal mit niedriger Geschwindigkeit versucht?> Leider nicht möglich, da ich keinen Zugriff auf die> Firmware der ATXmegas habe
Die Geschwindigkeit wird vom Master (deinem STM32) vorgegeben. Du musst
bei den Slaves nichts ändern.
Stefan ⛄ F. schrieb:> Auch in ausgeschaltetem Zustand messen. Von SDA nach VCC sollten es 1> bis 3,3kΩ sein. Gleiches gilt für SCL.
Ich hab es jetzt an jedem Slave gemessen, bei jedem Slave sinds bei der
SCL Leitung 995 Ohm, bei der SDA Leitung 1004 Ohm.
Stefan ⛄ F. schrieb:> Hast du jetzt mehrere Slaves, oder nicht?
Mehrere Slaves. Sorry blöd ausgedrückt. Meinte damit, zwischen jedem
Slave und dem Master.
Stefan ⛄ F. schrieb:> Die Geschwindigkeit wird vom Master (deinem STM32) vorgegeben. Du musst> bei den Slaves nichts ändern.
Stimmt. Probiere ich gleich.
Ich habe jetzt an einen GPIO einen Lackdraht angelötet und mit einem
weiteren Kanal vom Oszi verbunden.
Zu Beginn der oben gezeigten Funktion habe ich ergänzt, dass jender GPIO
auf High gesetzt und am Ende auf Low gesetzt werden soll (lila Kurve in
den beiden Bildern).
Beim Bild ohne_breakpoint.PNG habe ich die Funktion einfach durchlaufen
lassen, ohne irgendwo zu stoppen. Beim Bild mit_breakpoint.PNG habe ich
genau in der Zeile zum setzen des GPIO einen Breakpoint gesetzt. Nachdem
die Software den Punkt erreicht hat, einfach wieder Resume gedrückt,
nicht Zeile für Zeile durchgegangen oder ähnliches.
Noch ein Nachtrag.
Vor der Funktion zum Zurücksetzen der SDA Leitung habe ich noch eine
Funktion, welche überprüft, ob die SCL Leitung Low ist. Dies ist ein Bug
von der F1 Serie von STM, welcher manchmal auftritt. Ist SCL Low, wird
die ganze I2C Peripherie zurückgesetzt:
1
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==0)
2
{
3
/* reset the I2C1 periphery */
4
__HAL_RCC_I2C1_FORCE_RESET();
5
6
/* clear the reset flag */
7
__HAL_RCC_I2C1_RELEASE_RESET();
8
9
/* deinit and reinit I2C */
10
HAL_I2C_DeInit(&hi2c1);
11
MX_I2C1_Init();
12
}
13
14
15
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7)==0)
16
[...]
Und bei dem Bild vorhin, war SCL und SDA Low, weshalb SDA gleich zu
Beginn des Bildes wieder High ist. Da half ein Reset der I2C Peripherie.
Anbei jetzt ein Bild, wenn nur SDA Low ist und daher der Clock-Reset
durchgeführt werden sollte.
Mein Problem trat immer dann auf, wenn SDA und SCL low waren. SDA low,
weil der Slave noch was schicken wollte, SCL ist aufgrund eines Fehlers
in der STM32 Hardware manchmal low (Errata-Sheet).
Das eigentliche Problem war dann des zurücksetzen und neu intialisieren
der I2C Peripherie. Diese benötigt rund 450 ms (siehe Bild im Anhang.
Grün ist high, während der ersten if-Anweisung, pink is high, während
der zweiten if-Anweisung). Und klar, wenn ich einen Break-Point am
Anfang der zweiten if-Anweisung gestzt habe, ist genügend Zeit
vergangen. Ohne Breakpoint war/ist irgendwas noch nicht fertig und daher
der anschließende Fehler.
Ich muss jetzt noch herausfinden, was genau da so lange benötigt, da mir
jetzt die Quick&Dirty Lösung mit der while-Schleife so nicht gefällt.
Danke euch.