Forum: Mikrocontroller und Digitale Elektronik CubeIDE Variablen in externen Modul unbekannt


von Gunnar F. (gufi36)


Angehängte Dateien:

Lesenswert?

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!

von Harry L. (mysth)


Lesenswert?

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
von Gunnar F. (gufi36)


Lesenswert?

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.

von Harry L. (mysth)


Lesenswert?

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.

von Gunnar F. (gufi36)


Lesenswert?

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?

von Harry L. (mysth)


Lesenswert?

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.

von Rahul D. (rahul)


Lesenswert?

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.

von Harry L. (mysth)


Lesenswert?

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

von Gunnar F. (gufi36)


Lesenswert?

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?

von Gunnar F. (gufi36)


Lesenswert?

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!

von Stefan F. (Gast)


Lesenswert?

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.

von Thomas W. (Gast)


Lesenswert?

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.

von Gunnar F. (gufi36)


Lesenswert?

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.

von J. S. (jojos)


Lesenswert?

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.

von Gunnar F. (gufi36)


Lesenswert?

Danke auch dafür, ich mach das jetzt mal!

von Stefan F. (Gast)


Lesenswert?

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.

von Thomas F. (igel)


Lesenswert?

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?

von Stefan F. (Gast)


Lesenswert?

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).

von Thomas W. (Gast)


Lesenswert?

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.

von Gunnar F. (gufi36)


Lesenswert?

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
Noch kein Account? Hier anmelden.