diese Library dient zum ansteuern des Grafik LC-Displays auf dem STM32F429-Discovery mit dem ILI9341-Chip. (240 x 320 Pixel und 16bit Farbe)
Das Display hängt am TFT-Controller der CPU und wird im RGB-Mode (mit HSync, VSync und 24bit Farben) betrieben. Der Chip selber wird per SPI-5 angesteuert.
(aus dem Grund wird die SPI-5 Library zusätzlich benötigt)
Als Grafik-RAM wird ein Teil vom externen SD-RAM benutzt
(aus dem Grund wird die SDRAM-Library zusätzlich benötigt)
die Library bedient die Grundfunktionen wie Initialisierung, Screen-Ausrichtung, setzen vom Layer und der Transparenz, setzen vom Cursor und löschen vom Layer.
Für die Textausgabe gibt es eine Font-Library
Für Grafik-Funktionen gibt es eine Grafik-Library
Hinweise zu den Layern :
Das Grafik-RAM ist in zwei Layer unterteil. Layer_1 und Layer_2.
Layer_1 = Hintergrund, Layer_2 = Vordergrund.
Beide Layer haben einen Transparenz Wert [0…255]
Nach dem Init ist die Transparenz von beiden auf 255 aus dem Grund ist nur Layer_2 zu sehen (er verdeckt Layer_1). Man kann in beide Layer Daten schreiben und entweder Layer_1 oder Layer_2 oder beide gemischt darstellen.
Dazu muss zuvor per Funtkion “UB_LCD_SetLayer” der aktive Layer ausgewählt werden in den geschrieben oder dessen Transparenz geändert werden soll.
Hinweise zum Refresh :
Um bewegte Objekte darstellen zu können, wird ein Layer angezeigt und der andere wird aktiviert um Daten aufzunehmen. Wenn das beschreiben vom zweiten Layer fertig ist, reicht es, einmal die Funktion “UB_LCD_Refresh” aufzurufen. Diese tauscht den Layer der angezeigt wird mit dem der die Daten aufnimmt.
BUG Hinweis von “Flo” :
Nach Power-On per USB werden falsche Farben angezeigt.
Workaround : In der Funktion “P_LCD9341_InitChip”
einen LCD-Software Reset einfügen
per “P_LCD9341_CMD(0×01)” und danach eine 7ms Pause.
Benutzte Pins :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | PA3 = B5 PD3 = G7 PA4 = VSYNC PD6 = B2 PA6 = G2 PD13 = WRX (CMD/DATA) PA11 = R4 PF7 = SPI_CLK PA12 = R5 PF8 = SPI_MISO PB0 = R3 PF9 = SPI_MOSI PB1 = R6 PF10 = DE (Enable) PB8 = B6 PG6 = R7 PB9 = B7 PG7 = CLK PB10 = G4 PG10 = G3 PB11 = G5 PG11 = B3 PC2 = SPI_CS PG12 = B4 PC6 = HSYNC PC7 = G6 PC10 = R2 |
Standard Farben :
1 2 3 4 5 6 7 8 9 10 11 | #define RGB_COL_BLACK 0x0000 #define RGB_COL_BLUE 0x001F #define RGB_COL_GREEN 0x07E0 #define RGB_COL_RED 0xF800 #define RGB_COL_WHITE 0xFFFF #define RGB_COL_CYAN 0x07FF #define RGB_COL_MAGENTA 0xF81F #define RGB_COL_YELLOW 0xFFE0 #define RGB_COL_GREY 0xF7DE |
Funktionen :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | ErrorStatus UB_LCD_Init(void); // zum init vom Display void UB_LCD_LayerInit_Fullscreen(void); // zum init der Layer void UB_LCD_SetLayer_1(void); // stellt auf Hintergrund Layer void UB_LCD_SetLayer_2(void); // stellt auf Vordergrund Layer void UB_LCD_FillLayer(uint16_t color); // füllt den aktuellen Layer void UB_LCD_SetTransparency(uint8_t wert); // setzt die Transparenz void UB_LCD_SetCursor2Draw(uint16_t xpos, uint16_t ypos); // setzt den Cursor void UB_LCD_DrawPixel(uint16_t color); // zeichnet ein Pixel void UB_LCD_SetMode(LCD_MODE_t mode); // Modus : Portrait,Landscape void UB_LCD_Rotate_0(void); // Rotieren um 0 Grad void UB_LCD_Rotate_180(void); // Rotieren um 180 Grad void UB_LCD_Copy_Layer1_to_Layer2(void); // kopiert Inhalt von Hintergrund zum Vordergrund void UB_LCD_Copy_Layer2_to_Layer1(void); // kopiert Inhalt vom Vordergrund zum Hintergrund void UB_LCD_Refresh(void); // wechselt Layer und zeigt neuen Inhalt an |
Beispiel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | //-------------------------------------------------------------- // File : main.c // Datum : 24.10.2013 // Version : 1.0 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F429 // IDE : CooCox CoIDE 1.7.4 // GCC : 4.7 2012q4 // Module : CMSIS_BOOT, M4_CMSIS_CORE // Funktion : Demo der LCD-Library (ILI9341) // Hinweis : Diese zwei Files muessen auf 8MHz stehen // "cmsis_boot/stm32f4xx.h" // "cmsis_boot/system_stm32f4xx.c" // In Configuration diese Define hinzufügen : // "STM32F429_439xx" , "__ASSEMBLY__" , "USE_STDPERIPH_DRIVER" //-------------------------------------------------------------- #include "main.h" #include "stm32_ub_lcd_ili9341.h" int main(void) { uint32_t n; SystemInit(); // Quarz Einstellungen aktivieren // Init vom LCD UB_LCD_Init(); // Init der Layer UB_LCD_LayerInit_Fullscreen(); // auf Hintergrund schalten UB_LCD_SetLayer_1(); // Hintergrund komplett mit einer Farbe füllen UB_LCD_FillLayer(RGB_COL_WHITE); // auf Vordergrund schalten UB_LCD_SetLayer_2(); // Vordergrund komplett mit einer Farbe füllen UB_LCD_FillLayer(RGB_COL_GREEN); // Cursor setzen UB_LCD_SetCursor2Draw(10,50); // einen roten Strich zeichnen for(n=0;n<100;n++) { UB_LCD_DrawPixel(RGB_COL_RED); } while(1) { } } |
Hier die Library zum Download :
Hier der komplette CooCox-Projektordner zum Download :
Hallo,
danke erstmal für deine Arbeit! Ich beginne gerade damit, mich mit Mikrocontrollern zu beschäftigen und deine Librarys und Infos haben den Start erleichtert und beschleunigt.
Ich hätte eine Frage zu dieser Library:
Man kann ja den Displayinhalt über Memory Access Control (0×36) drehen und spiegeln, indem man die Scanrichtung über die Bits MV, MX, MX verändert. Das verwendest du auch in UB_LCD_Rotate_0 und UB_LCD_Rotate_180.
Vielleicht stehe ich gerade auf dem Schlauch, aber wäre es nicht sinnvoll, genau das für den Landscape-Modus zu benutzen (Command 0×36, Data 0×68 oder 0xA8), damit sich das Koordinatensystem nicht verändert – also z.B. 0,0 weiterhin oben links ist, wenn man das Board dreht, anstatt unten links? Ich weiß nicht, ob man dann nicht noch ein paar andere Dinge anpassen müsste (Sync und/oder LCD_COLUMN_ADDR bzw. LCD_PAGE_ADDR etc.), aber ich denke, dass es so möglicherweise “gedacht” ist, damit man nur initialisieren muss und der Rest mehr oder weniger von selbst passiert.
Falls das kein völliger Unsinn ist (wie gesagt, ich bin Anfänger …), wäre es toll, wenn du dir das mal ansehen könntest.
ja…dann probier das mal und sag bescheid wie es geht…ich habs nicht geschafft. Das Display wird im RGB-Mode angesteuert (mit HSync,VSync) und in dem Mode scheint es IMMER zuerst die Horizontale (kleine) Bildseite zu zeichnen, egal was man in die Register schreibt.
Schade, aber wenn es nicht geht, geht’s eben nicht. Scheint wohl an der Art der Ansteuerung zu liegen. Man kann das Bild drehen, aber dann fehlt auf der langen Seite ein 80 Pixel breiter Streifen (eben 320 – 240). Diesen bekomme ich breiter, aber nie schmaler als 80 Pixel oder gar ganz weg. Habe so etwas inzwischen auch im Mikrocontroller-Forum und auf my.st.com gelesen.
Hallo,
tolle webseite.
Habe eine Anwendung in der das externe RAM sinnvoll wäre aber das display zweitrangig ist, zumindest nicht die schnelle Ansteuerung nötig ist bzw. das display besser separat vom board. Ist es möglich/sinnvoll die Display Pins anders zu nutzen bzw. welche Pins bleiben trotzdem nicht nutzbar und müssen auf high oder low gesetzt werden. Kenn mich nicht so aus, aber könnte mir z.B. vorstellen wenn ich das display im Dauerreset halte, dass dann die uC pins nutzbar sind (brauche insgesamt 16 inputs + 16 outputs). Die meinsten Pins sind ja bei diesem Demo board schon vorbelegt…
Wenn jemand das auf die schnelle überblickt würde ich mich über einen Tipp freuen.
Danke.
wenn du das Display gar nicht brauchst, kannst du es auch komplett vom Eval-Board runterlöten. Das hat “Vampire” gemacht und dann einen VGA-Monitor angeschlossen. Hier ist die Pinbelegung zu finden : http://mikrocontroller.bplaced.net/wordpress/?page_id=2848
Es müssen keine Pins der CPU auf irgendwelche festen Signale gelegt werden.
Könnte man eigentlich auch per DMA auf einem Layer bzw. zwischen den beiden Layern alles oder Bereiche kopieren? Also so ähnlich wie mit UB_Graphic2D_CopyImgDMA in der 22-Graphic-DMA2D-Library, aber mit einem der Layer als Quelle?
klar, dem DMA ist egal woher er die Daten holt. Die Source-Adresse muss dann halt eine aus dem externen SD-RAM sein. Ich hab hier ein Beispiel das einen kompletten Screen (320×240) vom SD-RAM in einen anderen Bereich kopiert. (aus dem Oszi-Projekt)
Super, danke! Das ist sehr nützlich. Ich hatte befürchtet, dass es dabei irgendwelche Einschränkungen gibt.
Hi Uwe, is it possible to use other than spi5? Because I need to use 16 channels ADC.
Thanks,
The connection of the LCD on the STM32F429i-Disco-Board is fix. You cant change it without removing the complete display. Also you have not enough free ADC-Pins, only 4 are available (have a look on the pinout : http://mikrocontroller.bplaced.net/wordpress/wp-content/uploads/2013/10/Pinbelegung_f429_v100.html)
I’ll design a new board with 4.3″-7″ tft lcd. So, how should I use the pins configuration for 16 channels adc? I am wating your advise.
in a “new” design you are free to choose any SPI-Channel you want. But you can also add a 16-to-1 analog Multiplexer, in this case you only need one free ADC-Channel.
a little bit Fehler oben in der Pin-Liste:
PA3 = B5
Gruß Helmut
danke, ist auch im Source-File falsch !
Bei mir waren nach einem Power-on durch Stecken des USB-Kabels am STM32F429I-DISCO immer die Farben invertiert. Erst nach Reset durch Flashen oder den Reset-Button waren die Farben richtig.
In P_LCD9341_InitChip habe ich ganz am Anfang ein P_LCD9341_CMD (0×01) gefolgt von 7 ms Wartezeit eingebaut (5 ms reichen laut Datenblatt, aber man weiß ja nie). Das macht einen Software-Reset des LCD-Controllers und dann stimmen auch beim Kaltstart die Farben.
Danke, habe den Hinweis als “BUG” vermerkt.
Wie kann ich das LCD in ein absolut leeres Projekt einbinden also nur
die main.h mit noch nichts inizialisiert wie gehe ich da vor?
Das Projekt von hier “Demo_07″ ist doch absolut leer. Weniger geht nicht. was du machen kannst, ist alles innerhalb der Main.c löschen…aber dann fehlt dir die Initialisierung vom LCD !!!
MoinMoin,
ich hab mich auch mal an der Libary fürs Display auf dem STM32F429 Disco Board befasst, und wie Flo auch festgestellt, dass das Display nach PowerOn “rumspinnt”.
Jedoch wirft das Workaround bei mir nen Fehler:
”
[cc] C:\Users\Ichich\Desktop\ub_lib\font\ub_lib\stm32_ub_lcd_ili9341.c: In function ‘P_LCD9341_InitChip’:
[cc] C:\Users\Ichich\Desktop\ub_lib\font\ub_lib\stm32_ub_lcd_ili9341.c:526:3: error: stray ‘\327′ in program
[cc] P_LCD9341_CMD(0×01);
[cc] ^
[cc] C:\Users\Ichich\Desktop\ub_lib\font\ub_lib\stm32_ub_lcd_ili9341.c:526:19: error: expected ‘)’ before numeric constant
[cc] P_LCD9341_CMD(0×01);
[cc] ^
[cc] C:\Users\Ichich\Desktop\ub_lib\font\ub_lib\stm32_ub_lcd_ili9341.c:525:12: warning: unused variable ‘i’ [-Wunused-variable]
[cc] uint32_t i;
[cc] ^
”
Scheinbar wird P_LCD9341_CMD(0×01) nirgendwo definiert. Könntest du mir sagen, wie und wo ich was definieren muss, damit das Softreset vom LCD klappt?
Vielen Dank im vorraus und mit freundlichen Grüßen
Chaos
dein Fehler muss woanders liegen (die Zeile stimmt). Starte nochmal mit dem laufenden Projekt von hier und füge folgendes in die “P_LCD9341_InitChip” per Copy&Paste ein
Danke für die Antwort, ich hab meinen Fehler inzwischen gefunden. Ich hatte wohl in der falschen Reihenfolge includiert. Nachdem ich nun als erstes die stm32f4xx.h einbinde, klappt alles problemlos.
Noch viel mehr Dank als für die Antwort, gebührt dir für deine Libs, sie funktionieren, nachdem man eigene Fehler ausgemerzt hat, tadellos.
Ein kleiner Tipp, der meiner Meinung nach die Farbwahl erleichtert:
uint8_t Rot, Gruen, Blau;//Rot 0-31, Gruen 0-63, Blau 0-31
uint16_t Farbe;
Farbe = (Rot << RGB_R) | (Gruen << RGB_G) | (Blau << RGB_B);
UB_LCD_DrawPixel(Farbe);
MfG Chaos
P.S.
Ich hab die entsprechenden defines vergessen, hier nochmal die richtige Version:
#define RGB_R 11
#define RGB_G 5
#define RGB_B 0
uint8_t Rot, Gruen, Blau; //Rot 0-31, Gruen 0-63, Blau 0-31
uint16_t Farbe;
Farbe = (Rot << RGB_R) | (Gruen << RGB_G) | (Blau << RGB_B);
UB_LCD_DrawPixel(Farbe);
Ist es eigentlich auch möglich, den 18Bit-Farbmodus mit deiner Lib zu starten? Bzw kannst du mir auf die Schnelle sagen, was ich da umschreiben müsste?
Mit Dank und freundlichen Grüßen im Voraus,
Chaos
da musst du im Datenblatt vom Display nachlesen.
Hallo
ist es auch möglich, das Display ohne den SDRAM zu nutzen? Kann man in deiner Lib den SDRAM deaktivieren?
Danke