RA8875 Bitmap Pre-processing

For other supported Arduino products from Adafruit: Shields, accessories, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

RA8875 Bitmap Pre-processing

Post by rick1fx »

Hello everyone, I got a 7" tft touch screen and RA8875 driver board a few weeks ago and am using it with a ESP32. I want this screen to be able to draw bitmaps almost instantly. I am trying to find a way for the RA8875 driver to "pre-process" or "load" bitmaps fully when the board is booted up instead of having them load when the "drawBitmap" function is called. I want the fully loaded bitmaps to be layered on top of one another. To show one of the loaded bitmaps, I want to just call it up to the top layer of the screen so it can be shown. This is something that I don't know is even possible to do. Thanks!!!

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

@rick1fx,

Can you increase BUFFPIXEL from '20' to something much larger? I suspect you ESP32 has plenty of memory to accommodate.

Code: Select all

// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates.  It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel).  Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster.  20 pixels seems a
// good balance.

#define BUFFPIXEL 20
https://github.com/adafruit/Adafruit_RA ... p_fast.ino

Were you already using ra8875_bitmap_fast.ino example code linked to above?

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

Thanks for relaying! I have looked and reviewed the "ra8875_bitmap_fast.ino" program, but it is using .bmp and getting data from an external SD card. I want to be able to read hexadecimal numbers (eg. 0xffff), not .bmp files. Sorry for not being for specific about what format I wanted to read from. Also, just so you know, I am very new to the Adafruit RA8875 and GFX Libraries.

Code: Select all

#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include "Adafruit_GFX.h"
#include "Adafruit_RA8875.h"
#include "Adafruit_I2CDevice.h"

#define RA8875_CS 5
#define RA8875_RESET 21
#define RA8875_INT 22

Adafruit_RA8875 tft = Adafruit_RA8875(RA8875_CS, RA8875_RESET);

extern const uint16_t color_spectrum[];

void setup()
{
    Serial.begin(115200);

    tft.begin(RA8875_800x480);
    tft.displayOn(true);
    tft.GPIOX(true);
    tft.PWM1config(true, RA8875_PWM_CLK_DIV1024);
    tft.PWM1out(255);
    tft.setRotation(1);

    tft.drawRGBBitmap(0, 0, color_spectrum, 800, 480);
}

void loop()
{

}
In another .cpp file, I have converted a .png image in hexadecimal numbers (eg. 0xffff). I have used this converter to do so https://javl.github.io/image2cpp/.

Code: Select all

#include <Arduino.h>

extern const uint16_t color_spectrum[] PROGMEM = {
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, etc...

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

I really like the idea of storing images in the code in hex. You have them in flash space which already should be really fast. Does it feel slow?

If you want to load the array into memory (SRAM) which will be a little faster you should be able to use pgm_read_word_near() or pgm_read_byte_near() and populate an array. Here is some example code showing how to pull in flash based PROGMEM into SRAM.

https://www.arduino.cc/reference/en/lan ... s/progmem/

Code: Select all

// save some unsigned ints
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial port to connect. Needed for native USB

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (byte k = 0; k < 5; k++) {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  for (byte k = 0; k < strlen_P(signMessage); k++) {
    myChar = pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
}

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

Yes, it is very slow to load a hex bitmap. I want all the hex bitmap images that want for my program to be loaded when power is applied to the board and then be saved as a layer on the display. When I want to display one of the hex bitmaps, I want to call a certain layer to the top of the display so it will be visible. I honestly don't care about the load time at the beginning of the program, I just want to be able to save it and call that layer instantly later in my program. This display is something that will probably be on most the time so it won't need to be loaded often. Is this possible to do?

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

@rick1fx,

As long as you have the memory space (and our modern boards have a lot of space). You can use examples like the code above to populate SRAM from flash space so the images are preloaded.

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

I don't completely understand how this code works? Also, I thought I was already populating SRAM with the hex bitmap array with the keyword PROGMEM, is that not the case?

https://www.arduino.cc/reference/en/lan ... s/progmem/

Code: Select all

// save some unsigned ints
const PROGMEM uint16_t charSet[] = { 65000, 32796, 16843, 10, 11234};

// save some chars
const char signMessage[] PROGMEM = {"I AM PREDATOR,  UNSEEN COMBATANT. CREATED BY THE UNITED STATES DEPART"};

unsigned int displayInt;
char myChar;


void setup() {
  Serial.begin(9600);
  while (!Serial);  // wait for serial port to connect. Needed for native USB

  // put your setup code here, to run once:
  // read back a 2-byte int
  for (byte k = 0; k < 5; k++) {
    displayInt = pgm_read_word_near(charSet + k);
    Serial.println(displayInt);
  }
  Serial.println();

  // read back a char
  for (byte k = 0; k < strlen_P(signMessage); k++) {
    myChar = pgm_read_byte_near(signMessage + k);
    Serial.print(myChar);
  }

  Serial.println();
}

void loop() {
  // put your main code here, to run repeatedly:
}

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

@rick1fx,

The PROGMEM statement stores data in FLASH not SRAM.
Store data in flash (program) memory instead of SRAM
https://www.arduino.cc/reference/en/lan ... s/progmem/

You have to use the pgm_read*() functions to get the data into SRAM.

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

Thanks for the info. I currently am trying the .bmp method, I am getting many errors though. This is the code I am using right now. I copied most of this code from here. https://github.com/adafruit/Adafruit_RA ... p_fast.ino

Code: Select all

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <SD.h>
#include "Adafruit_RA8875.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SPIDevice.h"

#define RA8875_CS 5
#define RA8875_RESET 21
#define RA8875_INT 22

Adafruit_RA8875 tft = Adafruit_RA8875(RA8875_CS, RA8875_RESET);





#define BUFFPIXEL 20

void bmpDraw(const char *filename, int x, int y) {
  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
  uint16_t lcdbuffer[BUFFPIXEL];  // pixel out buffer (16-bit per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col, xpos, ypos;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();
  uint8_t  lcdidx = 0;
  boolean  first = true;

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == false) {
    Serial.println(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.println(F("File size: "));
    Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: "));
    Serial.println(bmpImageoffset, DEC);

    // Read DIB header
    Serial.print(F("Header size: "));
    Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);

    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: "));
      Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        ypos = y;
        for (row=0; row<h; row++) { // For each scanline...
          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;

          if (bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }
          xpos = x;
          for (col=0; col<w; col++) { // For each column...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              // Push LCD buffer to the display first
              if(lcdidx > 0) {
                tft.drawPixels(lcdbuffer, lcdidx, xpos, ypos);
                xpos += lcdidx;
                lcdidx = 0;
                first  = false;
              }

              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            lcdbuffer[lcdidx++] = color565(r,g,b);
            if (lcdidx >= sizeof(lcdbuffer) || (xpos - x + lcdidx) >= w) {
              tft.drawPixels(lcdbuffer, lcdidx, xpos, ypos);
              lcdidx = 0;
              xpos += lcdidx;
            }
          } // end pixel
            ypos++;
        } // end scanline

        // Write any remaining data to LCD
        if(lcdidx > 0) {
          tft.drawPixels(lcdbuffer, lcdidx, xpos, ypos);
          xpos += lcdidx;
        }

        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");

      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));

}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

byte decToBcd(byte val){
  // Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}






void setup()
{
    Serial.begin(115200);

    SD.begin(15);

    tft.begin(RA8875_800x480);
    tft.displayOn(true);
    tft.GPIOX(true);
    tft.PWM1config(true, RA8875_PWM_CLK_DIV1024);
    tft.PWM1out(255);
    tft.setRotation(1);

    tft.graphicsMode();
    bmpDraw("color_spectrum.bmp", 0, 0);
}

void loop()
{

}
These are the errors I am getting. I can't figure out what to do the debug them. Do you have any idea of what I can do to fix it?

Code: Select all

> Executing task: platformio run <

Processing esp32dev (platform: espressif32; board: esp32dev; framework: arduino)
----------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif32/esp32dev.html
PLATFORM: Espressif 32 (3.3.1) > Espressif ESP32 Dev Module
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
DEBUG: Current (esp-prog) External (esp-prog, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa)
PACKAGES: 
 - framework-arduinoespressif32 3.10006.210326 (1.0.6) 
 - tool-esptoolpy 1.30100.210531 (3.1.0) 
 - toolchain-xtensa32 2.50200.97 (5.2.0)
LDF: Library Dependency Finder -> http://BANNED/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 33 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <Adafruit RA8875> 1.4.0
|   |-- <Adafruit GFX Library> 1.10.10
|   |   |-- <Adafruit BusIO> 1.9.0
|   |   |   |-- <SPI> 1.0
|   |   |   |-- <Wire> 1.0.1
|   |   |-- <Wire> 1.0.1
|   |   |-- <SPI> 1.0
|   |-- <EEPROM> 1.0.3
|   |-- <SPI> 1.0
|-- <Adafruit GFX Library> 1.10.10
|   |-- <Adafruit BusIO> 1.9.0
|   |   |-- <SPI> 1.0
|   |   |-- <Wire> 1.0.1
|   |-- <Wire> 1.0.1
|   |-- <SPI> 1.0
|-- <Adafruit BusIO> 1.9.0
|   |-- <SPI> 1.0
|   |-- <Wire> 1.0.1
|-- <SD> 0.0.0-alpha+sha.041f788250
|   |-- <SPI> 1.0
|-- <SPI> 1.0
|-- <Wire> 1.0.1
Building in release mode
Compiling .pio/build/esp32dev/src/main.cpp.o
Compiling .pio/build/esp32dev/lib8c5/SD/File.cpp.o
Compiling .pio/build/esp32dev/lib8c5/SD/SD.cpp.o
Compiling .pio/build/esp32dev/lib8c5/SD/utility/Sd2Card.cpp.o
In file included from .pio/libdeps/esp32dev/SD/utility/Sd2Card.h:26:0,
                 from .pio/libdeps/esp32dev/SD/utility/SdFat.h:29,
                 from .pio/libdeps/esp32dev/SD/SD.h:25,
                 from src/main.cpp:4:
.pio/libdeps/esp32dev/SD/utility/Sd2PinMap.h:371:2: error: #error Architecture or board not supported.
 #error Architecture or board not supported.
  ^
In file included from .pio/libdeps/esp32dev/SD/utility/Sd2Card.h:26:0,
                 from .pio/libdeps/esp32dev/SD/utility/SdFat.h:29,
                 from .pio/libdeps/esp32dev/SD/SD.h:25,
                 from .pio/libdeps/esp32dev/SD/SD.cpp:53:
.pio/libdeps/esp32dev/SD/utility/Sd2PinMap.h:371:2: error: #error Architecture or board not supported.
 #error Architecture or board not supported.
  ^
In file included from .pio/libdeps/esp32dev/SD/utility/Sd2Card.h:26:0,
                 from .pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp:26:
.pio/libdeps/esp32dev/SD/utility/Sd2PinMap.h:371:2: error: #error Architecture or board not supported.
 #error Architecture or board not supported.
  ^
In file included from .pio/libdeps/esp32dev/SD/utility/Sd2Card.h:26:0,
                 from .pio/libdeps/esp32dev/SD/utility/SdFat.h:29,
                 from .pio/libdeps/esp32dev/SD/SD.h:25,
                 from .pio/libdeps/esp32dev/SD/File.cpp:15:
.pio/libdeps/esp32dev/SD/utility/Sd2PinMap.h:371:2: error: #error Architecture or board not supported.
 #error Architecture or board not supported.
  ^
src/main.cpp: In function 'void bmpDraw(const char*, int, int)':
src/main.cpp:52:20: error: 'read16' was not declared in this scope
   if(read16(bmpFile) == 0x4D42) { // BMP signature
                    ^
src/main.cpp:54:34: error: 'read32' was not declared in this scope
     Serial.println(read32(bmpFile));
                                  ^
src/main.cpp:131:49: error: 'color565' was not declared in this scope
             lcdbuffer[lcdidx++] = color565(r,g,b);
                                                 ^
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp: In member function 'uint8_t Sd2Card::init(uint8_t, uint8_t, int8_t, int8_t, int8_t)':
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp:302:17: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'volatile uint8_t* {aka volatile unsigned char*}' in assignment
     clkport     = portOutputRegister(digitalPinToPort(clockPin_));
                 ^
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp:304:17: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'volatile uint8_t* {aka volatile unsigned char*}' in assignment
     mosiport    = portOutputRegister(digitalPinToPort(mosiPin_));
                 ^
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp:306:17: error: cannot convert 'volatile uint32_t* {aka volatile unsigned int*}' to 'volatile uint8_t* {aka volatile unsigned char*}' in assignment
     misoport    = portInputRegister(digitalPinToPort(misoPin_));
                 ^
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp: In member function 'uint8_t Sd2Card::readData(uint32_t, uint16_t, uint16_t, uint8_t*)':
.pio/libdeps/esp32dev/SD/utility/Sd2Card.cpp:438:12: warning: unused variable 'n' [-Wunused-variable]
   uint16_t n;
            ^
*** [.pio/build/esp32dev/src/main.cpp.o] Error 1
*** [.pio/build/esp32dev/lib8c5/SD/utility/Sd2Card.cpp.o] Error 1
*** [.pio/build/esp32dev/lib8c5/SD/File.cpp.o] Error 1
*** [.pio/build/esp32dev/lib8c5/SD/SD.cpp.o] Error 1

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

I think this compilation error comes down your ESP32 arch not being correctly detected which is usually caused by an incorrect installation of the arduino esp32 core.

https://github.com/espressif/arduino-esp32/issues/2191

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

I have looked at the forum link you posted and specified what board I was using. I am still getting this error "#error Architecture or board not supported." Do you have any other ideas on how to fix this issue?

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

@rick1fx,

Agreed. The "#error Architecture or board not supported" is the message to focus on.

I would re-install the Arduino-ESP32 board libraries as suggested by the guide:

https://docs.espressif.com/projects/ard ... lling.html

https://github.com/espressif/arduino-esp32/

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

I have re-installed Arduino ESP32 board libraries and am still getting this error " #error Architecture or board not supported. " I don't understand why my SD Card Reader won't work with an ESP32 board.

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: RA8875 Bitmap Pre-processing

Post by mikeysklar »

@rick1fx,

This thread is off topic from the Bitmap pre-processing.

Let's troubleshoot your ESP32 / SD card setup elsewhere. Please start a new thread and include photos your setup and brief summary of your libraries / arduino version / controllers / firmware etc.

User avatar
rick1fx
 
Posts: 11
Joined: Wed Aug 11, 2021 6:20 pm

Re: RA8875 Bitmap Pre-processing

Post by rick1fx »

@mikeysklar,

I will make a new forum post when my new TFT display comes in a week or so. Thanks for all your help!!!

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Arduino products from Adafruit”