Forum: Mikrocontroller und Digitale Elektronik STM32: Zeigerübergabe Problem


von DraconiX (Gast)


Lesenswert?

Ich ärger mich nun schon die ganze Nacht durch an einem STM32 rum - um 
die I2C unter der ST HAL zum laufen zu bekommen, das klappt nun 
mittlerweile auch tadellos.

Aaaaalerdings habe ich da nun ein kleines Programmierproblem mit einem 
Zeiger auf ein Array:
1
const uint8_t ssd1306_font6x8 [] = {
2
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sp
3
    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, // !
4
    0x00, 0x00, 0x07, 0x00, 0x07, 0x00, // "
5
//..... Eingekürzt
6
  0x00, 0x00, 0x41, 0x77, 0x08, 0x00, // }
7
  0x00, 0x08, 0x04, 0x08, 0x08, 0x04, // ~
8
};

Und zwar gebe ich die Font über meine PUTS an den I2C raus... in der 
Reihenfolge:
1
//von hier:   (Font ist 8x6px - das Disp schiebt Zeilenweise)
2
3
void ssd1306_putc(char c){
4
    uint8_t ch = c - 32;
5
    WriteLongBuffer(0x40,ssd1306_font6x8[ch * 6],6);
6
}
7
8
//über da:
9
10
void WriteLongBuffer(uint8_t Command, uint8_t *aTxBuffer, uint16_t Size)
11
{  
12
  HAL_I2C_SSD_Transmit(&I2cHandle, SSD1306_SLAVE_ADDRESS,Command, (uint8_t*)aTxBuffer,Size, 35)
13
}
14
15
Bis hierhin:
16
17
HAL_StatusTypeDef HAL_I2C_SSD_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t Command, uint8_t *pData, uint16_t Size, uint32_t Timeout)
18
{
19
//...

Quasi von const char nacht *atxBuffer zu *pData.... und wenn ich bei der 
PUTC nicht mit dem & Zeiger arbeite kommt dies nicht an. Hab ich 
allerdings in der PUTC:
1
WriteLongBuffer(0x40,&ssd1306_font6x8[ch * 6],6);

funktioniert es zwar Augenscheinlich, aber mein Compiler wirft mir eine 
Warnung an den Kopf:
1
passing argument 2 of 'WriteLongBuffer' makes pointer from integer without a cast
2
3
und:
4
5
expected 'uint8_t * {aka unsigned char *}' but argument is of type 'const uint8_t * {aka const unsigned char *}'

Er kompiliert es zwar und es funktioniert, aber irgendwo muss doch da 
der Wurm drinn sein.

Wo wir gerade dabei sind: Gibt es bei dem STM32 auch eine Möglichkeit 
soetwas ins Flash zu legen (PROGMEM) wie bei den AVR? PROGMEM geht 
leider nicht.

von learn C (Gast)


Lesenswert?

der compiler beschwert sich doch nur wegen verschieden typen ("const"). 
caste doch einfach.

von learn C (Gast)


Lesenswert?

DraconiX schrieb:
> Wo wir gerade dabei sind: Gibt es bei dem STM32 auch eine Möglichkeit
> soetwas ins Flash zu legen (PROGMEM) wie bei den AVR? PROGMEM geht
> leider nicht.

Was denkst du denn, wo es aktuell liegt???

von Andreas E. (hismastersvoice)


Lesenswert?

Die zweite Meldung sagt es schon: WriteLongBuffer erwartet ein uint8_t*, 
Du übergibst aber ein const uint8_t*, d.h. aTxBuffer kann in 
WriteLongBuffer verändert werden, was Du übergibst kann es aber nicht! 
Darauf weist Dich der Compiler hin.
Daher mußt Du entweder die Parameter const machen, oder per cast das 
const entfernen, was man aber nur machen sollte, wenn man garantieren 
kann, das die Parameter nicht verändert werden können.
Zu Deinem Flash Problem: globale const Variablen sollten hier 
automatisch im Flash angelegt werden. Schaue mal in Dein Map File nach. 
PROGMEM ist hier daher nicht notwendig.
Darum auch mit dem const-wegcasten vorsichtig. Ändert Deine Funktion 
doch die Parameter und diese liegen im Flash...

von Markus F. (mfro)


Lesenswert?

DraconiX schrieb:
> Und zwar gebe ich die Font über meine PUTS an den I2C raus... in der
> Reihenfolge:
> //von hier:   (Font ist 8x6px - das Disp schiebt Zeilenweise)
>
> void ssd1306_putc(char c){
>     uint8_t ch = c - 32;
>     WriteLongBuffer(0x40,ssd1306_font6x8[ch * 6],6);
> }
>
> //über da:
>

warum und wie das (angeblich) funktionieren soll, entzieht sich meiner 
Kenntnis. Ich jedenfalls würde da als Compiler nix Vernünftiges draus 
machen.
Du übergibst das auszugebende Zeichen c und rechnest dann den Index (ch) 
in das Pixelarray aus. WriteLongBuffer() will offensichtlich eine 
Adresse sehen, Du übergibst aber den Wert, der dort steht. Das muß
1
    WriteLongBuffer(0x40, &ssd1306_font6x8[ch * 6], ...
heißen. Dann meckert auch der Compiler nicht mehr. Mit const oder nicht 
const hat das nix zu tun.

von DraconiX (Gast)


Lesenswert?

Andreas E. schrieb:
> Die zweite Meldung sagt es schon: WriteLongBuffer erwartet ein
> uint8_t*,
> Du übergibst aber ein const uint8_t*, d.h. aTxBuffer kann in
> WriteLongBuffer verändert werden, was Du übergibst kann es aber nicht!
> Darauf weist Dich der Compiler hin.
> Daher mußt Du entweder die Parameter const machen, oder per cast das
> const entfernen, was man aber nur machen sollte, wenn man garantieren
> kann, das die Parameter nicht verändert werden können.
> Zu Deinem Flash Problem: globale const Variablen sollten hier
> automatisch im Flash angelegt werden. Schaue mal in Dein Map File nach.
> PROGMEM ist hier daher nicht notwendig.
> Darum auch mit dem const-wegcasten vorsichtig. Ändert Deine Funktion
> doch die Parameter und diese liegen im Flash...

Dankeschön :-D Das wars! WriteLongBuffer übernimmt nun den const.

Markus F. schrieb:
> warum und wie das (angeblich) funktionieren soll, entzieht sich meiner
> Kenntnis. Ich jedenfalls würde da als Compiler nix Vernünftiges draus
> machen.
> Du übergibst das auszugebende Zeichen c und rechnest dann den Index (ch)
> in das Pixelarray aus. WriteLongBuffer() will offensichtlich eine
> Adresse sehen, Du übergibst aber den Wert, der dort steht. Das muß
> WriteLongBuffer(0x40, &ssd1306_font6x8[ch * 6], ...
> heißen. Dann meckert auch der Compiler nicht mehr. Mit const oder nicht
> const hat das nix zu tun.

Hatte ich ja beide Versionen, mit Zeiger auf die Position und ohne - Mit 
Zeiger hat er ebenfalls mit Warnung compiliert, aber auf die Falsche 
Position gezeigt, nämlich auf die Adressen welche im Array standen, 
logisch.

Es handelt sich ja auch nur um das eine Array was ich "zerpflückt" 
übergeben muss, bei den anderen übergebe ich ja eh nur den Arrayzeiger.

von Markus F. (mfro)


Lesenswert?

DraconiX schrieb:
> Hatte ich ja beide Versionen, mit Zeiger auf die Position und ohne - Mit
> Zeiger hat er ebenfalls mit Warnung compiliert, aber auf die Falsche
> Position gezeigt, nämlich auf die Adressen welche im Array standen,
> logisch.

wenn in deinem Array Adressen stehen, warum deklarierst Du das dann als 
char Array?

von DraconiX (Gast)


Lesenswert?

Markus F. schrieb:
> DraconiX schrieb:
>> Hatte ich ja beide Versionen, mit Zeiger auf die Position und ohne - Mit
>> Zeiger hat er ebenfalls mit Warnung compiliert, aber auf die Falsche
>> Position gezeigt, nämlich auf die Adressen welche im Array standen,
>> logisch.
>
> wenn in deinem Array Adressen stehen, warum deklarierst Du das dann als
> char Array?

Nein... Der Pointer hat den Inhalt des Arrays als Adresse übernommen, 
das war so nicht gewollt. Quasi nicht die Adresse, sondern den Inhalt 
als Adresse... weißt du was ich meine?!

von Markus F. (mfro)


Lesenswert?

DraconiX schrieb:
> weißt du was ich meine?!

Um ehrlich zu sein ..., nein.

Und ich fürchte, nicht ich bin derjenige, der hier ein wenig verwirrt 
ist ;).

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

DraconiX schrieb:
> Der Pointer hat den Inhalt des Arrays als Adresse übernommen, das war so
> nicht gewollt.

Das ist in Deinem ersten Beispiel der Fall:
1
    WriteLongBuffer(0x40,ssd1306_font6x8[ch * 6],6);

Da übergibst Du genau ein Byte aus Deinem Array, und das wird von 
WriteLongBuffer als Adresse interpretiert.

Wenn Du aber
1
    WriteLongBuffer(0x40, &ssd1306_font6x8[ch * 6], 6);

verwendest, wird eine Adresse eines Elements auf Dein Array berechnet 
und Deiner Funktion übergeben, was vollkommen korrekt ist.

In der übrigens
1
void WriteLongBuffer(uint8_t Command, uint8_t *aTxBuffer, uint16_t Size)
2
{  
3
  HAL_I2C_SSD_Transmit(&I2cHandle, SSD1306_SLAVE_ADDRESS,Command, (uint8_t*)aTxBuffer,Size, 35)
4
}

ist der typecast komplett überflüssig.

Wenn Du jetzt noch Deine Funktion so änderst:
1
void WriteLongBuffer(uint8_t Command, const uint8_t *aTxBuffer, uint16_t Size)
2
{  
3
  HAL_I2C_SSD_Transmit(&I2cHandle, SSD1306_SLAVE_ADDRESS,Command, aTxBuffer,Size, 35)
4
}

wandert die Warnung an eine andere Stelle.

Und die kannst Du genauso anpassen; Deine Funktion HAL_I2C_SSD_Transmit 
verändert schließlich die übergebenen Daten nicht, also kann sie auch so 
geändert werden:
1
HAL_StatusTypeDef HAL_I2C_SSD_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t Command, const uint8_t *pData, uint16_t Size, uint32_t Timeout)

von pegel (Gast)


Lesenswert?

@  DraconiX oder auch jemand mit Idee,

mich würde interessieren wie die Funktion

HAL_I2C_SSD_Transmit

ausssieht. Speziell geht es um das Kombinieren des Command mit dem 
aTxBuffer.

Man könnte einfach den Buffer ab Index 1 beschreiben und nachher Command 
auf Index 0 schreiben und der HAL_I2C_Master_Transmit übergeben.
Da ich auch lesen möchte, würden dann die Daten ab Index 0 beginnen und 
für Command ist dann kein Platz mehr.

Jetzt könnte ich eine Tx und einen Rx Puffer anlegen, die Daten 
umkopieren oder einen neuen Typ anlegen, aber welche ist die einfachste 
Lösung die wenig Zeit und wenig Speicher braucht um nur einen Puffer zu 
verwenden?

Kann sein das ich mich verlaufen habe und die simple Lösung nicht sehe.

Jemand eine Idee?

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.