Forum: Mikrocontroller und Digitale Elektronik OpenSTM32 Import von Source und Header files


von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hallo Freunde :-)

Ich bin ein Anfänger mit STM32. Ich benutze CubeMX und OpenSTM32 AC6 zum 
Programmieren. Mein erstes Projekt ist ein OLED-Display (ssd1306) auf 
dem Nucleon F411RE-Board. Ich möchte die Header und Source Files für das 
Oled Display in OpenSTM32 importieren. Kann aber keine Import-Funktion 
finden. Kann mir jemand sagen wie das geht.

Danke für die Hilfe. Rolf

PS: LD2 blinkt schon ;)

von Stefan F. (Gast)


Lesenswert?

Du musst die *.h und *.c Dateien einfach ins src Verzeichnis legen.

Wenn du magst, kannst du die *.h Dateien ins inc Verzeichnis legen. Ich 
mache das aber nicht so. Bei mir sind alle Quelltexte (außer HAL und 
CMSIS) im src Verzeichnis.

Welche konkrete Bibliothek willst du denn verwenden?

von Rolf D. (rolfdegen)


Lesenswert?

Reicht es aus, wenn ich die Files mit dem Dateimanager in das 
entsprechende Verzeichnis kopiere ? Oder muss ich das in OpenSTM32 
machen ?

von Stefan F. (Gast)


Lesenswert?

Rolf D. schrieb:
> Reicht es aus, wenn ich die Files mit dem Dateimanager in das
> entsprechende Verzeichnis kopiere ?

Ja sicher. Falls die IDE die neuen Files nicht direkt anzeigt, markiere 
den Ordner (in der IDE) und drücke F5.

von Rolf D. (rolfdegen)


Lesenswert?

Hab noch Probleme mit der typdef struct

// Enumeration for screen colors
typedef enum {
    Black =  0x00, // Black color, no pixel
    White =  0x01,  // Pixel is set. Color depends on OLED
} SSD1306_COLOR;

Error in der main.c: void ssd1306_Fill(Black);

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Rolf D. schrieb:
> Hab noch Probleme mit der typdef struct

Welche Probleme? Zitiere bitte die ganze Fehlermeldung.

von Rolf D. (rolfdegen)


Lesenswert?

Der Compiler zeigt error in der main.c "conflicting typs in 
ssd1306_Fill(Black)"

von Stefan F. (Gast)


Lesenswert?

Dann ist das Black wohl nicht eindeutig.

Hier ist ein Lösungsansatz in C++: 
https://stackoverflow.com/questions/34319637/how-solve-compiler-enum-redeclaration-conflict

In C würde ich die enums einfach durch #define ersetzen, weil mir dazu 
keine elegantere Lösung einfällt.

von Rolf D. (rolfdegen)


Lesenswert?

Danke für den Tip. Werde ich wohl so machen, da ich in C programmiere.

von Christopher J. (christopher_j23)


Lesenswert?

Rolf D. schrieb:
> Der Compiler zeigt error in der main.c "conflicting typs in
> ssd1306_Fill(Black)"

Ich tippe mal du hast eine Funktion wie
void ssd1306_Fill(unsigned somecolor)
Wenn du jetzt dieser Funktion ein enum übergibst welches du per typedef 
zu einem Typ propagierst, dann meckert der Compiler zu recht, das die 
Typen nicht passen.

Du hast zwei Möglichkeiten:
Entweder du schreibst deine Funktion um, so dass sie den Typ 
"SSD1306_COLOR" akzeptiert, d.h. die Signatur wäre
void ssd1306_Fill(SSD1306_COLOR somecolor)
oder du führst einen Typecast durch wenn du die Funktion aufrufst, in 
etwa
ssd1306_Fill((SSD1306_COLOR)Black)

von Rolf D. (rolfdegen)


Lesenswert?

Hab die Funktionen erst mal für eine normale int Var umgeschrieben. 
Jetzt meckert der Compiler aber bei einer Funktionen fürs Display, als 
ob das Header File nicht vorhanden wäre.

"Description  Resource  Path  Location  Type
undefined reference to `ssd1306_WriteCommand'  ssd1306.c  /Oled/Src 
line 70  C/C++ Problem"´


// Send a byte to the command register
void ssd1306_WriteCommand(uint8_t byte) {
  HAL_I2C_Mem_Write(&SSD1306_I2C_PORT, SSD1306_I2C_ADDR, 0x00, 1, &byte, 
1, HAL_MAX_DELAY);
}

: Bearbeitet durch User
von holger (Gast)


Lesenswert?

>Jetzt meckert der Compiler aber bei einer Funktionen fürs Display, als
>ob das Header File nicht vorhanden wäre.
>
>"Description  Resource  Path  Location  Type
>undefined reference to `ssd1306_WriteCommand'  ssd1306.c  /Oled/Src

undefined reference bekommt man immer wenn die Funktion vom Linker
nicht gefunden wurde. Ist ssd1306_WriteCommand wirklich der 
Funktionsname?
Buchstabe für Buchstabe richtig?

Steht im Header ein Prototyp für
void ssd1306_WriteCommand(uint8_t byte);
?

Stimmt uint8_t für den Parameter?
byte als Parametername würde ich sofort ändern.

von Rolf D. (rolfdegen)


Lesenswert?


von holger (Gast)


Lesenswert?

Da fehlt ein

-DSSD1306_USE_I2C

in den Compiler Optionen.

von Rolfdegen@hotmail.com (Gast)


Lesenswert?

Ok. Danke. Werde es heute Abend mal ausprobieren.

von Rolf D. (rolfdegen)


Lesenswert?

Wo und wie genau trage ich das ein ?

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hab jetzt mal einen Test mit dem Anlegen eines neuen Header Files 
gemacht. Das merkwürdiger dabei ist, dass beim Anlegen eines neuen 
h.Files in AC6 das vorhandene Inc Verzeichnis nicht angezeigt wird und 
man keine Möglichkeit hat, ein neues Header File in diesem Verzeichnis 
anzulegen. Stattdessen habe ich das Source Verzeichnis benutzt und 
danach das Header File manuell in das Inc Verzeichnis verschoben.

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Ich habe jetzt nicht alles gelesen, aber hast Du AC6 mal seinen Index 
erstellen lassen?


Index Rebuild

von Stefan F. (Gast)


Lesenswert?

Rolf D. schrieb:
> Das merkwürdiger dabei ist, dass beim Anlegen eines neuen
> h.Files in AC6 das vorhandene Inc Verzeichnis nicht angezeigt wird und
> man keine Möglichkeit hat, ein neues Header File in diesem Verzeichnis
> anzulegen.

Die gehören da auch nicht hin.

In ein include Verzeichnis gehören die Header von Libraries, die im 
Binärformat (ohne Quelltext) vorliegen. Das ist im µC Umfeld aber eine 
sehr seltene Ausnahme.

Pärchen aus C-Quelltext und C-Header gehören ins src Verzeichnis, wenn 
sie nicht Bestandteil einer umfangreicheren Bibliothek sind, die 
außerhalb des Projektes liegt.

von Rolf D. (rolfdegen)


Lesenswert?

- index Rebuild: Kein Erfolg
- Header nach Source verschoben: Kein Erfolg
- clean und neu debug: Kein Erfolg

Fehler "undefined reference.. " in der main

von Johannes S. (Gast)


Lesenswert?

Rolf D. schrieb:

> Fehler "undefined reference.. " in der main

Das ist doch ein Linkerfehler.

von Rolf D. (rolfdegen)


Lesenswert?

ja. Ich vermute dass es daran liegt, wie ich die h-files anlege. Da es 
keine Import-Funktion für Source- u. Header-Files gibt, habe ich leere 
c-Files u. h-Files über die Menü-Funktion in AC6 erzeugt und den Code 
für das Oled einfach hinein kopiert.

von Johannes S. (Gast)


Lesenswert?

Kann man einfacher über Drag and drop machen.
Ist im main.c auch das nötige include drin? Bekommst du vorher beim 
kompilieren schon eine implicit declaration angemeckert?

von holger (Gast)


Lesenswert?

>Ich vermute dass es daran liegt, wie ich die h-files anlege.

Nein. Mein Post von 14:46 sagt was fehlt. Also tauch in die Untiefen 
deiner
IDE und suche nach der Stelle wo man ein define für den Compiler 
hinzufügen kann.

Da gibst du dann ein SSD1306_USE_I2C ein.

Die folgende Fehlermeldung ignorierst du einfach und bastelst da an den 
völlig falschen Stellen rum:

#error "You should define SSD1306_USE_SPI or SSD1306_USE_I2C macro!"

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hab das hier probiert (Bild)... Aber keinen Erfolg !?

von Stefan F. (Gast)


Lesenswert?

Das Command-Line Pattern sollte normalerweise so aussehen:
> ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Definitionen setzt bei Preprocessor unter "Defined Symbols (-D)"

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hab ich auch schon probiert !? Ergebnis: Fehlermeldungen (siehe Bild)

von pegel (Gast)


Lesenswert?

Da nicht.
Geh mal 2 tiefer, auf Preprocessor.

Da sind schon welche. Kannst deins ohne -D einfach hinzufügen.

von Stefan F. (Gast)


Lesenswert?

Rolf D. schrieb:
> Hab ich auch schon probiert !?

Du hast dein Command-Line Pattern versaut. Ich habe Dir oben den 
richtigen String zitiert.

von pegel (Gast)


Lesenswert?

"Restore Defaults" könnte das noch retten.

von Rolf D. (rolfdegen)


Lesenswert?

Ok. Hab das Command-Line Pattern wieder hergestellt und den Eintrag 
"SSD1306_USE_I2C" im Preprocessor gemacht. Jetzt gibt es keine 
Fehlermeldungen mehr. Da soll ein "STM32 Beginner" drauf kommen ;) Aber 
man lernt ja nie aus.

Vielen dank für die tolle Unterstützung :)

Gruß Rolf aus Wuppertal

von Rolf Degen (Gast)


Lesenswert?

Hallöchen..

Ein kleines Problem gibt es noch. Nachdem ich das Projekt über Run 
gestartet habe tut sich auf dem ic2 Bus leider nichts. Pullups (1K) sind 
vorhanden. Oled ist richtig angeschlossen. Auf dem Scop ist wärend der 
Initialisierung und im Betrieb  auf SDA und SCL kein Signal zu sehen.

von pegel (Gast)


Lesenswert?

Dann musst Du wohl vergleichen, ob die Bezeichnung der Pins in der 
SSD1306 die Gleiche wie in allen für I2C zuständigen Quellen passt.

I2C starten nicht vergessen.

von Rolfdegen@hotmail.com (Gast)


Lesenswert?

Was meinst du mit i2c starten. In der Main wird i2c init  aufgerufen

von Bernd K. (prof7bit)


Lesenswert?

Rolf D. schrieb:
> Da soll ein "STM32 Beginner" drauf kommen

Das hat nichts mir "STM32-Beginner"³ zu tun sondern mit "Eclipse CDT 
Beginner"² und vielleicht sogar mit "C-Beginner"¹.

__
¹,²,³) Es baut halt eines auf dem anderen auf, und zwar in der 
Reihenfolge der Fußnotennumerierung. Jetzt kämpfst Du halt an 3 
Baustellen gleichzeitig.

von pegel (Gast)


Lesenswert?

Ich fürchte mit Stichworten ist jetzt nichts mehr zu machen.
Jetzt muss man die Quellen Schritt für Schritt durchgehen.

Zur Not solltest Du das erst einmal mit einem funktionierenden I2C 
Beispiel vergleichen.

Ist vermutlich nur ein kleiner Fehler wie Clock Enable, Pin Namen ....

von Rolfdegen@hotmail.com (Gast)


Lesenswert?

Ok. Vielen Dank für die Tips. Ich versuchs heute Abend noch einmal. Nie 
aufgeben ist meine Devise ?

von Stefan F. (Gast)


Lesenswert?

Rolf D. schrieb:
> Da soll ein "STM32 Beginner" drauf kommen ;) Aber
> man lernt ja nie aus.

Das sind Grundlagen der Programmiersprache. Deswegen empfehle ich immer, 
die Sprache und die Entwicklungstools erstmal auf einem PC ohne 
Mikrocontroller kennen zu lernen.

Selbst dieser Einstellungsdialog ist nicht für die IDE spezifisch. Jede 
andere IDE hat einen ganz ähnlichen Dialog, weil er letztendlich dazu 
dient, die Kommandozeilenparameter für den gcc zusammen zu basteln.

von Rolf D. (rolfdegen)


Lesenswert?

Hallo Stefanus..

Kleine Info über mich. Ich komme aus der Atmel Ecke und habe jahrelang 
mit Atmel Studio in C im Bereich der Musikelektronik gearbeitet. Mein 
größtes Projekte war der Degenerator. (Link: 
http://cczwei-forum.de/cc2/thread.php?threadid=5878&threadview=0&hilight=&hilightuser=0&page=34). 
So fremd ist mir das Ganze also nicht. Ich will erst einmal die 
Entwicklungsumgebung und die ARM Prozessoren kennen lernen und mit 
kleinen Projekten beginnen.

Gruß Rolf

von Rolf D. (rolfdegen)


Lesenswert?

Ich komme nicht weiter. Auf dem i2c Bus rührt sich immer noch nix. 
SCL(D15) und SDA(D14) sind auf dem Nucleo-Board mit Pullups von 1.2K auf 
+3.3V angeschlossen. Slave Adresse vom Display (0x78) ist defeniert.
Um Fehler auszuschließen, nutze ich die SSD1306 Lib vorerst nicht.

Hab noch einmal ein neues Projekt mit IC2 in CubeMX generiert. Fürs 
senden von Daten benutze ich den HAL_I2C_Master_Transmit.
1
/* USER CODE BEGIN Header */
2
/**
3
  ******************************************************************************
4
  * @file           : main.c
5
  * @brief          : Main program body
6
  ******************************************************************************
7
  * @attention
8
  *
9
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
10
  * All rights reserved.</center></h2>
11
  *
12
  * This software component is licensed by ST under BSD 3-Clause license,
13
  * the "License"; You may not use this file except in compliance with the
14
  * License. You may obtain a copy of the License at:
15
  *                        opensource.org/licenses/BSD-3-Clause
16
  *
17
  ******************************************************************************
18
  */
19
/* USER CODE END Header */
20
21
/* Includes ------------------------------------------------------------------*/
22
#include "main.h"
23
#include "i2c.h"
24
#include "usart.h"
25
#include "gpio.h"
26
27
/* Private includes ----------------------------------------------------------*/
28
/* USER CODE BEGIN Includes */
29
#include "string.h"
30
31
/* USER CODE END Includes */
32
33
/* Private typedef -----------------------------------------------------------*/
34
/* USER CODE BEGIN PTD */
35
36
//I2C_HandleTypeDef hi2c1;
37
38
/* USER CODE END PTD */
39
40
/* Private define ------------------------------------------------------------*/
41
/* USER CODE BEGIN PD */
42
#define SLAVE_ADD_7BIT 0x78
43
#define SLAVE_ADD_8BIT 0x78 << 1
44
45
/* USER CODE END PD */
46
47
/* Private macro -------------------------------------------------------------*/
48
/* USER CODE BEGIN PM */
49
50
51
/* USER CODE END PM */
52
53
/* Private variables ---------------------------------------------------------*/
54
55
/* USER CODE BEGIN PV */
56
57
/* USER CODE END PV */
58
59
/* Private function prototypes -----------------------------------------------*/
60
void SystemClock_Config(void);
61
/* USER CODE BEGIN PFP */
62
63
/* USER CODE END PFP */
64
65
/* Private user code ---------------------------------------------------------*/
66
/* USER CODE BEGIN 0 */
67
68
/* USER CODE END 0 */
69
70
/**
71
  * @brief  The application entry point.
72
  * @retval int
73
  */
74
int main(void)
75
{
76
  /* USER CODE BEGIN 1 */
77
78
  /* USER CODE END 1 */
79
  
80
81
  /* MCU Configuration--------------------------------------------------------*/
82
83
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
84
  HAL_Init();
85
86
  /* USER CODE BEGIN Init */
87
88
  /* USER CODE END Init */
89
90
  /* Configure the system clock */
91
92
  SystemClock_Config();
93
94
95
  /* USER CODE BEGIN SysInit */
96
97
  /* USER CODE END SysInit */
98
99
  /* Initialize all configured peripherals */
100
101
  MX_GPIO_Init();
102
  MX_I2C1_Init();
103
  MX_USART2_UART_Init();
104
105
  /* USER CODE BEGIN 2 */
106
107
  /* USER CODE END 2 */
108
109
  /* Infinite loop */
110
  /* USER CODE BEGIN WHILE */
111
  while (1)
112
  {
113
    /* USER CODE END WHILE */
114
115
    /* USER CODE BEGIN 3 */
116
117
    HAL_Delay(150);
118
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
119
120
    char buffer[16];
121
    strcpy((char*) buffer,  (const char*) "Test 1");
122
    
123
    HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADD_8BIT, (uint8_t *) buffer,  7, 1000);
124
   
125
    HAL_Delay(150);
126
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
127
  }
128
  /* USER CODE END 3 */
129
}
130
131
/**
132
  * @brief System Clock Configuration
133
  * @retval None
134
  */
135
void SystemClock_Config(void)
136
{
137
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
138
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
139
140
  /** Initializes the CPU, AHB and APB busses clocks 
141
  */
142
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
143
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
144
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
145
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
146
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
147
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
148
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
149
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
150
  {
151
    Error_Handler();
152
  }
153
  /** Initializes the CPU, AHB and APB busses clocks 
154
  */
155
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
156
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
157
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
158
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
159
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
160
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
161
162
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
163
  {
164
    Error_Handler();
165
  }
166
}
167
168
/* USER CODE BEGIN 4 */
169
170
/* USER CODE END 4 */
171
172
/**
173
  * @brief  This function is executed in case of error occurrence.
174
  * @retval None
175
  */
176
void Error_Handler(void)
177
{
178
  /* USER CODE BEGIN Error_Handler_Debug */
179
  /* User can add his own implementation to report the HAL error return state */
180
181
  /* USER CODE END Error_Handler_Debug */
182
}
183
184
#ifdef  USE_FULL_ASSERT
185
/**
186
  * @brief  Reports the name of the source file and the source line number
187
  *         where the assert_param error has occurred.
188
  * @param  file: pointer to the source file name
189
  * @param  line: assert_param error line source number
190
  * @retval None
191
  */
192
void assert_failed(uint8_t *file, uint32_t line)
193
{ 
194
  /* USER CODE BEGIN 6 */
195
  /* User can add his own implementation to report the file name and line number,
196
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
197
  /* USER CODE END 6 */
198
}
199
#endif /* USE_FULL_ASSERT */
200
201
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

: Bearbeitet durch User
von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Ich komme nicht weiter. Auf dem i2c Bus rührt sich immer noch nix.

Wie äussert sich das?

Wenn du keinen I2C Slave der passenden Adresse angeschlossen
hast ist nach dem ersten Byte das der Master sendet Funkstille.
Ganz normal, denn der Master wartet nach der Adresse auf ein
Ack vom Slave.

Poste mal dein ganzes Projekt, ich versuche es dann mal auf
einem Discovery-Board von mir anzuschauen.

von STM Unterstützer (Gast)


Lesenswert?

STM Unterstützer schrieb:
> Poste mal dein ganzes Projekt

Bitte auch das *.ioc File dazupacken.

von Rolf D. (rolfdegen)


Lesenswert?

Mmm.. Das OLED hat die Adresse 0x78 ! und ist angeschlossen. Auf dem 
Scope ist kein Signal zu erkennen. Auch wären der Initialisierung kein 
Signal. Alles bleibt auf High.

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hier mein Projekt..

von leo (Gast)


Lesenswert?

Rolf D. schrieb:
> #define SLAVE_ADD_7BIT 0x78
> #define SLAVE_ADD_8BIT 0x78 << 1

Ich schaetze mal, hier ist wieder der beliebte i2c-Adresse-Fehler.
Ich hab fuer mein Adafruit SSD1306 128x64 die Adresse 0x3C, also die 
Haelfte.

leo

von Rolf D. (rolfdegen)


Lesenswert?

Adresse 0x3C kann nicht sein. In meinem Atmel Projekt funktioniert das 
Display mit Adresse 0x78. Aber ich teste es mal..

von Harry L. (mysth)


Lesenswert?

Die HAL-Funktionen erwarten die Adresse in den oberen 7 Bit.
Ist also richtig so.

Allerdings gibts auch Displays die auf 0x7a hören.
Das kann man an den meisten Displays "umjumpern".

von Rolf D. (rolfdegen)


Lesenswert?

Nö.. kein Erfolg. Hätte mich auch gewundert ;)

von STM Unterstützer (Gast)


Lesenswert?

leo schrieb:
> Ich schaetze mal, hier ist wieder der beliebte i2c-Adresse-Fehler.

Ja, die OLED-Adresse 0x78 ist bereits die geshiftete Version.

von Bernd K. (prof7bit)


Lesenswert?

Harry L. schrieb:
> Die HAL-Funktionen erwarten die Adresse in den oberen 7 Bit.
> Ist also richtig so.

Aber er schiftet die 0x78 noch ein weiteres mal bevor ers ans HAL 
übergibt!

: Bearbeitet durch User
von Rolf D. (rolfdegen)


Lesenswert?

Hab die Adresse jetzt mal direkt benutzt. Aber ohne Erfolg.
1
HAL_I2C_Master_Transmit(&hi2c1, 0x78, (uint8_t *) buffer,  7, 1000);

von Rolf D. (rolfdegen)


Lesenswert?

Aber auf den IC2 Leitungen müsste sich doch prinzipiell was tun. Auch 
wenn die Adresse nicht stimmt !?

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Hab die Adresse jetzt mal direkt benutzt. Aber ohne Erfolg.

Nochmal meine Frage:

STM Unterstützer schrieb:
> Wie äussert sich das?

Und versuche das mal genau zu beschreiben.

Ein einzelnes Byte auf dem Bus mag für "den Anfänger"
schwierig zu detektieren sein.

von Bernd K. (prof7bit)


Lesenswert?

Wenn ich vor dem Problem stehe daß ich aus der Doku einer 
Hersteller-Library (z.B. HAL) nicht schlau werde und auch nicht die 
Nerven habe die Doku des eigentlichen Controllers Bit für Bit wieder 
rückwärts nach HAL zu übersetzen  (ein nervenaufreibender Vorgang) dann 
versuch ich als nächstes einfach mal einen *funktionierenden 
Beispielcode* irgendwo aufzutreiben der die fragliche Peripherie in 
Betrieb nimmt und den dann zu verstehen und nachzuvollziehen.

von Rolf D. (rolfdegen)


Lesenswert?

Hab ein Digital Scope mit guten Trigger Eigenschaften ;)

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Aber auf den IC2 Leitungen müsste sich doch prinzipiell was tun. Auch
> wenn die Adresse nicht stimmt !?

STM Unterstützer schrieb:
> Wenn du keinen I2C Slave der passenden Adresse angeschlossen
> hast ist nach dem ersten Byte das der Master sendet Funkstille.

Heisst also dass du pro HAL_I2C_Master_Transmit-Versuch genau
ein Byte sehen könntest, aber auch nicht mehr.

von Bernd K. (prof7bit)


Lesenswert?

Sind an den entsprechenden Pins schon die richtigen Alternate-Funktionen 
konfiguriert? Ist irgendwie schwer zu erkennen in dem ganzen 
HAL-Gestrüpp wo das passiert sein soll.

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> auf dem Nucleon F411RE-Board.

Du hast in deinem *.ioc File das falsche Board bzw den falschen
Controller (nämlich STM32F103RBTx) gewählt.

von Rolf D. (rolfdegen)


Lesenswert?

Macht doch CubeMX automatisch oder ?

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Macht doch CubeMX automatisch oder ?

Nein, alles Denken nimmt es einen nicht ab.

von Rolf D. (rolfdegen)


Lesenswert?

Hab aber in CubeMX Nucleo-F103RB ausgewählt

von Christopher J. (christopher_j23)


Lesenswert?

Rolf D. schrieb:
> Hab aber in CubeMX Nucleo-F103RB ausgewählt

Du hast aber geschrieben du hättest ein Nucleo-F411RE

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Hab aber in CubeMX Nucleo-F103RB ausgewählt

Rolf D. schrieb:
> dem Nucleon F411RE-Board.

Willst du mich jetzt verarschen?

von Rolf D. (rolfdegen)


Lesenswert?

Das habe ich auch. Zur Zeit benutze ich aber das Nucleo-F103RB

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Macht doch CubeMX automatisch oder ?

Rolf D. schrieb:
> Hab aber in CubeMX Nucleo-F103RB ausgewählt

Noch so eine Verarschung.

Entweder automatisch oder ausgewählt .....

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Das habe ich auch. Zur Zeit benutze ich aber das Nucleo-F103RB

Und das sollen wir riechen?

Das ist das erste Mal dass du davon berichtest.

von STM Unterstützer (Gast)


Lesenswert?

Bei solcher Verarschung bin ich dann mal weg.

von Rolf D. (rolfdegen)


Lesenswert?

????

Um es noch einmal klar zu stellen. Ich benutze das Nucleo-F103RB.

von STM Unterstützer (Gast)


Lesenswert?

Rolf D. schrieb:
> Um es noch einmal klar zu stellen.

Um es einmal klar zu stellen:

Eine Spur von Bedauern deinerseits könnte nicht schaden.

Aber scheinbar hast du nichts falsch gemacht, nur wir haben
nicht pingelig genug deine Salami-Scheiben abgefragt. Der
Fehler liegt also nur bei uns ....

von Rolf D. (rolfdegen)


Lesenswert?

Hab m

Rolf D. schrieb:
> Macht doch CubeMX automatisch oder ?

Ich hab mich da wohl etwas falsch ausgedrückt. Ich bitte um 
Entschuldigung.

Was ich mit automatisch meine, ist das die Codegenerierung für die 
benutzen Chip-Funktionen die in CubeMX automatisch erstellt werden.

von Bernd K. (prof7bit)


Lesenswert?

Rolf D. schrieb:
> Was ich mit automatisch meine, ist das die Codegenerierung für die
> benutzen Chip-Funktionen die in CubeMX automatisch erstellt werden.

Und Du benutzt PB6 und PB7, ist das zutreffend?

: Bearbeitet durch User
von Rolf D. (rolfdegen)


Lesenswert?

Hier ist das von CubeMX erzeugte I2C.c
1
 * File Name          : I2C.c
2
  * Description        : This file provides code for the configuration
3
  *                      of the I2C instances.
4
  ******************************************************************************
5
  * @attention
6
  *
7
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
8
  * All rights reserved.</center></h2>
9
  *
10
  * This software component is licensed by ST under BSD 3-Clause license,
11
  * the "License"; You may not use this file except in compliance with the
12
  * License. You may obtain a copy of the License at:
13
  *                        opensource.org/licenses/BSD-3-Clause
14
  *
15
  ******************************************************************************
16
  */
17
18
/* Includes ------------------------------------------------------------------*/
19
#include "i2c.h"
20
21
/* USER CODE BEGIN 0 */
22
23
/* USER CODE END 0 */
24
25
I2C_HandleTypeDef hi2c1;
26
27
/* I2C1 init function */
28
void MX_I2C1_Init(void)
29
{
30
31
  hi2c1.Instance = I2C1;
32
  hi2c1.Init.ClockSpeed = 400000;
33
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
34
  hi2c1.Init.OwnAddress1 = 0;
35
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
36
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
37
  hi2c1.Init.OwnAddress2 = 0;
38
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
39
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
40
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
41
  {
42
    Error_Handler();
43
  }
44
45
}
46
47
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
48
{
49
50
  GPIO_InitTypeDef GPIO_InitStruct = {0};
51
  if(i2cHandle->Instance==I2C1)
52
  {
53
  /* USER CODE BEGIN I2C1_MspInit 0 */
54
55
  /* USER CODE END I2C1_MspInit 0 */
56
  
57
    __HAL_RCC_GPIOB_CLK_ENABLE();
58
    /**I2C1 GPIO Configuration    
59
    PB6     ------> I2C1_SCL
60
    PB7     ------> I2C1_SDA 
61
    */
62
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
63
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
64
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
65
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
66
67
    /* I2C1 clock enable */
68
   __HAL_RCC_I2C1_CLK_ENABLE();
69
  /* USER CODE BEGIN I2C1_MspInit 1 */
70
71
  /* USER CODE END I2C1_MspInit 1 */
72
  }
73
}
74
75
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
76
{
77
78
  if(i2cHandle->Instance==I2C1)
79
  {
80
  /* USER CODE BEGIN I2C1_MspDeInit 0 */
81
82
  /* USER CODE END I2C1_MspDeInit 0 */
83
    /* Peripheral clock disable */
84
    __HAL_RCC_I2C1_CLK_DISABLE();
85
  
86
    /**I2C1 GPIO Configuration    
87
    PB6     ------> I2C1_SCL
88
    PB7     ------> I2C1_SDA 
89
    */
90
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);
91
92
  /* USER CODE BEGIN I2C1_MspDeInit 1 */
93
94
  /* USER CODE END I2C1_MspDeInit 1 */
95
  }
96
} 
97
98
/* USER CODE BEGIN 1 */
99
100
/* USER CODE END 1 */
101
102
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?

Ich hab mir deinen Code mal angeschaut.

Was soll sowas?
1
    char buffer[16];
2
    strcpy((char*) buffer,  (const char*) "Test 1");
3
4
    HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADD_8BIT, (uint8_t *) buffer,  7, 1000);

Erwartest du, daß du deinem Display Klartext schicken kannst?
Du kannst erstmal nur Pixel setzen/löschen.

Das ist auch völliger Unfug:
1
/* Private define ------------------------------------------------------------*/
2
/* USER CODE BEGIN PD */
3
#define SLAVE_ADD_7BIT 0x78
4
#define SLAVE_ADD_8BIT 0x78 << 1

0x78 ist bereits die 8bit-Version der Adresse.
Die 7bit-Adresse ist 0x3c

Wenn du unbedingt solche Defines bauen willst, dann bitte so:
1
/* USER CODE BEGIN PD */
2
#define SLAVE_ADD_7BIT 0x3c
3
#define SLAVE_ADD_8BIT (SLAVE_ADD_7BIT << 1)

von Bernd K. (prof7bit)


Lesenswert?

Und was hast Du getan um zu verifizieren daß sich an den Pins "nichts 
tut"?

Hast Du die Pullups angeschlossen? Hast Du ein Oszilloskop angeschlossen 
mit beiden Kanälen auf SCL und SDA und auf fallende Flanke getriggert?

Was hast Du gemessen? Bitte detailliert beschreiben oder Oszi-Screenshot 
beifügen!

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Ich habe den Fehler gefunden. Die automatische Zuweisung von Pin PB6 und 
PB7 für I2C1 ist in CubeMX nicht richtig. Es müssen PB8 und PB9 sein. 
Habe die Zuweisung in CubeMX manuell geändert und schon läufts 
problemlos.

@Bernd.K. Danke für deinen Hinweis.

Im Anhang aktuelle Hardware Konfiguration in CubeMx und Scope Signale

Vielen Dank an alle :)

von Stefan F. (Gast)



Lesenswert?

Vorab: Ich habe kaum Erfahrung mit Cube MX und HAL.

Ich habe dein Programm auf meinem Nucleo Board (nur mit Pull-Up 
Widerständen und Logic Analyzer) ausprobiert und kann bestätigen, dass 
sich an den I²C Pins nichts tut. Die Initialisierung der I²C 
Schnittstelle geht noch, aber die Kommunikation bricht mit einer 
Fehlermeldung ab, die ich im angehängten Screenshot sichtbar gemacht 
habe.

Es scheint sich um einen Kommunikationsfehler zu handeln.

> SCL(D15) und SDA(D14)

Das sind die Arduino Bezeichnungen. Die "richtigen" STM32 Port Nummern 
findest du auf der Papp-Karte, die in der Verpackung des Nucleo Boardes 
lag (und natürlich auch in der PDF Bedienungsanleitung).

Jedenfalls sind das aus Sicht des Mikrocontrollers die Pins PB8 und PB9, 
die als alternative Funktion "I2C1 remap" haben. In deinem *.ioc File 
sehe ich allerdings nichts für diese Pins.

Insofern bin ich ziemlich sicher, dass du die falschen Pins benutzt.

Ich denke, du solltest dein Display an die Pins PB6 und PB7 anschließen. 
Das würde mit dem *.ioc File überein stimmen:
1
PB6.Mode=I2C
2
PB6.Signal=I2C1_SCL
3
PB7.Mode=I2C
4
PB7.Signal=I2C1_SDA

Dein nächstes Problem ist, dass die Funktion HAL_I2C_Master_Transmit() 
fehlschlägt, weil im Register I2C1.SR2 das busy Flag High ist. Im 
Referenzhandbuch steht dazu "Set by hardware on detection of SDA or SCL 
low".

Jetzt habe ich mir mal die komplette Konfiguration in den Registern 
angesehen:

CR1 = 1
Peripheral enabled

CR2 = 100100
Peripheral Clock Frequency is 36 Mhz

OAR1 = 100000000000000
"Should always be kept at 1 by software."

OAR2 = 0
Ok

DR = 0
Ok

SR1 = 0
Keine Störung

SR2 = 10
Communication ongoing on the bus
Set by hardware on detection of SDA or SCL low, cleared by hardware on 
detection of a Stop condition.

CCR = 1000000000011110
Fast mode, die unteren Bits habe ich nicht geprüft

TRISE = 1011
habe ich nicht geprüft

Bis hierhin habe ich noch keinen Fehler erkannt, bis auf dieses Busy 
Flag. Deswegen habe ich zur Probe mal die folgenden Befehle direkt vor 
die while Schleife eingefügt:
1
  SET_BIT(I2C1->CR1,I2C_CR1_SWRST);
2
  CLEAR_BIT(I2C1->CR1,I2C_CR1_SWRST);
3
  MX_I2C1_Init();

Und siehe da: Es läuft (der angehängte Screenshot von PulseView beweist 
es).

Ich vermute, dass beim Initialisieren ein Timing-Problem besteht oder 
die Hardware in der falschen Reihenfolge initialisiert wird. Denn wenn 
ich die while Schleife mal leer mache, so dass nur die Peripherie 
initialisiert wird, sehe ich die beiden Pins flackern. Das sollte schon 
nicht der Fall sein. Siehe angehängter Screenshot. Ich denke, diese 
Pulse bringen den Bus zum Blockieren.

Dazu habe ich bei meinen eigenen bare-metal Programmierversuchen vor 
einigen Monaten Programmierversuchen etwas herausgefunden: Und zwar muss 
man zuerst den I²C initialisieren und erst dann die I/O Pins. Nur dann 
startet er sauber ohne falsche Impulse.

Wenn ich in deinem Code die beiden Zeilen tausche, klappt es aber 
trotzdem nicht:
1
  MX_I2C1_Init();
2
  MX_GPIO_Init();

Ich denke, dass der eigentliche Fehler (mal wieder) in der HAl steckt, 
und zwar in der Funktion HAL_I2C_Init(). Diese ruft nämlich zuerst
1
/* Init the low level hardware : GPIO, CLOCK, NVIC */
2
HAL_I2C_MspInit(hi2c);
auf, und initialisiert danach den I²C Controller. Das ist genau die 
falsche Reihenfolge - jedenfalls beim STM32F103. Beim STM32F303 wäre 
diese Reihenfolge Ok, nur mal so nebenbei bemerkt.

Damit habe ich dein Problem noch nicht gelöst, aber zumindest eine 
Richtung zur weiteren Analyse gegeben. Ich hoffe es bringt Dich weiter.

Nachtrag: Falls sich meine Antworten mit vorherigen überlappen, bitte 
ich um Entschuldigung. Ich habe eine ganze Weile gebraucht, um das 
Problem zu analysieren.

von Rolf D. (rolfdegen)


Lesenswert?

Hallo Stefanus. Vielen Dank für deine Hilfe. Du hattest natürlich recht. 
Mich hat CubeMX etwas in die Irre geführt.

Grüße aus Wuppertal. Rolf

von Stefan F. (Gast)


Lesenswert?

Du hast ja jetzt erfolgreich andere Pins verwendet als ich. Ich würde 
trotzdem nochmal prüfen, ob die Initialisierung (mit leerer 
while-Schleife) korrekt abläuft. Auf den beiden Pins dürfen dann keine 
Impulse sichtbar sein.

Falls doch, wirst du früher oder später wieder Probleme bekommen. Ich 
erinnere mich, dass dies hier öfters diskutiert wird. Irgendein 
Busteilnehmer blockiert bei Reset (oder Einschalten der Stromversorgung) 
sporadisch, dann sucht man sich einen Wolf.

Ich bin ziemlich sicher, dass die Initialisierungsreihenfolge der HAL 
hier fehlerhaft ist.

von Bernd K. (prof7bit)


Lesenswert?

Stefanus F. schrieb:
> Ich bin ziemlich sicher, dass die Initialisierungsreihenfolge der HAL
> hier fehlerhaft ist.

Cube und HAL hat doch in erster Linie die Maker als Zielgruppe, da sind 
so Feinheiten doch nicht weiter tragisch.

von Stefan F. (Gast)


Lesenswert?

Das war übrigens mein fünfter Kontakt zur HAL, vier davon sind wegen 
nachweislicher Bugs fehlgeschlagen, nur einer war erfolgreich.

von Rolf D. (rolfdegen)


Lesenswert?

Dummerweise sind bei meinem "noName" Oled-Display auch noch die 
Bezeichnungen SDA und SCL vertauscht. Das Clock-Signal liegt auf SDA und 
die Datenleitung auf SCL. Blöde Sache.. ;)

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Stefanus F. schrieb:
> HAL, vier davon sind wegen
> nachweislicher Bugs fehlgeschlagen

Du kannst die schon geshiftete I2C-Adresse auch dazuzaehlen. Das ist 
einfach ein Bloedsinn.

leo

von Rolf D. (rolfdegen)


Lesenswert?

Das sind die "einfachen" Code Beispiele aus dem Internet die nie richtig 
funktionieren. Aber man lernt halt draus. Das finde ich wichtig :)

Link: 
https://github.com/afiskon/stm32-ssd1306/tree/master/examples/i2c/stm32f1

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich wüsste auch gerne mal, warum die Platine mit den möchtegern Arduino 
kompatiblen Funktionen beschriftet ist, anstatt mit den "richtigen" 
Pinbezeichnungen des STM32.

Oder: Warum gibt es keinen USB Anschluss für das Target?

Für den niedrigen Preis sind das ja ganz nette Boards, aber ein paar 
kleine Details finde ich einfach nur gaga.

Ich würde vorschlagen, das nächste Problem in einem neuen Thread zu 
diskutieren. Von der ursprünglichen Frage sind wir ja inzwischen schon 
weit entfernt.

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hallöchen..

Spaßeshalber hab ich mal die I2C Datenübertragung vom Nucleo-F103RB Bord 
(Master) zum Oled-Display (Slave) mit dem Scope überprüft. Die 
Übertragungsgeschwindigkeit ist im Test auf den Standartmode (100KHz) 
eingestellt. Maximal sind im Fastmode aber 400KHz möglich.

Zur Info: Das SDA-Signal ist gelb und das SCL-Signal violett.

Im 1.Bild ist nach der Übermittlung der Slave-Adresse (7 Bit) und  dem 
ReadWrite-Bit (8.Bit) das Acknowledge-Bit (9.Bit) zu erkennen. Als 
Bestätigung für die richtige Adresse legt der Slave die Datenleitung auf 
low und signalisiert dem Master das er jetzt mit dem Senden eines 
Datenbyte beginnen kann.

Im 2.Bild übertrage ich eine andere Adresse an den Slave. Das 
Acknowledge-Bit bleibt high und der Master stoppt die Übertragung zum 
Slave.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Sieht gut aus. Ich denke, du kannst die Pull-Up Widerstände ruhig etwas 
hochohmiger machen.

von Rolf Degen (Gast)


Lesenswert?

Die sind auf 4.7K

von Stefan F. (Gast)


Lesenswert?

Rolf Degen schrieb:
> Die sind auf 4.7K

Ok, würde ich so lassen.

von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hallöchen..

Das Oled Display lebt ;)

Hab den Code von afiscon in dem ssd1306.h File etwas anpassen müssen, 
weil Fehler beim compilieren auftraten. Aber sonst läufts prima :)


Link zur benutzten Oled Lib: https://github.com/afiskon/stm32-ssd1306

Gruß Rolf

: Bearbeitet durch User
von Rolf D. (rolfdegen)


Angehängte Dateien:

Lesenswert?

Hallöchen..

Macht richtig Spaß mit den kleinen ARM MCUs. Auf jeden Fall schneller 
als die AVRs. Hab mal eine kleines Audio Scope programmiert. Der 
komplette Projekt Ordner im Anhang.

Link: https://youtu.be/3xvXjU5WA7M

: Bearbeitet durch User
von ali (Gast)


Lesenswert?

Hallo Rolf,

der Audio Scope sieht gut aus.

Im cc2 Forum fand ich den Artikel (STM32)über CubeMX sehr gut erklärt.

Aber beim "SW4STM32 System Workbench" hätte ich einige Fragen:


1.Welche einstellungen sind zu treffen damit mann über die SWD den code 
übertragen kann (habe nur Cpu STM32f103 und v-link) ?

2. Wie ist die Ordnerstruktur ?
<Wohin (ORDNER) SW4STM32 installieren >
<Wohin (ORDNER) Projekt >
<Wohin (ORDNER) SPL,HAL etc.>

3. Wie importiere ich ein fertiges Projekt zb. "OLEDScope" ?


MFG

Ali

von Stefan F. (Gast)


Lesenswert?

ali schrieb:
> Welche einstellungen sind zu treffen damit mann über die SWD den code
> übertragen kann

Guck Dir das an:
http://stefanfrings.de/stm32/system_workbench.html
http://stefanfrings.de/stm32/stm32f1.html

> Wie ist die Ordnerstruktur ?

Ziemlich egal, weil du in der IDE in den Projekteinstellungen die ganzen 
Pfade konfigurieren kannst. Für Arbeiten mit HAL generiert Cube MX 
komplette Projekte mit passender Verzeichnisstruktur und Konfiguration. 
Für Projekte ohne HAL generiert die IDE selbst (File/New Project) die 
grundsätzliche Verzeichnisstruktur.

Ich hab hier 
http://stefanfrings.de/mikrocontroller_buch2/Einblick%20in%20die%20moderne%20Elektronik.pdf 
ab Kapitel 9 einiges zur Verzeichnis-Struktur und der Konfiguration 
geschrieben.

> Wie importiere ich ein fertiges Projekt zb. "OLEDScope" ?

Steht auch in dem PDF. Schau dich mal im File Menü um, da findest du 
ganz viele spannende Funktionen, die zu deinen Fragen passen.

von Ali (Gast)


Lesenswert?

Hallo Stefan,vielen Dank für die Links.

Habe Sie kurz überflogen,werde Sie aber noch genauer anschauen.
Ich finde die Tutorials sind sehr gut gelungen. {TOP 5 STERNE}

Frage zur :  9.1  Projektvorlage kopieren

Behandelt die IDE das kopierte Projekt „Test1“ danach als neues 
eigenständiges Projekt?



Frage zur : 9.2  Projekt-Struktur

Wenn ich meinem Freund den Projekt-Ordner „Test1“ übergebe,müsste Es bei 
Ihm genauso funktionieren.
{Denn da ist ja Alles drinn !!!}

Reicht Es wenn ER „Test1“ importiert ?

MFG

Ali

von Stefan F. (Gast)


Lesenswert?

Ali schrieb:
> Behandelt die IDE das kopierte Projekt „Test1“ danach als neues
> eigenständiges Projekt?

Ja.

> Wenn ich meinem Freund den Projekt-Ordner „Test1“ übergebe,müsste
> Es bei Ihm genauso funktionieren. {Denn da ist ja Alles drinn !!!}

Ja. Ich habe ja schließlich auch nur diesen einen Ordner (im ZIP Format) 
bereit gestellt, damit man ein fertiges Projekt zum Anfangen hat.

> Reicht Es wenn ER „Test1“ importiert ?

Ja

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.