Forum: Mikrocontroller und Digitale Elektronik AVR Mega1284, Fontarray zu groß -> wie in Flash?


von Matthias (matthiasm)


Angehängte Dateien:

Lesenswert?

Guten Abend zusammen,

ich bin gerade dabei eine kleine Lib zu basteln und möchte dafür eine 
Fonttabelle auf meinem Mega1284 speichern.

Dieser hat 16kB SRAM und 128kB Flash.

Leider scheitern meine Versuche die Arrays auszulagern. PROGMEM 
ignoriert der Compiler (AVR Studio 7) vollkommen, bei EEMEM scheint er 
einen Teil auszulagern weil beim Compilieren der EEPROM mit 20% mit 
auftaucht. Allerdings ist der SRAM noch immer bei 115%. Lasse ich EEMEM 
weg steigt der SRAM auf ca. 117%.

Der Code liegt im Anhang, wäre super wenn mir jemand einen Tip geben 
könnte was ich falsch mache.

Vielen Dank!!

Gruß
Matthias

von Peter II (Gast)


Lesenswert?

Matthias M. schrieb:
> Dieser hat 16kB SRAM und 128kB Flash.
1
uint8_t OLED_PIXEL[2][65][129];

das sind doch schon 16k

da hilft es wenig den Font in den Flash auszulagern.

von Stefan F. (Gast)


Lesenswert?

Progem ist die Lösung. Wie hast du es denn versucht?

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Stefan U. schrieb:
> Progem ist die Lösung. Wie hast du es denn versucht?

Steht doch oben: Mit PROGMEM.

Es steht auch schon dort, dass sein "Grafik-RAM" das Problem ist und 
nicht die Fonts.

von Matthias (matthiasm)


Lesenswert?

Torsten C. schrieb:
> Steht doch oben: Mit PROGMEM.

Ja... so ;-)
1
#include <avr/pgmspace.h>
2
3
const uint8_t F6x8[][6] PROGMEM =
4
{
5
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   //sp0
6
    { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !1
7
    { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "2
8
    { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #3
9
    { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 },   // $4
10
    { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 },   // %5
11
     ...



> Es steht auch schon dort, dass sein "Grafik-RAM" das Problem ist und
> nicht die Fonts.

Sicher? Weil wenn ich die font.h auskommentiere habe ich keine 
Platzprobleme.

von Arduinoquäler (Gast)


Lesenswert?

Matthias M. schrieb:
> PROGMEM ignoriert der Compiler (AVR Studio 7) vollkommen

Woran erkennst du das?

Versuche
1
#include <avr/pgmspace.h>

in der Datei die den/die Font(s) deklariert.

von Peter II (Gast)


Lesenswert?

Matthias M. schrieb:
> Weil wenn ich die font.h auskommentiere habe ich keine
> Platzprobleme.

das zeigt aber auch das nächste Problem. Der Array sollte nicht in einer 
Header Datei stehen. Das macht man in eine c Datei.

von Arduinoquäler (Gast)


Lesenswert?

Mein WinAVR2010

macht das so korrekt (ins Flash)
1
#ifndef __FONT_H
2
#define __FONT_H
3
4
#include <avr/pgmspace.h>
5
6
const uint8_t PROGMEM F6x8[][6] = 
7
{
8
    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },   //sp0
9
    { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 },   // !1
10
    { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 },   // "2
11
    { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 },   // #3
12
...........

Device: atmega1284p

Program:    1052 bytes (0.8% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

Build succeeded with 0 Warnings...

von Arduinoquäler (Gast)


Lesenswert?

Arduinoquäler schrieb:
> macht das so korrekt (ins Flash)

... ja, in einer Datei <Fonts.c>

von Matthias (matthiasm)


Lesenswert?

Es liegt am Grafik-Ram. Der ist einfach zu groß... Mist.

Wenn ich den verkleinere dann läuft alles wunderbar.

:(

von Rudolph R. (rudolph)


Lesenswert?

Auch wenn das Display vielleicht sehr preiswert war, das ist nicht 
wirklich eine gute Wahl für die kleinen 8-Bit AVR.
Vor allem nicht mit Bild-Puffer.

Was anderes als SPI-Transfers wird der quasi nicht mehr machen und 
dennoch nur auf ein paar Bilder pro Sekunde komme.

Mit einem FT81x basiertem TFT hat man da erheblich mehr Freude, etwa dem 
RVT70UQFNWC00 von Riverdi.
Oder wenn es billiger sein soll sowas wie das FT811CB-HY50HD von HAOYU 
(hotmcu.com).
Auch wenn 800x480 in 5" für Bedien-Oberflächen etwas dumm sind und 
selbst 7" eigentlich noch zu klein für die Auflösung sind.
Naja, hauptsache große Zahlen fürs Marketing Geblubber, sieben RGB-Pixel 
pro Millimeter sind ja viel zu wenig und so, zwar Briefmarke aber 
Full-HD bitte...

Beitrag "FT800 / FT810 Library"

Die FT8xx haben auch gleich Zeichensätze mit eingebaut.
Der Witz an den Dingern ist, dass die quasi eine Grafik-Karte für 
MikroController sind, die nehmen dem Controller so richtig viel ab.
Statt nen Haufen Pixel für einen Button hinzuschicken den die Grafik-Lib 
auch noch ausrechnen muss schickt man dem nen Satz Daten über den SPI 
für Kommandos:
1
ft800_cmd_dl(TAG(12));
2
t800_cmd_button(150, 100, 100, 20, 26, button, "Click");

Das sind 3 Bytes Adresse, plus 16 Bytes Kommando plus 8 Bytes für den 
Text (muss durch vier teilbar sein) -> 27 SPI Transfers für das 
ft800_cmd_button() da oben.
Die Parameter dabei sind x-pos, y-pos, x-size, y-size, font-nummer, 
options.
In der Variable "button" steht drin, ob der Button flach oder in 3D 
gezeichnet werden soll und das mache ich abhängig davon, ob der Button 
als gedrückt erkannt wurde oder nicht.

Um den Touch kümmert sich der FT8xx selber, man weist einem einzelnen 
Objekt oder auch ganzen Gruppen von Objekten ein TAG zu.
Dann liest man einfach das Register dazu aus.
Touch-Koordinaten berechnen und selber ausrechnen, was auf dem 
Bildschirm gerade getroffen wurde wird komplett überflüssig.

Ich fahre die Dinger normalerweise mit 40 Bildern pro Sekunde, einfach 
weil es nichts kostet da 500+ Bytes alle 25ms hin zu schicken.
Das könnte man noch optimieren so das nur eine neue Display-Liste 
geschickt wird wenn auch Änderungen sind, dann müsste man aber auch 
aufpassen, dass das nicht häufiger als etwa 60 Bilder pro Sekunde wird.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Matthias M. schrieb:
> Es liegt am Grafik-Ram. Der ist einfach zu groß... Mist.

Das ist kein Mist, das ist auch kein Problem, da Dein Display sein 
Grafik-RAM in der benötigten Größe 'on board' hat.

Ein Grafik-RAM benötigt man z.B. bei LED-Matrix-Displays (Laufschrift, 
Displays an Häuser-Fassaden, ...).

Was machst Du z.B. bei 320x240 Pixel oder mehr in RGB?

Hier mal ein Beispiel: LCD_fillScreen, LCD_fillRect, LCD_DrawPixel, 
LCD_setViewport usw. schreiben direkt in das Display. Hier ist das zwar 
ein LCD-Controller, aber bei Deinem OLED müsste das so ähnlich gehen.

https://github.com/TorstenC/A137_TouchTFT_320x240/tree/master/Mikrocontroller/Atmel%20Studio/TimeTimer

Zum FT800: Brauchst Du einen Touch-Screen oder animierte Grafiken?

: Bearbeitet durch User
von Matthias (matthiasm)


Lesenswert?

Also erstmals Danke für eure zahlreichen Antworten! Danke auch an Rudolf 
bezüglich der FT800 Controller. Ich kenen diese, hab ich auf der 
Embedded World gesehen und ein Bekannter verwendet diese beruflich.
Für meinen Zweck war das aber einfach zu oversized und teuer. Bin da 
aber auch etwas blauäugig ran gegangen und dachte mir, die paar Zeichen 
wirst ja noch aufs Display bringen ;-)

Torsten C. schrieb:
> aber bei Deinem OLED müsste das so ähnlich gehen.

Hmm... also bei Kreisen und Rechtecken bin ich bei dir, das funktioniert 
auch schon. Dort gibt ich dem Controller einfach den CMD für Rechteck, 
sag ob ausgefüllt oder nicht, Start- Ende- Koordinaten und auf dem 
Display erscheint ein Rechteck.

Aber bei Texten?!

Torsten C. schrieb:
> Zum FT800: Brauchst Du einen Touch-Screen oder animierte Grafiken?

Nein, weder Farbe, noch Touch, noch Animationen...

Ein paar Linien und Texte sind für mich vollkommen ausreichend.

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Matthias M. schrieb:
> Hmm... also bei Kreisen und Rechtecken bin ich bei dir, …
> Aber bei Texten?!

Ich verstehe, dass man dazu unterschieldiche Meinungen haben kann. Meine 
Erfahrung war: Auch Texte mit Anti-Aliasing waren beim "TimeTimer" 
(s.o.) auf einem ATMega328p kein Problem: LCD_DrawGlyph, LCD_DrawChar 
und LCD_DrawSpacer.

: Bearbeitet durch User
von Matthias (matthiasm)


Lesenswert?

Torsten C. schrieb:
> Auch Texte mit Anti-Aliasing waren beim "TimeTimer"
> (s.o.) auf einem ATMega328p

Aber du hast das in C++ geschrieben, oder? Oder kann man in C Funktionen 
überladen?

So ganz verstehe ich deinen Code leider nicht.

Mit LCD_DrawGlyph() pickst du dir ein Zeichen aus deiner Fonts Tabelle 
(die im Flash liegt) heraus und schreibst dieses über LCD_DrawPixel() in 
das RAM vom Display, oder?


@All: wie bringe ich denn die von mir gepostete Lib aus dem 1. Post dazu 
den Text auf das Display zu packen? Ohne den RAM im µC vorzuhalten?

: Bearbeitet durch User
von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Matthias M. schrieb:
> Aber du hast das in C++ geschrieben, oder? Oder kann man in C Funktionen
> überladen?

Es wird aber nur Überladung genutzt und die Typ-Sicherheit war recht 
angenem. Weder Klassen noch new(). Die Code-Schnippsel sind also mit 
wenigen Änderungen direkt in C nutzbar.

Das Beispiel funktioniert zwar (den TimeTimer hatte mein Sohn eine Zeit 
lang in der Schule benutzt), das Beispiel ist aber nur als Vorlage und 
nicht zur direkten unveränderten Übernahme in ein neues Projekt 
geeignet. Die Font-Dateien hatte ich damals mit einem VisualStudio .NET 
Programm für die benötigten Glyphen erzeugt.

> So ganz verstehe ich deinen Code leider nicht.

Frag ruhig nach, wenn Du magst, ich ergänze gern entsprechende 
Kommentare.

Aber das Beispiel soll keine fertige universelle Lib sein, siehe auch 
"// TODO:" im Quelltext.

> Mit LCD_DrawGlyph() pickst du dir ein Zeichen aus deiner Fonts Tabelle
> (die im Flash liegt) heraus und schreibst dieses über LCD_DrawPixel() in
> das RAM vom Display, oder?

Genau:
https://github.com/TorstenC/A137_TouchTFT_320x240/blob/master/Mikrocontroller/Atmel%20Studio/TimeTimer/Fonts.cpp#L115
Vorher wird ein Viewport gesetzt, weil der Display-Controller dann 
automatisch nach einem DrawPixel in die nächste Spalte springt, wenn die 
Spalte davor voll ist. Ob Dein OLED-Controller sowas kann, steht im 
Datenblatt.

PS: Schrift mit Kantenglättung auf Hintergrund-Grafik geht so natürich 
nicht, dann wären wir wieder beim Grafik-RAM. Aber 'einfarbig' mit 
Kantenglättung auf 'einfarbig' könnte man so auch umsetzen.

PPS: Das hier ist eine Grafik und nicht mit dem o.g. Code erzeugt:
https://www.mikrocontroller.net/attachment/207191/DSC_6548.jpg
Mit Farbverlauf im Hintergrund und Schatten-Effekt an der Schrift. Da 
wollte ich mal hin, aber das war mir aus dem o.g. Grund zu aufwendig.

Für Schatten könnte man machen statt:
// (0x1 = Hintrergrund .. 0xE = Vordergrund)
den Bereich halbieren:
// (0x1 = Hintrergrund .. 0x8 = Vordergrund)
// (0x9 = Hintrergrund .. 0xE = Schatten)
Siehe:
https://github.com/TorstenC/A137_TouchTFT_320x240/blob/master/Mikrocontroller/Atmel%20Studio/TimeTimer/Fonts.cpp#L65

: Bearbeitet durch User
von Matthias (matthiasm)


Angehängte Dateien:

Lesenswert?

Leute ich brauch eure Hilfe... komm einfach nicht weiter mit der 
Textausgabe.

Display füllen, Linien und Rechtecke in verschiedenen Graustufen ist 
alles schon möglich und läuft.

Aber wie bringe ich ein Zeichen aus meinem Fonts Array auf das Display??

mein Array sieht so aus:
1
const uint8_t PROGMEM F4x6[95][3] = {
2
        {0x00,0x00,0x00},  //??
3
        {0x44,0x40,0x40},  //!
4
        {0xAA,0x00,0x00},  //"
5
        {0xAE,0xAE,0xA0},  //#
6
        {0x6C,0xE6,0xC0},  //$
7
        {0xA2,0x48,0xA0},  //%
8
        {0x4A,0x4A,0xE0},  //&
9
        {0x44,0x00,0x00},  //'
10
        {0x48,0x88,0x40},  //(
11
        {0x42,0x22,0x40},  //)
12
        {0x04,0xA4,0x00},  //*
13
        {0x04,0xE4,0x00},  //+
14
        {0x00,0x04,0xC0},  //,
15
        {0x00,0xE0,0x00},  //-
16
        {0x00,0x00,0x40},  //.
17
        {0x24,0x44,0x80},  //
18
        {0xEA,0xAA,0xE0},  //0
19
        {0x44,0x44,0x40},  //1
20
        {0xE2,0xE8,0xE0},  //2
21
        {0xE2,0xE2,0xE0},  //3
22
        {0xAA,0xE2,0x20},  //4
23
        {0xE8,0xE2,0xE0},  //5
24
        {0xE8,0xEA,0xE0},  //6
25
        {0xE2,0x22,0x20},  //7
26
        {0xEA,0xEA,0xE0},  //8
27
        {0xEA,0xE2,0xE0},  //9
28
        {0x04,0x04,0x00},  //:
29
        {0x04,0x04,0xC0},  //;
30
        {0x24,0x84,0x20},  //<
31
        {0x0E,0x0E,0x00},  //
32
        {0x84,0x24,0x80},  //>
33
        {0x4A,0x24,0x40},  //?
34
        {0xEA,0xEC,0xE0},  //@
35
        {0x4A,0xAE,0xA0},  //A
36
        {0xCA,0xCA,0xC0},  //B
37
        {0x68,0x88,0x60},  //C
38
        {0xCA,0xAA,0xC0},  //D
39
        {0xE8,0xE8,0xE0},  //E
40
        {0xE8,0xE8,0x80},  //F
41
        {0xE8,0xAA,0xE0},  //G
42
        {0xAA,0xEA,0xA0},  //H
43
        {0xE4,0x44,0xE0},  //I
44
        {0xE4,0x44,0xC0},  //J
45
        {0xAC,0x8C,0xA0},  //K
46
        {0x88,0x88,0xE0},  //L
47
        {0xAE,0xAA,0xA0},  //M
48
        {0xAE,0xEE,0xA0},  //N
49
        {0x4A,0xAA,0x40},  //O
50
        {0xEA,0xE8,0x80},  //P
51
        {0x4A,0xAE,0x60},  //Q
52
        {0xEA,0xEC,0xA0},  //R
53
        {0x68,0x42,0xC0},  //S
54
        {0xE4,0x44,0x40},  //T
55
        {0xAA,0xAA,0xE0},  //U
56
        {0xAA,0xAA,0x40},  //V
57
        {0xAE,0xEE,0x40},  //W
58
        {0xAA,0x4A,0xA0},  //X
59
        {0xAA,0xE4,0x40},  //Y
60
        {0xE2,0x48,0xE0},  //Z
61
        {0xC8,0x88,0xC0},  //[
62
        {0x84,0x44,0x20},  /*\*/
63
        {0x62,0x22,0x60},  //]
64
        {0x4A,0x00,0x00},  //^
65
        {0x00,0x00,0xE0},  //_
66
        {0x84,0x00,0x00},  //`
67
        {0x04,0xAC,0x60},  //a
68
        {0x88,0xEA,0xE0},  //b
69
        {0x0E,0x88,0xE0},  //c
70
        {0x22,0xEA,0xE0},  //d
71
        {0x4A,0xE8,0x60},  //e
72
        {0x64,0xE4,0xC0},  //f
73
        {0x6A,0xE2,0x60},  //g
74
        {0x88,0xEA,0xA0},  //h
75
        {0x40,0x44,0x40},  //i
76
        {0x20,0x62,0x60},  //j
77
        {0x8A,0xCC,0xA0},  //k
78
        {0x88,0x8A,0xC0},  //l
79
        {0x00,0xEE,0xA0},  //m
80
        {0x00,0xAE,0xA0},  //n
81
        {0x04,0xAA,0x40},  //o
82
        {0x4A,0xAC,0x80},  //p
83
        {0x4A,0xA6,0x20},  //q
84
        {0x8E,0xA8,0x80},  //r
85
        {0x68,0xE2,0xC0},  //s
86
        {0x44,0xE4,0x60},  //t
87
        {0x0A,0xAE,0x60},  //u
88
        {0x0A,0xAE,0x40},  //v
89
        {0x0A,0xAE,0xA0},  //w
90
        {0x00,0xA4,0xA0},  //x
91
        {0xAA,0xA4,0x80},  //y
92
        {0x0E,0x24,0xE0},  //z
93
        {0x64,0x84,0x60},  //{
94
        {0x44,0x44,0x40},  //|
95
        {0xC4,0x24,0xC0},  //}
96
        {0x02,0xE8,0x00},  //~
97
};

Das Zeichnen eines Pixels mache ich z.B. so:
1
void drawPxl()
2
{
3
  unsigned char x,y;
4
  writeDisp(0x15, CMD); /* set column address */
5
  writeDisp(0x15, CMD); /* set column start address */
6
  writeDisp(0x3f, CMD); /* set column end address */
7
  writeDisp(0x75, CMD); /* set row address */
8
  writeDisp(0x15, CMD); /* set row start address */
9
  writeDisp(0x3f, CMD); /* set row end address */
10
  
11
   writeDisp(0xFF, DATA); /* write Pixel with full brightness (0x00 = black) */
12
13
}

Das sieht dann so aus wie auf dem Bild im Anhang. Allerdings zeichnet er 
auf der horizontalen immer zwei Pixel... finde ich auch noch etwas 
"strange".

EDIT: Das mit den zwei Pixeln hab ich soeben rausgefunden:

-> writeDisp(0xFF, DATA); -> beschreibt 2 Pixels
-> writeDisp(0xF0, DATA); -> beschreibt 1 Pixel (das Linke)
-> writeDisp(0xF0, DATA); -> beschreibt 1 Pixel (das Rechte)

Sooo... nun aber, wie bringe ich es fertig dass ich z.B. folgende 
Funktion drawString("Hello World") aufs Display bringe??

Die Funktion drawString() muss mir dann ja für jeden Buchstaben den 
jeweiligen HexCode aus der Font Tabelle raussuchen, oder? Aber wie bring 
ich die Hex Zeichen dann aufs Display?

Ich hoffe ihr könnt mir helfen :)

Danke!!

: Bearbeitet durch User
von Matthias (matthiasm)


Lesenswert?

Matthias M. schrieb:
> -> writeDisp(0xF0, DATA); -> beschreibt 1 Pixel (das Rechte)

muss natürlich so heißen:

-> writeDisp(0x0F, DATA); -> beschreibt 1 Pixel (das Rechte)

von Arduinoquäler (Gast)


Lesenswert?

Matthias M. schrieb:
> muss natürlich so heißen:

... und ich dachte immmer: jedes Pixel bekommt 16 Bit.

Wieder was dazugelernt.

Again what learned sachd der Loddar.

von Matthias (matthiasm)


Angehängte Dateien:

Lesenswert?

Ich habe hier in einer anderen Lib ein recht übersichtliches Beispiel 
gefunden.

Benötige aber auch hier etwas Hilfestellung:

Hier wird ein CHAR Zeichen übergeben... angenommen wir möchten ein "r" 
zeichnen würde der Aufruf doch LCD_UC1701_PRINT_ASC(r) lauten, oder?
1
void LCD_UC1701_PRINT_ASC(unsigned char wert) { // zeichnet ein ASCII

So nun wird geschaut an welcher Stelle im Array das Zeichen steht:
1
// position im Array berechnen
2
c_pos=wert-LCD_FIRST_CHAR;

Etwas umgeschrieben heißt das doch: c_pos = r-0x20 ??

Habe ich da einen Knopf im Kopf oder wie kommt das Programm dabei auf 
eine vernünftige Position im Array?

Vielleicht könnt ihr mich erleuchten ;-) Danke!!

: Bearbeitet durch User
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.