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();
}