Standardized mbed GUI

UniGraphic

14 Feb 2015

Hi all, don't know if i'm going on the right way with this lib, i saw performance loss is not so much, so...take a look. I'm going to add pixelread, readID and PAR_16, i've already done it for per-display, just need to think about the most standardized way to do it.

Here is a demo to have a try I think IST3020 init can be used with the more common ST7565 with veryfew adjustement, sadly i've not yet an ST7565.

Import programUniGraphic_demo

UniGraphic demo for TFT and LCD, par or spi

17 Feb 2015

Dear Geremia-san and all,

Finally I could afford time to try UniGraphic library.
I tried with my TFT_test_frdm_kl25z program.

First good news
Yes, almost all of the program worked fine with only re-writing the include and constructor parts.
Good Job, Geremia-san!!!

Second bad news or my question
The location of text seemed to be moved left
may be this is because of the size of font or spacing, but not a big deal.

Right now one thing annoys me is there appears a brown box with white strips moving on the last letter.
I wonder if I'm missing something which was not required by the previous library?

/media/uploads/Rhyme/img_1076.jpg

/media/uploads/Rhyme/img_1077.jpg

/media/uploads/Rhyme/img_1078.jpg

Any suggestions will be appreciated.

http://developer.mbed.org/teams/GraphicsDisplay/code/testUniGraphic_150217/

moto

17 Feb 2015

Hi,

thanks for your report.

About font being more on the left, i think you previously used the character() function from Peter, which adds 2 blank pixels between 2 characters. I removed it but maybe is better to add at least 1 blank raw, it all depends if the font itself has already a blank border...need to check.

About the last character messed up, seems your display is getting some data which is intended for the touch controller? Keep in mind that after you plotted something, the display stays in a "ready to get pixeldata" state, i mean, CS is low, DC is high (data) and last spi write was pixelcolor, so whatever travels on the spi bus, the display will get it as next pixelcolor, and will be pushed into the last selected window (in your case, the 12x12 window of the last character printed). If you are sharing spi bus (but seems not in your code) there is a BusEnable(true/false) public function to disable display spi interface, because by default is enabled forever for speedup. Btw, you used tft backlight digitalout but you hooked to touch interrupt? I see in your code the messed up character is the one just before you set backlight on.

17 Feb 2015

Added 1 blank after each font char (if i set to 2 there would be no improvement in using small 6x8 font). I overlooked your code, you are in fact sharing spi bus with the touch ic, so just disable TFT here

TFT.BusEnable(false);
TSC.getRAWPoint(&x, &y, &z) ;
TFT.BusEnable(true);

I don't have yet any touch ic to test, but i leaved that BusEnable funtion to be passed somehow to touch ic interrupt function.

17 Feb 2015

Hello Geremia,

I had a first look and it is working. Nice work !

I think we can improve some things :

1. The lib has to control the cs line if there is a pin number in the constructor ! You have implement a #ifdef USE_CS , but you don`t set it if there is a pin number. The CS handling have to be implemented in the Graphic functions, not in the protocol level.

2. All command implementations, which are controller specific has to be in Inits. There will be no control value in the TFT class. The implementation of TFT::set_orientation() with the control register values have to be in the controller file. Same for TFT::set_orientation ... If the controller has no scroll command there will be a empty function.

We have to add a SPI 9 bit mode. Some controller can be used in 9 Bit mode without a command/data pin. Not all cpu's support 9 bit SPI.

Best Regards, Peter

17 Feb 2015

Dear Geremia-san,

I added TFT.BusEnable(true/false) at the beginning and end of display printing/plotting function.
Yes, the annoying rectangle noise is gone now.
No, but the problem which previously annoyed me came back,
which is when changing page, TFT.cls() fails to erase whole screen and
some leftover stays...

Meantime, I have just noticed that the library was updated, and I updated it,
the result was plotting the accelerometer reading is painfully slow now.

May be we need choice to have auto-cs and manual-cs mode.
Or was the SPI speed changed somewhere?

Added 1 blank after each font char (if i set to 2 there would be no improvement in using small 6x8 font).

Having no space is sometimes nice, especially when you must put lots of text.
It would be nice to have font-spacing (and/or line-spacing) function so that we have control over it.

Best Regards,
moto

17 Feb 2015

Motoo: i din't change the pixel() function, anyway try to put the enable/disable just prior and after calling touch reading, that's the place in your code where it hurts less. You are polling the touch ic every loop even if there is no touch activity, so the less gpio activity on CS, the more the speed.

I decided to go with CS fixed enabled to give display priority and speed, cause every digitalout activity takes time, and an unified library for all displays with 4-5 class inheritages builds up and array of array of array of array of pointers to functions :)

Peter: thanks for taking a look, and sorry if your original code now looks like messy:)

about #ifdef USE_CS, it's in protocol because was there when i wrote something per-display, but i don't #define it anywhere. What i tought about use/not use and when use cs, is try the best to avoid code to decide at runtime, so put it permanently low in Protocol and publish a method to disable it. If we tell Graphic class to call BusEnable() prior and after it's job, or directly tell Graphics to do _CS=0/1, would be ok for big jobs like printing a big font or a big filled rect, but if you are plotting 2pixels lines like a graph as Matoo does, it will be a performance killer. From another point of view, who needs the spi bus freed? Not the display itself (unless a bit in the spi protocol gets lost cause of bad wiring, the display slave spi will go "out of sync"), but rather something that shares the spi bus, so, that's why i tought the best place to handle CS was manually and outside and let the other slave decide if he wants the bus.

About driver control like set_orientation, TFT has the standard ones and some ILI specific, like the ones used to get device id. Anyway i left them virtual void, so you can override in init. I already do some override in UC1608, because it's too much far from standard. Similar can be for ILI932x, which have different cmds for set page/column address...., or a controller that does not have orientation can have a dummy set_orientation() overridden in its Init. In LCD/TFT the lowlevel wr_cmd8 wr_data8 etc are "replicated" (protected wr_cmd8 is redirected to proto->wr_cmd8) for this reason, to be used by derived class (Init) without knowing the final protocol. I know it's not the best way to redirect a function, but probably the compiler does a good optimization.

About spi 9bit, i think it's doable like another Protocol class SPI9, with some tricks like send 8bit cmd, rightshift data and insert DC bit on top, then the last 8bit chunk will just send data bit0 as MSB then 7 zeroes as padding, the driver will intend 7 zeroes as part of the next byte, so will stay there waiting the 8th bit to accept the byte, but we drive cs hi-low to interrupt. I'm doing somethin similar to read with dummy bit in SPI8::rd_reg_data32(unsigned char reg)

17 Feb 2015

BTW, actually there is a performance killer in TFT.cpp and LCD.cpp

void TFT::wr_cmd8(unsigned char cmd)
    {
        if(useNOP) proto->wr_cmd16(cmd); // 0x0000|cmd, 00 is NOP cmd for TFT
        else proto->wr_cmd8(cmd);
    }

using spi 16bit speeds up most of the times (well, DMA would speedup more for sure:) ), cause cmds 2A 2B 2C have 16bit data/parameter, but cmd is 8bit so i put a NOP cmd on MSB (8 spi clocks overhead but cpu is slower in sending 2x8bit). I don't know how to tell at compile time, so in runtime i need to check the useNOP flag for deciding is using the wr_cmd8 or wr_cmd16 with nop. I could add the nop in the SPI16 class, but LCD have different nop cmd......so use SPI16TFT.cpp and SPI16LCD.cpp with different nop cmd?!?!? Or, is there a way to put hands on the vtable of TFT class (once constructed) and swap the addr of pointed function? I would like this idea but i'm noob at programming.

18 Feb 2015

Dear Geremia-san,

Thanks for the update (or rewind?), the graph plotting is now fast enough!

I reformatted the first page text and it came out nicely
/media/uploads/Rhyme/img_1079.jpg

Currently my remaining problem is, when changing pages,
TFT.cls() often fails to really clear all display area,
I'm guessing that this must have something to do "window" function,
but not quite sure.

/media/uploads/Rhyme/img_1080.jpg

Any suggestions and/or hints to fix this will be greatly appreciated.

Best Regards,
moto

18 Feb 2015

case 2:
            if (prevPage != page) {
                TFT.background(Black) ;
                TFT.foreground(White) ;
                TFT.cls() ; // here actually bus is disabled
            }

same suggestion as before: put enable disable just before and after talking to touch ic, no other place.

TFT.BusEnable(false);
TSC.getRAWPoint(&x, &y, &z) ;
TFT.BusEnable(true);

or better, the touch ic should have an interrupt out pin, you could poll that pin in your main loop, if state change, disable cs of display, read touch ic, enable display cs and your main loop will be much faster

18 Feb 2015

Dear Geremia-san,

Thank you very much for your suggestion!

Although I'm very sorry for being stubborn,
I did not want to put BusEnable() around TSC.getRAWPoint().

Since the TFT panel also has spi-SDC
I wanted to encapsulate BusEnable() in TFT related functions
and leave other spi related classes free from TFT.

So what I did was

            if (prevPage != page) {
                TFT.BusEnable(true) ;
                TFT.background(Black) ;
                TFT.foreground(White) ;
                TFT.cls() ;
                TFT.BusEnable(false) ;
            }

and it is working beautifully now!

Best Regards,
moto

19 Feb 2015

Give a try at the fastwindow trick, it adds veryfew overhead in code if disabled, but when enabled (if you display controller likes it) you gets much faster pixel() readpixel() circle, oblique line(). Default disabled, just add FastWindow(true); in the init and be happy.

About spi 9bit, well....does anyone really need it? It feels like a waste of spi clocks for 8/16bit only boards.

19 Feb 2015

Dear Geremia-san,

I just tried

void initTFT(void)
{
    //Configure the display driver    
    TFT.FastWindow(true) ;
    TFT.background(Black);
    TFT.foreground(White);
    wait(0.01) ;
    TFT.cls();
}

First good news:
Yes, it does compile OK and worked fine!

Second (not so) bad news:
Since the library was reasonably fast even without it
it is difficult for my slow eyes(and brain) to notice how faster it is.

Well, it seems to be faster, though.

Best Regards,
moto

19 Feb 2015

Geremia G wrote:

BTW, actually there is a performance killer in TFT.cpp and LCD.cpp

void TFT::wr_cmd8(unsigned char cmd)
    {
        if(useNOP) proto->wr_cmd16(cmd); // 0x0000|cmd, 00 is NOP cmd for TFT
        else proto->wr_cmd8(cmd);
    }

well...i checked, the compiler seems to do a good job and does not waste too much time in it.

ROM:08002C76 sub_8002C76                             ; CODE XREF: sub_8005B60+6C2
ROM:08002C76                 LDRB.W          R3, [R0,#0x8C] ; bool useNOP
ROM:08002C7A                 LDR             R0, [R0,#0x5C]
ROM:08002C7C                 MOVS            R1, #0x13
ROM:08002C7E                 LDR             R2, [R0]
ROM:08002C80                 CBZ             R3, loc_8002C86
ROM:08002C82                 LDR             R2, [R2,#8] ; proto->wr_cmd16
ROM:08002C84                 BX              R2
ROM:08002C86 ; ---------------------------------------------------------------------------
ROM:08002C86
ROM:08002C86 loc_8002C86                             ; CODE XREF: sub_8002C76+A
ROM:08002C86                 LDR             R2, [R2] ; proto->wr_cmd8
ROM:08002C88                 BX              R2
02 Aug 2015

Dear Geremia-san,

Since then I have been using UniGraphic for my programs.
Note: I'm using ILI9341.

But recently, from some revision, I have been encountering problem,
which is the image gets horizontally flipped.
It occurs by reset timing, each time I reset the board,
I get flipped or normal randomly.

Following two pictures were generated by exactly same program.

Horizontally Flipped
/media/uploads/Rhyme/mirror.jpg

Normal
/media/uploads/Rhyme/normal.jpg

Could you check if it can be fixed?

Best Regards, 2-Aug-2015 Motoo Tanaka

02 Aug 2015

Hi,

really weird, not sure why you have this issue, could you check these points?

- do you have same issue with my demo program? https://developer.mbed.org/users/Geremia/code/UniGraphic_demo/ - are you using the (latest)ili9341 init i provide, or your edited one(from an early version of the lib)? - do you send a tft.cls() and tft.set_orientation(0) in your main? Or, in your code, are you using tft.set_orientation(orient) where orient is a "not initialized" variable, i.e declared in main.c like "char orient;" and used by set_orientation(orient) before you initialize it like orient=0;? Just guessing...

Regards

Geremia

02 Aug 2015

Dear Geremia-san,

I have just re-imported your UniGraphic_demo to my workspace and copied the UniGraphic.lib to my project and tried.
The result is still same about 50% of time I get flipped screen.
I use both TFT.cls() and TFT.set_orientation(0) in my initTFT() function, which is called in the main().

If I remember correct, I did not have this problem with earlier version of UniGrahic.lib but with later version I have this symptom.
May be this is caused by accessing TFT and TSC, but I'm not quite sure.

Would you let me know if there is/are registers in ILI9341 which can flip the picture?
I tried to find it in the datasheet, but I could figure out which one can make such trick.
(Note: except this issue, I've been very happy with UniGraphic.lig ;-)

Best Regards, 2-Aug-2015 Motoo Tanaka

02 Aug 2015

Hi,

it could be you are sending to tft something that is meant for tsc.....anyway register for orientation is 0x36, you can see it in the ILI9341 init and in TFT.cpp

in ILI9341.cpp, but you can also comment out this cmd in the initialization, because later the set_orientation() will send cmd 36 anyway.

wr_cmd8(0x36);      // MEMORY_ACCESS_CONTROL (orientation stuff)
wr_data8(0x48);

TFT.cpp

void TFT::set_orientation(int o)
{
    orientation = o;
    wr_cmd8(0x36);
    switch (orientation) {
        case 0:// default, portrait view 0°
            if(mipistd) wr_data8(0x0A); // this is in real a vertical flip enabled, seems most displays are vertical flipped
            else wr_data8(0x48); //for some other ILIxxxx (ILI9341 falls here)
            set_width(screensize_X);
            set_height(screensize_Y);
            break;

ILI9341 is not mipistandard, it could be it's wrongly detected as mipistd=true. In TFT.cpp the function Identify() sends some possible "ReadID" cmds and checks if all 3 bytes of ID are the same (implausible ID = cmd not supported).

void TFT::identify()
{
    // MIPI std read ID cmd
    tftID=rd_reg_data32(0xBF);
    mipistd=true;
 //   debug("ID MIPI : 0x%8X\r\n",tftID);
    if(((tftID&0xFF)==((tftID>>8)&0xFF)) && ((tftID&0xFF)==((tftID>>16)&0xFF)))
    {
        mipistd=false;
        // ILI specfic read ID cmd
        tftID=rd_reg_data32(0xD3)>>8; 
    //    debug("ID ILI : 0x%8X\r\n",tftID);
    }

The Identify() is called in the ILI9341.cpp after busenable (tft CS low), in case you have some collision on the spi bus between TFT and TSC, you shoudl get also a wrong display ID (my demo shows dislay ID after reset). In case, check if touch CS pin is not low when you init the tft.

Let me know

Geremia

02 Aug 2015

Dear Geremia-san,

Thank you very much for your help!

While I was double checking my init routines,
I found a conflict with TFT and TSC.

After disabling cs of TSC, I tried with 2 systems each 10 times
and all came up correct rotation!

Thank you for your helping me out of the mirror world!

Best Regards, 2-Aug-2015 Motoo Tanaka

02 Aug 2015

Hi,

You welcome

Have fun!

Geremia

01 Dec 2015

Hello Geremia, can You please provide some library to use TFT with BUS_8 interface and with non SPI Touch Panel, which as I've found out is sharing A1, A2, D6, D7 pins with TFT?

Or maybe there is one lib for that kind of Touch, but i could not find one.