Hi Leute, ich steh auf dem Schlauch: Ich schreibe einen Treiber für einen VFD-Controller, habe dafür eine externe VFD.h und VFD.c geschrieben. Die Main.c tut noch gar nichts zur Sache, da ist kein User Code drin. Die von der CubeMX erzeugte main.h deklariert darin die ganzen Bezeichner für GPIO Pins. Der SPI-Handler aus der main.c ist in VFD.c unbekannt. Das konnte ich umschiffen, indem ich ihn als extern SPI_HandleTypeDef hspi1; neu deklariert habe. Ich kriege da sonst eine Fehlermeldung 'hspi1' undeclared (first use in this function) Was mache ich da falsch? Im Code von anderen sehe ich das nicht. Habe noch nicht viel Erfahrung mit Modularisierung. Und dann nochwas: Der alte Chip LC5710NE erwartet eine 8-Bit Adresse mit CE=L, dann drei Datenworte mit CE=H. Ich habe mir da mit einem Callback und Pufferpointer beholfen. Geht das auch besser? Dies mal unter der Voraussetzung, dass ich das mit der SPI-Hardware und nicht per Bit-Banging erledige. Danke!
Gunnar F. schrieb: > Der SPI-Handler aus der main.c ist in VFD.c unbekannt. > Das konnte ich umschiffen, indem ich ihn als > extern SPI_HandleTypeDef hspi1; > neu deklariert habe. Dafür gibt es die Callback-Funktionen. Neu definieren ist eine ganz, ganz schlechte Idee! Gunnar F. schrieb: > Ich kriege da sonst eine Fehlermeldung > 'hspi1' undeclared (first use in this function) #include "spi.h" Doku lesen und verstehen! Hier als Beispiel für F3xx (gibts entsprechend für alle anderen Familien genauso) https://www.st.com/resource/en/user_manual/um1786-description-of-stm32f3-hal-and-lowlayer-drivers-stmicroelectronics.pdf
:
Bearbeitet durch User
Harry L. schrieb: > #include "spi.h" > Doku lesen und verstehen! ist ja sehr nett von dir, aber ich verstehe es leider nicht. hspi1 ist eine Variable aus der main.c. Warum soll die über spi.h deklariert werden? Harry L. schrieb: > Dafür gibt es die Callback-Funktionen. > Neu definieren ist eine ganz, ganz schlechte Idee! die verwende ich ja! Die ist __weak deklariert und ST erklärt in deren Trainings und Webinaren, dass man die im eigenen Code neu definieren soll. So kenne ich das und es hat auch so funktioniert. Aber das war auch nicht meine Frage, sondern wenn ich vier Bytes per SPI übertrage und nur beim ersten davon ein CE Pin High sein soll, ob ich dann per Zähler und erneutem Senden, nach dem ersten Byte den Pegel ändere.
Gunnar F. schrieb: > Aber das war auch nicht meine Frage, sondern wenn ich vier Bytes per SPI > übertrage und nur beim ersten davon ein CE Pin High sein soll, ob ich > dann per Zähler und erneutem Senden, nach dem ersten Byte den Pegel > ändere. Nö. Dann musst du /CE eben manuell setzen. Auch das kann man im CubeMX einstellen.
Harry L. schrieb: > Nö. > Dann musst du /CE eben manuell setzen mache ich doch!? Und wie ausser per Callback erfahre ich, wann es so weit ist?
Gunnar F. schrieb: > Harry L. schrieb: >> Nö. >> Dann musst du /CE eben manuell setzen > > mache ich doch!? Und wie ausser per Callback erfahre ich, wann es so > weit ist? Für das, was du willst, musst du zeichenweise senden, mit Callback nach jedem Zeichen und mitzählen.
Gunnar F. schrieb: > extern SPI_HandleTypeDef hspi1; > neu deklariert habe. Was sagt der Linker dazu? Wenn der nicht meckert, ist doch alles gut (natürlich sollte man die Variable auch irgendwann mal verwenden, weil sie sonst wegoptimiert wird.) Ansonsten hilft ein Blick in die spi.h-Datei, was da alles veröffentlich wurde.
Rahul D. schrieb: > Gunnar F. schrieb: >> extern SPI_HandleTypeDef hspi1; >> neu deklariert habe. > > Was sagt der Linker dazu? > Wenn der nicht meckert, ist doch alles gut (natürlich sollte man die > Variable auch irgendwann mal verwenden, weil sie sonst wegoptimiert > wird.) Wird sie nicht! Darin stecken alle Register der Schnittstelle, und die werden bereits bei der von CubeMX generierten Initialisierung referenziert. > Ansonsten hilft ein Blick in die spi.h-Datei, was da alles veröffentlich > wurde. SPI_HandleTypeDef steckt in stm32f3xx_hal_spi.h und nicht in spi.h spi.h gibt es sowieso nur, wenn man die entsprechnde Option in CubeMX gesetzt hat. Ansonsten steckt das in der main.h (default)
1 | harry@harry-DT:~/LaborLocal/STM32Cube/STM32Cube_FW_F3_V1.11.0/Drivers/STM32F3xx_HAL_Driver/Inc$ ls *spi.h |
2 | stm32f3xx_hal_spi.h stm32f3xx_ll_spi.h |
Rahul D. schrieb: > Was sagt der Linker dazu? > Wenn der nicht meckert, ist doch alles gut Der Linker kommt gar nicht zum Zuge, weil schon der Compiler mit Fehler abbricht. Nochmal, es geht nicht um einen Datentyp, sondern: Gunnar F. schrieb: > hspi1 ist eine Variable aus der main.c. Warum soll die über spi.h > deklariert werden?
Harry L. schrieb: > SPI_HandleTypeDef steckt in stm32f3xx_hal_spi.h Das stimmt, aber wie erwartet, wenn ich die inkludiere, bleibt der Fehler bestehen, wie schon: Gunnar F. schrieb: > Ich kriege da sonst eine Fehlermeldung > 'hspi1' undeclared (first use in this function) Wo bleibt Stefanus? Ich warte auf Dich!
Gunnar F. schrieb: > Wo bleibt Stefanus? Ich warte auf Dich! Ich kenne mich mit der HAL nicht aus. Habe eine Meinung dazu, aber die hilft hier niemandem.
Gunnar F. schrieb: > Der SPI-Handler aus der main.c ist in VFD.c unbekannt. > Das konnte ich umschiffen, indem ich ihn als > extern SPI_HandleTypeDef hspi1; > neu deklariert habe. Das ist doch das geplante Verhalten: In einer (main.c)-Datei wird die Variable deklariert, in einer weiteren (vfd.c)-Datei wird die Variable extern deklariert, so dass der Linker alles zusammenbasteln kann. Das war so in the beginning (K&R, 1.Edition). Oder habe ich das Problem nicht richtig verstanden? Gruesse Th.
Thomas W. schrieb: > as ist doch das geplante Verhalten: In einer (main.c)-Datei wird die > Variable deklariert, in einer weiteren (vfd.c)-Datei wird die Variable > extern deklariert, so dass der Linker alles zusammenbasteln kann. Danke Thomas! Ja, ich habe mich inzwischen mit einem erfahrenen Programmierer unterhalten, der hat mir dasselbe bestätigt. Das ist normal, die Variable dann im externen Modul als extern nochmal neu zu deklarieren. Ich hatte das nur noch nie in fremden Code so aktiv zur Kenntnis genommen. Als ich dann (dank zum ersten mal der Versuch einer ordentlichen Modularisierung!) in die Situation kam, erschien es mir seltsam.
Gunnar F. schrieb: > Das ist > normal, die Variable dann im externen Modul als extern nochmal neu zu > deklarieren. CubeMX klatscht das als Voreinstellung alles in main.c, entsprechend müsste man die externals in main.h reinschreiben. Schöner ist es die neuere Option in den Projekteinstellungen zu verwenden die für die Peripherie eigene .c / .h Pärchen anlegt. Dann bekommt man die spi.h mit den externals geschenkt.
Ich habe mir angewöhnt, solche globalen Variablen in eine separate global.h / global.c zu schreiben. Die Namen main.h /main.c finde ich auch OK.
Stefan F. schrieb: > Ich habe mir angewöhnt, solche globalen Variablen in eine separate > global.h / global.c zu schreiben. Als C-Einsteiger interessiert mich das jetzt auch: Wie geht es dann weiter? Wo wird die global.h includiert? In der main.c? Und was steht dann in den Header-Dateien der "Unter"-Module?
Thomas F. schrieb: > Wo wird die global.h includiert? In allen Quelltexten, die auf globale Variablen zugreifen. Im Zweifelsfall in wirklich allen (kann nicht schaden). Thomas F. schrieb: > Und was steht dann in den Header-Dateien der "Unter"-Module? Da werden die Kopfzeilen der Funktionen aufgelistet, die woanders benutzbar sein sollen. Eine Header Datei geschreibt, was die zugehörige C Datei nach außen bereit stellt. Außerden definiert man in Header Dateien die zugehörigen Konstanten (#define) und Strukturen (typedef).
Man muss natuerlich aufpassen, dass man die richtigen Datentypen benutzt (bei Dir SPI_HandleTypeDef). Nehmen wir zwei Prograemmchen:
1 | #include "stdio.h" |
2 | void call_zwei(); |
3 | |
4 | float var = 0; |
5 | |
6 | int main(int argc, char* argv[]) |
7 | {
|
8 | var=42.0; |
9 | printf("var = %f\r\n", var); |
10 | call_zwei(); |
11 | printf("var = %d\r\n", var); |
12 | }
|
und das zweite Modul:
1 | #include "stdio.h" |
2 | extern int var; |
3 | void call_zwei() |
4 | {
|
5 | var = 42; |
6 | }
|
D.h. ich habe aus Versehen die Variable var (den Speicherbereich) einmal als Float und einmal als int benutzt. Jetzt compile, link (wir ignorieren die sehr eindeutige Warnung) und execute:
1 | tom@dbstw:/tmp$ gcc -Wall -c -o eins.o eins.c |
2 | eins.c: In function 'main': |
3 | eins.c:13:18: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=] |
4 | 11 | printf("var = %d\r\n", var); |
5 | | ~^ ~~~ |
6 | | | | |
7 | | int double |
8 | | %f |
9 | tom@dbstw:/tmp$ gcc -Wall -c -o zwei.o zwei.c |
10 | tom@dbstw:/tmp$ gcc -o drei eins.o zwei.o |
11 | tom@dbstw:/tmp$ ./drei |
12 | var = 42.000000 |
13 | var = 964698784 |
Bei diesem Drei-Zeiler ist das alles offensichtlich, ist das Modul etwas groesser ist so ein Type-Mismatch manchmal schwierig zu finden. Du siehst, external ist ein sehr leistungsfaehiges Instrument um sich in das Knie zu schiessen. Gruesse Th.
Thomas W. schrieb: > Du siehst, external ist ein sehr leistungsfaehiges Instrument um sich in > das Knie zu schiessen. Na das macht mich ja jetzt noch glücklicher! ;-) Jetzt habe ich mich am WE gefreut, mein Projekt in separate .c/.h Dateien aufgeteilt, wie von Stefan geraten. Ja, das wird schon übersichtlicher. Dann mein hspi1 nochmal als extern im der VFD.c deklariert und alles passte. Bin auch schon weiter gekommen, das könnte demnächst funktionieren. Aber ich verstehe schon, dass Du hier auf Feinheiten hinweist, die sich mir als (noch immer) Einsteiger, noch gar nicht so erschließen. Aber so wie ich bisher verstand, ist C sowieso die Sprache, mit der man sich effektvoll ins Knie schießen kann, nein? Da der F103 (Bluepill) nur ein SPI hat, baue ich jetzt gerade das zweite Interface zu Fuß als State Machine und BitBanging auf, und bin dann gespannt, ob etwas funktioniert. Aber auf jeden Fall danke fürs Augen Öffnen! Happy knee shooting!
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.