Tricked Out MKRZero

I recently bought a MKRZero, impressed with its speed, memory, and the built-in SD Reader. It is fun to work with (even if a bit finicky). I am building a TOS tricorder simulation to insert inside a MARKO tricorder case. There is very limited space.

I am using the Adafruit_ILI9341 library with the TFT is hooked up through the default SPI:

#define TFT_DC 6     // DC and CS seem to be swappable without change in speed
#define TFT_CS 7     // DC and CS seem to be swappable without change in speed
#define TFT_RS 4     // Labelled as "#define PIN_SPI_SS    (4u)" in "github.com/.../variants/mkrzero/variant.h"
// PIN_SPI_MISO  (10u)
// PIN_SPI_MOSI  (8u)
// PIN_SPI_SCK   (9u)
Adafruit_ILI9341 myTft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RS);

I can swap DC and CS with little effect on the speed. I originally had RS running through a resistor to Vcc, but I much prefer it software wired in.

To engage the SD reader, I just used the code:

 if (!SD.begin(SDCARD_SS_PIN)) {
  Serial.println("failed!");
 }

The documentation indicates it has its very own SPI, and it works wonderfully. I use it to store and read my 16-byte, 565 RAW bitmaps (using BITMAP3HEADER). I wrote code (with the assistance of Bodmer and Prentice) that employs tft.pushColor to draw the RAW images from the SD reader to the screen. Because they are 16-byte, 565 RAW files, the read time is much faster than reading BMP files. The average time is around 1580 ms for a full 320×240 screen image. I would like to reduce the time. More on that later.

I hooked up an MP3Player through Serial1 using the built in RX and TX lines (pins 13 and 14):

#include <DFRobotDFPlayerMini.h>  // MP3 player
// extern Uart Serial1;
// PIN_SERIAL1_RX (13ul)
// PIN_SERIAL1_TX (14ul)
DFRobotDFPlayerMini myDFPlayer;                   // Creates player object
Serial1.begin(9600);
if (!myDFPlayer.begin(Serial1)) {
    Serial.println(F("Unable to begin:"));
}

I did this (rather than having the MKRZero play the music) because I wanted the music playing while, for example, reading a RAW image to the screen. I send a quick code through TX, and the MP3Player happily plays that track to its end. I did have to set up a logic shifter for TX and RX because the MP3Player prefers 5V rather than 3V3.

I used CapacitiveSensor.h to set up three capacitive touch buttons that control the functions of the tricorder.

I also have three LEDs that signal at various times.

All of these things work together quite nicely with, seemingly, no conflicts. It's quite a tricked out MKRZero! I even have a few pins (A0, A4, A5, A6, D0, D11, and D12) left for future expansion. It seems as though the MKRZero has slipped under the radar a bit. It would be nice to see more people have success with it.

My next step is to try to augment a library (I have never tried that before) to pushColor more than one piece of data at a time. I think that could dramatically improve the read time of the RAW images from the SD reader. Wish me luck!

I have one question for anyone familiar with the Adafruit_GFX and Adafruit_ILI9341 libraries: Is there a way to tft.pushColor a BMP (or RAW image in my case) to the screen without first having to call the tft.fillScreen or tft.fillRect command? Or the question may be better phrased: What happens in the tft.fillScreen and tft.fillRect commands that allows a RAW image to be loaded? Any help would be appreciated.

Minimal.zip (353 KB)

Question:
Is there a way to tft.pushColor a BMP (or RAW image in my case) to the screen without first having to call the tft.fillScreen or tft.fillRect command? Or the question may be better phrased: What happens in the tft.fillScreen and tft.fillRect commands that allows a RAW image to be loaded?

I managed to get the write time for a 320×240 RAW image down to about 1100 ms and I eliminated the need for a fillScreen call by using the tft.writePixels() function in <Adafruit_SPITFT.h>

It would be nice to get the write time down even more, but I am quite happy with my progress to date.

/*     ####    ####   ####    #####   #####   #   #   ####     ###    #   #
      #       #       #   #   #       #       ##  #   #   #   #   #   #   #
       ###    #       ####    ###     ###     # # #   ####    #####   # # #
          #   #       #   #   #       #       #  ##   #   #   #   #   # # #
      ####     ####   #   #   #####   #####   #   #   #   #   #   #    ###

Description:     Fills the entire scre by drawing a 565 format 16 bit RAW image file at 0, 0
Requirements:    The screen must be in 320 by 240 landscape (rotation 1 or 3)
Based On:        Bodmer's drawRAW with help from Prentice
Modified by:     KodiakBart Feburary 2021
***************************************************************************************/
void screenRAW(char *filename, int c) {
  File     rawFile;               // File name to draw
  int16_t rawWidth = 320;         // Width of screen RAWs
  int16_t rawHeight = 240;        // Height of screen RAWs
  uint16_t  sdBuffer[rawWidth];   // SD read pixel buffer (16 bits per pixel)
  uint32_t drawTime;              // Keep track of speed
  uint32_t headerReader;          // To read data from the header
  uint32_t imageOffset;           // To read image offset data from the header

  if ((rawFile = SD.open(filename)) == NULL) {     // Check file exists and open it
    Serial.println(F("File not found"));           // Send a message to Serial
    return;                                        // Exit function if the file is not found
  }
  Serial.print(F("File Name = "));                 // Serial info
  Serial.println(filename);                        // Show in serial monitor
  //myTft.fillScreen(c);                           // Clear the screen -- THERE HAS TO BE A BETTER WAY
  drawTime = millis();                             // Save current time for performance evaluation
  myTft.startWrite();                              // Initiate the write sequence
  myTft.setAddrWindow(0, 0, rawWidth, rawHeight);  // Set whole screen as writable window starting at top left

  // Parse the RAW (Bitmap) header
  rawFile.read(sdBuffer, 10);                          // Reads 10 bytes for File Type, File Size, and Reserved data
  imageOffset = read32(rawFile);                       // Reads 4 bytes for image offset
  Serial.print(F("Header Size = "));                   // Serial info
  Serial.println(imageOffset);                         // Show in serial monitor
  headerReader = read32(rawFile);                      // Reads unused header size
  headerReader = read32(rawFile);                      // Reads 4 bytes for width
  Serial.print(F("Width = "));                         // Serial info
  Serial.println(headerReader);                        // Show in serial monitor
  headerReader = read32(rawFile);                      // Reads 4 bytes for height
  Serial.print(F("Height = "));                        // Serial info
  Serial.println(4294967296 - headerReader);           // Show in serial monitor
  rawFile.read(sdBuffer, imageOffset - 26);            // Reads the rest of the header
  Serial.print(F("Size of sdBuffer = "));              // Serial info
  Serial.println(sizeof(sdBuffer));                    // Show in serial monitor
  for (int row = 0; row < 240; row++) {                // Read and push the data
    rawFile.read(sdBuffer, 640);                       // Read the row
    myTft.writePixels(sdBuffer, uint32_t(rawWidth));   // Write the row
  }
  myTft.endWrite();                                    // End the write sequence
  rawFile.close();                                     // Close file
  drawTime = millis() - drawTime;                      // Show draw time
  Serial.print(F("Draw Time in ms = "));
  Serial.println(drawTime);
  Serial.println();
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.