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 ;)
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?
Reicht es aus, wenn ich die Files mit dem Dateimanager in das entsprechende Verzeichnis kopiere ? Oder muss ich das in OpenSTM32 machen ?
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.
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
Rolf D. schrieb: > Hab noch Probleme mit der typdef struct Welche Probleme? Zitiere bitte die ganze Fehlermeldung.
Der Compiler zeigt error in der main.c "conflicting typs in ssd1306_Fill(Black)"
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.
Danke für den Tip. Werde ich wohl so machen, da ich in C programmiere.
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)
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
>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.
Da fehlt ein -DSSD1306_USE_I2C in den Compiler Optionen.
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
Ich habe jetzt nicht alles gelesen, aber hast Du AC6 mal seinen Index erstellen lassen? Index Rebuild
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.
- index Rebuild: Kein Erfolg - Header nach Source verschoben: Kein Erfolg - clean und neu debug: Kein Erfolg Fehler "undefined reference.. " in der main
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.
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?
>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!"
Hab das hier probiert (Bild)... Aber keinen Erfolg !?
Das Command-Line Pattern sollte normalerweise so aussehen:
> ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}
Definitionen setzt bei Preprocessor unter "Defined Symbols (-D)"
Hab ich auch schon probiert !? Ergebnis: Fehlermeldungen (siehe Bild)
Da nicht. Geh mal 2 tiefer, auf Preprocessor. Da sind schon welche. Kannst deins ohne -D einfach hinzufügen.
Rolf D. schrieb: > Hab ich auch schon probiert !? Du hast dein Command-Line Pattern versaut. Ich habe Dir oben den richtigen String zitiert.
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
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.
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.
Was meinst du mit i2c starten. In der Main wird i2c init aufgerufen
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.
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 ....
Ok. Vielen Dank für die Tips. Ich versuchs heute Abend noch einmal. Nie aufgeben ist meine Devise ?
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.
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
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>© 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
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.
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.
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
Adresse 0x3C kann nicht sein. In meinem Atmel Projekt funktioniert das Display mit Adresse 0x78. Aber ich teste es mal..
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".
leo schrieb: > Ich schaetze mal, hier ist wieder der beliebte i2c-Adresse-Fehler. Ja, die OLED-Adresse 0x78 ist bereits die geshiftete Version.
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
Hab die Adresse jetzt mal direkt benutzt. Aber ohne Erfolg.
1 | HAL_I2C_Master_Transmit(&hi2c1, 0x78, (uint8_t *) buffer, 7, 1000); |
Aber auf den IC2 Leitungen müsste sich doch prinzipiell was tun. Auch wenn die Adresse nicht stimmt !?
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.
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.
Hab ein Digital Scope mit guten Trigger Eigenschaften ;)
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.
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.
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.
Rolf D. schrieb: > Hab aber in CubeMX Nucleo-F103RB ausgewählt Du hast aber geschrieben du hättest ein Nucleo-F411RE
Rolf D. schrieb: > Hab aber in CubeMX Nucleo-F103RB ausgewählt Rolf D. schrieb: > dem Nucleon F411RE-Board. Willst du mich jetzt verarschen?
Das habe ich auch. Zur Zeit benutze ich aber das Nucleo-F103RB
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 .....
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.
???? Um es noch einmal klar zu stellen. Ich benutze das Nucleo-F103RB.
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 ....
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.
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
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>© 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
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)
|
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!
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 :)
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.
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
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.
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.
Das war übrigens mein fünfter Kontakt zur HAL, vier davon sind wegen nachweislicher Bugs fehlgeschlagen, nur einer war erfolgreich.
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
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
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
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.
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
Sieht gut aus. Ich denke, du kannst die Pull-Up Widerstände ruhig etwas hochohmiger machen.
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
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
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
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.