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
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.
Progem ist die Lösung. Wie hast du es denn versucht?
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.
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.
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.
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.
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...
Es liegt am Grafik-Ram. Der ist einfach zu groß... Mist. Wenn ich den verkleinere dann läuft alles wunderbar. :(
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.
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
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
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
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
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
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
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)
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.