FTDI Community

Please login or register.

Login with username, password and session length.
Advanced Search  

News:

Welcome to the FTDI Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ FTDI Support


New Bridgetek Community is now open

Please note that we have created the Bridgetek Community to discuss all Bridgetek products e.g. EVE, MCU.

Please follow this link and create a new user account to get started.

Bridgetek Community

Author Topic: Displaying images from GRAM - Why ARGB4 instead of RGB565  (Read 1273 times)

jberkhout

  • Newbie
  • *
  • Posts: 31
    • View Profile
Displaying images from GRAM - Why ARGB4 instead of RGB565
« on: June 29, 2018, 07:33:36 PM »

Hi,

I am working on a EVE library for the mbed (ARM Cortex) platform in combination with the EVE ME813A-WH50C display.

It is now working, displaying images from the displays GRAM, after a lot of trying.

I have edited this post when I discovered more about the cause of the problem.

After loading images into RAM (only once), they display correctly, in gray color.

The below code loads and shows 4 bitmaps on the correct place and in the correct gray color (On and Off buttons, in narrow and wide versions):

Code: [Select]
    TFT.DLstart();                              // start a new display command list
    TFT.DL(CLEAR_COLOR_RGB(0x25, 0x25, 0x25));  // set the clear color to white
    TFT.DL(CLEAR(1, 1, 1));                     // clear buffers -> color buffer,stencil buffer, tag buffer

    TFT.SetLoadAddress(0);
 
    //  Narrow On button, 100x132, Address 0-26400
    TFT.DL(BITMAP_HANDLE(0));
    TFT.Png("/fs/SWITCH_BUTTON_SMALL_ON_100x131.png", 20, 20);
 
    // Narrow Off button, 100x132, Address 26400-52800
    TFT.DL(BITMAP_HANDLE(1));
    TFT.Png("/fs/SWITCH_BUTTON_SMALL_OFF_100x131.png", 125, 20);

    // Wide On button, 182x132, Address 52800-100848
    TFT.DL(BITMAP_HANDLE(2));
    TFT.Png("/fs/SWITCH_BUTTON_LARGE_ON_181x131.png", 230, 20);

    // Wide Off button, 182x132, Address 100848-148896
    TFT.DL(BITMAP_HANDLE(3));
    TFT.Png("/fs/SWITCH_BUTTON_LARGE_OFF_181x131.png", 416, 20);

    TFT.DL(DISPLAY());                          // Display the image
    TFT.Swap();                                 // Swap the current display list
    TFT.Flush_Co_Buffer();                      // Download the command list into fifo
    TFT.WaitCmdfifo_empty();                    // Wait till coprocessor completes the operation

In TFT.png, the image was loaded using below code, which seems to work fine:

Code: [Select]
    // In short
    //    WrCmd32(CMD_LOADIMAGE);
    //    WrCmd32(_address);             //destination address of png decode
    //    WrCmd32(0);             // Output format of the bitmap OPT_RGB565
    //    WrCmdBuf((uint8_t *)pbuff, blocklen); //alignment is already taken care by this api

ft_uint8_t FT813::LoadPng(char* filename, ft_int16_t* x_size, ft_int16_t* y_size)
{
    int bufferSize = 8192;
    uint32_t marker1;
    uint32_t marker2;
    unsigned short length;
    unsigned char data[32];

    ft_uint16_t blocklen;
 
    FILE *fp = fopen(filename, "rb");
    if(fp == NULL) {
        printf("LoadPng: Cannot open file \"%s\".\n", filename);
        return (-1);         // cannot open file
    }

    // Get file size
    fseek(fp, 0, SEEK_END);
    unsigned int Fsize = ftell(fp);
    // search for 0x89504E47 and 0x0D0A1A0A markers "‰PNG...."
    fseek(fp, 2, SEEK_SET); // Beginning of file
    fread(data, 32, 1, fp); // Read first 32 bytes
    printf("LoadPng: Filesize %d\n", Fsize);
   
    // Check that this is indeed a PNG file
    unsigned char png_header[] = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
    if (memcmp(data, png_header, 8)) {
        printf("LoadPng: Not a PNG file.\n");
        return (-2);  // No FFC0 Marker, wrong format no baseline DCT-based JPEG
    }

    // Make sure you have an IHDR
    unsigned char ihdr_name[] = "IHDR";
    if (memcmp(data+8+4, ihdr_name, 4)) {
        // not an IHDR chunk, invalid PNG file
        printf("LoadPng: Not an IHDR chunk, invalid PNG file.\n");
        return (-3);  // No FFC0 Marker, wrong format no baseline DCT-based JPEG
    }
   
    // PNG actually stores integers in big-endian.
    *x_size = ReadBigInt32(data, 24 - 8);
    *y_size = ReadBigInt32(data, 24 - 4);
    uint16_t size_x = ReadBigInt32(data, 24 - 8);
    uint16_t size_y = ReadBigInt32(data, 24 - 4);
 
    if(*x_size > DispWidth || *y_size > DispHeight)
    {
        printf("LoadPng: Too big to fit on screen\n");
        printf("LoadPng: PNG (%dx%d) does not fit on TFT (%dx%d)\n", *x_size, *y_size, DispWidth, DispHeight);
        return (-3);  // Too big to fit on screen
    }

    fseek(fp, 0, SEEK_SET); // Beginning of file
   
    // http://www.ftdichip.com/Support/Documents/AppNotes/AN_339%20Using%20JPEGs%20with%20the%20FT800%20series.pdf
    // CMD_LOADIMAGE: This function will decode the JPEG file, produce
    // either RGB565 or L8 bitmap data and store this in graphics RAM.
    // It also writes commands to the display list to set the source, layout and size of the
    // image (BITMAP_SOURCE, BITMAP_LAYOUT and BITMAP_SIZE).
    // Note that only a BEGIN and VERTEX2F (or VERTEX2II) display list commands are then
    // required to complete the display list needed to render the image.
    WrCmd32(CMD_LOADIMAGE);
    WrCmd32(_address);             //destination address of png decode

    // Increment _address
    _addresses[_bitmap_count] = _address;
    _bitmap_count++;
    _address += (uint32_t) (size_x * size_y * 2);
    _addresses[_bitmap_count] = _address;

    // 0 OPT_RGB565
    // 1 OPT_MONO
    // 2 OPT_NODL
    // 256 OPT_FLAT
    // 256 OPT_SIGNED
    // 512 OPT_CENTERX
    // 1024 OPT_CENTERY
    // 1536 OPT_CENTER
    // 2048 OPT_RIGHTX
    // 4096 OPT_NOBACK
    // 8192 OPT_NOTICKS
    // By default, option OPT_RGB565 means the loaded bitmap is in RGB565 format.
    WrCmd32(0);             // Output format of the bitmap OPT_RGB565

    char* pbuff = (char*)malloc(bufferSize);

    unsigned int FsizeCounter = Fsize;
    while(FsizeCounter > 0) {
        /* download the data into the command buffer by 8kb one shot */
        blocklen = FsizeCounter > bufferSize ? bufferSize : FsizeCounter;

        /* copy the data into pbuff and then transfter it to command buffer */
        int size = fread(pbuff, 1, blocklen, fp);
        FsizeCounter -= blocklen;
        /* copy data continuously into command memory */
        WrCmdBuf((uint8_t *)pbuff, blocklen); //alignment is already taken care by this api
    }
    fclose(fp);

    // If the number of bytes in the JPEG file to be written to the command buffer is not a multiple of
    // four, then one, two or three bytes (of any value) should be added to ensure four-byte alignment of
    // the next command.
    blocklen = Fsize % 4;
    memset(pbuff, 0, bufferSize);
    WrCmdBuf((uint8_t *)pbuff, blocklen); //alignment is already taken care by this api
 
    free(pbuff);
    printf("LoadPng: Done.\n");

    return(0);
}

And the shown correctly with following code:

Code: [Select]
    DL(BEGIN(BITMAPS));                 
    DL(VERTEX2F(x * 16, y * 16));

Then, it should display several of the pre-loaded images from the displays GRAM at different locations on the screen.

It turnes out this works fine if I specify ARGB4 for the format in GRAM (trial and error). Why does it not match the RGB565 layout?

Code: [Select]
    TFT.DLstart();                              // start a new display command list
    TFT.DL(CLEAR_COLOR_RGB(0x25, 0x25, 0x25));  // set the clear color to white
    TFT.DL(CLEAR(1, 1, 1));                     // clear buffers -> color buffer,stencil buffer, tag buffer
             
    //  Narrow On button, 100x132, Address 0-26400
    TFT.DL(BITMAP_SOURCE(TFT.GetBitmapAddress(0)));
    TFT.DL(BITMAP_LAYOUT(ARGB4, 100*2, 132));    // <------- Why ARGB4 instead of RGB565?
    TFT.DL(BITMAP_SIZE(NEAREST, BORDER, BORDER, 100, 132));
    TFT.DL(BEGIN(BITMAPS));   
    TFT.DL(VERTEX2II(125, 190, 0, 0));

    // Narrow Off button, 100x132, Address 26400-52800
    TFT.DL(BITMAP_SOURCE(TFT.GetBitmapAddress(1)));
    TFT.DL(BITMAP_LAYOUT(ARGB4, 100*2, 132));    // <------- Why ARGB4 instead of RGB565?
    TFT.DL(BITMAP_SIZE(NEAREST, BORDER, BORDER, 100, 132));
    TFT.DL(BEGIN(BITMAPS));   
    TFT.DL(VERTEX2II(20, 190, 0, 0));

    // Wide On button, 182x132, Address 52800-100848
    TFT.DL(BITMAP_SOURCE(TFT.GetBitmapAddress(2)));
    TFT.DL(BITMAP_LAYOUT(ARGB4, 182*2, 132));    // <------- Why ARGB4 instead of RGB565?
    TFT.DL(BITMAP_SIZE(NEAREST, BORDER, BORDER, 182, 132));
    TFT.DL(BEGIN(BITMAPS));   
    TFT.DL(VERTEX2II(416, 190, 0, 0));

    // Wide Off button, 182x132, Address 100848-148896
    TFT.DL(BITMAP_SOURCE(TFT.GetBitmapAddress(3)));
    TFT.DL(BITMAP_LAYOUT(ARGB4, 182*2, 132));    // <------- Why ARGB4 instead of RGB565?
    TFT.DL(BITMAP_SIZE(NEAREST, BORDER, BORDER, 182, 132));
    TFT.DL(BEGIN(BITMAPS));   
    TFT.DL(VERTEX2II(230, 190, 0, 0));

    TFT.DL(END());                 
    TFT.DL(DISPLAY());                          // Display the image (erases the other images!)
    TFT.Swap();                                 // Swap the current display list
    TFT.Flush_Co_Buffer();                      // Download the command list into fifo
    TFT.WaitCmdfifo_empty();                    // Wait till coprocessor completes the operation

Definitions of RGB565, BITMAP_LAYOUT and BITMAP_SIZE_H:

Code: [Select]
#define RGB565               7UL

#define BITMAP_LAYOUT(format,linestride,height) ((7UL<<24)|(((format)&31UL)<<19)|(((linestride)&1023UL)<<9)|(((height)&511UL)<<0))

#define BITMAP_SIZE_H(width,height) ((41UL<<24)|(((width)&3UL)<<2)|(((height)&3UL)<<0))

I have added photos of the screen.

How can I define this upfront, if I'd like to try L8 format, using CMD_LOADIMAGE?
Is that possible?

I try to contribute in a positive way, and update posts with code that finally works.
Despite this seems useful and helpful information for others, this message still is awaiting approval by a moderator, for many days.
Is my contribution (as a new user) not appreciated?

I hope somebody can help me in the right direction.

Kind regards,
Jack.
« Last Edit: July 04, 2018, 07:45:07 PM by jberkhout »
Logged

FTDI Community

  • Administrator
  • Sr. Member
  • *****
  • Posts: 263
    • View Profile
Re: Displaying images from GRAM - Why ARGB4 instead of RGB565
« Reply #1 on: July 04, 2018, 03:51:28 PM »

Hello,

Can you please have a look at the following application note:
http://brtchip.com/wp-content/uploads/Support/Documentation/Application_Notes/ICs/EVE/AN_303-FT800-Image-File-Conversion.pdf

It covers using the EVE Image Convertor, the different output formats (L8, ARGB4, etc) and how to implement these in code.

Best Regards,
FTDI Community
Logged

jberkhout

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Displaying images from GRAM - Why ARGB4 instead of RGB565
« Reply #2 on: July 04, 2018, 06:51:06 PM »

Thank yes, I was reading in it this afternoon, it is useful.

To load raw, this function is used:

Code: [Select]
hal_spi_wr8s(phost, ram_start, imbuff, blocklen);

I'm looking for the implementation of this function, so I can test it.

Is it something like:

Code: [Select]
ft_void_t FT813::Wr8s(ft_uint32_t addr, ft_uint8_t *buffer, ft_uint8_t length)
{
    _ss = 0;       // cs low
    _spi.write(0x80 | (addr >> 16));
    _spi.write(addr >> 8);
    _spi.write(addr & 0xff);

    while (length--) {
        _spi.write(*buffer);
        buffer++;
    }
    _ss = 1;
}

« Last Edit: July 04, 2018, 07:47:13 PM by jberkhout »
Logged

Rudolph

  • Newbie
  • *
  • Posts: 24
    • View Profile
Re: Displaying images from GRAM - Why ARGB4 instead of RGB565
« Reply #3 on: July 05, 2018, 08:22:46 AM »

You can also check out my library: https://github.com/RudolphRiedel/FT800-FT813

It is plain C, cross-plattform in a sense that it uses a minimalistic set of mostly one-line functions that are target specific while almost everything else is not.
And while I have not used it with ARM myself I have reports that it has been used successfully with a whole bunch of ARM controllers: STM32, SAM3, SAM4, SAMV70, SAMC21, SAMD20.
The last platform I needed to adapt to was Infineon Aurix, with the help of the software engineer I was to provide a visualisation for it took about 20 minutes with a bit of explaining for the target specific lines and built flawlessly in the scope of his project.
Next up für me is SAME51.

A good starting point would be the "FT8xx_Test_90CAN_FT813_EVE2-35G" example I provided, it should be updated with the latest FT8_commands.c though.
You should be able to adapt it to your target quite easily and from there it should provide some ideas for your own library.
Logged

FTDI Community

  • Administrator
  • Sr. Member
  • *****
  • Posts: 263
    • View Profile
Re: Displaying images from GRAM - Why ARGB4 instead of RGB565
« Reply #4 on: July 05, 2018, 11:02:02 AM »

Hello,

In General the wr8s function would do the following:
  • Bring CS low
  • Write the Address
  • Burst write the data buffer
  • Bring CS high when the data has been written

Best Regards,
FTDI Community
Logged