Libraries TinyStepper_28BYJ_48.h and Adafruit_ST7735.h 1.8'' display libraries collide somehow - how is that even possible?

Hi all,

I am using a stepper motor 28BYJ with an ULN2003 driver in the same project as a ST7735 1.8'' display. The stepper is connected to pins 4,5,6 and 7. The display is connected to pins 8,9, and 10.

I use the Adafruit library for the display and the TinyStepper library for the motor, which seem common and tested libraries to me.

I can run the motor without the display just fine. I can add the display and it works fine as well, but then the motor only buzzes but does not really turn.

I could break it down to the line

tft.initR(INITR_BLACKTAB);

If I comment that line out, the motor runs as expected. With the line, it shows the behavior that I expect if the motor control is not run fast enough. But according to documentation, the motor.moveRelativeInSteps(x); command that I use is blocking and will only return after finished, so this should not be possible to happen.

The power supply is through a 5V power supply that seems to have a lot of names: Yatwin YwRobot MB-V2 545043 are some of them. It is the black one with the yellow pins for use in small breadboards that can be seen everywhere. It feeds into the Nanos 5V pin, the TFTs VCC and the second connector to the ULN2003s Vmotor. The TFT LED pin is powered through the Nanos 3.3V output.

Here is the code:

#include <TinyStepper_28BYJ_48.h>

// >>> TFT <<<
// import Adafruit ST7735 Library for the 1.8'' display
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <SPI.h>
#include <ezButton.h>

// TFT
#define TFT_CS        10
#define TFT_RST        8 // Or set to -1 and connect to Arduino RESET pin
#define TFT_DC         9

// create TFT object
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

TinyStepper_28BYJ_48 motor;

void setup() {
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  
  motor.connectToPins(4, 5, 6, 7);
  motor.setSpeedInStepsPerSecond(1000);
  motor.setAccelerationInStepsPerSecondPerSecond(2000);
}

void loop() {
  motor.moveRelativeInSteps(300);
  delay(1000);
  motor.moveRelativeInSteps(-300);
  delay(1000);
}

If I comment out the tft.initR(...) line, the motor starts turning normaly.

My question is, how is that even possible? The devices do not share pins, the motor command should be blocking. The power during motor run only drops from 5V to 4.99V, so extremely stable.

What is happening here?

In most cases the libraries use the same timer. In some libraries the timer can be changed to some (hopefully) free and compatible timer.

1 Like

I think that might be a little ambitious. Try something very easy, like 10 per second. first. Then increase the speed until you discover the limit.

Mmmh, that would be a good reason. Unfortunately I am not in any way proficient with timers, so I did some reading and then tried out the following:

  Serial.println("Before calling tft.initR:");
  PrintTimerRegistersToSerial();
  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  Serial.println("After calling tft.initR:");
  PrintTimerRegistersToSerial();
[...]
void PrintTimerRegistersToSerial (){
  Serial.print("   TCCR0A: ");
  Serial.print(TCCR0A);
  Serial.print("   TCCR0B: ");
  Serial.print(TCCR0B);
  Serial.print("   TCNT0: ");
  Serial.print(TCNT0);
  Serial.print("   OCR0A: ");
  Serial.print(OCR0A);
  Serial.print("   TIMSK0: ");
  Serial.println(TIMSK0);
  
  Serial.print("   TCCR1A: ");
  Serial.print(TCCR1A);
  Serial.print("   TCCR1B: ");
  Serial.print(TCCR1B);
  Serial.print("   TCNT1: ");
  Serial.print(TCNT1);
  Serial.print("   OCR1A: ");
  Serial.print(OCR1A);
  Serial.print("   TIMSK1: ");
  Serial.println(TIMSK1);
  
  Serial.print("   TCCR2A: ");
  Serial.print(TCCR2A);
  Serial.print("   TCCR2B: ");
  Serial.print(TCCR2B);
  Serial.print("   TCNT2: ");
  Serial.print(TCNT2);
  Serial.print("   OCR2A: ");
  Serial.print(OCR2A);
  Serial.print("   TIMSK2: ");
  Serial.println(TIMSK2);

The output is:

11:07:40.826 -> Before calling tft.initR:
11:07:40.826 ->    TCCR0A: 3   TCCR0B: 3   TCNT0: 142   OCR0A: 0   TIMSK0: 1
11:07:40.826 ->    TCCR1A: 1   TCCR1B: 3   TCNT1: 75   OCR1A: 0   TIMSK1: 0
11:07:40.826 ->    TCCR2A: 1   TCCR2B: 4   TCNT2: 34   OCR2A: 0   TIMSK2: 0
11:07:41.996 -> After calling tft.initR:
11:07:41.996 ->    TCCR0A: 3   TCCR0B: 3   TCNT0: 81   OCR0A: 0   TIMSK0: 1
11:07:41.996 ->    TCCR1A: 1   TCCR1B: 3   TCNT1: 84   OCR1A: 0   TIMSK1: 0
11:07:41.996 ->    TCCR2A: 1   TCCR2B: 4   TCNT2: 43   OCR2A: 0   TIMSK2: 0

So it does not look to me that the timers have changed, as TCNTx is just the counter and has to change over time. Or do I need to look at something else?

1 Like

It works just fine if tft.initR is not called before the motor run. Why would the performance limit of the stepper motor decrease after the TFT is initialized?

Look at the use of timer registers in the library code.

I did. I think this timer thing is a dead end.

I checked the TFT library:

It includes the Adafruit GFX library, sources here:

I downloaded both trees locally and ran a search for files that contain the strings TCCR, TCNT, OCR or TIMSK.

There are no occurrences in any of the files. The TFT libraries do not access timer registers.

Also, I have shown above that the timer registers remain unchanged when the line of code that causes the issues is run.

Something is clearly changing, but it is not the timers.

I tried to make a workaround using the CheapStepper lib instead of the TinyStepper lib. Same problem. The TFT and the stepper work individually, but if run together, only the TFT works and the stepper only buzzes but stays in place.

I think I found the culprit.

Your answer gave me the idea to look at other registers than timer registers and if they change. That gave me the result that other than the expected changes, the register PIND was set from 00000001 to 10000001, so the value for pin D7 is set to true by tft.initR.

This is the input register. The pin is set to Output (DDRD = 11110000). I have no idea what a changing input value means for an output pin, nor why tft.initR would change a pin it does not use.

I will keep you updated.

Well, it wasn't that either... :roll_eyes: I set everything up on a breadboard, avoiding pin 7, and the result is sill the same.

Good ideas would be greatly appreciated!

IMO it's time to contact the library maintainers. I don't want to dig into details of libraries which I can not use and test myself.

Okay, now I found the culprit and have to say I am sorry for the holdup. It was my sloppy soldering skills.

On my self-soldered headers, Pins 7 and 8 were (barely visibly) connected by a solder blob.

So the motor using pins 4-7 worked fine in isolation, and so did the TFT on pins 8-11, but when running them simultaneously, the TFT init would set D8 = RESET to HIGH, also setting the motor controller pin 7 constantly to high. That is why I had this crazy interference, and it is also why the PIND register for D7 was set to high...

So yeah, I am learning...

1 Like

Congrats for mastering that long way :slight_smile:

I'll add your experience to mine, that 99% of all problems are homemade, and often it's hard to find the trouble source from afar.

1 Like

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