[Solved]TFT text mirrored/SD module type/reset method/SPI pullups/order of init

Bread-boarded 328p-pu with Adafruit 3.5" TFT (HX8357 controller) with microSD card.

After 328p power cycle reset, TFT SD card “begins” ok but text is mirrored.

After 328p manual reset (or reset after FTDI upload), text is NOT mirrored (yay!), but TFT SD card “begin” fails!

If an Adafruit microSD breakout is used instead of the TFT microSD, I get the same mirroring behavior as described above, but SD card works fine regardless of reset method. So, I can get “good” text and have an operational microSD by doing a manual reset of the “board” after powering up.

That’s great, but I want to use the TFT SD card, not a separate SD breakout.

I’ve been unable to find a solution via Google.

The code is attached and embedded… (part 1 of 3):

//******************
// Window02
// for the uC on the window ledge
// version - = original
// version a = deleted LCD - now TFT only
// version b = for wt scale calibration
// version c = changed txt loc'ns

//******************
// libraries
#include <Wire.h>            // for Chronodot and LCD (I2C)
#include "Chronodot.h"
#include <Adafruit_GFX.h>    // Core graphics lib
#include "Adafruit_HX8357.h" // TFT
#include <SPI.h>             // TFT and SD
#include <SdFat.h>
#include "RS485_protocol.h"
#include <SoftwareSerial.h>

//******************
// analog pins
// * = input, so pinmode not necessary, or pinmoded by library
const byte CntRstPin = A0;  // output (digital) to 74HCT393 (cntr) reset pin
// open                A1
const byte btn =       A2;  // input, but need pullup
const byte VinPin =    A3;  // * input from electric eye
//       I2C SDA - pin A4      * for Chronodot (and LCD, if used)
//       I2C SCL - pin A5   ditto

//******************
// digital pins
// * = pinmoded by library, or an input, so pinmode not necessary
// not available     0
// not available     1
const byte txPin =   2;  // * tx data to rs485 chip; pinmoded by SoftwareSerial lib
const byte enPin =   3;  //   enable rs485 pin NOT pinmoded by lb
const byte rxPin =   4;  // * rcv data from rs485 chip; pinmoded by lib
// open              5
// open              6
const byte TFT_CS =  7;  // * Chip Select
const byte TFT_DC =  8;  // * Data/Control
const byte ledPin =  9;  // led, buzzer, and 393 counter
const byte SD_CS =  10;  // * Chip Select
// SPI   MOSI - pin 11      * for TFT+SD
//       MISO - pin 12      *
//        CLK - pin 13      * (beware: bootloader toggles high)

//******************
// create objects
Chronodot RTC;
DateTime RtcTmBlkd, RtcTm;
SdFat SD;
File myFile;
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC);
SoftwareSerial rs485 (rxPin, txPin);

//******************
// misc
byte bDToday, bChkDate;     // day of the month, for daily reset system
byte StateNow = 0;          // 0 = Open and 1 = blocked
byte StatePrev = 0;         // ditto
int rqCnt = 0;              // number of times data requested from bh
int rxCnt = 0;              // number of times data received from bh
int iMstrt;                 // free ram at start
int iDCnt = 0;              // num brks in current day (up to 1500 or so)
int volts;                  // analog read of VinPin
boolean blkd;               // digital read of VinPin
boolean chkV = false;       // whether or not to do analogRead of "volts"
const int iWait = 1000;     // update display of volts every xxxx ms
unsigned long Tprev, Tnow;  // for timing display of volts
unsigned long TDprev;       // for timing when to check for new day
unsigned long TStrt, TBlkd; // for timing hole block (unsigned int..65sec..not enough)
const unsigned long ulDWait = 300000; // request weight/temp and chk new day
//  5 min = 300,000 ms
// 10 min = 600,000 ms
// 15 min = 900,000 ms

//**************************************************************
// 485 callback routines
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}


//**************************************************************
void setup() {

  Serial.begin(115200);
  Serial.print(F("Window02c"));

  //******************
  // init pins
  pinMode(enPin, OUTPUT);   // default OUTPUT state is LOW
  // LOW disables rs485 sending & enables receive
  pinMode(ledPin, OUTPUT);     // LED, buzzer, and counter
  pinMode(CntRstPin, OUTPUT);  // to reset 74HCT393 counter
  pinMode(btn, INPUT_PULLUP);

  //******************
  // init TFT
  tft.begin(HX8357D);
  tft.setRotation(3);
  tft.fillScreen(HX8357_BLACK);
  tft.setTextColor(HX8357_WHITE, HX8357_BLACK);
  tft.setTextSize(2); // smaller text is faster
  // for one character (a "9"):
  // size 1 = 5.9 ms   6 x  9  pixels
  // size 2 = 7.1 ms  12 x 18
  // size 3 = 8.8 ms  18 x 27
  // time for "n" characters is "n" times those durations
  // I2C LCD = 2.8 ms, and multiple characters only add about 1.3 ms per char
  tft.setCursor(0, 0);
  //         123456789
  tft.print(F("Window02c"));
  delay(10000);

  //******************
  // init rs485
  rs485.begin(28800);

  //******************
  // init Chronodot
  Wire.begin();
  RTC.begin();
  if (! RTC.isrunning()) {
    // set to date & time this sketch was compiled
    RTC.adjust(DateTime(__DATE__, __TIME__));
    tft.setCursor(0, 0);
    //         123456789012
    tft.print(F("RTC reset!"));
    delay(15000);
  }

  //******************
  // init the daily reset system and counters
  Rst393();               // reset LED counters
  RtcTm = RTC.now();
  bDToday = RtcTm.day() ; //today's day as integer

  //******************
  // init SD card
  if (!SD.begin(SD_CS)) {
    tft.setCursor(0, 0);
    tft.print(F("SD begin err  "));
    //         123456789012
    delay(15000);
  }
  // do a test write
  myFile = SD.open("16tstSD.txt", FILE_WRITE);
  if (myFile) {
    RtcTm = RTC.now();
    writeDateTime(RtcTm);
    myFile.close();
  }
  else {
    tft.setCursor(250, 200);
    tft.print(F("SDwriteErr0"));
    delay(15000);
  }

  //******************
  // init variables for periodic printing of volts
  // and checking date
  Tprev = millis();
  TDprev = Tprev;

  //******************
  // set up TFT
  tft.setCursor(0, 0);
  //         123456789012
  tft.print("Brk=0       ");
  //         01234  "cnt" strts @ 4th char=4x12=48 pixel position
  //         since size 2 text is 12 pixels wide
  tft.setCursor(0, 20);
  tft.print(F("aRead="));
  // so "volts" starts @ 6th char=6x12=72 pixel position
  tft.setCursor(72, 20);
  tft.print(chkV);

  //******************
  // other
  iMstrt = freeRam(); // memory at start

} //end setup

Window02c.ino (15.7 KB)

Part 2 of the code:

//**************************************************************
void loop() {

  //******************
  // periodically query bh for wt & temp
  // and check for new day.  If a new day,
  // update count, weight, and temp plots
  // and reset the count varable and the 74HCT393 counter
  Tnow = millis();
  if (Tnow - TDprev >= ulDWait) {
    TDprev = Tnow;

    //---------------------------
    // query bh for weight and temp
    // and show values as text on TFT, save to SD card
    getWtTmp();

    //---------------------------
    // check for new day
    RtcTm = RTC.now();
    bChkDate = RtcTm.day() ; //today's date
    if (bChkDate != bDToday) {
      // update graphs    <-- NOT CODED YET ***************
      bDToday = bChkDate;   // set to new date number
      iDCnt = 0;            // reset day counter
      tft.setCursor(48, 0);
      tft.print(iDCnt);     // show zero count
      tft.print("   ");
      Rst393();             // reset 74HCT393 counter
    }
  }

  //******************
  // read the voltage input pin
  // previously did analogRead which takes 0.11 ms or about 20% of loop time of 0.6 ms
  // digitalRead takes 0.005 ms, so loop time should drop to about 0.5 ms
  // LOW  if < 0.3Vcc = 1.5 v = 307 read
  // HIGH if > 0.6Vcc = 3.0 v = 613 read
  // actual low is about 0.98 v = 200 read (mx on 4 Feb 2016)
  // actual high is about 4.5 v = 935 read (ditto)
  blkd = digitalRead(VinPin);
  if (! blkd) {     // previously volts < 350 (with analogRead)
    StateNow = 0;   // open
  }
  else if (blkd) {  // previously volt > 650
    StateNow = 1;   // blked
  }
  if (StatePrev == 0 && StateNow == 1) {   // hole has been blocked since last read
    TStrt = millis();                      // start timing
    digitalWrite(ledPin, HIGH);            // turn on led and buzzer
    RtcTmBlkd = RTC.now();                 // save date and time
  }
  else if (StatePrev == 1 && StateNow == 0) { // hole has become unblocked since last read
    TBlkd = millis() - TStrt;
    digitalWrite(ledPin, LOW);
    iDCnt += 1;                               // increment day count

    // print break count
    // TFT added in 2016 takes 7 ms for one size 2 char, 14 ms for two chars
    // and, if fastIncr is used (currently is not), an average of about 9 ms
    // vs the paralleled LCD (3 ms) used in previous years
    // note: I2C LCD takes 31ms to write "cnt=" and the count
    tft.setCursor(48, 0);
    tft.print(iDCnt);

    // save dt, tm, & duration blkd to SD card
    // takes about 9 ms w/ breakout used prior to 2016;
    // takes about 6.3 ms w/ TFT SD used in 2016
    WriteBlkTm();
  }

  StatePrev = StateNow;

  //******************
  // periodically show "voltage" to check for drooping voltage/failing IR system
  if (Tnow - Tprev >= iWait && chkV) {
    volts = analogRead(VinPin);
    if (volts > 512) {
      tft.setCursor(0, 40); // print HIGH value here
    }
    else {
      tft.setCursor(0, 60); // print LOW value here
    }
    tft.print(volts);
    Tprev = Tnow;
  }

  chkButtons(); // every push also toggles "chkV"

} // end loop
// 0.5 ms/loop if digitalRead is used to check blocked/open
// 0.6 ms/loop if analogRead is used (prior to 2016)


//**************************************************************
void Rst393() {
  digitalWrite(CntRstPin, HIGH);   // reset...
  delay(1);
  digitalWrite(CntRstPin, LOW);   // ready to count
  delay(1);
}

//**************************************************************
void WriteBlkTm() {

  myFile = SD.open("16tstCNT.txt", FILE_WRITE);
  if (myFile) {
    // write date and time
    writeDateTime(RtcTmBlkd);

    // write duration blocked
    myFile.print(TBlkd, DEC);

    // return and close
    myFile.println();
    myFile.close();

  }
  else {  // end write to myfile, if it opened
    tft.setCursor(250, 200);
    tft.print("SDwriteErr1");
  }
}


//**************************************************************
void chkButtons() {

  // if button pushed (taken LOW)
  // show memory and date/current time
  // and toggle analogRead of "voltage"
  if (! digitalRead(btn)) {
    PrntDT();  // show current date and time
    PrntMem();  // show initial and current free memory
    chkV = !chkV; // toggle
    tft.setCursor(84, 20);
    tft.print(chkV);
  }
}

Part 3

//**************************************************************
void PrntDT() {
  RtcTm = RTC.now();

  tft.setCursor(300, 160);
  if (RtcTm.month() < 10) tft.print("0");
  tft.print(RtcTm.month(), DEC);
  tft.print('/');
  if (RtcTm.day() < 10) tft.print("0");
  tft.print(RtcTm.day(), DEC);
  tft.print(" ");
  if (RtcTm.hour() < 10) tft.print("0");
  tft.print(RtcTm.hour(), DEC);
  tft.print(':');
  if (RtcTm.minute() < 10) tft.print("0");
  tft.print(RtcTm.minute(), DEC);
}

//**************************************************************
void PrntMem() {
  tft.setCursor(300, 180);
  tft.print(F("M0="));
  tft.print(iMstrt);
  tft.print(F(" Mi="));
  tft.print(freeRam());
}

//**************************************************************
void getWtTmp() {

  //---------------------------
  //query bh for weight and temp

  //count number of times data requested
  rqCnt += 1; // over 90 days at 4x per hour, should be 90*24*4=8640 max...fits in int
  tft.setCursor(0, 120);
  tft.print(rqCnt);

  // for debugging
  tft.setCursor(0, 80);
  tft.print(F("request wt n tmp"));
  //           0123456789012345

  // assemble message
  byte msg [] = {
    5    // command (arbitrary number)
  };

  // send to bh
  digitalWrite (enPin, HIGH);  // enable sending
  sendMsg (fWrite, msg, sizeof msg);
  digitalWrite (enPin, LOW);  // disable sending

  byte received = 0;
  // wait for response
  byte buf [5]; // contains txCnt, MSByte and LSBbyte of weight, count dev from mean, temp
  received = recvMsg (fAvailable, fRead, buf, sizeof buf, 2000);
  // Returns length if received.
  // Returns or 0 if times out, CRC check fails, or if length exceeds size of buf.
  // Default time out: 500 ms.  Increase time out to 2000 ms
  // to allow time for bh to get weight and respond
  // (takes about 900 ms per testing 4 Feb 2016)

  // for debugging
  //  tft.setCursor(0,20);
  //  tft.print("rcd=");
  //  tft.print(received);
  //  tft.print(" txCnt=");
  //  tft.print(buf[0]);
  //  tft.print(" MSB=");
  //  tft.print(buf[1]);
  //  tft.print(" LSB=");
  //  tft.print(buf[2]);
  //  tft.print("   ");

  if (received) {
    // count number of times data received
    rxCnt += 1;

    // re-assembly centigrams (0.01 g)
    // should never be negative nor greater than 20000 cg (200 g)
    int cGram = buf[1] << 8;  // shift MSByte into high position
    cGram |= buf[2];          // compound bitwise OR the LSByte into the low position

    // more debugging
    tft.setCursor(0, 100);
    tft.print("wt=");
    tft.print(cGram);
    tft.print("cg  dev=");
    tft.print(buf[3]);
    tft.print("cnts  tmp=");
    tft.print(buf[4]);
    tft.print("degF  ");

    tft.setCursor(0, 120);
    tft.print(rqCnt);
    tft.print(" ");
    tft.print(rxCnt);
    tft.print(" ");
    tft.print(buf[0]); // txCnt from bh
    tft.print(" ");

    tft.setCursor(0, 80);
    tft.print(F("                "));


    myFile = SD.open("16tstWT.txt", FILE_WRITE);
    if (myFile) {

      // write data and time (has ending comma)
      RtcTm = RTC.now();
      writeDateTime(RtcTm);

      // write data
      myFile.print(rqCnt); // window request count
      myFile.print(',');

      myFile.print(rxCnt); // window received count
      myFile.print(',');

      myFile.print(buf[0]); // bh transmission count
      myFile.print(',');

      // all three of the above should be the same

      myFile.print(cGram);  // weight, in centigrams....from buf[1] and [2]
      myFile.print(',');

      myFile.print(buf[3]); // avg dev of mx & mn used in the mean, in ADC "counts"
      myFile.print(',');

      myFile.print(buf[4]);  // temperature, in deg F

      // return and close
      myFile.println();
      myFile.close();

    }
    else {  // end write to myfile, if it opened
      tft.setCursor(250, 220);
      tft.print(F("SDwriteErr2"));
    }
  } else {
    tft.setCursor(250, 240);
    tft.print(F("rs485readErr"));
  }

} // end getWtTmp

//**************************************************************
void writeDateTime(DateTime DTobject) {

  // write data and time to myFile
  // comma delimited
  // used for duration blocked and for weight and temp

  // write date
  myFile.print(DTobject.year(), DEC);
  myFile.print('/');
  if (DTobject.month() < 10) myFile.print("0");
  myFile.print(DTobject.month(), DEC);
  myFile.print('/');
  if (DTobject.day() < 10) myFile.print("0");
  myFile.print(DTobject.day(), DEC);
  myFile.print(',');

  // write time
  if (DTobject.hour() < 10) myFile.print("0");
  myFile.print(DTobject.hour(), DEC);
  myFile.print(':');
  if (DTobject.minute() < 10) myFile.print("0");
  myFile.print(DTobject.minute(), DEC);
  myFile.print(':');
  if (DTobject.second() < 10) myFile.print("0");
  myFile.print(DTobject.second(), DEC);
  myFile.print(',');

}


//**************************************************************
int freeRam()
{
  extern int __heap_start, *__brkval;
  int v;
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

Try using begin () and init () for the display and sd card right at the beginning of setup() and also try changing the order, ie. SD first or display first.

Ok - thanks for the suggestions. Will give them a try.

Also check you power supply is up to providing power for all your bits an pieces. Bear in mind that TFT displays and SD Cards take gulps of current that can cause brown-outs that result in incorrect initialisation of the displays.

Check if the SD Card and TFT libraries have SPI "Transaction Support" and make sure it is enabled. (This lets 2 SPI devices that require slightly different CPU register settings to coexist.)

This worked: putting the SD initialization at the top of setup() and the TFT initialization immediately after the SD init.

Now the text is not mirrored and the SD begin does not fail (using the TFT’s SD) regardless of reset method (power cycle, FTDI, or manual)!

Thanks very much for the suggestion. +1 But why the heck should location and order within setup() matter?

Declarations and top part of setup() now look like this:

//******************
// Window02
// for the uC on the window ledge
// version - = original
// version a = deleted LCD - now TFT only
// version b = for wt scale calibration
// version c = changed txt loc'ns
// version test1 = put SD and TFT initialization at top of setup, in that order

//******************
// libraries
#include <Wire.h>            // for Chronodot and LCD (I2C)
#include "Chronodot.h"
#include <Adafruit_GFX.h>    // Core graphics lib
#include "Adafruit_HX8357.h" // TFT
#include <SPI.h>             // TFT and SD
#include <SdFat.h>
#include "RS485_protocol.h"
#include <SoftwareSerial.h>

//******************
// analog pins
// * = input, so pinmode not necessary, or pinmoded by library
const byte CntRstPin = A0;  // output (digital) to 74HCT393 (cntr) reset pin
// open                A1
const byte btn =       A2;  // input, but need pullup
const byte VinPin =    A3;  // * input from electric eye
//       I2C SDA - pin A4      * for Chronodot (and LCD, if used)
//       I2C SCL - pin A5   ditto

//******************
// digital pins
// * = pinmoded by library, or an input, so pinmode not necessary
// not available     0
// not available     1
const byte txPin =   2;  // * tx data to rs485 chip; pinmoded by SoftwareSerial lib
const byte enPin =   3;  //   enable rs485 pin NOT pinmoded by lb
const byte rxPin =   4;  // * rcv data from rs485 chip; pinmoded by lib
// open              5
// open
const byte TFT_CS =  7;  // * Chip Select
const byte TFT_DC =  8;  // * Data/Control
const byte ledPin =  9;  // led, buzzer, and 393 counter
const byte SD_CS =  10;  // * Chip Select
// SPI   MOSI - pin 11      * for TFT+SD
//       MISO - pin 12      *
//        CLK - pin 13      * (beware: bootloader toggles high)

//******************
// create objects
Chronodot RTC;
DateTime RtcTmBlkd, RtcTm;
SdFat SD;
File myFile;
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC);
SoftwareSerial rs485 (rxPin, txPin);

//******************
// misc
byte bDToday, bChkDate;     // day of the month, for daily reset system
byte StateNow = 0;          // 0 = Open and 1 = blocked
byte StatePrev = 0;         // ditto
int rqCnt = 0;              // number of times data requested from bh
int rxCnt = 0;              // number of times data received from bh
int iMstrt;                 // free ram at start
int iDCnt = 0;              // num brks in current day (up to 1500 or so)
int volts;                  // analog read of VinPin
boolean blkd;               // digital read of VinPin
boolean chkV = false;       // whether or not to do analogRead of "volts"
const int iWait = 1000;     // update display of "volts" every xxxx ms
unsigned long Tprev, Tnow;  // for timing display of volts
unsigned long TDprev;       // for timing when to check for new day
unsigned long TStrt, TBlkd; // for timing hole block (unsigned int..65sec..not enough)
const unsigned long ulDWait = 300000; // request weight/temp and chk new day
//  5 min = 300,000 ms
// 10 min = 600,000 ms
// 15 min = 900,000 ms

//**************************************************************
// 485 callback routines
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}


//**************************************************************
void setup() {

  //******************
  // init SD card
  boolean SDbeginFail=false;
  if (!SD.begin(SD_CS)) {
//    tft.setCursor(0, 0);
//    tft.print(F("SD begin err  "));
    //         123456789012
//    delay(15000);
SDbeginFail=true;
  }
  // do a test write
  boolean SDwriteFail=false;
  myFile = SD.open("16tstSD.txt", FILE_WRITE);
  if (myFile) {
    RtcTm = RTC.now();
    writeDateTime(RtcTm);
    myFile.close();
  }
  else {
//    tft.setCursor(250, 200);
//    tft.print(F("SDwriteErr0"));
//delay(15000);
SDwriteFail=true;
  }

  //******************
  // init TFT
  tft.begin(HX8357D);
  tft.setRotation(3);
  tft.fillScreen(HX8357_BLACK);
  tft.setTextColor(HX8357_WHITE, HX8357_BLACK);
  tft.setTextSize(2); // smaller text is faster
  // for one character (a "9"):
  // size 1 = 5.9 ms   6 x  9  pixels
  // size 2 = 7.1 ms  12 x 18
  // size 3 = 8.8 ms  18 x 27
  // time for "n" characters is approximately "n" times those durations
  // I2C LCD = 2.8 ms, and multiple characters only add about 1.3 ms per char
  tft.setCursor(0, 0);
  //         123456789
  tft.print(F("Window02tst1"));
  tft.print("begin=");
  tft.print(SDbeginFail);
  tft.print(" write=");
  tft.print(SDwriteFail);

  delay(20000);

DaveEvans:
But why the heck should location and order within setup() matter?[/i]

It is best to put SPI initialisation code at the beginning of setup so the SD and TFT Chip Select (CS) lines get configured as outputs early on and put into their inactive (logic HIGH) state.

If you call tft.begin(HX8357D); first then the SD Card CS line can flap about due to "cross talk" and noise on the line as it is in a high impedance state. Thus the SD Card SPI port can be inadvertently activated during the setting of the TFT driver registers (happens during tft.begin()) and can upset the SD Card.

Configuring the SD Card first is better because later the TFT is reset and then fully configured even if duff values have been inadvertently been written to the TFT while the SD Card is being setup.

The correct way around this is to have pullups on the CS lines built into the shield, some shields have them but on Cheap Chinese ones they are sometimes omitted.

One way around this is to set the CS lines as output and HIGH right at the start of setup() before any libraries try to configure any devices on the SPI bus, e.g.

pinMode(TFT_CS, OUTPUT);
digitalWrite(TFT_CS, HIGH);
pinMode(SD_CS, OUTPUT);
digitalWrite(SD_CS, HIGH);
...
Then library begin and init type functions can be called in any order.

I expect the external SD Card reader you used had a pullup on the CS line and thus you did not see the problem.

It's one of those "gotchas" that Arduino users keep coming across. It is partly down to bad circuit design and also a poor software approach within the device support libraries.

Glad to hear the problem is solved. Good luck with your project.

That makes sense - thanks for the explanation and thanks again for the assistance!

I tried my original code (with TFT initialization before SD init, and neither of them right at the top of setup) but I added

pinMode(TFT_CS, OUTPUT);
digitalWrite(TFT_CS, HIGH);
pinMode(SD_CS, OUTPUT);
digitalWrite(SD_CS, HIGH);

right at the top of setup. Same old behavior, darn it.

Then I tried the original code with 10k pullups on both CS lines. Same same.

So, I'm going back to what works: initializing the SD first, right at the top of setup, followed by the TFT init.

OK, it is interesting that those changes did not fix it, it looks like something else is going on in this case. I think it would take a lot of message exchanges to find the true root cause but as you have a working setup this is not necessary, but the bad news is that without a definite cure the problem might come back later.

DaveEvans:
This worked: putting the SD initialization at the top of setup() and the TFT initialization immediately after the SD init.

Now the text is not mirrored and the SD begin does not fail (using the TFT’s SD) regardless of reset method (power cycle, FTDI, or manual)!

Thanks very much for the suggestion. +1 But why the heck should location and order within setup() matter?

Declarations and top part of setup() now look like this:

//******************

// Window02
// for the uC on the window ledge
// version - = original
// version a = deleted LCD - now TFT only
// version b = for wt scale calibration
// version c = changed txt loc’ns
// version test1 = put SD and TFT initialization at top of setup, in that order

//******************
// libraries
#include <Wire.h>            // for Chronodot and LCD (I2C)
#include “Chronodot.h”
#include <Adafruit_GFX.h>    // Core graphics lib
#include “Adafruit_HX8357.h” // TFT
#include <SPI.h>            // TFT and SD
#include <SdFat.h>
#include “RS485_protocol.h”
#include <SoftwareSerial.h>

//******************
// analog pins
// * = input, so pinmode not necessary, or pinmoded by library
const byte CntRstPin = A0;  // output (digital) to 74HCT393 (cntr) reset pin
// open                A1
const byte btn =      A2;  // input, but need pullup
const byte VinPin =    A3;  // * input from electric eye
//      I2C SDA - pin A4      * for Chronodot (and LCD, if used)
//      I2C SCL - pin A5  ditto

//******************
// digital pins
// * = pinmoded by library, or an input, so pinmode not necessary
// not available    0
// not available    1
const byte txPin =  2;  // * tx data to rs485 chip; pinmoded by SoftwareSerial lib
const byte enPin =  3;  //  enable rs485 pin NOT pinmoded by lb
const byte rxPin =  4;  // * rcv data from rs485 chip; pinmoded by lib
// open              5
// open
const byte TFT_CS =  7;  // * Chip Select
const byte TFT_DC =  8;  // * Data/Control
const byte ledPin =  9;  // led, buzzer, and 393 counter
const byte SD_CS =  10;  // * Chip Select
// SPI  MOSI - pin 11      * for TFT+SD
//      MISO - pin 12      *
//        CLK - pin 13      * (beware: bootloader toggles high)

//******************
// create objects
Chronodot RTC;
DateTime RtcTmBlkd, RtcTm;
SdFat SD;
File myFile;
Adafruit_HX8357 tft = Adafruit_HX8357(TFT_CS, TFT_DC);
SoftwareSerial rs485 (rxPin, txPin);

//******************
// misc
byte bDToday, bChkDate;    // day of the month, for daily reset system
byte StateNow = 0;          // 0 = Open and 1 = blocked
byte StatePrev = 0;        // ditto
int rqCnt = 0;              // number of times data requested from bh
int rxCnt = 0;              // number of times data received from bh
int iMstrt;                // free ram at start
int iDCnt = 0;              // num brks in current day (up to 1500 or so)
int volts;                  // analog read of VinPin
boolean blkd;              // digital read of VinPin
boolean chkV = false;      // whether or not to do analogRead of “volts”
const int iWait = 1000;    // update display of “volts” every xxxx ms
unsigned long Tprev, Tnow;  // for timing display of volts
unsigned long TDprev;      // for timing when to check for new day
unsigned long TStrt, TBlkd; // for timing hole block (unsigned int…65sec…not enough)
const unsigned long ulDWait = 300000; // request weight/temp and chk new day
//  5 min = 300,000 ms
// 10 min = 600,000 ms
// 15 min = 900,000 ms

//**************************************************************
// 485 callback routines
void fWrite (const byte what)
{
  rs485.write (what);
}
int fAvailable ()
{
  return rs485.available ();
}
int fRead ()
{
  return rs485.read ();
}

//**************************************************************
void setup() {

//******************
  // init SD card
  boolean SDbeginFail=false;
  if (!SD.begin(SD_CS)) {
//    tft.setCursor(0, 0);
//    tft.print(F("SD begin err  "));
    //        123456789012
//    delay(15000);
SDbeginFail=true;
  }
  // do a test write
  boolean SDwriteFail=false;
  myFile = SD.open(“16tstSD.txt”, FILE_WRITE);
  if (myFile) {
    RtcTm = RTC.now();
    writeDateTime(RtcTm);
    myFile.close();
  }
  else {
//    tft.setCursor(250, 200);
//    tft.print(F(“SDwriteErr0”));
//delay(15000);
SDwriteFail=true;
  }

//******************
  // init TFT
  tft.begin(HX8357D);
  tft.setRotation(3);
  tft.fillScreen(HX8357_BLACK);
  tft.setTextColor(HX8357_WHITE, HX8357_BLACK);
  tft.setTextSize(2); // smaller text is faster
  // for one character (a “9”):
  // size 1 = 5.9 ms  6 x  9  pixels
  // size 2 = 7.1 ms  12 x 18
  // size 3 = 8.8 ms  18 x 27
  // time for “n” characters is approximately “n” times those durations
  // I2C LCD = 2.8 ms, and multiple characters only add about 1.3 ms per char
  tft.setCursor(0, 0);
  //        123456789
  tft.print(F(“Window02tst1”));
  tft.print(“begin=”);
  tft.print(SDbeginFail);
  tft.print(" write=");
  tft.print(SDwriteFail);

delay(20000);

Hi DaveEvans,

I’m new to Arduino.
Is it possible to use the code with other types of TFT?
Also an explanation to “Chronodot.h”.