Forum: Mikrocontroller und Digitale Elektronik Beim Setzen von Pixel werden 2 statt 1 gesetzt (STM32F4 + ili9341))


von Mächtiger M. (mchtiger_m)


Lesenswert?

Hallo,

ich sammle gerade meine erste ersten Erfahrungen mit Mikrocontrollern 
und habe mir dafür das Board STM32 F4 Discovery Board 29zit ausgesucht. 
Als Programmiersprache verwende ich C++.

Mein Ziel ist es Bilder und Animationen auf dem auf dem Board verbauten 
Display anzuzeigen. Aktuell habe ich das Problem, dass meine Funktion 
drawPixel(int const x, int const y, int const color) zwei statt einem 
Pixel zeichnet.

Mein allgemeines Vorgehen:
- SDRAM initalisiert
- SPI initialisiert (Für die Ili9341 InitSequence)
- Ili9341 initialisiert
- LTDC initalisiert
- Layer 1 von 2 erstellt mit der Abmessung des Displays
- Funktion zum Setzten eines Pixels

Mein Code:
1
  
2
  static constexpr int const width = 240U;
3
  static constexpr int const height = 320U; 
4
5
  static constexpr int const hSync = 10;               
6
  static constexpr int const vSync =  2;        
7
  static constexpr int const horBackPorch = 20;
8
  static constexpr int const verBackPorch =  2;
9
  static constexpr int const horFrntPorch = 10;
10
  static constexpr int const verFrntPorch =  4;  
11
  static constexpr unsigned const horTotal = hSync + horBackPorch + width  + horFrntPorch;
12
  static constexpr unsigned const verTotal = vSync + verBackPorch + height + verFrntPorch;
13
  
14
  //Setze Display-Maße
15
  ltdc.SSCR = ((hSync - 1) << INDX_LTDC_SSCR_HSW) | ((vSync - 1) << INDX_LTDC_SSCR_VSH);  
16
  ltdc.BPCR = ((hSync + horBackPorch - 1) << INDX_LTDC_BPCR_AHBP) | ((vSync + verBackPorch - 1) << INDX_LTDC_BPCR_AVBP);
17
  ltdc.AWCR = ((hSync + horBackPorch + width - 1) << INDX_LTDC_AWCR_AAW) | ((vSync + verBackPorch + height - 1) << INDX_LTDC_AWCR_AAH);
18
  ltdc.TWCR = ((verTotal - 1) << INDX_LTDC_TWCR_TOTALH) | ((horTotal - 1) << INDX_LTDC_TWCR_TOTALW);
19
  
20
  //Hintergrundfarbe Schwarz
21
  ltdc.BCCR = (0x000000);
22
  
23
  //Aktiviere Imitiate Reload
24
  ltdc.SRCR |= MASK_LTDC_SRCR_IMR;
25
  
26
  //Setze FrameBuffer (externer SDRAM)
27
  layer.CFBAR = 0xD0000000; 
28
  layer.CFBLR |= (width * 2) << 16 | (width * 2 + 3); //*2 = PixelSize von RGB565
29
  layer.CFBLNR |= height;
30
  
31
  //Setze Pixelformat
32
  layer.PFCR |= MASK_LTDC_Lx_PFCR_RGB565;
33
  
34
  //Setze Transparenz (Keine)
35
  layer.CACR = 255; 
36
  
37
  //Setze Layergröße auf Displaygröße
38
  layer.WHPCR = hSync+horBackPorch+width-1 << INDX_LTDC_Lx_WHPCR_WHSPPOS | hSync+horBackPorch;  
39
  layer.WVPCR = vSync+verBackPorch+height-1 << INDX_LTDC_Lx_WVPCR_WVSPPOS | vSync+verBackPorch;
40
  
41
  //Aktiviere die erste Layer
42
  layer.CR |= MASK_LTDC_Lx_CR_LEN; 
43
  
44
  //Aktiviere den LTDC
45
  ltdc.GCR |= MASK_LTDC_GCR_LTDCEN;
46
  
47
  //Setze den ersten Pixel des Displays weiß.
48
  int x = 0;
49
  int y = 0;
50
  *((uint32_t *) 0xD0000000 + (x + y * width)) = 0xFFFF;
51
  //Resultat: Die ersten 2 Pixel sind weiß. Unabhängig vom x und y werden immer zwei Pixel gesetzt.

Ich kann an jede Stelle des Displays einen Pixel setzen, allerdings wird 
der Pixel rechts daneben auch gesetzt. Habe ich evtl etwas falsch 
konfiguriert?

Ich hoffe mir kann jemand helfen, ich bin am verzweifeln :-).

von Jim M. (turboj)


Lesenswert?

RGB565 ist ein 16-Bit Format, du schreibst 32 Bits (uint32_t) in den 
Speicher.

Hätte eigentlich einen weißen und einen schwarzen Pixel schreiben 
sollen, denn 0x0000FFFF ist einmal weiß 16 Bits und einmal schwarz 16 
Bits IMHO.

von Andreas S. (igel1)


Lesenswert?

@Jim M.:  ... scharfes Auge!

@Mächtiger M.:

Jim M.'s Vermutung hört sich stimmig an.
Wenn's das nicht sein sollte, so hänge doch bitte den gesamten Code als 
Attachment an.

Viele Grüße

Igel1

von Follsplunk dulch Technik (Gast)


Lesenswert?

> hänge doch bitte den gesamten Code als Attachment an.

Ausserdem sollte der Code natuerlich funktionieren und
ordentlich dokumentiert sein.
Nicht funktionierenden Code braucht kein Mensch.

von Mächtiger M. (mchtiger_m)


Angehängte Dateien:

Lesenswert?

Hallo, danke für eure Antworten.
Ich habe tatsächlich einen uint32_t-Wert als Color verwendet statt einen 
uint16_t allerdings hat das bei mir keine Auswirkung auf die Darstellung 
gehabt.
1
 *((uint32_t *) 0xD0000000 + (x + y * width)) = 0xFFFF;

Das uint32_t hier bezieht sich auf die Speicheradresse.


Ich weiß immer noch nicht, weshalb 2 statt ein Pixel gezeichnet werden 
und habe deshalb meinen Code angehängt. Allerdings glaube ich, dass oben 
schon alle Konfigurationen, die das Zeichnen des Pixels beeinflüssen 
können, zu sehen sind.

- LTDC Konfiguration
- Layer Konfiguration
- Zeichnen-Funktion



Viele Grüße

Matthias

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Mächtiger M. schrieb:
> Das uint32_t hier bezieht sich auf die Speicheradresse.

Nö!
Mit dem Konstrukt baust du einen uint32_t Pointer auf die Adresse und 
dereferenzierst den gleich wieder.
Daher ist das ein uint32_t Zugriff auf diese Adresse.
Die Adresslänge kennt der Compiler selber weil er weil er eben für ARM 
kompiliert.

von guest (Gast)


Lesenswert?

Mächtiger M. schrieb:
> *((uint32_t *) 0xD0000000 + (x + y * width)) = 0xFFFF;
>
> Das uint32_t hier bezieht sich auf die Speicheradresse.

Nö, das uint32_t bezieht sich auf die Speichestelle wo Deine Adresse 
hinzeigt. Oder anders gesagt: Du schreibst immer noch mit 32 Bit.
Und vermutlich am Ende auch deutlich über Deinen Framebuffer hinaus.

von Mächtiger M. (mchtiger_m)


Lesenswert?

Jim. M und unbekannter guest, ich danke euch.

Ich hätte es gleich probieren sollen, so hätte ich 2 Stunden heute 
gespart :-)

Edit: Danke auch dir Mw E.  :)

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Aber anstatt so rumzuwurschteln nimm ein uint16_t 2D Array und pack das 
per Linkerscript an den Anfang des Adressraums vom FMC.

von Mächtiger M. (mchtiger_m)


Lesenswert?

Mw E. schrieb:
> Aber anstatt so rumzuwurschteln nimm ein uint16_t 2D Array und pack das
> per Linkerscript an den Anfang des Adressraums vom FMC.

Per Linkerscript?

Damit würde der Zugriff sicher einfacherer werden, aber kostet das nicht 
width  height  2 Byte(uint16_t) Speicherplatz?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Das braucht so viel Speicherplatz wie dein Framebuffer jetzt auch.
Meinste den Framebuffer gibts kostenlos?

Wenn du aber nicht weist was ein Linkerscript ist kann das eine schwere 
geburt werden.
Makefile und Linkerscript sind übrigens nicht in deinem zip vorhanden.

von Mitlesa (Gast)


Lesenswert?

guest schrieb:
> Nö, das uint32_t bezieht sich auf die Speichestelle wo Deine Adresse
> hinzeigt. .......

Leuchtet mir als Mitlesender noch nicht ganz ein.

Für einen Schreibvorgang 32 Bit erzeugt der FMC ja nur einen
Write Strobe. Da das Display einen 16-Bit Port hat kann es doch
eigentlich auch nur 16 Bit (also ein Pixel-Wort) durch einen
Write Zyklus bekommen.

Wenn zwei Pixel geschrieben werden braucht es einen weiteren
Write Strobe. Wo soll der herkommen? Das zweite Pixel des
Diaplays liegt ja auf den oberen 16 Bit der ersten Adresse
des STM Adressraums.

Oh ich glaube es wird mir klar: da der FMC nur 16 Bit breit
ist schreibt ein 32 Bit Zugriff tatsächlich 2 mal hinter-
einander und generiert daurch zwei Write Strobes.

Der Gedanke kommt beim Schreiben ... oder so ähnlich heisst
das Sprichwort.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Nö!
Am FMC hängt sein SDRAM.
Aus dem SDRAM läd der LTDC die Framebufferdaten per DMA.
Diese gibt er dann auf dem RGB Interface des STM32 aus.
An dem dann das LCD hängt.

von Johannes S. (Gast)


Lesenswert?

Man kann auch einen Pointer auf ein uint16_t deklarieren und den auf die 
Startadresse setzen.

von Mitlesa (Gast)


Lesenswert?

Mw E. schrieb:
> Am FMC hängt sein SDRAM.

Naja, das SDRAM ist auch nicht breiter (bzw der Bus bleibt
16 Bit breit auch wenn noch so breites xyRAM dranhängt),
ergibt also auch zwei Schreibvorgänge ....

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.