1.44" TFT freaks out when trying to dim with PWM

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
euniqe
 
Posts: 4
Joined: Mon Nov 12, 2018 9:13 pm

1.44" TFT freaks out when trying to dim with PWM

Post by euniqe »

Hello everyone, this is a copy of a post I made on the Arduino forums but haven't received any replies yet. In hindsight perhaps I should have posted here first.

In my car I have an Arduino UNO running an Adafruit 1.44" TFT (non eye-spi) screen which receives CAN BUS data from an Arduino 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 pins, it controls 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 TFT makes erroneous displays and crashes/resets 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 wash random colors over the screen and looks as though it is receiving a garbage signal.

The backlight always responds correctly - full brightness when dimming 'disactivated' (analogWrite(255)) and dimmed when activated (analogWrite(127)). 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. The TFT also shows random colors and pixels all over the place on top of the bitmap I have set to display for a second during setup, after a reset.

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 program functions perfectly, continuously, when the dimming is inactive. Any kind of ground signal on the Lite pin appears to break the TFT - I have tried stripping the wire and manually pressing it against ground with my hand, it always breaks the TFT, despite the backlight responding correctly.

Is it possible I have a dud TFT? I am willing to purchase and test another one, but I would like to know if perhaps there is a coding issue or something I'm missing or have done incorrectly.

Thanks in advance.

UNO Code:

Code: Select all

// 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 VSC_out 5              // pin to control state of VSC 
#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

// 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 <SdFat.h>                // SD card & FAT filesystem library
 #include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
 #include <Adafruit_ImageReader.h> // Image-reading functions
 
 #define SD_CS          6 // 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 
 #define USE_SD_CARD

 //SD Card stuff 
  SdFat SD; // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys
 
 Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); 
 Adafruit_Image       img;        // An image loaded into RAM
 int32_t              width  = 0, // BMP image dimensions
                      height = 0;
 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>
 #include <SPI.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;

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

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

//millis to set delay between cycles of program
 unsigned long millisStart = 0;

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

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

void oilTemp (void)
{
  oilRawValue = analogRead(analogIn);
  oilReading = ((log(0.15905837 * ((oilRawValue * 5.0) / 1023.0))) / -0.0207);
}
void batVolts (void)
{
  batVoltage = (((analogRead(batAnalogIn)) * 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
    //following code to make it indent right - blanks numbers on screen when necessary
        if (int1 >= 100){   
      big1 = 1;
      start = 1; //stops int3 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);

  // TFT
  tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab
  tft.fillScreen(black);
  
  //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 defined(USE_SD_CARD)
  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
  }
  #else
  // SPI or QSPI flash requires two steps, one to access the bare flash
  // memory itself, then the second to access the filesystem within...
  if(!flash.begin()) {
    Serial.println(F("flash begin() failed"));
    for(;;);
  }
  if(!filesys.begin(&flash)) {
    Serial.println(F("filesys begin() failed"));
    for(;;);
  }
  #endif
  Serial.println(F("OK!"));
  
  // Load full-screen BMP file 'lily128.bmp' at position (0,0) (top left).
  // Notice the 'reader' object performs this, with 'tft' as an argument.
  Serial.print(F("Loading lily128.bmp to screen..."));
  stat = reader.drawBMP("/lily128.bmp", tft, 0, 0);
  reader.printStatus(stat);   // How'd we do?     

  //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);
  digitalWrite(VSC_out, LOW);
  
  //bitmaps, bars, static numbers
  tft.fillScreen(black);
  //tft.drawBitmap(0, 0, oil_lamp, 47, 32, white);
  //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);

if ( millis() >= millisStart + 200 ) {
  oilTemp();
  batVolts();
  recvWithStartEndMarkers();

  if (newData == true) {
      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;
        } 
       tft.setTextSize(3); 
       tft.setTextColor(white,black); //(textcolor,background)

      //print data
       //int1 - Oil temp digits
       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");

       /*//Oil temp gauge
       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);
       }
       */
       //test volts/analog oil temp
       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);      
      
      newData = false;
     }
   millisStart = millis();
   } 
}
Nano code:

Code: Select all

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

User avatar
euniqe
 
Posts: 4
Joined: Mon Nov 12, 2018 9:13 pm

Re: 1.44" TFT freaks out when trying to dim with PWM

Post by euniqe »

Right, so I've made not-progress with this. I don't blame anyone for not replying, this is a ridiculous issue and my latest discovery is even more nonsensical.

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.

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 product completely. I cannot have a full-bright screen in my car 24 hours a day and the crashing makes no sense. Everything works absolutely fine until the scren 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 to show data in real time :(


MEGA code:

Code: Select all

// 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: <#,#,#>

#define VSC_out 5              // pin to control state of VSC 
#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

// 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 <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>
 
 #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 
 #define USE_SD_CARD
  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;
 bool change2 = 0;

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

 //headlight dimming
 #define headlightSignal 31
 int headlights = 0;
 
 //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,",");      // 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
    //following code to make it indent right - blanks numbers on screen when necessary
        if (int1 >= 100){   
      big1 = 1;
      start = 1; //stops int3 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);
  
  pinMode(12,OUTPUT); //dimmer
  digitalWrite(12,LOW);
  pinMode(headlightSignal,INPUT);

  //establish VSC I/O
  pinMode(max_pin, INPUT);            // max button
  pinMode(VSC_out, OUTPUT);           // VSC output

  //establish pins 2 and 3 as interrupts to select mode
  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
  tft.fillScreen(black);
  
  //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 defined(USE_SD_CARD)
  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
  }
  #else
  // SPI or QSPI flash requires two steps, one to access the bare flash
  // memory itself, then the second to access the filesystem within...
  if(!flash.begin()) {
    Serial.println(F("flash begin() failed"));
    for(;;);
  }
  if(!filesys.begin(&flash)) {
    Serial.println(F("filesys begin() failed"));
    for(;;);
  }
  #endif
  Serial.println(F("OK!")); 
  
  // Load full-screen BMP file 'lily128.bmp' at position (0,0) (top left).
  // Notice the 'reader' object performs this, with 'tft' as an argument.
  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);
  delay(2500);
  digitalWrite(VSC_out, LOW);
  
  //bitmaps, bars, static numbersb
  tft.fillScreen(black);
  tft.drawBitmap(0, 0, oil_lamp, 47, 32, white);
  //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);
  tft.drawChar(102,7,0x09,white,black,2);
  tft.setTextSize(2);
  tft.setCursor(112,13);
  tft.print("C");

  millisStart = millis();
}

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

void loop() 
{
max_state = digitalRead(max_pin);

//headlights = digitalRead(headlightSignal);
//if (headlights == 1) {
//  analogWrite(12,50);
//}
//else {
//  analogWrite(12,255);
//}

  recvWithStartEndMarkers();
  
if ( millis() >= millisStart + 200 ) {

//  if (change1 == 0) {
//  tft.invertDisplay(true);
//  }
//  if (change1 == 1) {
//  tft.invertDisplay(false);
//  }


 batVolts();
  
 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();
      
       //blank bigger numbers
       if (change1 == 1 && start == 1) {
       tft.fillRect(50,0,12,28,black); //(x,y,w,h,color)
       change1 = 0;
        } 
       tft.setTextSize(3); 
       tft.setTextColor(white,black); //(textcolor,background)

      //print data
       //int1 - Oil temp digits
       if (big1 == 0) {
        tft.setCursor(50,7); 
        tft.print(int1);
       }
       else { 
        tft.setCursor(50,7);
        tft.print(int1);
       }

       //Oil temp gauge
       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);
       }
       
       //test volts/analog oil temp
       tft.setTextSize(2);
      tft.setTextColor(red,black);
       tft.setCursor(10,100);
        tft.println(batVoltage);
       
//       tft.setTextSize(2);
//      tft.setTextColor(red,black);
//       tft.setCursor(10,100);
//        tft.println();
//       
//       tft.setTextColor(blue,black);
//       tft.setCursor(100,100);
//       tft.println(headlights);
       //Serial.println(headlights);    
      
      newData = false;
     }
     //change1 = !change1;  //for inverting
   millisStart = millis();
   } 
}

User avatar
euniqe
 
Posts: 4
Joined: Mon Nov 12, 2018 9:13 pm

Re: 1.44" TFT freaks out when trying to dim with PWM

Post by euniqe »

I was reading the support page and it ocurred to me I should show some pictures. So here they are, and here's a video of the tft crashing.

Image
Image
Image
Image
Image

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”