Recent changes
Slingshot user guide
tag Guide, user
NFCLamp user guide
tag Guide, user
Homepage
MPL115A2
Compiler Error 42
From the mbed microcontroller Cookbook.  

SPI driven QVGA TFT

The TFT from MikroElektronika http://www.mikroe.com/eng/products/view/474/tft-proto-board/ come on a pcb with a easy to use pinout.

/media/uploads/dreschpe/tft_proto_01.jpg

Connecting to the mbed

The board use 3.3V so we can attach it direct to the mbed. The backlite LED need a resistor to limit the current. I use two 10R resistors parallel to get 5R driven by 3.3V.

The interface can be driven in 16 bit,8 bit, 18 bit, 9 bit or SPI mode. Because I don't want to spend all mbed IOs to the display I use the SPI mode. The IMx-pins have to set to IM0,IM1,IM3 : GND, IM2 : 3.3V. The RST pin is connected to reset, RS and FMARK are not used.

For SPI mode we need only the tree SPI signals, a cs and a reset signal. 5 pins at all. SPI is serial and we have to transfer 320 * 240 * 16 = 1228800 bits to the display to fill it up. Will it be to slow ? No ! We can drive the SPI to display with 48Mhz clock speed ! 50Mhz is the limit, but the mbed is running at 96Mhz and we can divide this clock by two.

/media/uploads/dreschpe/tft.png

Software: SPI_TFT library

latest Version :

DMA use

I have change the code to use DMA transfer, please test - there are a lot of changes.

The lib is using the SSEL0 or SSEL1 signal to generate the CS. This is faster, but you have to use PIN8 for CS if you use SPI on PIN 5-7 or you have to use PIN14 for CS if you use SPI on PIN 11-13.

The cls() is six times faster !
http://mbed.org/users/dreschpe/libraries/SPI_TFT/m83izx

If you run into problems please use the old lib :
http://mbed.org/users/dreschpe/libraries/SPI_TFT/m369bx
This will also run on LPC11U24, but the flash is limited for the fonts.

How to get nice looking fonts ?

To print characters to a graphic screen we need a font. To code a font by paper is ok for a small lcd, but for a 320*240 pixel display we need bigger fonts. A 12*12 pixel font is readable, but a lot of work to construct.

Fonts can be made with the GLCD Font Creator also from http://www.mikroe.com .

With this program you can load a window font and convert it into a c-array. To use this Font with my lib you have to add 4 parameter at the beginning of the font array. - the number of byte / char - the vertial size in pixel - the horizontal size in pixel - the number of byte per vertical line (it is vertical size / 8 ) You also have to change the array to char[]. After that you can switch between different fonts with set_font(unsigned char* font); The horizontal size of each character is also stored in the font. It look better if you use bigger fonts or italic. The letter M is wider than a l.

Text commands :

You can use the claim() function to redirect the output to stdout or stderr to the TFT. After claim(stdout) you can simply use the printf function to print to the TFT.

There are two parameter to setup the color of the text :

Graphic commands :

How to transfer a grafic to the mbed ?

The hard way - but fast to load :

Load from mbed flash. To construct a bitmap array we can use gimp. http://www.gimp.org/ Load a image (edit and resize) and save it as BMP. You have to select the option 16 bit R5 G6 B5 !

To convert this file into a c-array you can use the hex-editor winhex. (http://www.x-ways.net/winhex/index-m.html) The eval version can handle the small files. We don`t need the bmp header. Mark the data starting at offset 0x46 to the end of file. Use "edit -> copy block -> C Source" to export this data as C array. Paste the data into a C file into the mbed compiler. The editor will generate a array of char[]. To use 16 bit DMA on this we have to put a __align(2) in front of the definition. To put it into Flash we change it to static const unsigned char bmp[]{...}

Code

__align(2)
static const unsigned char bmp[]{
      0xCB, 0x5A, 0x5C, 0xE7,....

};

The easy way - but slower to load:

With the BMP_16 command we can load a picture out of the internal drive to the display.

simply copy test.bmp to mbed usb drive - saved with the options 16 bit R5 G6 B5 and load it.

The demo code : (It is difficult to make pictures from the screen - it looks better)

Code

 // example to test the TFT Display
 // Thanks to the GraphicsDisplay and TextDisplay classes from 

#include "stdio.h"
#include "mbed.h"
#include "SPI_TFT.h"
#include "string"
#include "Arial12x12.h"
#include "Arial24x23.h"
#include "Arial28x28.h"
#include "font_big.h"

extern unsigned char p1[];  // the mbed logo

// the TFT is connected to SPI pin 5-7 
SPI_TFT TFT(p5, p6, p7, p8, p15,"TFT"); // mosi, miso, sclk, cs, reset

int main() {
    int i;
    TFT.claim(stdout);      // send stdout to the TFT display 
    //TFT.claim(stderr);      // send stderr to the TFT display

    TFT.background(Black);    // set background to black
    TFT.foreground(White);    // set chars to white
    TFT.cls();                // clear the screen
    TFT.set_font((unsigned char*) Arial12x12);  // select the font
      
    // first show the 4 directions  
    TFT.set_orientation(0);
    TFT.locate(0,0);
    printf("  Hello Mbed 0");
    TFT.set_orientation(1);
    TFT.locate(0,0);
    printf("  Hello Mbed 1");
    TFT.set_orientation(2);
    TFT.locate(0,0);
    printf("  Hello Mbed 2");
    TFT.set_orientation(3);
    TFT.locate(0,0);
    printf("  Hello Mbed 3");
    TFT.set_orientation(1);
    TFT.set_font((unsigned char*) Arial24x23);
    TFT.locate(48,115);
    TFT.printf("TFT orientation");
       
    wait(5);        // wait two seconds 

/media/uploads/dreschpe/orientation.jpg

Code

 // draw some graphics 
    TFT.cls();          
    TFT.set_orientation(1);
    TFT.set_font((unsigned char*) Arial24x23);
    TFT.locate(120,115);
    TFT.printf("Graphic");
     
    TFT.line(0,0,100,200,Green);
    TFT.rect(100,50,150,100,Red);
    TFT.fillrect(180,25,220,70,Blue);
    TFT.circle(80,150,33,White);

/media/uploads/dreschpe/graphic.jpg

Code

 wait(5);        // wait two seconds
    
    // bigger text
    TFT.foreground(White);
    TFT.background(Blue);
    TFT.cls();
    TFT.set_font((unsigned char*) Arial24x23);
    TFT.locate(0,0);
    TFT.printf("Different Fonts :");
    
    TFT.set_font((unsigned char*) Neu42x35);
    TFT.locate(0,50);
    TFT.printf("Hello Mbed 1");
    TFT.set_font((unsigned char*) Arial24x23);
    TFT.locate(50,100);
    TFT.printf("Hello Mbed 2");
    TFT.set_font((unsigned char*) Arial12x12);
    TFT.locate(55,150);
    TFT.printf("Hello Mbed 3");

/media/uploads/dreschpe/fonts.jpg

Code

wait(5);
  
    // mbed logo  
    TFT.set_orientation(1);
    TFT.background(Black);
    TFT.cls();
    TFT.Bitmap(90,90,172,55,p1);
}

/media/uploads/dreschpe/logo.jpg

The touchscreen

The Touch_tft class is derived from the SPI_TFT class.

I add the support for the touchscreen :

http://mbed.org/users/dreschpe/notebook/touchscreen/

http://mbed.org/users/dreschpe/libraries/Touch_tft/lx1972

/media/uploads/dreschpe/_scaled_touch.jpg

A Demo to use the touch function : http://mbed.org/users/dreschpe/notebook/micro-paint/




calendar Page history
Last modified 1 week, 2 days ago, by   user Peter Drescher   tag LCD, QVGA, TFT | 30 comments  

30 comments on SPI driven QVGA TFT:

15 Aug 2011

Colour LCD for the masses. This looks very cool indeed.They are available from www.mcustore.com in Southampton.

06 Sep 2011

Hey Peter, I noticed that you've updated your TFT / touch routines yesterday. Anything important in the updates? ...kevin

06 Sep 2011

Hello Kevin, i change the locate function to index pixel. You can place the text more precise. After that i realize that other people are using this lib and have to change the code. I think i will add a locate_xy function to address pixel and change back the locate to row and column. Minor fix : I changed the numbers fonts to a constant wide. It looks better if you print out numbers. I also patch a bug inside the Bitmap function. You have to padd the number of data in a line to a multiple of 4.

Peter

15 Sep 2011

Hi Peter, This is a very nice piece of work. It saved me a load of time and the display boards are very reasonably priced. Also, mine was delivered extremely fast, actually the next day.

I have a minor problem, perhaps someone can help. When I try to compile the example code, it fails because the linker can't find the external char p1[] (the MBED bitmap). Have you published this, or can you tell me where I can get a copy? Much thanks in advance,

Mark

15 Sep 2011

You could use google, and find the software to make the image into an array. Or of course, the easy way: Wait for him to answer ;-)

Lerche

15 Sep 2011

This is probably the BEST graphical LCD I have used, so easy (with your code)

hear are two test files to replace p1,

a R5G6B5 version (not tested, because I have modified the code to read standard Windows 24 Bit RGB)

... just remove the .pdf on the end (I hope)

/media/uploads/ceri/mbed16.bmp.pdf

/media/uploads/ceri/mbed24.bmp.pdf

Enjoy

Ceri

15 Sep 2011

Not possible to open files, not recognized. Rename the .bmp to .doc, and upload again, this should be possible.

Lerche

15 Sep 2011

I have tested them just now, download file, then remove the .pdf from end of file name.

Ceri

15 Sep 2011

Try this file. I converted it using GIMP 2.6.11. Be sure to remove the ".txt" from the file name before using. Use orientation 0 on TFT to load the image.

...kevin

/media/uploads/loopsva/test.bmp.txt

16 Sep 2011

Here is the code with the graphic: http://mbed.org/users/dreschpe/programs/TFT/lxnh2g

The fastest way to get a graphic to the screen is to load it with GIMP, save it as BMP with options 16 bit R5 G6 B5 and put it to the mbed drive.

Code

BMP_16(x0,y0,myfile.bmp);

will load the picture.

Hint : it is slow, compared with the flash.

...Peter

19 Sep 2011

Very good Peter! Your work is great! I can't visualize bitmap if I use -Bitmap function of TFT library:why? I followed your instructions that are: 1) convert bitmap 16 in array C trhough WinHex from address 0x46 2) create an array in the project 3)call Bitmap function with orientation = 0 for example

Image doesn't appear : why?

Obviusly if I use BMP16 it works fine; can you or anyone help me?

Thanks

19 Oct 2011

Please have you got an example of bmp file with the corresponding C array ? The function "Bitmap" doesn't work, I think that conversoin is the problem Thanks

19 Oct 2011

Hello GB R

can u upload as a sample of your c arry and how are u calling it using Bitmap ... i already used this function successfully

19 Oct 2011

user Mesbah Uddin Mohammed wrote:

Hello GB R

can u upload as a sample of your c arry and how are u calling it using Bitmap ... i already used this function successfully

certainly. This is the functions

  1. include "p1.h"

extern unsigned char data[];

TFT.Bitmap(90,90,172,55,data);

p1.h is in attachment with the corresponding .bmp /media/uploads/giamby3000/icon.zip I followed your instructions that are: 1) convert bitmap 16 in array C trhough WinHex from address 0x46 2) create an array in the project 3)call Bitmap function Thanks

20 Oct 2011

The problem is here:

TFT.Bitmap(90,90,172,55,data); coordinates isn't correct with bmp weight and height

thanks!

23 Nov 2011

Can anyone help, we have modified the library for the BMP16 method within the SPI_TFT file to use the SD card as a source for the bitmap files. This works well for 2 images but when we try to put a 3rd image up it does not show. I have been through the code but can't find the fault. Can anyone help? We are using the SD Card Filesystem as in the cookbook. Thanks...

23 Nov 2011

Hello Mark, have you try to load this image from the internal drive ? The image has to be 16 bit. The code test if the image fits on the screen. At the moment my code does not clip the picture.

Peter

12 Dec 2011

Hi Peter,

I'm having trouble with the pixel function, I was wondering if you (or anyone else) could help? I'm trying to make the screen display a graph of some data using the pixel command, this wasn't working, so I worked back to trying to output a few pixels when it initialises the graph axis and that's not working either, can you see what I'm doing wrong?

Code

void DrawGraphOutline(void) {
    //Draw Graph Outline Function
    
    tt.line(0,220,319,220,Black);               // Graph Line Across
    tt.line(25,25,25,239,Black);                // Graph Line Down  
    
    tt.locate(1,1);
    printf("Temps");
    
    tt.locate(260,222);                         // X axis labels
    printf("1");    
    tt.locate(200,222);
    printf("2");    
    tt.locate(140,222);
    printf("3");    
    tt.locate(80,222);
    printf("4");
    
    tt.locate(1,170);                         // Y axis labels
    printf("25");    
    tt.locate(1,120);
    printf("50");
    tt.locate(1,70);
    printf("75");
    
    tt.pixel(150, 150, Red);
    tt.pixel(150, 151, Red);
    tt.pixel(150, 149, Red);
    tt.pixel(151, 150, Red);
    tt.pixel(149, 150, Red);
    
    tt.pixel(50, 150, Red);
    tt.pixel(50, 151, Red);
    tt.pixel(50, 149, Red);
    tt.pixel(51, 150, Red);
    tt.pixel(49, 150, Red);
    
    tt.pixel(50, 50, Red);
    tt.pixel(50, 51, Red);
    tt.pixel(50, 49, Red);
    tt.pixel(51, 50, Red);
    tt.pixel(49, 50, Red);
}

All of the tt.line and printf statements work, but the tt.pixel doesn't output anything to the screen.

Any ideas?

Cheers,

Matt

12 Dec 2011

Hello Matt, you have found a bug. I have fix the pixel function. Please use the new version.

To speed up the setting of pixels, i set only two of the four registers wich declare the actual painting area. This work if you use the WindowMax() function before. The WindowMax function itself is declared protected - you can only use it inside the class at the moment.

I decide to fix the pixel function by setting the area every time. This use some additional register transfers, but the user has not to send a WindowMax() in front of pixel operations.

Peter

14 Dec 2011

Hi Peter,

That's great thanks, that solved my issue :-)

Cheers,

Matt

21 Dec 2011

Hi Peter, me again :-)

I've noticed that writing out an array of pixels one at a time is a bit slow, and I was wondering if I could speed it up. Here's my code:

Code

void DrawGraph(void) {   
    tt.fillrect(26,26,319,219,Black);
    int pix;
    int width = GraphWidth - ScreenWidth;
    for(pix = GraphWidth; pix > width ; pix--){
        if(GPUtemp[pix] > 0){tt.pixel(pix - 1, 220 - (GPUtemp[pix] * 2), Green);}
        if(CPUtemp[pix] > 0){tt.pixel(pix - 1, 220 - (CPUtemp[pix] * 2), Blue);}
        if(SYStemp[pix] > 0){tt.pixel(pix - 1, 220 - (SYStemp[pix] * 2), Red);}
    }
    tt.locate(30,30);                         
    printf("GPU: %i", GPUtemp[GraphWidth - 1]);    
    tt.locate(30,45);
    printf("CPU: %i", CPUtemp[GraphWidth - 1]);    
    tt.locate(30,60);
    printf("SYS: %i", SYStemp[GraphWidth - 1]);    
}

Do you think that building a bitmap in code and writing that to the screen would be quicker?

Cheers,

Matt

21 Dec 2011

Hello Matt,

if you set up a bitmap you don't have to erase the screen with the fillrect. This will be be fast, but you need to much ram :

(319 - 26 + 1) * (219 - 26 + 1) = 57036 word = 114072 byte !

I have speed up the pixel command from 45 byte to 25 byte spi transfer. A lot of Registers for 2 bytes of color...

Please test the new version.

You can try to erase only the old pixel. I think the fillrect will be slower because it set all pixel. You only need 3 times a second array for the old temperatures.

Peter

23 Dec 2011

Hi Peter,

That worked really well, removing the rectangle and just erasing the old pixel made things look a lot smoother, as you didn't get the pause while the whole graph had to be redrawn.

I've also reduced the number of times I need to set the pixels by checking if the value I'm replacing is the same.

Code

void DrawGraph(void) {   
    int pix;
    int width = GraphWidth - ScreenWidth;
    for(pix = GraphWidth; pix > width ; pix--){
        if((GPUtemp[pix] > 0) && (GPUtemp[pix - 1] != GPUtemp[pix])){
            if(GPUtemp[pix -1] > 0){tt.pixel(pix - 1, 220 - (GPUtemp[pix - 1] * 2), Black);}
            tt.pixel(pix - 1, 220 - (GPUtemp[pix] * 2), Green);
            }
        if((CPUtemp[pix] > 0) && (CPUtemp[pix - 1] != CPUtemp[pix])){
            if(CPUtemp[pix -1] > 0){tt.pixel(pix - 1, 220 - (CPUtemp[pix - 1] * 2), Black);}
            tt.pixel(pix - 1, 220 - (CPUtemp[pix] * 2), Blue);
            }
        if((SYStemp[pix] > 0) && (SYStemp[pix - 1] != SYStemp[pix])){
            if(SYStemp[pix -1] > 0){tt.pixel(pix - 1, 220 - (SYStemp[pix - 1] * 2), Black);}
            tt.pixel(pix - 1, 220 - (SYStemp[pix] * 2), Red);
            }
    }
    tt.locate(30,30);                         
    printf("GPU: %i", GPUtemp[GraphWidth - 1]);    
    tt.locate(30,45);
    printf("CPU: %i", CPUtemp[GraphWidth - 1]);    
    tt.locate(30,60);
    printf("SYS: %i", SYStemp[GraphWidth - 1]);    
}

Thanks again :-)

Matt

29 Dec 2011

Hey Peter, On the latest code, tt.cls doesn't always work ...kevin

30 Dec 2011

cls bug fixed

Peter

30 Dec 2011

Thanks Peter, CLS is fixed. I have another issue regarding vectored lines. (imagine displaying an analog or mechanical meter movement...) I am constantly repainting a vectored line every time the meter has a change in "movement". When the movement starts, first I paint over the old line in Black to erase it (Black background), then paint the new line in White. I do this fairly often, 5 - 6 times a second. About 30% of the time, the old line never fully erases before painting the new line. This leaves ghosts of partial old While lines lying around.

This use to work properly in your older code, but broken in the later updates. I do switch between orientation 0 and 1 quite a bit. 0 for text and 1 for graphics.

...kevin

30 Dec 2011

"I do switch between orientation 0 and 1 quite a bit. 0 for text and 1 for graphics. " Oops!! I meant 0 for graphics and 1 for text ...kevin

02 Jan 2012

Hello Kevin, I think I have a fix, but the publish function has problems since yesterday. Try it with a WindowMax(); at the end of the set_orientation() function.

Peter

05 Jan 2012

Peter, All is right with the world now. The new version of SPI_TFT has fixed my issues. I did not have to add WindowMax(); either. I made no other changes other than to update your code. Thanks.

...kevin

01 Feb 2012

Peter, FYI, I wrote a program that turns the TFT into an analog meter. Made for users of the MikroElektronika TFT display. Right now it's just a demo program, but is easily expandable.

http://mbed.org/users/loopsva/programs/AnalogMeter-100/m4n3pw

Note that my TFT pin out is different from the defaults in your example. ...kevin

Please login to post comments.