Forum: Mikrocontroller und Digitale Elektronik C: Pointerübergabe in Funktion


von Pointeraufruf (Gast)


Lesenswert?

Hallo, ich habe hier diese Funktion:
1
SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pTxData);

Den Inputparameter *hspi fülle ich mit &hspi, das ist soweit klar, also 
SPI_Transmit(&hspi, ...)

Wie aber geht es nun weiter, wie fülle ich den *pTxData?

kann ich dafür einfach
uint8 daten = 1;
1
SPI_Transmit(&hspi, &daten);
schreiben?

von Falk B. (falk)


Lesenswert?

Ja

von foobar (Gast)


Lesenswert?

Wie sieht denn der Body von SPI_Transmit aus?
Aus Compilersicht kannst du das schon so schreiben.

von Wilhelm M. (wimalopaan)


Lesenswert?

Pointeraufruf schrieb:
> Hallo, ich habe hier diese Funktion:
>
1
> SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pTxData);
2
>
>
> Den Inputparameter *hspi fülle ich mit &hspi, das ist soweit klar, also
> SPI_Transmit(&hspi, ...)
>
> Wie aber geht es nun weiter, wie fülle ich den *pTxData?
>
> kann ich dafür einfach
> uint8 daten = 1;
>
>
1
SPI_Transmit(&hspi, &daten);
> schreiben?


Allein aus der Signatur folgt, dass daten bei Dir ein Output-Parameter 
ist. D.h. nach dem Aufruf ist daten gefüllt mit dem was vom SPI-Slave 
kam.

von ui (Gast)


Lesenswert?

foobar schrieb:
> Wie sieht denn der Body von SPI_Transmit aus?
> Aus Compilersicht kannst du das schon so schreiben.

spielt doch keine Rolle.
Es ist ja offensichtlich ganz klar was passieren soll. Die Funktion will 
eine Speicheraddresse einer 8-bit Zahl. Da das ganze SPI_Transmit heißt, 
sollte irgendwo in der Funktionsdoku stehen, dass das der Wert ist, der 
versendet werden soll.
Was ich noch nie verstanden habe, warum man 8bit Zahlen als Pointer 
übergibt. Ob jetzt die Addresse übertragen wird oder der Wert bleibt 
doch völlig wurscht. In nem 32-bit System hat man sogar mehr kopiert als 
wenn man Call by Value macht...

von danvet (Gast)


Lesenswert?

Fehlt da nicht noch die Angabe, wieviel Bytes verschickt werden sollen?

von Wilhelm M. (wimalopaan)


Lesenswert?

ui schrieb:
> foobar schrieb:
>> Wie sieht denn der Body von SPI_Transmit aus?
>> Aus Compilersicht kannst du das schon so schreiben.
>
> spielt doch keine Rolle.
> Es ist ja offensichtlich ganz klar was passieren soll. Die Funktion will
> eine Speicheraddresse einer 8-bit Zahl. Da das ganze SPI_Transmit heißt,
> sollte irgendwo in der Funktionsdoku stehen, dass das der Wert ist, der
> versendet werden soll.
> Was ich noch nie verstanden habe, warum man 8bit Zahlen als Pointer
> übergibt. Ob jetzt die Addresse übertragen wird oder der Wert bleibt
> doch völlig wurscht. In nem 32-bit System hat man sogar mehr kopiert als
> wenn man Call by Value macht...

s.o.: OutputParameter

SPI ist immer bidirectional.

von Urmeter (Gast)


Lesenswert?

@  Pointeraufruf

Ich würde ja gerne mal die Dokumentation oder die Implementierung der 
Funktion dazu sehen. Gibt es nicht einen Link darauf? Oder, falls Du sie 
selbst geschrieben hast, poste doch bitte mal den Quelltext.

von ui (Gast)


Lesenswert?

Wilhelm M. schrieb:
> ui schrieb:
>> foobar schrieb:
>>> Wie sieht denn der Body von SPI_Transmit aus?
>>> Aus Compilersicht kannst du das schon so schreiben.
>>
>> spielt doch keine Rolle.
>> Es ist ja offensichtlich ganz klar was passieren soll. Die Funktion will
>> eine Speicheraddresse einer 8-bit Zahl. Da das ganze SPI_Transmit heißt,
>> sollte irgendwo in der Funktionsdoku stehen, dass das der Wert ist, der
>> versendet werden soll.
>> Was ich noch nie verstanden habe, warum man 8bit Zahlen als Pointer
>> übergibt. Ob jetzt die Addresse übertragen wird oder der Wert bleibt
>> doch völlig wurscht. In nem 32-bit System hat man sogar mehr kopiert als
>> wenn man Call by Value macht...
>
> s.o.: OutputParameter
>
> SPI ist immer bidirectional.

ja. aber da spi mosi und miso hat, würde ich bei diesem Funktionsheader 
davon ausgehen, dass man übertragen will. ansonsten receive.
Bidirektional ja, aber nicht über ein Medium.

von Wilhelm M. (wimalopaan)


Lesenswert?

ui schrieb:
> Wilhelm M. schrieb:
>> ui schrieb:
>> s.o.: OutputParameter
>>
>> SPI ist immer bidirectional.
>
> ja. aber da spi mosi und miso hat, würde ich bei diesem Funktionsheader
> davon ausgehen, dass man übertragen will. ansonsten receive.
> Bidirektional ja, aber nicht über ein Medium.

Man füllt vom dem Senden daten mit dem zu sendenden Byte, danach ist 
daten gefüllt mit dem, was vom Slave kam.

Ich hätte oben besser sagen sollen: Input-Output-Parameter.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

ui schrieb:
> ja. aber da spi mosi und miso hat, würde ich bei diesem Funktionsheader
> davon ausgehen, dass man übertragen will. ansonsten receive.

Wenn Du per SPI ein Byte verschickst, bekommst Du automatisch im 
gleichen Rutsch auch ein Byte zurück von Deinem "Gesprächspartner". Das 
heisst, man sendet und empfängt bei SPI gleichzeitig. Das ist 
prinzipbedingt.

Daher ist es sinnvoll, hier einen Pointer herunterzugeben. Das Byte wird 
gesandt und man bekommt selbst wieder ein Byte zurück.

von ui (Gast)


Lesenswert?

Frank M. schrieb:
> ui schrieb:
>> ja. aber da spi mosi und miso hat, würde ich bei diesem Funktionsheader
>> davon ausgehen, dass man übertragen will. ansonsten receive.
>
> Wenn Du per SPI ein Byte verschickst, bekommst Du automatisch im
> gleichen Rutsch auch ein Byte zurück von Deinem "Gesprächspartner". Das
> heisst, man sendet und empfängt bei SPI gleichzeitig. Das ist
> prinzipbedingt.
>
> Daher ist es sinnvoll, hier einen Pointer herunterzugeben. Das Byte wird
> gesandt und man bekommt selbst wieder ein Byte zurück.

Wilhelm M. schrieb:
> Man füllt vom dem Senden daten mit dem zu sendenden Byte, danach ist
> daten gefüllt mit dem, was vom Slave kam.

Ich weiß wie SPI funktioniert.
Allerdings könnte man sich auch vorstellen, dass man das Byte extra 
ausliest.

Für mich bedeutet Transmit = nur Versenden
Receive = nur lesen
und Transceive ist beides.

Aber schön wie man sieht, wie man für mit demselben Begriff total 
unterschiedliche Dinge assoziiert.

von foobar (Gast)


Lesenswert?

Frank M. schrieb:
> Wenn Du per SPI ein Byte verschickst, bekommst Du automatisch im
> gleichen Rutsch auch ein Byte zurück von Deinem "Gesprächspartner". Das
> heisst, man sendet und empfängt bei SPI gleichzeitig. Das ist
> prinzipbedingt.
>
> Daher ist es sinnvoll, hier einen Pointer herunterzugeben. Das Byte wird
> gesandt und man bekommt selbst wieder ein Byte zurück.

Glaub ich dir so nicht.
SPI ohne MISO macht durchaus Sinn. Ich glaube mich sogar zuerinnern an 
an Display geschrieben zu haben, das keinen Rückkanal hat.

von S. R. (svenska)


Lesenswert?

SPI ohne MISO ist aus Softwaresicht genau dasselbe wie SPI mit MISO, bis 
auf den Fakt, dass die empfangenen Werte Gülle sind.

Bei SPI macht "Receive" keinen Sinn, und selbst "Transmit" nur 
eingeschränkt, weil SPI prinzipbedingt gleichzeitig sendet und empfängt. 
Das sollte aber jedem klar sein, der mit SPI arbeitet, weil es eben kein 
I2C ist.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Allein aus der Signatur folgt, dass daten bei Dir ein Output-Parameter
> ist.

Das halte ich für eine gewagte Annahme. Das kann so sein, muss aber 
nicht. Die Tatsache, daß der Parameter "pTxData" heißt, spricht dafür, 
daß das die zu sendenden Daten sind (Tx als Kurzform von "transmit").

Nur weil es ein Pointer ist (und jemand das die Angelegenheit eindeutig 
machende "const" weggelassen hat), würde ich hier nicht auf 
Output-Parameter schließen.

Ja, da steht kein "const", aber steht das irgendwo sonst bei 
Funktionsdeklarationen aus der selben Feder? So etwas wird gerne 
übersehen, und dann ist das Fehlen kein Indikator für "output 
parameter".

von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:
> Wilhelm M. schrieb:
>> Allein aus der Signatur folgt, dass daten bei Dir ein Output-Parameter
>> ist.
>
> Das halte ich für eine gewagte Annahme. Das kann so sein, muss aber
> nicht. Die Tatsache, daß der Parameter "pTxData" heißt, spricht dafür,
> daß das die zu sendenden Daten sind (Tx als Kurzform von "transmit").
>
> Nur weil es ein Pointer ist (und jemand das die Angelegenheit eindeutig
> machende "const" weggelassen hat), würde ich hier nicht auf
> Output-Parameter schließen.
>
> Ja, da steht kein "const", aber steht das irgendwo sonst bei
> Funktionsdeklarationen aus der selben Feder? So etwas wird gerne
> übersehen, und dann ist das Fehlen kein Indikator für "output
> parameter".

Wenn das so ist (und deswegen keine Parameterübergabe per-value 
stattfindet), dann würde ich das entweder nicht benutzen oder 
umschreiben:

"Ein Schnittstelle soll einfach richtig und schwer falsch zu benutzen 
sein"

pointer-to-non-const sind (input)output-parameter

Allerdings wäre noch der Typ der Funktion interessant: ist er bool oder 
ggf. uint8_t oder optional<uint8_t> (bei C++), wobei letzteres nur bei 
C++ geht und dann der uint8_t* vollkommen sinnlos ist ...

von ui (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Das halte ich für eine gewagte Annahme. Das kann so sein, muss aber
> nicht. Die Tatsache, daß der Parameter "pTxData" heißt, spricht dafür,
> daß das die zu sendenden Daten sind (Tx als Kurzform von "transmit").
>
> Nur weil es ein Pointer ist (und jemand das die Angelegenheit eindeutig
> machende "const" weggelassen hat), würde ich hier nicht auf
> Output-Parameter schließen.
>
> Ja, da steht kein "const", aber steht das irgendwo sonst bei
> Funktionsdeklarationen aus der selben Feder? So etwas wird gerne
> übersehen, und dann ist das Fehlen kein Indikator für "output
> parameter".

Seh ich genauso, wenn auch nicht so ausführlich erklärt.

Wilhelm M. schrieb:
> Wenn das so ist (und deswegen keine Parameterübergabe per-value
> stattfindet), dann würde ich das entweder nicht benutzen oder
> umschreiben:
>
> "Ein Schnittstelle soll einfach richtig und schwer falsch zu benutzen
> sein"
>
> pointer-to-non-const sind (input)output-parameter

Es hat keiner Gesagt, dass die Library gut ist.
Ich bleib dabei:
Transmit = nur senden

von Wilhelm M. (wimalopaan)


Lesenswert?

ui schrieb:

>
> Es hat keiner Gesagt, dass die Library gut ist.
> Ich bleib dabei:
> Transmit = nur senden

Bezogen auf die Benennung der Funktion und des Parameters gebe ich Dir 
recht. Aber wie gesagt macht für SPI ein "nur Senden" technisch keinen 
Sinn. man empfängt zwangsläufig was (auch wenn der Pin gar nicht 
angeschlossen ist). Ein Receive allein im Gegenzug macht ebenfalls 
keinen Sinn, weil man ohne Transmit kein Receive durchführen kann ...

Zum Thema Schnittstelle vllt noch folgender Link:

https://isocpp.org/wiki/faq/const-correctness

Zudem ist ja ein pointer-type größer als ein uint8_t und man sich ja die 
zusätzliche Stacktiefe ersparen kann, wenn nur Input.

Also es sprechen m.E. mehr Punkte dafür, dass es ein 
Input/Output-Parameter ist.

Natürlich kann es auch sein, dass der Entwickler dieses Interfaces so 
gar nicht nachgedacht hat: bei der Wahl der Typen, beim weglassen des 
const, bei der Benennung, ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wilhelm M. schrieb:
> Aber wie gesagt macht für SPI ein "nur Senden" technisch keinen Sinn.

Aber sicher kann das einen Sinn haben. Ein per SPI angesteuerter DAC 
beispielsweise hat in Gegenrechtung wenig mitzuteilen, ein per SPI 
angesteuertes Schieberegister (an dem z.B. irgendwelche LEDs hängen) 
sieht da nicht anders aus.

> man empfängt zwangsläufig was (auch wenn der Pin gar nicht angeschlossen
> ist).

Das ist zwar so, aber wenn man mit Datensenken (s.o.) redet, senden die 
nichts zurück und man muss, um nichts zu empfangen, auch keinen 
Übergabeparameter verwenden.

> Ein Receive allein im Gegenzug macht ebenfalls keinen Sinn, weil man
> ohne Transmit kein Receive durchführen kann ...

Das ist korrekt. Aber kennen wir die anderen Deklarationen aus der 
Codesammlung, aus der die hier diskutierte Funktion stammt?

> Zudem ist ja ein pointer-type größer als ein uint8_t und man sich ja die
> zusätzliche Stacktiefe ersparen kann, wenn nur Input.

O nein, das können ja auch mehrere uint8_t sein, ein Array, und die 
Anzahl der zu sendenden Elemente ist entweder in der anderen übergebenen 
Struktur verborgen, implizit festgelegt oder wie z.B. bei in C 
verwendeten Stringfunktionen durch ein Endezeichen (\0 o.ä.) definiert.

Das kann man der Funktion so alles nicht ansehen.

> Zum Thema Schnittstelle vllt noch folgender Link:
> https://isocpp.org/wiki/faq/const-correctness

Das ist die Lehrbuchmeinung, aber --wie schon mehrfach erwähnt-- kann 
man ohne die restlichen Funktionen aus der gleichen Feder zu kennen, das 
nicht als gegeben ansehen.

"const" ist eines der am meisten ignorierten (d.h. weggelassenen) 
Schlüsselwörter in C/C++.

von Wilhelm M. (wimalopaan)


Lesenswert?

Rufus Τ. F. schrieb:
> Wilhelm M. schrieb:
>> Aber wie gesagt macht für SPI ein "nur Senden" technisch keinen Sinn.
>
> Aber sicher kann das einen Sinn haben. Ein per SPI angesteuerter DAC
> beispielsweise hat in Gegenrechtung wenig mitzuteilen, ein per SPI
> angesteuertes Schieberegister (an dem z.B. irgendwelche LEDs hängen)
> sieht da nicht anders aus.

Aber die HW-SPI Schnittstelle empfänger per-definitionem immer etwas - 
in dem Fall dann hoffentlich nur "0" oder "1", weil der MISO geklemmt 
ist.

>
>> man empfängt zwangsläufig was (auch wenn der Pin gar nicht angeschlossen
>> ist).
>
> Das ist zwar so, aber wenn man mit Datensenken (s.o.) redet, senden die
> nichts zurück und man muss, um nichts zu empfangen, auch keinen
> Übergabeparameter verwenden.

Genau deswegen meine ich ja, das es ein Input/Output-Parameter ist.

>
>> Ein Receive allein im Gegenzug macht ebenfalls keinen Sinn, weil man
>> ohne Transmit kein Receive durchführen kann ...
>
> Das ist korrekt. Aber kennen wir die anderen Deklarationen aus der
> Codesammlung, aus der die hier diskutierte Funktion stammt?
>
>> Zudem ist ja ein pointer-type größer als ein uint8_t und man sich ja die
>> zusätzliche Stacktiefe ersparen kann, wenn nur Input.
>
> O nein, das können ja auch mehrere uint8_t sein, ein Array, und die
> Anzahl der zu sendenden Elemente ist entweder in der anderen übergebenen
> Struktur verborgen,

Du meinst, man muss erst mit einer anderen Funktion die Länge des rohen 
Arrays festlegen - Gott bewahre!

> implizit festgelegt oder wie z.B. bei in C
> verwendeten Stringfunktionen durch ein Endezeichen (\0 o.ä.) definiert.

Oh je!!! Dann sollte es besser ein const char* sein, weil man dort per 
Konvention den definitv ungültigen Wert '\0' gibt als Senstinel 
erwartet. Bei primitiven DT ausser Zeiger gibt es per Definitionem keine 
ungültigen Werte, die als Sentinel dienen könnten. Sonst könnte man ja 
bspw. keine Werte 0 mehr senden.

>
> Das kann man der Funktion so alles nicht ansehen.
>
>> Zum Thema Schnittstelle vllt noch folgender Link:
>> https://isocpp.org/wiki/faq/const-correctness
>
> Das ist die Lehrbuchmeinung, aber --wie schon mehrfach erwähnt-- kann
> man ohne die restlichen Funktionen aus der gleichen Feder zu kennen, das
> nicht als gegeben ansehen.
>
> "const" ist eines der am meisten ignorierten (d.h. weggelassenen)
> Schlüsselwörter in C/C++.

Es ist eines der wichtigsten, neben constexpr!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Weitere Spekulationen sind müßig - der Threadstarter müsste zumindest 
mal die anderen zum Softwarepaket gehörenden Funktionsprotoypen 
verraten, oder vielleicht auch einfach die Quelle nennen.

Da er sich hier aber noch nicht wieder hat blicken lassen ...

Googelt man übrigens nach dem Funktionsprototypen, so findet man /das 
hier/ hier:
1
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

https://developer.mbed.org/users/dreschpe/code/mbed-F401/docs/4e95b79aa640/stm32f4xx__hal__spi_8c.html

... das sieht doch irgendwie nicht ganz unverwandt aus.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Das stimmt ... da bin ich ja mal gespannt ;-)

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.