Adafruit TFT crashes/resets on dimming

Hello everyone, thanks for your help in advance

In my car I have an UNO running an Adafruit 1.44" TFT (non eye-spi) screen which receives CAN BUS data from a Nano via software serial. The UNO is also running other functions and as a result has all of its digital pins (sans 0 and 1) consumed. The TFT's backlight can be dimmed by sending a PWM signal to the board's Lite pin, which is normally high (100% ground = off).

As the Nano has spare digital pins, I tasked it with controlling the PWM signal (setting analogWrite() to either 127 or 255 depending on an analogue input connected to the car's radio dimming wire) to dim the TFT . As the Nano shares a ground with the UNO to enable the software serial to work, the dimming also works.

However - either the UNO or the TFT (unsure as yet) crashes/rests about 2 seconds after the car's headlights are switched on, which activates the dimming. The screen usually goes completely white (which it does both on initial start and when no signal is input) but other times I have seen it display random colors and looks as though it is receiving a garbage signal.

The backlight always responds correcetly - full brightness when dimming disactivated and dimmed when activated. But when I disable the dimming, the TFT remains borked. If I reset the Uno whilst the dimming signal is still active from the Nano, the same thing happens - clear display and signal from the Uno for about 2 or 3 seconds, then back to white display/random colors.

I have checked that no wires are shorted and there is no solder overlap on any of the pins. Everything seems to be in order hardware wise, and the Uno/TFT functions perfectly, continuously, when the dimming is inactive.

Is it possible I have a dud TFT? I am willing to purchase another one to find out as they are relatively cheap, but I would like to know if perhaps there is a coding issue or something I'm missing.

Nano code:

//RPM Shift Lights using an MCP2515 CAN bus board.
//Adafruit NeoPixel LED Sticks, two 8-led RGBW warm-white sticks.
//NeoPixel codes is (#,#,#,#,#) = (numberOfLed,Red,Green,Blue,White) numberOfLed = 0-15, Color is in brightness 0-255
//4N25 Opto-coupler input for dimming. 12v on diode side, ground on switch.

#include <mcp2515.h>
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>

#define rxPin 4
#define txPin 3

// Set up a new SoftwareSerial object
SoftwareSerial softSerial (rxPin, txPin);

int RPMno = 6000;   //base RPM for LED activation
int vehicleRPM = 0; //rpm value to be provided by CAN bus
int oilTemp = 0; //oil temperature from CAN bus
int coolant = 0; // coolant temperature from CAN bus

struct can_frame canMsg;
MCP2515 mcp2515(7); // bracketed number is number of CS pin
int ex = 0;
int why = 0;


//NeoPixels
#define PIN 6
#define NUM_LEDS 16
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRBW + NEO_KHZ800);
//full brightness
uint32_t r = strip.Color  (200, 0, 0, 0);
uint32_t g = strip.Color  (0, 180, 0, 0);
uint32_t b = strip.Color  (0, 0, 255, 0);
uint32_t w = strip.Color  (0, 0, 0, 120);
uint32_t y = strip.Color  (200, 120, 0, 0);
//dimmed
uint32_t rd = strip.Color (16, 0, 0, 0);
uint32_t gd = strip.Color (0, 14, 0, 0);
uint32_t bd = strip.Color (0, 0, 10, 0);
uint32_t wd = strip.Color (0, 0, 0, 6);
uint32_t yd = strip.Color (20, 10, 0, 0);
//off
uint32_t o = strip.Color   (0, 0, 0, 0);

int space = 100; //delay for led startup sequence

//Input for headlight circuit
#define headlights 2
bool val = 1;

unsigned long millisStart = 0;

//   _____ ______ _______ _    _ _____
//  / ____|  ____|__   __| |  | |  __ \ 
// | (___ | |__     | |  | |  | | |__) |
//  \___ \|  __|    | |  | |  | |  ___/
//  ____) | |____   | |  | |__| | |
// |_____/|______|  |_|   \____/|_|

void setup()
{
  //initiate neopixels
  strip.begin();
  //set strip to nothing, flushes potential random colors
  strip.clear();
  strip.fill(o);
  strip.show();

  ledStartup();

  //assign input for Optocoupler and PWM Output
  pinMode(headlights, INPUT_PULLUP);
  pinMode(10, OUTPUT);

  //setup the CANBus module
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_16MHZ);
  mcp2515.setListenOnlyMode();

  softSerial.begin(9600);
  Serial.begin(9600);
  
  millisStart = millis();
}


//  _      ____   ____  _____
// | |    / __ \ / __ \|  __ \ 
// | |   | |  | | |  | | |__) |
// | |   | |  | | |  | |  ___/
// | |___| |__| | |__| | |
// |______\____/ \____/|_|

void loop()
{
  //get CAN Message
  if ((mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK)) {
    getMessage();
  }
  strip.clear();
  dimmer();
  

  if (millis() >= millisStart + 200) {
    softSerial.println("<");
    softSerial.println(oilTemp);
    softSerial.println(",");
    softSerial.println(coolant);
    softSerial.println(",");
    softSerial.println(vehicleRPM);
    softSerial.println(">");
    millisStart = millis();
  }

  Serial.println(val);
  
}



//__      ______ _____ _____
// \ \    / / __ \_   _|  __ \ 
//  \ \  / / |  | || | | |  | |
//   \ \/ /| |  | || | | |  | |
//    \  / | |__| || |_| |__| |
//     \/   \____/_____|_____/
//
//            _
//  __ _  ___| |_ _ __ _ __  _ __ ___
// / _` |/ _ \ __| '__| '_ \| '_ ` _ \ 
//| (_| |  __/ |_| |  | |_) | | | | | |
// \__, |\___|\__|_|  | .__/|_| |_| |_|
// |___/              |_|

void getMessage (void) {           //formerly getRPM
  if (canMsg.can_id == 0x140) {
   ex = canMsg.data[2];
   why = canMsg.data[3];
   //combine the 2 digit hex for field 2 and field 3 to get decimal rpm
   vehicleRPM = (why & 0x3f) * 256 + ex;
   //Serial.print("RPM: ");
   //Serial.println(vehicleRPM);
  }
  if (canMsg.can_id == 0x360) {
    oilTemp = (canMsg.data[2]) - 40;
    coolant = (canMsg.data[3]) - 40;
    //Serial.println("Oil:");
    //Serial.println(oilTemp);
    //Serial.println("Coolant:");
    //Serial.println(coolant);
  }
}

//     _ _
//  __| (_)_ __ ___  _ __ ___   ___ _ __
// / _` | | '_ ` _ \| '_ ` _ \ / _ \ '__|
//| (_| | | | | | | | | | | | |  __/ |
// \__,_|_|_| |_| |_|_| |_| |_|\___|_|

void dimmer (void) {

  val = digitalRead(headlights);
  if (val == HIGH) {
    leds();
     analogWrite(10,255); //100% backlight - diming of TFT - PWM output
  }
  else {
    ledsDimmed();
     analogWrite(10,127); //50% backlight - diming of TFT - PWM output
  }
}


//  _          _
// | | ___  __| |___
// | |/ _ \/ _` / __|
// | |  __/ (_| \__ \
// |_|\___|\__,_|___/  font = ogre

void leds(void) {

  if (vehicleRPM > 0 && vehicleRPM < (RPMno - 1000) )
  {
    strip.fill(o); //----------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno - 1000) && vehicleRPM < (RPMno - 500) )
  {
    strip.fill(g, 14);  //gg--------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno - 500) && vehicleRPM < RPMno )
  {
    strip.fill(g, 12);  //gggg------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno) && vehicleRPM < (RPMno + 167))
  {
    strip.fill(b, 10);  //yyyyyy----------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 167) && vehicleRPM < (RPMno + 334))
  {
    strip.fill(b, 8);  //yyyyyyyy--------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 334) && vehicleRPM < (RPMno + 501))
  {
    strip.fill(b, 6);  //yyyyyyyyyy------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 501) && vehicleRPM < (RPMno + 668))
  {
    strip.fill(r, 4);        //yyyyyyyyyyyy----
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 668) && vehicleRPM < (RPMno + 835))
  {
    strip.fill(r, 2);        //rrrrrrrrrrrrrr--
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 835) && vehicleRPM < (RPMno + 1000))
  {
    strip.fill(r, 0);       //rrrrrrrrrrrrrr
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 1000) && vehicleRPM < (RPMno + 1500))
  {
    strip.fill(w);        //wwwwwwwwwwwwwwww
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 1500) && vehicleRPM < (RPMno + 2000) )
  {
    strip.fill(o);
    strip.show();
  }

  if (vehicleRPM > 10000)
  {
    strip.fill(o);
    strip.show();
  }
}

//  _          _        ___ _                              _
// | | ___  __| |___   /   (_)_ __ ___  _ __ ___   ___  __| |
// | |/ _ \/ _` / __| / /\ / | '_ ` _ \| '_ ` _ \ / _ \/ _` |
// | |  __/ (_| \__ \/ /_//| | | | | | | | | | | |  __/ (_| |
// |_|\___|\__,_|___/___,' |_|_| |_| |_|_| |_| |_|\___|\__,_|

void ledsDimmed(void)  {
  
  if (vehicleRPM > 0 && vehicleRPM < (RPMno - 1000) )
  {
    strip.fill(o); //----------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno - 1000) && vehicleRPM < (RPMno - 500) )
  {
    strip.fill(gd, 14);  //gg--------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno - 500) && vehicleRPM < RPMno )
  {
    strip.fill(gd, 12);  //gggg------------
    strip.show();
  }

  if (vehicleRPM >= (RPMno) && vehicleRPM < (RPMno + 167))
  {
    strip.fill(bd, 10);  //yyyyyy----------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 167) && vehicleRPM < (RPMno + 334))
  {
    strip.fill(bd, 8);  //yyyyyyyy--------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 334) && vehicleRPM < (RPMno + 501))
  {
    strip.fill(bd, 6);  //yyyyyyyyyy------
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 501) && vehicleRPM < (RPMno + 668))
  {
    strip.fill(rd, 4);        //yyyyyyyyyyyy----
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 668) && vehicleRPM < (RPMno + 835))
  {
    strip.fill(rd, 2);        //rrrrrrrrrrrrrr--
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 835) && vehicleRPM < (RPMno + 1000))
  {
    strip.fill(rd, 0);       //rrrrrrrrrrrrrr
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 1000) && vehicleRPM < (RPMno + 1500))
  {
    strip.fill(wd);        //wwwwwwwwwwwwwwww
    strip.show();
  }

  if (vehicleRPM >= (RPMno + 1500) && vehicleRPM < (RPMno + 2000) )
  {
    strip.fill(o);
    strip.show();
  }

  if (vehicleRPM > 10000)
  {
    strip.fill(o);
    strip.show();
  }
}

//  _          _      __ _             _
// | | ___  __| |___ / _\ |_ __ _ _ __| |_ _   _ _ __
// | |/ _ \/ _` / __|\ \| __/ _` | '__| __| | | | '_ \ 
// | |  __/ (_| \__ \_\ \ || (_| | |  | |_| |_| | |_) |
// |_|\___|\__,_|___/\__/\__\__,_|_|   \__|\__,_| .__/
//                                             |_|
void ledStartup(void)
{
  strip.fill(o);
  strip.show();
  delay(space);

  strip.fill(gd, 14);
  strip.show();
  delay(space);

  strip.fill(gd, 12);
  strip.show();
  delay(space);

  strip.fill(gd, 10);
  strip.show();
  delay(space);

  strip.fill(bd, 8);
  strip.show();
  delay(space);

  strip.fill(bd, 6);
  strip.show();
  delay(space);

  strip.fill(bd, 4);
  strip.show();
  delay(space);

  strip.fill(rd, 2);
  strip.show();
  delay(space);

  strip.fill(rd);
  strip.show();
  delay(space);
  //---------------------------
  strip.fill(wd);
  strip.show();
  delay(space * 2);
  //----------------------------
  strip.clear();
  strip.fill(rd);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(rd, 2);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(bd, 4);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(bd, 6);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(bd, 8);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(gd, 10);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(gd, 12);
  strip.show();
  delay(space);

  strip.clear();
  strip.fill(gd, 14);
  strip.show();
  delay(space);

  strip.fill(o);
  strip.show();
}

UNO Code:

// Arduino Uno R3 board
// Adafruit 1.44" 128x128 TFT screen
// Wire from Oil Temperature Sensor on engine
// Voltage divider sourced from 12v socket for Battery Voltage
// 2 modes, 0 and 1
// Auto-Switch for 86 VSC buttons - all off on startup
//softwareSerial for reading data from Nano in glovebox - Expected message: <#,#,#>

#define max_pin 7              // button to display maximumn recorded value for each parameter
#define VSC_out 5              // pin to control state of VSC 

int max_state = 0;             // state of max button
int modeButton = 0;     // counter for the number of mode button presses
int buttonUp = 0;
int buttonDown = 0;
int buttonStateUp = 0;
int buttonStateDown = 0;

unsigned long millisStart = 0;
unsigned long oilMillis = 0;
unsigned long voltsMillis = 0;
unsigned long buttonMillis = 0;

// TFT (use tft.### functions i.e. tft.println() )
 #include <Adafruit_GFX.h>    // Core graphics library
 #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
 #include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
 #include <SdFat.h>                // SD card & FAT filesystem library
 #include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
 #include <Adafruit_ImageReader.h> // Image-reading functions
 #include <SPI.h>
 #define TFT_CS        10
 #define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
 #define TFT_DC         8
 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); 
 float p = 3.1415926;
 //variables to hold cursor coordinates
 int x = 0;
 int y = 0;
 uint32_t black = 0x0000;
 uint32_t white = 0xFFFF;
 uint32_t red = 0xF800;
 uint32_t blue = 0x001F;
 uint32_t yellow = 0xFFE0;
 uint32_t green = 0x07E0;
 uint32_t cyan = 0x07FF;
 uint32_t magenta = 0xF81F;


//Software Serial  https://forum.arduino.cc/t/serial-input-basics-updated/382007/3
 #include <SoftwareSerial.h>
 #define rxPin 4
 #define txPin 1
 // Set up a new SoftwareSerial object
 SoftwareSerial softSerial (rxPin, txPin);

 const byte numChars = 32;        //32 bit serial buffer
 char receivedChars[numChars];
 char tempChars[numChars];        // temporary array for use when parsing  

 // variables to hold the parsed data
 int int1 = 0;
 int int2 = 0;
 int int3 = 0;

 //variables to clear screen when bigger number
 boolean newData = false;
 
 //for blanking screen over bigger/smaller numbers
 bool start = 0;
 bool big1 = 0;
 bool change1 = 0;
 bool big2 = 0;
 bool change2 = 0;
 bool big3 = 0;
 bool change3 = 0;
 
 



// Oil Temp Sensor and OBD int's
const int analogIn = A0; //for oil temp sensor voltage meter
int RawValue = 0;
float Voltage = 0;
int oilTemperature = 0;
int oilReading = 0;
int lastOil = 0;
int oilTemp_max = 0;
int oilTempDisplay = 0;
int nudat = 0;

//battery voltage
const int batAnalogIn = A5;
float batVoltage = 0;
float batValue = 0;
float bat_min = 100;
float batLast = 0;
float batAvg = 0;
float batVoltDisplay = 0;

//symbols
static const unsigned char PROGMEM battery[] = {
// 'Battery', 47x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xe0, 0x0f, 0x80, 0x00, 0x00, 
0x03, 0xe0, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xe0, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xe0, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 
0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x06, 0xc0, 0x00, 0x00, 0x00, 
0x03, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x06, 0xcf, 0xe0, 0x00, 0x00, 0x1f, 0xe6, 0xcf, 0xe0, 
0x00, 0x00, 0x1f, 0xe6, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x06, 
0xc0, 0x00, 0x00, 0x00, 0x03, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 
0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 
0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 
0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 
0x00, 0x06, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

static const unsigned char PROGMEM oil_lamp[] = {
// 'Oil Temp', 47x32px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 
0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 
0x3e, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xc0, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xf0, 0x38, 0x00, 
0x00, 0xf8, 0x7f, 0xf0, 0x38, 0x00, 0x0f, 0xfc, 0x79, 0xf0, 0x38, 0x00, 0x3f, 0xfe, 0x78, 0x3c, 
0x3f, 0x81, 0xff, 0x9c, 0xfc, 0x3e, 0x3f, 0x87, 0xff, 0x00, 0xff, 0xbe, 0x38, 0x1f, 0xfe, 0x00, 
0x3f, 0xfc, 0x38, 0x3f, 0x9e, 0x08, 0x0f, 0xf8, 0x38, 0x7c, 0x1c, 0x1c, 0x03, 0xf8, 0x7c, 0x70, 
0x38, 0x1c, 0x00, 0x78, 0xfe, 0x00, 0x70, 0x1c, 0x00, 0x38, 0xfe, 0x00, 0xe0, 0x1c, 0x00, 0x38, 
0x7c, 0x01, 0xe0, 0x3e, 0x00, 0x38, 0x38, 0x03, 0xc0, 0x3e, 0x00, 0x38, 0x00, 0x07, 0x80, 0x3e, 
0x00, 0x38, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x1c, 0x00, 0x3f, 0xff, 0xfe, 
0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

//  __      ______ _____ _____
//  \ \    / / __ \_   _|  __ \ 
//   \ \  / / |  | || | | |  | |
//    \ \/ /| |  | || | | |  | |
//     \  / | |__| || |_| |__| |
//      \/   \____/_____|_____/

//============

void oilTemp (void)
{
  RawValue = analogRead(analogIn);
  Voltage = (RawValue * 5.0) / 1023.0;
  oilReading = ((log(0.15905837 * Voltage)) / -0.0207);
  oilTemperature = (oilReading + lastOil) / 2;
  
  if ( oilTemperature > 150) 
   {
    oilTemperature = 0;
   }
  if ( oilTemperature > oilTemp_max)  
   {
    oilTemp_max = oilTemperature;
   }
   
  if (max_state == 1)
   {
    oilTempDisplay = oilTemp_max;
   }
   else
    {
     oilTempDisplay = oilTemperature;
    }
  
  lastOil = oilTemperature;
}

//============

void batVolts (void)
{
  batValue = analogRead(batAnalogIn);
  batVoltage = ((batValue * 5.0) / 1023.0) * 3.0545;
  batAvg = (batVoltage + batLast) / 2;
  batVoltDisplay = batAvg;   
  batLast = batAvg;
}

//============

void mode_counter_increase (void)
{
modeButton = 1;
}

//============

void mode_counter_decrease (void)
{
modeButton = 0;
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (softSerial.available() > 0 && newData == false) {
        rc = softSerial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    // strtokIndx = strtok(tempChars,",");      // get the first part - the string
    // strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC - make messageFromPC into strtokIndx
 
    strtokIndx = strtok(tempChars, ","); //NULL is after first delimiter, before first delimiter use tempChars
    int1 = atoi(strtokIndx);     // atoi = conver string to integer
        if (int1 >= 100){   
      big1 = 1;
      start = 1; //stops int3 being empty when program runs
     }
    else {
      if (big1 == 1); {
        change1 = 1;
      }
      big1 = 0;
    }
    
    strtokIndx = strtok(NULL, ",");
    int2 = atoi(strtokIndx);
        if (int2 >= 100){   
      big2 = 1;
      start = 1; //stops int3 being empty when program runs
     }
    else {
      if (big2 == 1); {
        change2 = 1;
      }
      big2 = 0;
    }

    strtokIndx = strtok(NULL, ",");
    int3 = atoi(strtokIndx);
    if (int3 >= 100){   
      big3 = 1;
      start = 1; //stops int3 being empty when program runs
     }
    else {
      if (big3 == 1); {
        change3 = 1;
      }
      big3 = 0;
    }
}



//   _____ ______ _______ _    _ _____
//  / ____|  ____|__   __| |  | |  __ \ 
// | (___ | |__     | |  | |  | | |__) |
//  \___ \|  __|    | |  | |  | |  ___/
//  ____) | |____   | |  | |__| | |
// |_____/|______|  |_|   \____/|_|

void setup()
{
  Serial.begin(9600);
  softSerial.begin(9600);

  // TFT
  tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
  tft.fillScreen(black);        
  //bitmaps, bars, static numbers
   tft.drawBitmap(0, 0, oil_lamp, 47, 32, white);
   tft.fillRect(0,34,2,2,white);
   tft.fillRect(25,34,2,2,white);
   tft.fillRect(55,34,2,2,white);
   tft.fillRect(110,34,2,2,white);
   tft.fillRect(126,34,2,2,white);
   tft.fillRect(83,34,2,2,white);
   tft.fillRect(0,36,128,1,white);
   tft.setTextColor(white);
   tft.setTextSize(1);
   tft.setCursor(21,39);
   tft.print(40);
   tft.setCursor(51,39);
   tft.print(85);
   tft.setCursor(75,39);
   tft.print(125);
   tft.setCursor(102,39);
   tft.print(170);
  

  //establish pin IO
  pinMode(max_pin, INPUT);            // max button
  pinMode(VSC_out, OUTPUT);           // VSC output
  pinMode(analogIn, INPUT);           // Oil Temp sensor

  //establish pins 2 and 3 as interrupts to select mode
  attachInterrupt(digitalPinToInterrupt(2), mode_counter_increase, FALLING);  // modeButton = 1
  attachInterrupt(digitalPinToInterrupt(3), mode_counter_decrease, FALLING);  // modeButton = 0
  
  delay(2000);
  digitalWrite(VSC_out, HIGH);
  delay(1500);
  millisStart = millis();
  digitalWrite(VSC_out, LOW);
 
}

//   _      ____   ____  _____
//  | |    / __ \ / __ \|  __ \ 
//  | |   | |  | | |  | | |__) |
//  | |   | |  | | |  | |  ___/
//  | |___| |__| | |__| | |
//  |______\____/ \____/|_|

void loop()
{
max_state = digitalRead(max_pin);
//tft.setCursor(50,50);
//tft.print(oilTempDisplay);
//tft.setCursor(100,50);
//tft.print(batAvg);


if ( millis() >= millisStart + 200 ) {
  Serial.println(nudat);
   oilTemp();
   batVolts();
 recvWithStartEndMarkers();


  if (newData == true) {
      nudat = 1;
      strcpy(tempChars, receivedChars);
          // this temporary copy is necessary to protect the original data
          //   because strtok() used in parseData() replaces the commas with \0
      parseData();
      
       //blank bigger numbers
       if (change1 == 1 && start == 1) {
       tft.fillRect(50,0,12,28,black); //(x,y,w,h,color)
       change1 = 0;
        } 
       if (change2 == 1 && start == 1) {
       tft.fillRect(112,50,28,28,black); //(x,y,w,h,color)
       change2 = 0;
        }       
       if (change3 == 1 && start == 1) {
       tft.fillRect(112,50,28,28,black); //(x,y,w,h,color)
       change3 = 0;
        } 
       tft.setTextSize(3); 
       tft.setTextColor(white,black); //(textcolor,background)

      //print data
       //int1
       if (big1 == 0) {
        tft.setCursor(67,7); 
        tft.print(int1);
       }
       else { 
        tft.setCursor(50,7);
        tft.print(int1);
       }
       tft.drawChar(102,7,0x09,white,black,2);
       tft.setTextSize(2);
       tft.setCursor(112,13);
       tft.print("C");
       if (int1 < 85) {
        tft.fillRect(0,31,2,3,blue);
        tft.fillRect(2,31,(int1*0.6484375),3,blue);
        tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
       }
       if (int1 >= 85 && int1 <=125) {
        tft.fillRect(0,31,2,3,green);
        tft.fillRect(2,31,(int1*0.6484375),3,green);
        tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
       }
       if (int1 >= 126) {
        tft.fillRect(0,31,2,3,red);
        tft.fillRect(2,31,(int1*0.6484375),3,red);
        tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
       }
       //int2
       tft.setTextSize(2);
       tft.setTextColor(red,black);
       tft.setCursor(10,100);
       if (modeButton == 0); {
        tft.println(oilTempDisplay);
       }
       if (modeButton == 1); { 
       tft.println(batVoltDisplay); 
       }
       
       tft.setTextColor(blue,black);
       tft.setCursor(100,100);
       tft.println(modeButton);
      
      //Serial.print("change");
      //Serial.println(change1);
      
      
      newData = false;
     }
   millisStart = millis();
   } 
 //Serial.println(buttonStateUp);    for diagnostic purposes
 //Serial.println(buttonStateDown);
 //Serial.println(max_state);
 //Serial.println(millisStart);

}

bump - no one? I thought it might have been the fact I hooked up the wires necessary for the SD card functions of the screen without adding any of the code, but today I set up the SD card functions in the code (which work) and it is still crashing when Lite recives a PWM signal.

Have you proven this outside your sketch - something minimal, nothing but the display with 'hello world" or something, and PWM'ing the 'Lite' pin?

Thank you for replying.

Yes, I tried the example sketch from Adafruit ImageReader library for the SD Card and added a bit in loop to show a simple increasing integer on the screen every 500ms (otherwise didn't touch code except for changing Card CS Pin from 4 to 6) and it still crashes - responds the same.

Update - since making the original post I've switched the UNO for a MEGA, as the sketch was too big, and am now also running PWM from the MEGA instead of the Nano. Furthermore, I purchased a brand new 1.44" TFT which is the latest model with a black PCB and eye-spi. I have modified the wiring so that the wire coming from the Lite pin now has a pull-down resistor to ground, and the MEGA writes the Lite wire to high from a digital pin to 'turn on' the screen. It works perfectly, but using anything other than analogWrite(255) to the Lite wire pin crashes the screen still. The dimming is now activated when receiving a high signal from a digital pin connected to the Nano, which writes high when the headlights are on.

For whatever reason I can now acheive crash-free dimming on the Adafruit GFX Library example sketch, which is activated upon reading a digital pin connected to an digitalWrite from the Nano corresponding to the headlights being on or not.

However, when running my program nothing has changed. It still crashes when turning the headlights on, but now instead of random colors the black background of the screen goes navy blue for a microsecond and then the whole screen goes white.

So naturally and at my wit's end, I commented out line by line of my code until I could dim the TFT without crashing, knowing that it wasn't a hardware issue as it works crash-free with the example sketch. And I made a discovery. If any text at all is being over-written, then it crashes. To clarify; it does not crash when anything is written to the screen in voidSetup, or if the screen is inverted in voidLoop. It only crashes when repeated text/font calls are made during voidLoop.

I have made certain that it does not crash when text is being written to the screen, if that text has no background specified (which makes the characters overlay on top of each other, leading to just white mess) but if I set a background color, leading to readable text, it will crash. It ONLY crashes when text is being written over other text, whilst the dimmer is activated. As there is no such thing in the example sketch, it works fine. This also explains why it would crash when I tried the increasing integer in the SD card library sketch - apparently, having tft.setCursor or tft.setColor in voidLoop crashes the screen if it is dimmed...

I am quite baffled by this, I am also baffled by the fact that the SD card bitmap display all of a sudden seems very glitchey, I now get random artefacting every time I load a bmp in voidSetup for a 'splash' screen, but I digress.

I'm pulling my hair out over this and quite frankly I'm about ready to try a different screen. Everything works absolutely fine until the screen dims. I have quintuple-checked wiring. Why does writing text whilst dimming cause crashing?? I'm begging someone, anyone, to help and give me some idea where to go next because I don't have any ideas other than to try a compltely different screen. Is there some different better way to write text to the screen? I just want a display with adjustable brightness to show data in real time :frowning:

// Arduino MEGA board
// Adafruit 1.44" 128x128 TFT screen
// Voltage divider sourced from 12v socket for Battery Voltage
// Auto-Switch for 86 VSC buttons - all off on startup
// softwareSerial for reading data from Nano in glovebox - Expected message: <#,#,#>

 #include <Adafruit_GFX.h>    // Core graphics library
 #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
 #include <SdFat.h>                // SD card & FAT filesystem library
 #include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
 #include <Adafruit_ImageReader.h> // Image-reading functions
 #include <SoftwareSerial.h>
 #include <SPI.h>
 
 // TFT (use tft.### functions i.e. tft.println() )
 #define SD_CS          13 // SD card select pin
 #define TFT_DC         8 // TFT display/command pin
 #define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
 #define TFT_CS        10 // TFT select pin 
 
 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); 

 //SD Card stuff 
  SdFat SD; // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys 

 Adafruit_Image       img;        // An image loaded into RAM
 int32_t              width  = 0, // BMP image dimensions
                      height = 0;
 
 //variables to hold cursor coordinates
 int x = 0;
 int y = 0;
 uint32_t black = 0x0000;
 uint32_t white = 0xFFFF;
 uint32_t red = 0xF800;
 uint32_t blue = 0x001F;
 uint32_t yellow = 0xFFE0;
 uint32_t green = 0x07E0;
 uint32_t cyan = 0x07FF;
 uint32_t magenta = 0xF81F;

//Software Serial  https://forum.arduino.cc/t/serial-input-basics-updated/382007/3
 #define rxPin 11
 #define txPin 42
 // Set up a new SoftwareSerial object
 SoftwareSerial softSerial (rxPin, txPin);

 const byte numChars = 32;        //32 bit serial buffer
 char receivedChars[numChars];
 char tempChars[numChars];        // temporary array for use when parsing  

 // variables to hold the parsed data
 int int1 = 0;
 int int2 = 0;
 int int3 = 0;
 int disp1 = 0;
 int disp2 = 0;
 int disp3 = 0;

 //variables to clear screen when bigger number
 boolean newData = false;
 
 //for blanking screen over bigger/smaller numbers
 bool start = 0;
 bool big1 = 0;
 bool change1 = 0;

//battery voltage
 const int batAnalogIn = A5;
 float batVoltage = 0;
 float batLast = 0;
 float batAvg = 0;

//headlight dimming
 #define headlightSignal 31
 #define Lite 12
 int headlights = 0;
 
//VSC control 
 #define VSC_out 5 //pin to control state of VSC 
 
//max value reading and mode buttons
//#define max_pin 7 //button to display maximumn recorded value for each parameter
//int max_state = 0; // state of max button
//int modeButton = 0; // counter for the number of mode button presses
 
 //debugging
 //bool nudat = 0;
 //int increase = 0;
 
 //millis to set delay between cycles of program
 unsigned long millisStart = 0;

static const unsigned char PROGMEM oil_lamp[] = {
  // 'Oil Temp', 47x32px
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 
  0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x38, 0x00, 0x00, 0x00, 
  0x3e, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xc0, 0x3f, 0x80, 0x00, 0x00, 0x3f, 0xf0, 0x38, 0x00, 
  0x00, 0xf8, 0x7f, 0xf0, 0x38, 0x00, 0x0f, 0xfc, 0x79, 0xf0, 0x38, 0x00, 0x3f, 0xfe, 0x78, 0x3c, 
  0x3f, 0x81, 0xff, 0x9c, 0xfc, 0x3e, 0x3f, 0x87, 0xff, 0x00, 0xff, 0xbe, 0x38, 0x1f, 0xfe, 0x00, 
  0x3f, 0xfc, 0x38, 0x3f, 0x9e, 0x08, 0x0f, 0xf8, 0x38, 0x7c, 0x1c, 0x1c, 0x03, 0xf8, 0x7c, 0x70, 
  0x38, 0x1c, 0x00, 0x78, 0xfe, 0x00, 0x70, 0x1c, 0x00, 0x38, 0xfe, 0x00, 0xe0, 0x1c, 0x00, 0x38, 
  0x7c, 0x01, 0xe0, 0x3e, 0x00, 0x38, 0x38, 0x03, 0xc0, 0x3e, 0x00, 0x38, 0x00, 0x07, 0x80, 0x3e, 
  0x00, 0x38, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x3f, 0xff, 0xff, 0x00, 0x1c, 0x00, 0x3f, 0xff, 0xfe, 
  0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  };

//  __      ______ _____ _____
//  \ \    / / __ \_   _|  __ \ 
//   \ \  / / |  | || | | |  | |
//    \ \/ /| |  | || | | |  | |
//     \  / | |__| || |_| |__| |
//      \/   \____/_____|_____/

//============

void batVolts (void)
{
  batVoltage = (((analogRead(batAnalogIn)) * 5.0) / 1023.0) * 3.0545;
  batAvg = (batVoltage + batLast) / 2;
  batLast = batAvg;
}

//============

void mode_counter_increase (void)
{
modeButton = 1;
}

//============

void mode_counter_decrease (void)
{
modeButton = 0;
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (softSerial.available() > 0 && newData == false) {
        rc = softSerial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars, ","); //NULL is after first delimiter, before first delimiter use tempChars
    int1 = atoi(strtokIndx);     // atoi = conver string to integer
    //following code to make it indent right - blanks numbers on screen when necessary
    //to fix in future
//        if (int1 >= 100){   
//      big1 = 1;
//      start = 1; //stops int1 being empty when program runs
//     }
//    else {
//      if (big1 == 1); {
//        change1 = 1;
//      }
//      big1 = 0;
//    }

    //2nd digit in serial sequence
    strtokIndx = strtok(NULL, ",");
    int2 = atoi(strtokIndx);

    //3rd digit etc..
    strtokIndx = strtok(NULL, ",");
    int3 = atoi(strtokIndx);
}



//   _____ ______ _______ _    _ _____
//  / ____|  ____|__   __| |  | |  __ \ 
// | (___ | |__     | |  | |  | | |__) |
//  \___ \|  __|    | |  | |  | |  ___/
//  ____) | |____   | |  | |__| | |
// |_____/|______|  |_|   \____/|_|

void setup()
{
  Serial.begin(9600);
  softSerial.begin(9600);
  
  //headlights I/O
  pinMode(Lite,OUTPUT);
  digitalWrite(Lite,LOW);
  pinMode(headlightSignal,INPUT);

  //VSC
  pinMode(VSC_out, OUTPUT); // VSC output

  //establish pins 2 and 3 as interrupts, mode increase button
  pinMode(max_pin, INPUT); // max button
  attachInterrupt(digitalPinToInterrupt(2), mode_counter_increase, RISING);  // modeButton = 1
  attachInterrupt(digitalPinToInterrupt(3), mode_counter_decrease, RISING);  // modeButton = 0

  // TFT
  tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
  
  //SD Card stuff
  ImageReturnCode stat; // Status from image-reading functions
  // The Adafruit_ImageReader constructor call (above, before setup())
  // accepts an uninitialized SdFat or FatVolume object. This MUST
  // BE INITIALIZED before using any of the image reader functions!
  Serial.print(F("Initializing filesystem..."));
  if(!SD.begin(SD_CS, SD_SCK_MHZ(10))) { // Breakouts require 10 MHz limit due to longer wires
    Serial.println(F("SD begin() failed"));
    for(;;); // Fatal error, do not continue
  }
  Serial.println(F("OK!")); 
  Serial.print(F("Loading 86x128.bmp to screen..."));
  stat = reader.drawBMP("/86x128.bmp", tft, 0, 0);
  reader.printStatus(stat);   // How'd we do?     
    
  analogWrite(12,255); //turn on backlight
  
  delay(1000);
  digitalWrite(VSC_out, HIGH); //'hold down' VSC button
  delay(2500);
  digitalWrite(VSC_out, LOW); //'release' VSC button
  
  tft.fillScreen(black);
  
  //bitmaps, bars, static numbers
   tft.drawBitmap(0, 0, oil_lamp, 47, 32, white);
   tft.drawChar(102,7,0x09,white,black,2);
   tft.setTextSize(2);
   tft.setCursor(112,13);
   tft.print("C");
   //oil temp gauge
   tft.fillRect(0,34,2,2,white);
   tft.fillRect(25,34,2,2,white);
   tft.fillRect(55,34,2,2,white);
   tft.fillRect(110,34,2,2,white);
   tft.fillRect(126,34,2,2,white);
   tft.fillRect(83,34,2,2,white);
   tft.fillRect(0,36,128,1,white);
   tft.setTextColor(white);
   tft.setTextSize(1);
   tft.setCursor(21,39);
   tft.print(40);
   tft.setCursor(51,39);
   tft.print(85);
   tft.setCursor(75,39);
   tft.print(125);
   tft.setCursor(102,39);
   tft.print(170);

  millisStart = millis();
}

//   _      ____   ____  _____
//  | |    / __ \ / __ \|  __ \ 
//  | |   | |  | | |  | | |__) |
//  | |   | |  | | |  | |  ___/
//  | |___| |__| | |__| | |
//  |______\____/ \____/|_|

void loop() 
{
 //max_state = digitalRead(max_pin); //to setup in future

 //headlights = digitalRead(headlightSignal); 
 //if (headlights == 1) {                     //// causes crashing of the TFT >:|
 //  analogWrite(12,50);
 //}
 //else {
 //  analogWrite(12,255);
 //}

 if ( millis() >= millisStart + 200 ) {
 
  recvWithStartEndMarkers();
  batVolts();
  
  //collect data from softSerial
  if (newData == true) {
      //nudat = 1;  //debugging
      //Serial.println(nudat);
      strcpy(tempChars, receivedChars);
          // this temporary copy is necessary to protect the original data
          //   because strtok() used in parseData() replaces the commas with \0
      parseData();
      newData = false;
      }
      
  //blank bigger numbers for oil temp
//to fix in future  
//   if (change1 == 1 && start == 1) {
//   tft.fillRect(50,0,12,28,black); //(x,y,w,h,color)
//   change1 = 0;
//   } 
 
  //Oil temp gauge - horizontal bar
   if (int1 < 85) {
   tft.fillRect(0,31,2,3,blue);
   tft.fillRect(2,31,(int1*0.6484375),3,blue);
   tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
   }
   if (int1 >= 85 && int1 <=125) {
   tft.fillRect(0,31,2,3,green);
   tft.fillRect(2,31,(int1*0.6484375),3,green);
   tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
   }
   if (int1 >= 126) {
   tft.fillRect(0,31,2,3,red);
   tft.fillRect(2,31,(int1*0.6484375),3,red);
   tft.fillRect(int1*0.6484375,31,(128-(int1*0.6484375+2)),3,black);
   }
  
  //print data
   //int1 = Oil temp value
   tft.setTextSize(3); 
   tft.setTextColor(white,black); //(textcolor,background)
//   if (big1 == 0) {
//   tft.setCursor(50,7); 
//   tft.print(int1);
//   }
//   else { 
   tft.setCursor(50,7);
   tft.print(int1);
//   }
   
  //battery voltage
  tft.setTextSize(2);
  tft.setTextColor(red,black);
  tft.setCursor(10,100);
  tft.print(batVoltage);
       

  //as yet unassigned value, maybe coolant temp
//  tft.setTextColor(blue,black);
//  tft.setCursor(100,100);
//  tft.println(headlights);
    
  
  millisStart = millis();
   } 
}

Here's pics btw, and a video of the tft crashing.





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