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.
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!
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.
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.
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.
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
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?
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.
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.
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?
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
voidcall_zwei();
3
4
floatvar=0;
5
6
intmain(intargc,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
externintvar;
3
voidcall_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:
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!