Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprites all going to PSRAM despite setAttribute function #3576

Open
gkeepleft opened this issue Dec 13, 2024 · 3 comments
Open

Sprites all going to PSRAM despite setAttribute function #3576

gkeepleft opened this issue Dec 13, 2024 · 3 comments

Comments

@gkeepleft
Copy link

Hi,

I hope someone can help me.

I have been trying for a while to send certain sprites to SRAM and others to PSRAM on a ESP32 wrover and they are all going to PSRAM regardless of any combination of uncommented lines in my setup. The LCD displays the sprites perfectly fine.

programCode.zip

I have tried using different boards in the board manager :
ESP32 dev module
ESP32 wrover module
ESP32 wrover kit (all versions)

Im using:
arduino IDE version 2.3.3
TFT_eSPI version 2.5.43
SSD1963 TFT controller in 8 bit parallel

The pins in the User_Setup.h file are:

// The ESP32 and TFT the pins used for testing are:
#define TFT_CS   33  // Chip select control pin (library pulls permanently low
#define TFT_DC   15  // Data Command control pin - must use a pin in the range 0-31
#define TFT_RST  32  // Reset pin, toggles on startup

#define TFT_WR    4  // Write strobe control pin - must use a pin in the range 0-31
#define TFT_RD    2  // Read strobe control pin

#define TFT_D0   12  // Must use pins in the range 0-31 for the data bus
#define TFT_D1   13  // so a single register write sets/clears all bits.
#define TFT_D2   26  // Pins can be randomly assigned, this does not affect
#define TFT_D3   25  // TFT screen update performance.
#define TFT_D4   5   
#define TFT_D5   19   
#define TFT_D6   27
#define TFT_D7   14

in this example im just tring to push some nested sprites to another sprite and then to the lcd. which works fine. but its going to the wrong RAM allocation.
see code below.

#include <TFT_eSPI.h>  // Include the TFT_eSPI library

TFT_eSPI tft = TFT_eSPI();  // Create TFT object

TFT_eSprite spr1 = TFT_eSprite(&tft);  // Main sprite 1 (SRAM)
TFT_eSprite spr2 = TFT_eSprite(&tft);  // Main sprite 2 (PSRAM)
TFT_eSprite nestedSpr = TFT_eSprite(&tft);  // Nested sprite (used for rectangles)

void setup() {
  Serial.begin(115200);
  
  spr1.setColorDepth(16);
  //tft.setAttribute(PSRAM_ENABLE, false);
  spr1.setAttribute(PSRAM_ENABLE, false);
  //psramInit();
  spr2.setColorDepth(16);
  //tft.setAttribute(PSRAM_ENABLE, true);
  spr2.setAttribute(PSRAM_ENABLE, true);
  // Initialize PSRAM (the ESP32 should automatically handle this, but we can check it)
  if (psramFound()) {
    Serial.println("PSRAM is available and initialized.");
  } else {
    Serial.println("PSRAM is not available.");
  }

  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);

  uint32_t startTime, elapsedTime;

  // **1. Main Sprite in SRAM**
  startTime = micros();  // Start timer in microseconds
  spr1.createSprite(240, 240);  // Increased sprite size to 240x240
  spr1.fillSprite(TFT_RED);  // Fill background with red

  // Nested Sprite for White Rectangles

  nestedSpr.createSprite(240, 240);
  nestedSpr.fillSprite(TFT_PURPLE);  // Transparent background

  // Draw sequentially smaller white rectangles inside the sprite and push each to the main sprite
  for (int i = 0; i < 6; i++) {
    int offset = i * 20;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, 240 - 2 * offset, 240 - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr1, 0, 0, TFT_PURPLE);  // Push each rectangle
  }

  spr1.pushSprite(0, 0);  // Push main sprite to display
  elapsedTime = micros() - startTime;  // Total time in microseconds
  uint32_t totalTimeSRAM = elapsedTime;

  // Free nested sprite
  nestedSpr.deleteSprite();

  // **2. Main Sprite in PSRAM**
  startTime = micros();  // Start timer for PSRAM
  spr2.createSprite(240, 240);  // Increased sprite size to 240x240
  spr2.fillSprite(TFT_BLUE);  // Fill background with blue

  // Nested Sprite for White Rectangles

  nestedSpr.createSprite(240, 240);
  nestedSpr.fillSprite(TFT_PURPLE);  // Transparent background

  // Draw sequentially smaller white rectangles inside the sprite and push each to the main sprite
  for (int i = 0; i < 6; i++) {
    int offset = i * 20;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, 240 - 2 * offset, 240 - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr2, 0, 0, TFT_PURPLE);  // Push each rectangle
  }

  spr2.pushSprite(0, 240);  // Push main sprite to display (offset down to avoid overlap)
  elapsedTime = micros() - startTime;  // Total time in microseconds
  uint32_t totalTimePSRAM = elapsedTime;

  // Set larger font size and display timings beneath each sprite
  tft.setTextColor(TFT_WHITE, TFT_BLACK);  // White text, black background
  tft.setTextDatum(TR_DATUM);              // Top-right align text
  tft.setTextSize(2);                      // Increase font size (default is 1)
  
  // Adjust text positioning and display the timings in microseconds
  tft.drawString("SRAM: " + String(totalTimeSRAM) + " us", 780, 40);  // SRAM timing
  tft.drawString("PSRAM: " + String(totalTimePSRAM) + " us", 780, 100);  // PSRAM timing

  // Check sprite memory allocation
  checkSpriteMemory("spr1", spr1);
  checkSpriteMemory("spr2", spr2);
  
  // Free all sprites
  spr1.deleteSprite();
  spr2.deleteSprite();
  nestedSpr.deleteSprite();
}

void loop() {
  // Nothing here
}

void checkSpriteMemory(const char* spriteName, TFT_eSprite& sprite) {
  uint8_t* spriteBuffer = (uint8_t*)sprite.getPointer();
  if (spriteBuffer != nullptr) {
    if (esp_ptr_external_ram(spriteBuffer)) {
      Serial.print(spriteName);
      Serial.println(" is stored in PSRAM...........................***********");
    } else if (esp_ptr_internal(spriteBuffer)) {
      Serial.print(spriteName);
      Serial.println(" is stored in internal SRAM..........................");
    } else {
      Serial.print(spriteName);
      Serial.println(" memory location could not be determined.");
    }
  } else {
    Serial.print(spriteName);
    Serial.println(" buffer is NULL (not allocated).");
  }
}

The output im getting is:

rst:0x1 (POWERON_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
flash read err, 1000
ets_main.c 371 
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x33 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
PSRAM is available and initialized.
spr1 is stored in PSRAM...........................***********
spr2 is stored in PSRAM...........................***********
@Basitadam
Copy link

What happens if you disable PSRAM via board manager?

@gkeepleft
Copy link
Author

gkeepleft commented Dec 13, 2024

Ahh bugger, Hey, thanks for pointing that out.. They are too big to fit in SRAM... But if i change all of the spr1 spr2 and nestedSprites to 120 x 120 they both go into SRAM. And after this change if I enable PSRAM in the board manager, they both go into PSRAM.

Ive also moved the tft.begin() up to the top of the setup.

Any ideas?

@gkeepleft
Copy link
Author

gkeepleft commented Dec 15, 2024

Hey, so i have an update.

I've since found out that this works, but only for sprites under 45 x 45 pixels. Is there a way of making the allowed size for sprites using SRAM bigger? i have had SRAM successfully hold 2 sprites at 200 x 150 pixels without problem (after turning PSRAM: Enabe off in the IDE setup.

#include <TFT_eSPI.h>  // Include the TFT_eSPI library

int spriteXSize = 45;
int spriteYSize = 45;

TFT_eSPI tft = TFT_eSPI();  // Create TFT object

TFT_eSprite spr1 = TFT_eSprite(&tft);  // Main sprite 1 (SRAM)
TFT_eSprite spr2 = TFT_eSprite(&tft);  // Main sprite 2 (PSRAM)
TFT_eSprite nestedSpr = TFT_eSprite(&tft);  // Nested sprite (used for rectangles)

void setup() {
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);

  spr1.setColorDepth(16);
  spr1.setAttribute(3, false);  // Disable PSRAM for spr1 (use SRAM)
  
  // Allocate sprite in SRAM
  spr1.createSprite(spriteXSize, spriteYSize);

  spr2.setColorDepth(16);
  spr2.setAttribute(PSRAM_ENABLE, true);  // Enable PSRAM for spr2
  
  // Allocate sprite in PSRAM
  spr2.createSprite(spriteXSize, spriteYSize);

  // Initialize PSRAM (the ESP32 should automatically handle this, but we can check it)
  if (psramFound()) {
    Serial.println("PSRAM is available and initialized.");
  } else {
    Serial.println("PSRAM is not available.");
  }

  uint32_t startTime, elapsedTime;

  // **1. Main Sprite in SRAM**
  startTime = micros();  // Start timer in microseconds
  spr1.fillSprite(TFT_RED);  // Fill background with red

  // Nested Sprite for White Rectangles
  nestedSpr.createSprite(spriteXSize, spriteYSize);
  nestedSpr.fillSprite(TFT_PURPLE);  // Transparent background

  // Draw sequentially smaller white rectangles inside the sprite and push each to the main sprite
  for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr1, 0, 0, TFT_PURPLE);  // Push each rectangle
  }
    for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr1, 0, 0, TFT_PURPLE);  // Push each rectangle
  }
    for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr1, 0, 0, TFT_PURPLE);  // Push each rectangle
  }

  spr1.pushSprite(0, 0);  // Push main sprite to display
  elapsedTime = micros() - startTime;  // Total time in microseconds
  uint32_t totalTimeSRAM = elapsedTime;

  // Free nested sprite
  nestedSpr.deleteSprite();

  // **2. Main Sprite in PSRAM**
  startTime = micros();  // Start timer for PSRAM
  spr2.fillSprite(TFT_BLUE);  // Fill background with blue

  // Nested Sprite for White Rectangles
  nestedSpr.createSprite(spriteXSize, spriteYSize);
  nestedSpr.fillSprite(TFT_PURPLE);  // Transparent background

  // Draw sequentially smaller white rectangles inside the sprite and push each to the main sprite
  for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr2, 0, 0, TFT_PURPLE);  // Push each rectangle
  }
    for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr2, 0, 0, TFT_PURPLE);  // Push each rectangle
  }
    for (int i = 0; i < 8; i++) {
    int offset = i * 3;  // Larger offset for visibility in 240x240 sprite
    nestedSpr.drawRect(offset, offset, spriteXSize - 2 * offset, spriteYSize - 2 * offset, TFT_WHITE);
    nestedSpr.pushToSprite(&spr2, 0, 0, TFT_PURPLE);  // Push each rectangle
  }

  spr2.pushSprite(0, 240);  // Push main sprite to display (offset down to avoid overlap)
  elapsedTime = micros() - startTime;  // Total time in microseconds
  uint32_t totalTimePSRAM = elapsedTime;

  // Set larger font size and display timings beneath each sprite
  tft.setTextColor(TFT_WHITE, TFT_BLACK);  // White text, black background
  tft.setTextDatum(TR_DATUM);              // Top-right align text
  tft.setTextSize(2);                      // Increase font size (default is 1)
  
  // Adjust text positioning and display the timings in microseconds
  tft.drawString("SRAM: " + String(totalTimeSRAM) + " us", 780, 40);  // SRAM timing
  tft.drawString("PSRAM: " + String(totalTimePSRAM) + " us", 780, 100);  // PSRAM timing

  // Check sprite memory allocation
  checkSpriteMemory("spr1", spr1);
  checkSpriteMemory("spr2", spr2);
  
  // Free all sprites
  spr1.deleteSprite();
  spr2.deleteSprite();
  nestedSpr.deleteSprite();
}

void loop() {
  // Nothing here
}

void checkSpriteMemory(const char* spriteName, TFT_eSprite& sprite) {
  uint8_t* spriteBuffer = (uint8_t*)sprite.getPointer();
  if (spriteBuffer != nullptr) {
    if (esp_ptr_external_ram(spriteBuffer)) {
      Serial.print(spriteName);
      Serial.println(" is stored in PSRAM...........................***********");
    } else if (esp_ptr_internal(spriteBuffer)) {
      Serial.print(spriteName);
      Serial.println(" is stored in internal SRAM..........................");
    } else {
      Serial.print(spriteName);
      Serial.println(" memory location could not be determined.");
    }
  } else {
    Serial.print(spriteName);
    Serial.println(" buffer is NULL (not allocated).");
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants