Using TFT and Neopixel at the same time

Hello, I am trying to get a TFT screen and a Neopixel ring to work on an arduino due at the same time.

For now, I'd just like the neopixel ring to continue rotating a red colour, while the screen plays a variety of pictures in an animation.

What I'm actually getting, is the neopixel ring rotates once, then turns off, then the tft screen starts playing its animations.

Next I'd also like to interupt an animation whenever a pin is high, and do another animation, but they won't be interupted, they just go through all animations then it does whatever pin high requests. For now I have not included any input pins, the interupt will by via serial from an arduino Pro Mini.

I believe that the Neopixels, the TFT screen AND the Pro Mini will all be using serial, and maybe that's what is causing the problem, but this is way outside of my comfort zone, so feel free to correct me.

I have the TFT screen connected to the SPI pins on the Due.

So for now, how can I get the Neopixels to start up at the same time as the TFT screen and continue animating while the TFT is displaying images. Here's my code:

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ILI9341_due_config.h>
#include <ILI9341_due.h>
#include <Adafruit_NeoPixel.h>

#define TFT_RST 8	// uncomment if you have ILI9340
#define TFT_DC 9	// Command/Data for LCD
#define TFT_CS 10	// Chip Select for LCD
#define SD_CS 4		// Chip Select for SD card
#define BUFFPIXELCOUNT 160	// size of the buffer in pixels
#define SD_SPI_SPEED SPI_HALF_SPEED	// SD card SPI speed, try SPI_FULL_SPEED
#define PIN      6
#define N_LEDS 144

int incomingByte;      // a variable to read incoming serial data into


SdFat sd; // set filesystem
SdFile bmpFile; // set filesystem
//ArduinoOutStream cout(Serial);

//ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC);		//ILI9341
ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, TFT_RST);	//ILI9340


// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
  Serial.begin(9600);
  strip.begin();
  tft.begin();
  //tft.setSPIClockDivider(4);
  progmemPrint(PSTR("Initializing SD card..."));

  if (!sd.begin(SD_CS, SD_SPI_SPEED)) {
    progmemPrintln(PSTR("failed!"));
    return;
  }
  progmemPrintln(PSTR("OK!"));
}

void loop()
{
  tft.setRotation(iliRotation90);

  chase(strip.Color(255, 0, 0)); // Red animation on Neopixel Ring, only plays once

  Overdrive(); // TFT animation, waits until neopixel has finished

}

unsigned long Overdrive() {
  bmpDraw("OD_1.565", 0, 0);
  bmpDraw("OD_7.565", 0, 0);
  bmpDraw("OD_8.565", 0, 0);
  bmpDraw("OD_9.565", 0, 0);
  bmpDraw("OD_10.565", 0, 0);
  bmpDraw("OD_11.565", 0, 0);
  bmpDraw("OD_12.565", 0, 0);
  bmpDraw("OD_13.565", 0, 0);
  bmpDraw("OD_14.565", 0, 0);
  bmpDraw("OD_18.565", 0, 0);
  bmpDraw("OD_19.565", 0, 0);
  bmpDraw("OD_20.565", 0, 0);
  bmpDraw("OD_21.565", 0, 0);
  bmpDraw("OD_22.565", 0, 0);
  bmpDraw("OD_23.565", 0, 0);
  bmpDraw("OD_24.565", 0, 0);
  bmpDraw("OD_25.565", 0, 0);
  bmpDraw("OD_26.565", 0, 0);
  bmpDraw("OD_27.565", 0, 0);
  bmpDraw("OD_28.565", 0, 0);
  bmpDraw("OD_29.565", 0, 0);
  bmpDraw("OD_30.565", 0, 0);
  bmpDraw("OD_31.565", 0, 0);
  bmpDraw("OD_32.565", 0, 0);
  bmpDraw("OD_33.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);
  bmpDraw("OD_34.565", 0, 0);

}

//Neopixel animation from movie
void chase(uint32_t c) {
  for (uint16_t i = 0; i < strip.numPixels() + 40; i++) {
    strip.setPixelColor(i  , c); // Draw new pixel
    strip.setPixelColor(i - 40, 0); // Erase pixel a few steps back
    strip.show();
    delay(25);
  }
}

// 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 RAM but
// makes loading a little faster.

void bmpDraw(const char* filename, int x, int y) {

  SdFile   bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint8_t	 headerSize;
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;     // Not always = bmpWidth; may have padding
  uint32_t fileSize;
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip = true;        // BMP is stored bottom-to-top
  uint16_t w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime;

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

  progmemPrint(PSTR("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');
  startTime = millis();
  // Open requested file on SD card
  if (!bmpFile.open(filename, O_READ)) {
    Serial.println("File open failed.");
    return;
  }
  else {
    //Serial.println("File opened.");
  }

  // Parse BMP header
  if (read16(bmpFile) == 0x4D42) { // BMP signature
    fileSize = read32(bmpFile);
    //progmemPrint(PSTR("File size: ")); Serial.println(fileSize);
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    //progmemPrint(PSTR("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    headerSize = read32(bmpFile);
    //progmemPrint(PSTR("Header size: ")); Serial.println(headerSize);
    bmpWidth = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      //progmemPrint(PSTR("Bit Depth: ")); Serial.println(bmpDepth);
      if (read32(bmpFile) == 0) // 0 = uncompressed
      {
        //progmemPrint(PSTR("Image size: "));
        //Serial.print(bmpWidth);
        //Serial.print('x');
        //Serial.println(bmpHeight);

        // 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
        tft.setAddrWindow(x, y, x + w - 1, y + h - 1);

        if (bmpDepth == 16)	//565 format
        {
          goodBmp = true; // Supported BMP format -- proceed!

          uint16_t buffer[BUFFPIXELCOUNT]; // pixel buffer

          bmpFile.seekSet(54);	//skip header
          uint32_t totalPixels = (uint32_t)bmpWidth * (uint32_t)bmpHeight;
          uint16_t numFullBufferRuns = totalPixels / BUFFPIXELCOUNT;
          for (uint32_t p = 0; p < numFullBufferRuns; p++) {
            // read pixels into the buffer
            bmpFile.read(buffer, 2 * BUFFPIXELCOUNT);
            // push them to the diplay
            tft.pushColors(buffer, 0, BUFFPIXELCOUNT);

          }

          // render any remaining pixels that did not fully fit the buffer
          uint32_t remainingPixels = totalPixels % BUFFPIXELCOUNT;
          if (remainingPixels > 0)
          {
            bmpFile.read(buffer, 2 * remainingPixels);
            tft.pushColors(buffer, 0, remainingPixels);
          }

        }
        else
        {
          progmemPrint(PSTR("Unsupported Bit Depth."));
        }

        if (goodBmp)
        {
          progmemPrint(PSTR("Loaded in "));
          Serial.print(millis() - startTime);
          Serial.println(" ms");
        }
      }
    }
  }

  bmpFile.close();
  if (!goodBmp) progmemPrintln(PSTR("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(SdFile& f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(SdFile& 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;
}

// Copy string from flash to serial port
// Source string MUST be inside a PSTR() declaration!
void progmemPrint(const char *str) {
  char c;
  while (c = pgm_read_byte(str++)) Serial.print(c);
}

// Same as above, with trailing newline
void progmemPrintln(const char *str) {
  progmemPrint(str);
  Serial.println();
}

As the Due is not running a operating System or multitasking scheduler the functions get called sequentially. So the behavior is exactly what you would expect.

As you have a Mini Pro, program that to run the Neopixels and use the Due to the more processing intensive animations. A digital signals between the Due and Mini Pro can be used to synchronise the actions of each processor.

To "interrupt" the animation you need to check for the abort signal after each individual image is loaded and "return" from the function, doing this means keeps the display tidy without partial images and the SD Card files get closed properly etc.

The pro mini will be unable to control the Neopixels. It is in another location (serial via bluetooth). Is there no way of programming the neopixels to "do this until I tell you to stop".

Abort signal on images? This sounds interesting. I will look into this more. However, there is a total of around 100 - 200 images. I had to remove them from my code here because it went over the allowed character limit. I dont min'd stopping half way through an image, if it saves me finding abort codes for 200 images.

If it is going to be completely impossible to run the Neopixels and TFT simultaneously, I guess I can get another pro mini to handle the Neopixels, I'd rather avoid this though.

MagicD48:
Is there no way of programming the neopixels to "do this until I tell you to stop".

No, the neopixels change colour only when the processor is sending data to them. So add a pro mini to drive the neopixels, a digital I/O line can tell it when to start and stop driving them.

MagicD48:
Abort signal on images? This sounds interesting. I will look into this more. However, there is a total of around 100 - 200 images. I had to remove them from my code here because it went over the allowed character limit. I dont min'd stopping half way through an image, if it saves me finding abort codes for 200 images.

Check if an animation needs to be stopped at the end of the bmpDraw(...) function and set a flag called say "stop" to 1 if the animation is to stop. At the beginning of bmpDraw() add the line:

if (stop) return;

You will need to set "stop" to 0 somewhere when you want the animation to start again.

MagicD48:
If it is going to be completely impossible to run the Neopixels and TFT simultaneously, I guess I can get another pro mini to handle the Neopixels, I'd rather avoid this though.

Adding another mini pro is the simplest solution otherwise you will need to figure out how to multiplex between display and neopixel updates. Your posted questions indicate you will probably find this very difficult to do and you may be disappointed at how slow the animation becomes anyway!

Perfect response. Thank you. I'll buy a new pro mini :slight_smile:

bodmer:
No, the neopixels change colour only when the processor is sending data to them. So add a pro mini to drive the neopixels, a digital I/O line can tell it when to start and stop driving them.

Check if an animation needs to be stopped at the end of the bmpDraw(...) function and set a flag called say "stop" to 1 if the animation is to stop. At the beginning of bmpDraw() add the line:

if (stop) return;

You will need to set "stop" to 0 somewhere when you want the animation to start again.

Adding another mini pro is the simplest solution otherwise you will need to figure out how to multiplex between display and neopixel updates. Your posted questions indicate you will probably find this very difficult to do and you may be disappointed at how slow the animation becomes anyway!

Can not get these flags to work... Stopping the animation seems impossible.

@MagicD48

Post a copy of your latest sketch so I can suggest mods.

bodmer:
@MagicD48

Post a copy of your latest sketch so I can suggest mods.

I have removed a lot of the tat that you don't need to bother with. Might be some irrelevant stuff still in there though. Also, sorry for the VERY slow reply, I've been off this part of the project for quite some time. It was stressing me out.

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ILI9341_due_config.h>
#include <ILI9341_due.h>

#include <Servo.h>
Servo myservo;  // create servo object to control a servo 
int pos = 0;    // variable to store the servo position 

#define TFT_RST 8 // uncomment if you have ILI9340
#define TFT_DC 9 // Command/Data for LCD
#define TFT_CS 10 // Chip Select for LCD
#define SD_CS 4 // Chip Select for SD card
#define BUFFPIXELCOUNT 160 // size of the buffer in pixels
#define SD_SPI_SPEED SPI_HALF_SPEED // SD card SPI speed, try SPI_FULL_SPEED

boolean stop = false;
boolean odstop = true;

int inPin = 7;
int inPin1 = 53; 
int val = 0;

int incomingByte;      // a variable to read incoming serial data into


SdFat sd; // set filesystem
SdFile bmpFile; // set filesystem
//ArduinoOutStream cout(Serial);

//ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC); //ILI9341
ILI9341_due tft = ILI9341_due(TFT_CS, TFT_DC, TFT_RST); //ILI9340


// store error strings in flash to save RAM
#define error(s) sd.errorHalt_P(PSTR(s))

void setup()
{ 
 Serial.begin(9600);
  pinMode (53, INPUT);
 tft.begin();
 //tft.setSPIClockDivider(4);
 progmemPrint(PSTR("Initializing SD card..."));

 if (!sd.begin(SD_CS, SD_SPI_SPEED)){
 progmemPrintln(PSTR("failed!"));
 return;
 }
 progmemPrintln(PSTR("OK!"));
  tft.setRotation(iliRotation90);

}

void loop()
{
  digitalWrite (53, HIGH);
  val = digitalRead(53); { // read input value of sWITCH
        if (val == HIGH) {
         stop = true;
         odstop = true;
        }
        else {
         stop = false;
         odstop = false;
        }
        }
  if (stop == true)
    {
     WhoYa();
    }
  else if (stop == false)
    {
      Overdrive();
    }
}


void Overdrive() {
    bmpDraw("OD_1.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_2.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_3.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_4.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_5.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_6.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_7.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_8.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_9.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_18.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_18.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_19.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_19.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_20.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_20.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_21.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_21.565", 0, 0);
    if (odstop) return;
    bmpDraw("OD_22.565", 0, 0);
    if (odstop) return;
    
    }


void WhoYa() {
  bmpDraw("WYGC1.565", 0, 0);
  bmpDraw("WYGC2.565", 0, 0);
  bmpDraw("WYGC3.565", 0, 0);
  bmpDraw("WYGC4.565", 0, 0);
  bmpDraw("WYGC5.565", 0, 0);
  bmpDraw("WYGC7.565", 0, 0);
  bmpDraw("WYGC9.565", 0, 0);
  bmpDraw("WYGC10.565", 0, 0);
  bmpDraw("WYGC11.565", 0, 0);
  bmpDraw("WYGC12.565", 0, 0);
  bmpDraw("WYGC13.565", 0, 0);
  bmpDraw("WYGC14.565", 0, 0);
  bmpDraw("WYGC15.565", 0, 0);
  bmpDraw("WYGC16.565", 0, 0);
}



// 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 RAM but
// makes loading a little faster.  

void bmpDraw(const char* filename, int x, int y) {

 SdFile   bmpFile;
 int      bmpWidth, bmpHeight;   // W+H in pixels
 uint8_t  bmpDepth;              // Bit depth (currently must be 24)
 uint8_t headerSize;
 uint32_t bmpImageoffset;        // Start of image data in file
 uint32_t rowSize;     // Not always = bmpWidth; may have padding
 uint32_t fileSize;
 boolean  goodBmp = false;       // Set to true on valid header parse
 boolean  flip = true;        // BMP is stored bottom-to-top
 uint16_t w, h, row, col;
 uint8_t  r, g, b;
 uint32_t pos = 0, startTime;

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

 progmemPrint(PSTR("Loading image '"));
 Serial.print(filename);
 Serial.println('\'');
 startTime = millis();
 // Open requested file on SD card
 if (!bmpFile.open(filename, O_READ)) {
 Serial.println("File open failed.");
 return;
 }
 else {
 //Serial.println("File opened.");
 }

 // Parse BMP header
 if (read16(bmpFile) == 0x4D42) { // BMP signature
 fileSize = read32(bmpFile);
 //progmemPrint(PSTR("File size: ")); Serial.println(fileSize);
 (void)read32(bmpFile); // Read & ignore creator bytes
 bmpImageoffset = read32(bmpFile); // Start of image data
 //progmemPrint(PSTR("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
 // Read DIB header
 headerSize = read32(bmpFile);
 //progmemPrint(PSTR("Header size: ")); Serial.println(headerSize);
 bmpWidth = read32(bmpFile);
 bmpHeight = read32(bmpFile);
 if (read16(bmpFile) == 1) { // # planes -- must be '1'
 bmpDepth = read16(bmpFile); // bits per pixel
 //progmemPrint(PSTR("Bit Depth: ")); Serial.println(bmpDepth);
 if (read32(bmpFile) == 0) // 0 = uncompressed
 {
 //progmemPrint(PSTR("Image size: "));
 //Serial.print(bmpWidth);
 //Serial.print('x');
 //Serial.println(bmpHeight);

 // 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
 tft.setAddrWindow(x, y, x + w - 1, y + h - 1);

 if (bmpDepth == 16) //565 format
 {
 goodBmp = true; // Supported BMP format -- proceed!

 uint16_t buffer[BUFFPIXELCOUNT]; // pixel buffer

 bmpFile.seekSet(54); //skip header
 uint32_t totalPixels = (uint32_t)bmpWidth*(uint32_t)bmpHeight;
 uint16_t numFullBufferRuns = totalPixels / BUFFPIXELCOUNT;
 for (uint32_t p = 0; p < numFullBufferRuns; p++) {
 // read pixels into the buffer
 bmpFile.read(buffer, 2 * BUFFPIXELCOUNT);
 // push them to the diplay
 tft.pushColors(buffer, 0, BUFFPIXELCOUNT);
 
 }

 // render any remaining pixels that did not fully fit the buffer
 uint32_t remainingPixels = totalPixels % BUFFPIXELCOUNT;
 if (remainingPixels > 0)
 {
 bmpFile.read(buffer, 2 * remainingPixels);
 tft.pushColors(buffer, 0, remainingPixels);
 }

 }
 else
 {
 progmemPrint(PSTR("Unsupported Bit Depth."));
 }

 if (goodBmp)
 {
 progmemPrint(PSTR("Loaded in "));
 Serial.print(millis() - startTime);
 Serial.println(" ms");
 }
 }
 }
 }

 bmpFile.close();
 if (!goodBmp) progmemPrintln(PSTR("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(SdFile& f) {
 uint16_t result;
 ((uint8_t *)&result)[0] = f.read(); // LSB
 ((uint8_t *)&result)[1] = f.read(); // MSB
 return result;
}

uint32_t read32(SdFile& 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;
}

// Copy string from flash to serial port
// Source string MUST be inside a PSTR() declaration!
void progmemPrint(const char *str) {
 char c;
 if (c = pgm_read_byte(str++)) Serial.print(c);
}

// Same as above, with trailing newline
void progmemPrintln(const char *str) {
 progmemPrint(str);
 Serial.println();
}

I've refreshed this page about a million times hoping you'll come back. I feel lost without you lol
:cry: Please come back.

Try this: MEGA BMP slider

libraries inside: ILI9341_due (V094), Utouch, Adafruit_Neopixel, Adafruit:GFX, Adafruit_NeoMatrix, SdFat

Details:
Arduino MEGA
Neopixel
TFT ILI9341 2.4", with touch panel, ILI9341_due (V94), Utouch

22 images on 565 format

The upload of a single image (in 565 format) requiered the full load of the MCU, so the neopixel-cicle continues after the image is on the TFT

TFTLCDCyg:
Try this: MEGA BMP slider

libraries inside: ILI9341_due (V094), Utouch, Adafruit_Neopixel, Adafruit:GFX, Adafruit_NeoMatrix, SdFat

Details:
Arduino MEGA
Neopixel
TFT ILI9341 2.4", with touch panel, ILI9341_due (V94), Utouch

22 images on 565 format

The upload of a single image (in 565 format) requiered the full load of the MCU, so the neopixel-cicle continues after the image is on the TFT

Hey do you think this will work on a teensy?

I don´t have idea, but you can explore it with the ILI9341_t3 library, by the way, the load of bmp is very slow.

Teensy 3.6 and FT813

I have a teensy 3.6, with a FT813 TFT 5"@GD3_SDIO, with a 8x5 WS2812 matrix and your idea is posible

#include <SPI.h>
#include <GD3_SDIO.h>  //THX RndMnkIII

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>

File archivo;
SdFatSdio SD;

unsigned long start;

//Neopixel
#define PIN 21
#define NUMPIXELS      40

Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(5, 8, 1, 1, PIN,
  NEO_MATRIX_COLUMNS + NEO_MATRIX_BOTTOM + NEO_MATRIX_LEFT,
  NEO_GRB + NEO_KHZ800);

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
int BrilloMX = 150;

void setup()
{
  pixels.begin(); // This initializes the NeoPixel library
  matrix.begin();    matrix.setBrightness(BrilloMX); 

  GD.begin();
  GD.cmd_setrotate(0);
  
  SD.begin();

  JPGSlider();
}

void loop(){}

char nombre[32];
int ID = 1;
long previousMillisBMP = 0, previousMillisNEO = 0;
long intervalBMP = 100,  intervalNEO = 30;

void JPGSlider()
{
  GD.wr(REG_PWM_DUTY, 0);
  while(1){
  GD.wr(REG_PWM_DUTY, 30);
  unsigned long currentMillisNEO = millis();        
   if(currentMillisNEO - previousMillisNEO > intervalNEO)
    {previousMillisNEO = currentMillisNEO;
     Cylon1(100,0,0); pixels.show();}
    
  unsigned long currentMillisBMP = millis();        
   if(currentMillisBMP - previousMillisBMP > intervalBMP)
    {previousMillisBMP = currentMillisBMP;   
     start = millis();
     snprintf(nombre, 30, "V%03d.jpg", ID);
     String str(nombre);
     archivo = SD.open(str);      
     GD.cmd_loadimage(0, 0);
     GD.loadSDIO(archivo);
     CargaJPG();  ID++;   if (ID>=161){ID=1;}
    }
  }
}

void CargaJPG()
{
   GD.Clear();
   GD.Begin(BITMAPS);  
   GD.Vertex2ii(0, 0); 
   
   GD.ColorRGB(0,255,0);  GD.cmd_number(730,465,21,OPT_CENTER|OPT_SIGNED,millis() - start);              
   GD.swap();
}

Video: BMP slider MEGA vs Teensy 3.6

correct me if im wrong but wouldnt you just put yield in your bmp load? which as i understand or remember correctly makes arduino work on longer slow processes "when it can"

ps why do you have a blow up doll as your avatar?

tbillion:
correct me if im wrong but wouldnt you just put yield in your bmp load? which as i understand or remember correctly makes arduino work on longer slow processes "when it can"

ps why do you have a blow up doll as your avatar?

It's not a blow up doll!!!!! That's my damn face!!!!! I'm poking my tongue out, not opening my mouth.

https://www.instagram.com/p/4MhuJtgub4/

I have achieved the main goal of this thread now.

Thanks to everyone that helped.