element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Arduino
  • Products
  • More
Arduino
Blog Arduino Uno Q and DIYables 3.5in color TFT Display
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Arduino to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: rsc
  • Date Created: 21 Jan 2026 4:21 PM Date Created
  • Views 4277 views
  • Likes 12 likes
  • Comments 3 comments
  • tft screen
  • arduino uno q
  • adafruit
Related
Recommended

Arduino Uno Q and DIYables 3.5in color TFT Display

rsc
rsc
21 Jan 2026

The Arduino Uno Q is a very powerful and feature rich device, however, some features are tricky to implement, TFT displays and SD cards included.

It took me a few days to determine what libraries to use to get my TFT display to work.

This is the display I wanted to use, since it was already in the usual Arduino shield configuration.

https://diyables.io/products/3.5-inch-color-tft-lcd-display-screen-module-320x480-non-touch-for-arduino-uno-and-mega-ili9486-8-bit-parallel-interface

image

The way I approached this task was to configure two systems, one with an Arduino Uno and a TFT display, and the second with an Arduino Uno Q with a TFT display. Then I tried to compile and run each of the example programs included with the various TFT and GFX libraries I had installed into the Arduino IDE on each system to see what features would compile, and which would not compile.

When an example file successfully compiled as received, I saved that file with an extension "WorksWithUno" or "WorksWithQ" as a first pass.

After that, I combined code from each working model to get the display working with correct colors and fonts, and the SD file system working while displaying a local bitmap file on the screen.

I also needed to install the Arduino serial monitor bridge code and change all the serial.println("") code to Monitor.print("") code needed for the Q interface to App Lab.

There was one compile error I fixed by editing this file:

\AppData\Local\Arduino15\libraries\SD\src/utility/SdFatUtil.h:40:15: error: conflicting declaration 'int __bss_end'

extern int __bss_end;

I changed it to:

extern char __bss_end[]; and it compiled.

image

The library MCUFRIEND_kbv works well on the UNO, but will not compile for the Q.

Now that I have a working TFT display, I will try and share data across the "bridge" between the Python program and the Arduino sketch....to be continued...

I added an Adafruit Proto-Screwshield to the board and it lets me get at the pins for experimenting with sensors.

https://learn.adafruit.com/adafruit-proto-screw-shield/intro

image

image

Here is the test code that finally worked.

/*
   Arduino Uno Q with DIYables 3.5 inch 480 x 240 TFT display
   CapperLabs 11 January 2026
   *** To Do ***
   
*/

#include <Arduino.h>
#include <Arduino_RouterBridge.h>
#include <Adafruit_GFX.h>    // Core graphics library
#include <DIYables_TFT_Shield.h>
#include <SD.h>
#include <Fonts/FreeSansBold24pt7b.h>

#define MAGENTA   DIYables_TFT::colorRGB(255, 0, 255)
#define ORANGE    DIYables_TFT::colorRGB(255, 165, 0)
#define PINK      DIYables_TFT::colorRGB(255, 192, 203)
#define VIOLET    DIYables_TFT::colorRGB(148, 0, 211)
#define TURQUOISE DIYables_TFT::colorRGB(64, 224, 208)
#define YELLOW    DIYables_TFT::colorRGB(255, 255, 40)
#define BLACK   0x0000
#define RED     0xF800
#define BLUE    0x001F
#define GREEN   0x07E0
#define WHITE   0xFFFF
#define GREY    0x8410

#define BUFFPIXEL 20  // Buffer size remains the same

DIYables_TFT_ILI9486_Shield TFT_display;
#define SD_CS 10
File bmpFile;
uint16_t SCREEN_WIDTH;
uint16_t SCREEN_HEIGHT;

void showmsgXY(int x, int y, int sz, const GFXfont *f, const char *msg)
{
    int16_t x1, y1;
    uint16_t wid, ht;
    TFT_display.setFont(f);
    TFT_display.setCursor(x, y);
    TFT_display.setTextColor(GREEN);
    TFT_display.setTextSize(sz);
    TFT_display.print(msg);
}
  // Create a Bridge instance

void setup() {

  Bridge.begin();
  Monitor.begin();
  if (!SD.begin(SD_CS)) {
    Monitor.println("SD card initialization failed!");
    return;
  }
  Monitor.println("SD card initialized successfully.");
  Monitor.println(F("TFT Test Jan2026"));

  TFT_display.begin();
  TFT_display.setFont(&FreeSansBold24pt7b);
  // Set the rotation (0 to 3)
  TFT_display.setRotation(1);  // Rotate screen 90 degrees
  // After rotation, update screen dimensions
  SCREEN_WIDTH = TFT_display.width();
  SCREEN_HEIGHT = TFT_display.height();
  TFT_display.fillScreen(BLACK);
  // Outlined round rectangle (Full Screen)
  TFT_display.drawRoundRect(5, 5, 470, 310, 15, RED);
  showmsgXY(130, 120, 1, &FreeSansBold24pt7b, "TFT Test");
  showmsgXY(130, 200, 1, &FreeSansBold24pt7b, "Jan 2026");
  // Show a .bmp file from SD card
  // Get image dimensions
  uint32_t imgWidth, imgHeight;
  if (getBMPDimensions("mybmp.bmp", imgWidth, imgHeight)) {
    Monitor.print("BMP Image Width: ");
    Monitor.println(imgWidth);
    Monitor.print("BMP Image Height: ");
    Monitor.println(imgHeight);
  } else {
    Monitor.println("Failed to get BMP dimensions");
  }

  // Center the image based on its dimensions
  int x = (SCREEN_WIDTH - imgWidth) / 2;
  int y = (SCREEN_HEIGHT - imgHeight) / 2;

  drawBMP("mybmpf.bmp", x, 220);  // Draw image at calculated position
  delay(2000);
}
void loop(void) {
  delay(2000);
  TFT_display.fillScreen(BLACK);
  TFT_display.drawRoundRect(5, 5, 470, 310, 15, RED);
  showmsgXY(130, 120, 1, &FreeSansBold24pt7b, "TFT Test");
  showmsgXY(170, 200, 1, &FreeSansBold24pt7b, "Jan 2026");
  drawBMP("mybmp.bmp", 120, 220);  // Draw image at calculated position
  delay(2000);
}
// Helper functions to read BMP file header
uint16_t read16(File &f) {
  uint16_t result;
  result = f.read();
  result |= (f.read() << 8);
  return result;
}

uint32_t read32(File &f) {
  uint32_t result;
  result = f.read();
  result |= ((uint32_t)f.read() << 8);
  result |= ((uint32_t)f.read() << 16);
  result |= ((uint32_t)f.read() << 24);
  return result;
}

// Function to read a signed 32-bit integer
int32_t readS32(File &f) {
  int32_t result;
  result = f.read();
  result |= ((uint32_t)f.read() << 8);
  result |= ((uint32_t)f.read() << 16);
  result |= ((uint32_t)f.read() << 24);
  return result;
}

// Function to draw BMP from SD card
void drawBMP(const char *filename, int x, int y) {
  bmpFile = SD.open(filename);
  if (!bmpFile) {
    Monitor.println("File not found");
    return;
  }

  if (read16(bmpFile) != 0x4D42) {  // Check BMP signature
    Monitor.println("Not a BMP file");
    bmpFile.close();
    return;
  }

  // Skip unnecessary BMP header details
  Monitor.println("BMP signature OK");

  uint32_t fileSize = read32(bmpFile);
  Monitor.print("File Size: ");
  Monitor.println(fileSize);

  read32(bmpFile);                         // Reserved bytes (skip)
  uint32_t imageOffset = read32(bmpFile);  // Start of image data
  Monitor.print("Image Data Offset: ");
  Monitor.println(imageOffset);

  uint32_t dibHeaderSize = read32(bmpFile);  // DIB header size
  Monitor.print("DIB Header Size: ");
  Monitor.println(dibHeaderSize);

  // Now read the width and height of the image
  uint32_t bmpWidth = read32(bmpFile);
  int32_t bmpHeight = readS32(bmpFile);  // Read as signed 32-bit integer
  Monitor.print("Image Width: ");
  Monitor.println(bmpWidth);
  Monitor.print("Image Height: ");
  Monitor.println(bmpHeight);

  bool topDown = true;  // Flag to check if the image is top-down
  if (bmpHeight < 0) {
    bmpHeight = -bmpHeight;  // Make height positive for processing
    topDown = true;          // Mark the BMP as top-down
  }

  if (read16(bmpFile) != 1) {  // Planes must be 1
    Monitor.println("Invalid BMP file");
    bmpFile.close();
    return;
  }

  uint16_t depth = read16(bmpFile);  // Color depth
  Monitor.print("Bit Depth: ");
  Monitor.println(depth);

  if (depth != 24) {  // Only 24-bit BMP supported
    Monitor.println("Only 24-bit BMP is supported");
    bmpFile.close();
    return;
  }

  if (read32(bmpFile) != 0) {  // No compression
    Monitor.println("Unsupported BMP compression");
    bmpFile.close();
    return;
  }

  // Move to the start of the image data
  bmpFile.seek(imageOffset);

  uint8_t sdbuffer[3 * BUFFPIXEL];  // Buffer for 20 pixels (3 bytes per pixel)
  uint16_t color;
  uint32_t rowSize = (bmpWidth * 3 + 3) & ~3;  // BMP rows are padded to 4-byte boundaries

  // Adjust x and y if image is larger than screen
  if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) {
    Monitor.println("Image position out of screen bounds");
    return;
  }

  uint32_t maxRow = min(bmpHeight, SCREEN_HEIGHT - y);
  uint32_t maxCol = min(bmpWidth, SCREEN_WIDTH - x);

  // Draw the image
  for (uint32_t row = 0; row < maxRow; row++) {
    int32_t rowPos = topDown ? row : bmpHeight - 1 - row;  // Adjust for top-down BMPs

    uint32_t filePosition = imageOffset + rowPos * rowSize;
    bmpFile.seek(filePosition);  // Move to the correct row

    for (uint32_t col = 0; col < maxCol; col += BUFFPIXEL) {
      uint32_t pixelsToRead = min(BUFFPIXEL, maxCol - col);  // Avoid reading beyond row width
      bmpFile.read(sdbuffer, 3 * pixelsToRead);              // Read multiple pixels at once

      for (uint32_t i = 0; i < pixelsToRead; i++) {
        uint8_t b = sdbuffer[i * 3];
        uint8_t g = sdbuffer[i * 3 + 1];
        uint8_t r = sdbuffer[i * 3 + 2];
        color = DIYables_TFT::colorRGB(r, g, b);

        // Draw pixel on screen if within bounds
        if ((x + col + i) < SCREEN_WIDTH && (y + row) < SCREEN_HEIGHT) {
          TFT_display.drawPixel(x + col + i, y + row, color);
        }
      }
    }
  }

  bmpFile.close();  // Close file when done
  Monitor.println("Finished drawing BMP");
}

// Function to get BMP image dimensions
bool getBMPDimensions(const char *filename, uint32_t &width, uint32_t &height) {
  File bmpFile = SD.open(filename);
  if (!bmpFile) {
    Monitor.println("File not found");
    return false;
  }

  if (read16(bmpFile) != 0x4D42) {  // Check BMP signature
    Monitor.println("Not a BMP file");
    bmpFile.close();
    return false;
  }

  read32(bmpFile);  // Skip file size
  read32(bmpFile);  // Skip reserved bytes
  uint32_t imageOffset = read32(bmpFile);  // Start of image data

  uint32_t dibHeaderSize = read32(bmpFile);  // DIB header size

  // Read the width and height of the image
  width = read32(bmpFile);
  int32_t bmpHeight = readS32(bmpFile);  // May be negative for top-down images
  height = (bmpHeight < 0) ? -bmpHeight : bmpHeight;

  bmpFile.close();  // Close the file
  return true;      // Success
  delay(20000);
}

This code works on both the Arduino IDE compiler and the Arduino App Lab compiler, however, the Arduino Ide uses "Serial" instead of "Monitor" commands.

  • Sign in to reply
  • robogary
    robogary 7 months ago

    thanks - will be needing to reference your discoveries in the future

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • rsc
    rsc 7 months ago in reply to DAB

    I have two projects in mind that could use upgrades, but nothing immediately.

    I'm assuming there will be a Q.v2, Q.v3...etc until they settle on the design.  It might go like the RPi series.  I'm having trouble upgrading a RPi3B+ project currently due to issues compiling the old libraries.  I like the platform though.  The more people work with it and publish examples, the more likely it will survive.  They should probably start the "Q" magazine now...

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB 7 months ago

    Nice post.

    Are you planning an application for these devices?

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube