Library issue Elegoo_TFTLCD and AFMotor

I need some expert help. New to forum, but an old timer with uPs.
Not sure where to post this as this is my first post on this forum.

I have a Elegoo 2.8 inch touchscreen display shield stacked on a L293D V1 motor shield on a Arduino uno processor board. The hardware all works correctly. I can run the display test programs. I can run the stepper motor test program.
The libraries involved are
#include <Elegoo_GFX.h> // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <AFMotor.h> // Arduino Stepper Library
When I attempt to issue the class statements
Elegoo_TFTLCD tft(A3, A2, A1, A0, A4);
AF_Stepper motor(800,1); // Steps/rev, channel M1
I get data corruption on the LCD screen.

Setting the channel to 1 (channel M1) causes the display to corrupt the written characters. The triangle and line functions kind of work, but the corruption is seen in the characters and the drawn lines. Also the left and top boundaries are messed up.
The code works until the AF_Stepper motor class is declared. I've tried many ways to isolate the corruption problem, but it comes back to the class code that runs the devices corrupting the LCD driver. I have not resorted to a logic analyzer or probe yet, but I'm convinced its library problem.

Attempting to initialize the LCDTFT display with both classes declared results in a white screen. I know this is because the AF_stepper motor( ) channel constant value is at fault. It only will initialize before the AF_Stepper motor() statement is issued.

Using the code below, the display makes the first pass with no corruption. The second pass results in LCD running corrupted. Pushing reset will repeat exactly the same as download restart.

Code follows (excuse my commented out stuff)

// IMPORTANT: ELEGOO_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Elegoo_TFTLCD.h FOR SETUP.
// Technical support:goodtft@163.com

#include <Elegoo_GFX.h>    // Core graphics library
#include <Elegoo_TFTLCD.h> // Hardware-specific library
#include <AFMotor.h>       // Arduino Stepper Library

// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS    A3 // Chip Select goes to Analog 3
#define LCD_CD    A2 // Command/Data goes to Analog 2
#define LCD_WR    A1 // LCD Write goes to Analog 1
#define LCD_RD    A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
//   D0 connects to digital pin 8  (Notice these are
//   D1 connects to digital pin 9   NOT in order!)
//   D2 connects to digital pin 2
//   D3 connects to digital pin 3
//   D4 connects to digital pin 4
//   D5 connects to digital pin 5
//   D6 connects to digital pin 6
//   D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board)


// Create instance of Stepper Class
// Specify Pins used for motor coils
// The pins used are 8,9,10,11
// Connected to ULN2003 Motor Driver In1, In2, In3, In4 
// Pins entered in sequence 1-3-2-4 for proper step sequencing
// Stepper steppermotor(Steps_per_rev, 8, 10, 9, 11);


// Assign human-readable names to some common 16-bit color values:
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
//AF_Stepper motor(800,0);   // Steps/rev, channel M1  
Elegoo_TFTLCD tft(A3, A2, A1, A0, A4);
//   Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// AF_Stepper motor(400,1);   // Steps/rev, channel M1
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Elegoo_TFTLCD tft;
// --------------------------------SET UP-----------------------------------


uint16_t identifier;
void setup(void) {
//  Elegoo_TFTLCD tft(A3, A2, A1, A0, A4);
//  Serial.begin(9600);  
  tft.reset();
  delay(1);
  //identifier=tft.readID();
  tft.begin(tft.readID());  //This works without setting an identifier variable
}

// ---------------------------------MAIN------------------------------------
void loop(void) {
//  Elegoo_TFTLCD tft(A3, A2, A1, A0, A4);  //address lines hard coded
//  Serial.begin(9600);
//  tft.reset();
//  delay(10);
//  tft.begin(tft.readID());
//  setup();

//  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);

//  Serial.print(F("Lines                    "));
  Serial.println(testLines(CYAN));
  delay(500);

//  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(RED, BLUE));
  delay(500);

//  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(GREEN));
  delay(500);

//  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(YELLOW, MAGENTA));
  delay(500);

//  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, MAGENTA));

//  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, WHITE));
  delay(500);

//  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);

//  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);

//  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);

//  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);

  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000); 
  }
 stepit(); 

}

// -------------------------------MACRO FUNCTIONS TO USE-------------------------------
  unsigned long stepit() {
  unsigned long start = micros();
// The AF_Stepper motor is a problem causing LCD screen write curroption
// Specifically with the AF_Stepper motor() statement
//  digitalWrite(A3, LOW);
   AF_Stepper motor(800,1);   // Steps/rev, channel M1  
// Rotate the stepper motor
// Rotate CW 1/2 turn slowly
  
  motor.setSpeed(12);
  motor.step(800, FORWARD, INTERLEAVE);
  motor.release();
  delay(1000);

// Rotate CCW 1/2 turn slowly 
  motor.setSpeed(12);
  motor.step(800, BACKWARD, INTERLEAVE);
  motor.release();
  delay(1000);
//  digitalWrite(A3, HIGH);  
// Attempt to change pins 8,9,10,11)
/*
// claimed used pins for stepper motor
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
*/  
  return micros() - start; 
}

unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(BLACK);
  tft.fillScreen(RED);
  tft.fillScreen(GREEN);
  tft.fillScreen(BLUE);
  tft.fillScreen(BLACK);
  return micros() - start;
}

unsigned long testText() {
  
  tft.fillScreen(BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(YELLOW); tft.setTextSize(2);
  tft.println(identifier, HEX);
  tft.setTextColor(RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(BLACK);

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  tft.fillScreen(BLACK);

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(BLACK);

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(BLACK);

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(0, 0, i));
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i, i));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i, i, 0));
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
  }

  return micros() - start;
}

Do not have your hardware to really test, but the symptoms point to an SRAM issue. The Uno only has 2K of SRAM and this may not be enough for your application. The Elegoo boards state they are Mega2560 compatible as well as the Uno, so the extra SRAM in the 2560 may be an option.

I'm pretty sure it is not an SRAM issue, but I could be wrong. Here is the compile summary--

Sketch uses 18848 bytes (58%) of program storage space. Maximum is 32256 bytes.
Global variables use 476 bytes (23%) of dynamic memory, leaving 1572 bytes for local variables. Maximum is 2048 bytes.

There is another curious issue with this unit. After the AF_Stepper class is declared the LCDTFT display can no longer be initialized. I have tried reset() followed by the appropriate code and it will not work. I have switched the order of the class declarations and no matter what I do the LCDTFT board will not initialize after the AF_Stepper class is declared.

This again points at a library conflict -or- heaven forbid faulty code for the LCDTFT display. In other words, their code relies on hardware reset and if put in certain states is not resettable.

Thanks everyone.

Hi
I have spent too much time on this. After several tries and the process of elimination, everything points to a library issue conflict likely caused by the Elegoo LCDTFT display libraries being temperamental. I put into my code a dump memory routine and looked at 0100 to 07FF and found very little differences before and after issuing the AF_Stepper motor() function. Pursuing it much farther I attempted to set the pins on the arduino to specific states with no luck. Finally, I removed the stepper shield and ran the code and with no stepper shield stacked got the same result. So I focused on the AF_Stepper motor(800,chan), placing the variable chan into this statement and decrementing it from 5 to 0 each time thru the loop. I had no issues until I got chan= 2 and 1. For the value 2, the screen froze. For the value 1 the screen ran with corrupted images. For all other values the screen was ok displaying exactly what is expected. After running a loop with 2 or 1, the display would not recover for subsequent loop iterations with chan<>1,2.
So it is the chan number that is the problem. So I looked at the .cpp code for the AF_stepper motor() and found this:
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();

// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH); }

I have messed with pins 3 & 11 already and am dismissing these as the problem. If I run the loop with the stepper statements commented out all is fine. No issues with the LCD display. I can set pins 3 & 11 in the loop w/o stepper being called with no issues. In the sketch, the line where the AF_Stepper is introduced-- after the LCD is not able to initialize.
There may be other issues with the compile that I'm unaware of, but it seems to focus on the MC.Latch tx() statement as being the possible culprit.
I cannot rule out the Elegoo_TFTLCD and GFX libraries.
At run time something is messing with the Elegoo LCDTFT shield making it unresponsive and not able to initialize. Only get white screen.
I have not tried a different library to support this L293D shield. I know it's old, old, old. Should have gotten a V2 shield.

Any help thoughts appreciated!

I have been through this many times now and after close examination the Elegoo LCDTFT unit sits on the bus causing conflicts while in operation. So this is a warning to those who have a wish to purchase this display unit. It will NOT work with another stacked shield that uses the data bus unless you have a shield that isolates the two shields. After a lot of work I was able to make the stepper shield and the LCDTFT shield stacked work by resetting the LCDTFT shield while stepping the motor. However, I will need to disable the stepper 74HC595 device while the LCDTFT display is in operation and tolerate a blank dark screen while stepping. I also had to write my own code to step the stepper motor as the AF_Stepper routine will cause the TFTLCD device to go into a non-resetable condition that involves a hard reset to get out of.

So bottomline, beware of the TFTLCD screen Elegoo shield and its library if you wish to use it with another shield that uses the system data bus. Yes, I did try using the address lines that select the LCDTFT display A3 to disable it. It doesn't kick it off the bus.

One more final reply on this topic.
This LCDTFT shield library has many commands and none of them are formally documented as to how they work and their use. The manufacturer assumes that show and tell will make their use obvious.
So while looking I found this call tft.flush(). It wasn't obvious what it does and there is no documentation on it. I tried it and it does kick the shield off the data lines and leave the screen frozen with the last image. So for those of you with this shield, using the flush call may help if you are stacking shields or attempting to use data lines 2-9 as command or sense lines.
However it didn't fix the issue with the library conflict. The library all for the AF_Stepper causes the LCDTFT shield to white screen and not recover.
Hopefully this may help a few of you. It has been very painful getting these two stacked shields to function. With my own stepper driver written in the sketch, no AF_Stepper.h, and the Elegoo libraries it is now functional.

The only difference between this library and the same from Adafruit is a replacement of "Adafruit" by "Elegoo".
They have some tables of the registers that are formatted differently, but after the quick compare by eyes, I don't see too many differences.
So I would recommend trying Adafruit_GFX and Adafruit_TFTLCD. Even it your display will not work "out of the box" - at least you may use documentation and examples (and I also suppose the fonts) from Adafruit that has far better support and documentation (I think Elegoo just cloned it but didn't bothered to provide any support)

Maxbul

Yes, much better support. Cannot find the description for this function however.
tft.flush();
I believe this releases the data lines from the computer. This was a primary issue. With the TFT display on the data lines, stealing them away left the display in an inoperable state. I could not recover. I couldn't remove and reinstate the instance of the TFT without hard starting (master reset). The flush command (undocumented, maybe called something else by Adafruit) was part of the fix that allowed me to use the display & touchpad with the L293D shield. Here is the stepper motor driver I used to make it all work.

For anyone interested, here is the code I wrote to make it all work.

//Stepper Shield is V1 293D Driver
//The libaray associated with it is not used, incompatible with TFTLCD
//Stepper motor variables global
//p[] defines the bit positions in the 74HC595 to rotate CW & CCW
//uint8_t p[] {0x10,0x18,0x08,0x0A,0x02,0x06,0x04,0x14};
uint8_t p[] {0x14,0x04,0x06,0x02,0x0A,0x08,0x18,0x10};
int16_t position;                            //Stepper absolute position
void stepit(int16_t steps, uint16_t speed) { 
unsigned long start;
uint8_t phase;
//Serial.print("Running Stepper Motor  Position= "); Serial.print(position);
//Serial.print("  steps="); Serial.print(steps); Serial.print("   speed="); Serial.println(speed);
tft.flush();            //LCDTFT release data lines
pinMode(4,OUTPUT);            //Clock SR
pinMode(7,OUTPUT);            //Output Enable
pinMode(8,OUTPUT);            //Data SR
pinMode(12,OUTPUT);           //Clock output Latch
digitalWrite(4,HIGH);
digitalWrite(7,HIGH);
digitalWrite(12,HIGH);
int i, j, k;

for(k=0; k<abs(steps); k++) {

  for(i=0; i<8; i++) {
    if(steps>0) phase=p[i]; 
    else  phase=p[7-i];

    for(j=0; j<8; j++){
      digitalWrite(4,LOW);                    //SR clock low
      if(phase & 0x80) digitalWrite(8,LOW);   //Data to SR
      else digitalWrite(8,HIGH);
      digitalWrite(4,HIGH);                   //SR clock jth bit into register
      phase = phase<<1;                       //Shift bit to right next bit
    }
  digitalWrite(12,LOW);  
  digitalWrite(12,HIGH);                    //Latch byte

  digitalWrite(7,LOW);                        //Drive motor power
  delay(speed);                               //Wait for motor to settle
  digitalWrite(7,HIGH);                       //Drive motor power off
  }
 }                                           //Do process step times
position=position+steps;
return micros() - start;
}
``

Yes, that flush function works perfectly. Thanks for your comment.
Need to be called every time before the reading of the touch and then the next call of Adafruit's function will restore the normal display functioning.

But the combination of the analog device (resistive t.s.) and chip-select pin of the display...
Arrrrrgggghhhh.

maxbul

Here is what I did. I defined the analog input pin touch in the top of program
// Assign the Elegoo_TFTLCD class library
// Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
Elegoo_TFTLCD tft(A3, A2, A1, A0, A4 ); //Must be present here to make first pass work.
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300); //--- Define Touch
XP, YP, XM, YM are defined above (not shown )

I setup the buttons and screen in the setup section of program. These stay permanent for the screen, buttons and the like.

Then in the main loop, I first updated the screen and then issued the the command to read the touch on the display with the following.

TSPoint p;
p= ts.getPoint();

This must be done after you refresh the display with whatever images you want to be seen. After the instruction above is issued, wait for the screen to be touched and react. It is very painful if you have other things to do while waiting for screen touch.

The program I wrote is to drive a mechanical capacitor to tune an antenna. It could be used to point or turn a device with a bit of modification work. I'm using a 5-1 stepdown stepper to get better accuracy for the mechanical device I'm turning with the stepper. It also has a benefit of a bit more torque.

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