Hallo alle Miteinander,
ich bin zur Zeit dabei, mich in die 32Bit Welt einzuarbeiten. Hierzu
habe ich mir ein Nucleo Board gekauft. Nun möchte ich damit ein I2C
Display zu laufen bringen.
Allerdings habe ich hierbei kein Erfolg. Warum auch immer kommt absolut
kein I2C Signal raus (Oszi hängt an SDA und SCL).
Programmieren tu ich mit Atollic TrueStudio und STM32 CubeMX.
Die Hardwaresettings habe ich in CubeMX durchgeführt.
Verwendet habe ich erfolglos schon folgende Befehle:
I2C Port ist in CubeMX auf Standard und auf Pin PB6 und PB7 eingestellt.
Pullups sind angelötet (je 10kOhm)
Ich hoffe es kann mir jemand weiterhelfen. Ich bin mit meinem Latein am
Ende.
Kevin X. schrieb:> I2C Port ist in CubeMX auf Standard und auf Pin PB6 und PB7 eingestellt.> Pullups sind angelötet (je 10kOhm)
2,2kOhm wären besser wobei ich nicht glaube, dass das dein Problem ist.
Niklas G. schrieb:> Kevin X. schrieb:>> Verwendet habe ich erfolglos schon folgende Befehle:>> Sonst nix zur Initialisierung? Das klappt wohl nicht...
Man sollte hier schon die komplette Initialisierung sehen...
Du hast I2C-Interrupts aktiviert, benutzt aber die polling-Funktion.
Vielleicht kommentierst du einfach mal folgende Zeilen in der
stm32f1xx_hal_msp.c aus:
// HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
// HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
Wenn Du Interrupts benutzen willst, musst Du mit den dafür geeigneten
Funktionen arbeiten, z.B. HAL_I2C_Master_Transmit_IT(...) (siehe
stm32f1xx_hal_i2c.h)
Klaus S. schrieb:> Du hast I2C-Interrupts aktiviert, benutzt aber die polling-Funktion.> Vielleicht kommentierst du einfach mal folgende Zeilen in der> stm32f1xx_hal_msp.c aus:>> // HAL_NVIC_SetPriority(I2C1_EV_IRQn, 0, 0);> // HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);> // HAL_NVIC_SetPriority(I2C1_ER_IRQn, 0, 0);> // HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);>> Wenn Du Interrupts benutzen willst, musst Du mit den dafür geeigneten> Funktionen arbeiten, z.B. HAL_I2C_Master_Transmit_IT(...) (siehe> stm32f1xx_hal_i2c.h)
Das habe ich gerade mal gemacht, aber kein Erfolg.
Aus dem Link von pegel habe ich mal den Code ausprobiert:
d==2 bedeutet HAL_BUSY. Vermutlich ist der I2C-Bus durch eine nicht
erfolgreiche vorhergehende Transaktion blockiert.
Was macht denn die Funktion "DisplayInit()" in der main? Falls da
I2C-Transaktionen stattfinden solltest Du die Funktion auch mal
auskommentieren.
Welches Display möchtest Du denn ansteuern ?
Klaus S. schrieb:> d==2 bedeutet HAL_BUSY. Vermutlich ist der I2C-Bus durch eine nicht> erfolgreiche vorhergehende Transaktion blockiert.> Was macht denn die Funktion "DisplayInit()" in der main? Falls da> I2C-Transaktionen stattfinden solltest Du die Funktion auch mal> auskommentieren.>> Welches Display möchtest Du denn ansteuern ?
Ah okay. Das ist schonmal gut zu wissen.
Ja im DisplayInit() wird das Display initialisiert mit der u8g Lib. Das
habe ich aber auch schon auskommentiert gehabt. bzw. bei dem obrigen
letzten Test, wo auch die Screenshots aus dem Debuging dabei sind, ist
das nicht mehr einkommentiert.
Ich will den Fehler eingrenzen und daher hab ich nur die I2C_Write_Byte
Funktion aktuell aktiv. Aber es geht einfach nicht.
Oft hängen sich die I2C Bausteine auf, wenn sie falsch angesteuert
werden. Ist mir oft in der Entwicklungsphase mit Temperatursensoren so
ergangen. Vielleicht trennst du mal die Spannungsversorgung und probiert
danach nochmal. Ein Logikanalysator am Bus kann vllt auch nicht schaden.
Mir fallen spontan noch folgende Punkte ein:
- SDA und SCL korrekt verbunden (hatte ich auch schon mal vertauscht)
- Device-Adresse korrekt ?
Ich hänge Dir mal meine u8g-Initialisierungsroutinen für ein
SSD1306-Display an. Die main.c ist auf die relevanten Teile gekürzt.
Klaus S. schrieb:> Mir fallen spontan noch folgende Punkte ein:> - SDA und SCL korrekt verbunden (hatte ich auch schon mal vertauscht)> - Device-Adresse korrekt ?>> Ich hänge Dir mal meine u8g-Initialisierungsroutinen für ein> SSD1306-Display an. Die main.c ist auf die relevanten Teile gekürzt.
Danke für die Dateien, leider funktionieren diese bei mir nicht, da er
einige weitere Bibliotheken nicht findet bzw. Funktionen welche sich
wahrscheinlich in irgendwelchen anderen header Datein befindetn.
EDIT: Anbei noch mein komplettes Testprojekt. Vielleicht kann sich das
ja jemand mal anschauen.
In der main.c passiert ja gar nichts.
Selbst in den auskommentierten Versuchen hast du das Display nicht
initialisiert. Wie soll das ein ACK zu Stande kommen?
pegel schrieb:> In der main.c passiert ja gar nichts.> Selbst in den auskommentierten Versuchen hast du das Display nicht> initialisiert. Wie soll das ein ACK zu Stande kommen?
Ich versuche ja erstmal nur irgendwas auf den Bus zu senden. Oder geht
das so nicht?
Brauch ich immer ein Empfänger? Das mit dem Display soll dann später
gemacht werden. Aber da das nicht funktioniert hatte, habe ich jetzt
alles komplett abgespeckt und nur Pullup dran und fertig.
Ich empfehle das I2C Protokoll zu studieren.
Und dann die Initialisierung des SSD1307.
Für den Anfang wäre vielleicht ein PCF8574 ein guter Kandidat um eine
Ein- und Ausgabe zu programmieren.
Hallo Kevin,
habe ich richtig verstanden, Du hast gar nichts am I2C angeschlossen ?
Das geht so nicht, da die Kommunikation nur funktioniert wenn der
Partner angeschlossen ist !
So ich hab das Display mal dran gehängt und nochmal meine U8g Lib
aufgespielt.
Jetzt bekom ich auf der SDA Leitung Zyklisch ein Signal (Siehe Anhang).
Auf der SDL Leitung passiert aber nix (durchgehend 3,3V).
Code:
1
voiddraw(void)
2
{
3
u8g_SetFont(&u8g,u8g_font_profont10);//set current font
4
u8g_DrawStr(&u8g,2,12,"Hello!");//write string - you set coordinates and string
Kevin X. schrieb:> Jetzt bekom ich auf der SDA Leitung Zyklisch ein Signal
Was soll das sein? Ein Signal?
Ich dachte an ein Profil von einem Abwassergraben.
Ist die u8g eigentlich deine einzige Option, oder würden es auch
einfache Funktionen tun?
Kevin X. schrieb:> I2C Port ist in CubeMX auf Standard und auf Pin PB6 und PB7 eingestellt.
Die .ioc in deiner letzten zip sieht aber anders aus.
PB8 -> I2C1_CLK
PB9 -> I2C2_DAT
Ausserdem kann der SSD1306 auch mit 400kHz umgehen.
pegel schrieb:> Kevin X. schrieb:>> I2C Port ist in CubeMX auf Standard und auf Pin PB6 und PB7 eingestellt.>> Die .ioc in deiner letzten zip sieht aber anders aus.>> PB8 -> I2C1_CLK> PB9 -> I2C2_DAT>> Ausserdem kann der SSD1306 auch mit 400kHz umgehen.
Ja ich hab das mal auf diese Ports geändert, da ich dachte, vielleicht
ist ein Port kaputt.
Probiere halt alles mögliche aus. Bin schon die ganze Woche an diesem
I2C dran....
Ich weiß, dass dieses Signal kein I2C Signal ist, aber das kommt nunmal
raus. Schön alle 2Sekunden, wie mein Delay ist.
Es geht auch ohne Lib, aber da tut sich dann gar nichts. Also wenn ich
mit den normalen I2C Funktionen was senden möchte...
Bei 100kHz I2C-Frequenz solltest Du die Zeitbasis Deines Oszilloskops
nochmals überdenken :-)
Kevin X. schrieb:> So ich hab das Display mal dran gehängt und nochmal meine U8g Lib> aufgespielt.> Jetzt bekom ich auf der SDA Leitung Zyklisch ein Signal (Siehe Anhang).> Auf der SDL Leitung passiert aber nix (durchgehend 3,3V).>
folgendes ist mir noch aufgefallen:
in der u8g_arm.c benutzt Du I2C_Handler, in der main.c hi2c1. Das passt
schin mal nicht zusammen.
In die Funktion u8g_com_hw_i2c_fn würde ich folgendes schreiben:
case U8G_COM_MSG_WRITE_BYTE:
{
hal_status = HAL_I2C_Mem_Write(&hSSD1306_I2C, SSD1306_I2C_ADDRESS,
control, 1, &arg_val, 1, SSD1306_I2C_TIMEOUT);
}
break;
case U8G_COM_MSG_WRITE_SEQ:
case U8G_COM_MSG_WRITE_SEQ_P:
{
hal_status = HAL_I2C_Mem_Write(&hSSD1306_I2C, SSD1306_I2C_ADDRESS,
control, 1, arg_ptr, arg_val, SSD1306_I2C_TIMEOUT);
}
break;
Funktioniert bei mir wunderbar. Sorry für die Formatierung :-)
Kevin X. schrieb:> Ich hoffe es kann mir jemand weiterhelfen. Ich bin mit meinem Latein am> Ende.
Habe irgendwo gelesen, dass man im vom CubeMX generierten Code in der
Funktion "HAL_I2C_MspInit" die I2C Clock mit __HAL_RCC_I2C1_CLK_ENABLE()
bereits aktivieren soll, bevor das HAL_GPIO_Init aufgerufen wird.
Kevin X. schrieb:> Ich bin mit meinem Latein am Ende.
gallia est omnis divisa in partes tres...
Und warum versuchst du es dann nicht mal ganz simpel per Software? Ich
nehme ja mal an, daß du an deinem I2C nur ein Gerät, nämlich das Display
dran hast. Also könntest du ja (!!!) zu allererst mal versuchen, die
beiden Portbeine Clk und Data als O.C. GPIO zu schalten und in aller
Ruhe auszuprobieren, ob du da per Kommando auch wirklich hi und lo sehen
kannst. Anschließend schreibst du dir ne Mini-Routine um ein Byte
auszugeben und Ack zu empfangen. Dann noch eine Mini-Routine, mit der du
alle I2C-Adressen abklapperst und guckst, ob und wo du ein Ack bekommst.
Das alles ist ja nun wirklich nicht schwer - und es hilft dir ungemein,
erstmal herauszubekommen, ob deine Leitungen zum Display richtig
verschaltet sind, ob deine I2C-Pins sich rühren, ob dein Display auf den
erwarteten Adressen auch wirklich sich zeigt - und wenn du schon soweit
gekommen bist, dann kannst du auf dieser Soft-Basis auch deine gesamte
Display-Ausgabe in die Gänge kriegen. Den I2C-Peripheriecore dann
anzuwerfen und dir auf dessen Basis einen passenden Display zu
schreiben, kannst du dann anschließend erledigen, sobald du wenigstens
die allerersten Steine aus dem Weg geräumt hast.
Nochwas: in vielen Fällen ist eine reine Softwarelösung gerade beim I2C
völlig ausreichend - und es ist mit weitem Abstand die simpelste Lösung,
die schlichtweg überall funktioniert. Das klingt erstmal verwunderlich,
stimmt aber. Grund ist im Prinzip, daß man ja beim I2C ja sowieso fast
immer auf das Ende aller einzelnen Übertragungen und das Ack warten muß.
Das ist ganz anders als z.B. beim UART, wo man sehr schön gepuffert und
per Interrupt arbeiten kann.
W.S.
Also ich habe jetzt heute früh den Nucleo an der gleichen Schaltung
gestartet sowie das Oszi eingeschaltet. Und siehe da es kommt mehr als
am Freitag, obwohl ich nichts an der Programmierung oder Hardware
gemacht habe.
Anbei hierzu die Screenshots.
Wie man aber sieht, sind es keine sauberen Rechtecksignale.
Ich werde nun noch die in den letzten Beiträgen stehenden Tipps mal
ausprobieren.
so endlich habe ich was auf dem Display. Warum weiß ich aber noch nicht
so richtig.
Ich habe einmal den Tipp von Klaus umgesetzt und in die u8g_arm.c lib
den Befehl
reingeschrieben.
Außerdem die Device_ADDRESS um 1 verringert.
Außerdem bin ich dem Hinweis von Johnny mal nachgegangen und habe in der
stm32f1xx_hal_msp.c die HAL_I2C_MSPInit angepasst:
1
voidHAL_I2C_MspInit(I2C_HandleTypeDef*hi2c)
2
{
3
4
GPIO_InitTypeDefGPIO_InitStruct;
5
if(hi2c->Instance==I2C1)
6
{
7
/* USER CODE BEGIN I2C1_MspInit 0 */
8
9
/* USER CODE END I2C1_MspInit 0 */
10
11
/**I2C1 GPIO Configuration
12
PB6 ------> I2C1_SCL
13
PB7 ------> I2C1_SDA
14
*/
15
GPIO_InitStruct.Pin=GPIO_PIN_6|GPIO_PIN_7;
16
GPIO_InitStruct.Mode=GPIO_MODE_AF_OD;
17
GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;
18
19
__HAL_RCC_I2C1_CLK_ENABLE();
20
HAL_GPIO_Init(GPIOB,&GPIO_InitStruct);
21
22
/* Peripheral clock enable */
23
// __HAL_RCC_I2C1_CLK_ENABLE(); //Diesen Befehl vor HAL_GPIO_Init
24
/* USER CODE BEGIN I2C1_MspInit 1 */
25
26
/* USER CODE END I2C1_MspInit 1 */
27
}
28
29
}
Jetzt muss ich das Display noch invertieren, da alles spiegelverkehrt
dargestellt ist.
Dann werde ich weiter experimentieren.
Ich hoffe, dass es der Fehler war :-)
Ach ja. Das I2C Signal ist jetzt auch sauber Rechteckig wie es sein
sollte.
Du kannst doch da nicht einfach nacheinander irgentwas "ausprobieren"...
Schnapp Dir das Datenblatt vom Controller und sieh Dir an, wie die
Hardware im µC verwendet. Wie willst Du jemals einen Fehler finden, wenn
mal etwas nicht funtkioniert?!?
Ich finde diese Herangehensweise abenteuerlich, nur mal so.
Hello, Kevin XY
You must shift left for 1 bit the address of your I2C device (no matter
you write or read) because the value is only on 7 bits expressed (or 0 -
127).
Left shifting makes room for the last bit wich is R/W bit.
If you study the file stm32fxxx_hal_i2c (.c and .h) of your uC you will
see that addressing mode is on 7 bits or 10 bits (ex. #define
I2C_ADDRESSINGMODE_7BIT or #define I2C_ADDRESSINGMODE_10BIT) and nowhere
the value of this address is shifted one bit left to treat R/W bit.
I discover it on the hard way.
Best regards