Multiple definition of ... Calculator with touch screen

Hey guys!

I am trying to build a simple calculator with my Teensy and a TFT ILI9341 display for touch screen input. Unfortunately, I don't really understand how to use libraries inside my own libraries. I would be glad about every help! Thank you! :slight_smile:
This is the error I get:

.pio/build/teensy40/src/ScreenInit.cpp.o:(.bss.tft+0x0): multiple definition of `tft'
.pio/build/teensy40/src/GetTouchValues.cpp.o:(.bss.tft+0x0): first defined here
.pio/build/teensy40/src/ScreenInit.cpp.o:(.data.ts+0x0): multiple definition of `ts'

Main code:

#include "Arduino.h"
#include "Arithmetik.h"
#include "ScreenInit.h"
#include "GetTouchValues.h"

Arithmetik arithmetik(10, 2);
ScreenInit screenInit;
GetTouchValues getTouchValues;

boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

void setup()
{
  screenInit.startDisplay();
}

void loop()
{
  // boolean istouched = ts.touched();
  // int X;
  // float Y;
  /* if (istouched)
  {
    TS_Point p = ts.getPoint(); // point getter function */
}

GetTouchValues.cpp:
#include "Arduino.h"
#include "GetTouchValues.h"

GetTouchValues::GetTouchValues()
{
}

float GetTouchValues::GetPoints()
{
if (istouched)
{
TS_Point p = ts.getPoint(); // point getter function
p.x = _x;
p.y = _y;
return _x;
return _y;
}
}

GetTouchValues.h:
#ifndef GetTouchValues_h
#define GetTouchvalues_h
#include "ScreenInit.h"
#include "Arduino.h"

class GetTouchValues
{
public:
GetTouchValues();
float GetPoints();

private:
boolean istouched = ts.touched();
float _x;
float _y;

};

#endif

ScreenInit.cpp:
#include "Arduino.h"
#include "ScreenInit.h"

ScreenInit::ScreenInit()
{
}

void ScreenInit::redrawButtons()
{
}

void ScreenInit::clearDisplay()
{
tft.fillScreen(ILI9341_RED);
redrawButtons();
}

void ScreenInit::startDisplay()
{
Serial.begin(38600);
tft.begin();
tft.setRotation(1);
tft.fillScreen(ILI9341_RED);
ts.begin();
ts.setRotation(1);
while (!Serial && (millis() <= 1000)); // weiß nicht was das ist
}

ScreenInit.h:
#ifndef ScreenInit_h
#define ScreenInit_h

#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>

#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN 2
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

#include "Arduino.h"

class ScreenInit
{
public:
ScreenInit();
void clearDisplay();
void redrawButtons();
void startDisplay();

};
#endif

You are instantiating the ts and tft objects in ScreenInit.h. Every time you include that header the compiler attempts to define those objects, hence the multiple definitions.

You should define those objects in one file.

In ScreenInit.h change this:

XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN 2
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

to:

extern XPT2046_Touchscreen ts;
#define TIRQ_PIN 2
extern ILI9341_t3 tft;

Then put the declarations in ScreenInit.cpp:

XPT2046_Touchscreen ts(CS_PIN);
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

Hey John! It worked with your solution thank you!! Todd, I was trying to do what you just wrote, because it's a better solution to have everything inside one class, as you said it. For some reason, I still get the same error.

My new main code:

#include "Arduino.h"
#include "Arithmetik.h"
#include "Display.h"

Arithmetik arithmetik(10, 2);
Display display;

boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

void setup()
{
  display.start();
}

void loop()
{
  // boolean istouched = ts.touched();
  // int X;
  // float Y;
  /* if (istouched)
  {
    TS_Point p = ts.getPoint(); // point getter function */
}

Display.h:

#ifndef Display_h
#define Display_h
#include "Arduino.h"
#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>

#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN 2
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

class Display
{
public:
    Display();
    float getPoints();
    void clear();
    void redrawButtons();
    void start();

private:
    boolean istouched = ts.touched();
    float _x;
    float _y;
};

#endif

[color=#c586c0]#endif[/color][/color]

Display.cpp:

#include "Arduino.h"
#include "Display.h"

Display::Display()
{
}

float Display::getPoints()
{
    if (istouched)
    {
        TS_Point p = ts.getPoint(); // point getter function
        p.x = _x;
        p.y = _y;
        return _x;
        return _y;
    }
}

void Display::redrawButtons()
{

}

void Display::clear()
{
    tft.fillScreen(ILI9341_RED);
    redrawButtons();
}

void Display::start()
{
 Serial.begin(38600);
 tft.begin();
 tft.setRotation(1);
 tft.fillScreen(ILI9341_RED);
 ts.begin();
 ts.setRotation(1);
 while (!Serial && (millis() <= 1000)); // weiß nicht was das ist
}

Error:

.pio/build/teensy40/src/taschenrechner.cpp.o:(.bss.tft+0x0): multiple definition of tft' .pio/build/teensy40/src/Display.cpp.o:(.bss.tft+0x0): first defined here /Users/Mate/.platformio/packages/toolchain-gccarmnoneeabi/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld: Disabling relaxation: it will not work with multiple definitions .pio/build/teensy40/src/taschenrechner.cpp.o:(.data.ts+0x0): multiple definition of ts'
.pio/build/teensy40/src/Display.cpp.o:(.data.ts+0x0): first defined here
collect2: error: ld returned 1 exit status
*** [.pio/build/teensy40/firmware.elf] Error 1

It looks like those two variables are defined in both "taschenrechner.cpp" and "Display.cpp". Where did "taschenrechner" come from?!?

taschenrechner is my main code!

The problem is that by using the extern declaration, the screen stops working. If I write the whole code in one main code, without any .h and .cpp files, it works, but then obviously I don't need the extern addition. I can't upload anything new to the screen, like simply changing a color. :confused: It's an ILI9341 TFT Touch Display.

My new code:

Main Code (taschenrechner.cpp):

#include "Arduino.h"
#include "Arithmetik.h"
#include "Display.h"

Arithmetik arithmetik(10, 2);
Display display; 

void setup()
{
  display.start();
  display.clear();
}

void loop()
{
  display.clear();
}

Display.cpp:

#include "Arduino.h"
#include "Display.h"

XPT2046_Touchscreen ts(CS_PIN); // Instanziierung eines ts Objekts der Klasse XPT2046_Touchscreen
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);


Display::Display()
{
}

float Display::getPoints()
{
    if (istouched)
    {
        TS_Point p = ts.getPoint(); // point getter function
        p.x = _x;
        p.y = _y;
        return _x;
        return _y;
    }
    else {
        return 0;
    }
}

void Display::redrawButtons()
{

}

void Display::clear()
{
    tft.fillScreen(ILI9341_GREEN);
    redrawButtons();
}

void Display::start()
{
 Serial.begin(38600);
 tft.begin();
 tft.setRotation(1);
 tft.fillScreen(ILI9341_GREEN);
 ts.begin();
 ts.setRotation(1);
 while (!Serial && (millis() <= 1000)); // weiß nicht was das ist
}

boolean Display::pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

Display.h:

#ifndef Display_h
#define Display_h
#include "Arduino.h"
#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>

#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

/* XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN 2
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC); */

extern XPT2046_Touchscreen ts; // declare the existence of global variable
#define TIRQ_PIN 2
extern ILI9341_t3 tft; // declare the existence of global variable

class Display
{
public:
    Display();
    float getPoints();
    void clear();
    void redrawButtons();
    void start();
    boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH);

private:
    boolean istouched = ts.touched();
    float _x;
    float _y;
};

#endif

I did not include Arithmetik, because it's not relevant..

Unfortunately, I don't have a Teensy 3.x and the ILI9341_t3 library won't compile on anything else. I used the "Adafruit_ILI9341" library and commented out the "Arithmetik" stuff and it compiled with one warning:

sketch/Display.cpp: In member function 'float Display::getPoints()':
sketch/Display.cpp:16:14: warning: variable 'p' set but not used [-Wunused-but-set-variable]
     TS_Point p = ts.getPoint(); // point getter function
              ^

The code it points to is bizarre so I'm surprised it didn't generate more warnings:

  {
    // Why fetch 'p', and overwrite its contents, without doing anything with it?
    TS_Point p = ts.getPoint(); // point getter function
    p.x = _x;  
    p.y = _y;


    return _x;  // Did you maybe intend the function to return 'p'?


    return _y;  // You'll never reach this line...
  }

Hello John!
I am aware of the warning because of p. My main problem is though, that the display won't do anything as soon as I begin to use external declaration. This time, I tried to instantiate ts and tft from the classes XPT2046_Touchscreen and ILI9341_t3 inside my class Display. Then I wanted to initialize them in the .cpp, but for some reason I get the error: no match for call to '(XPT2046_Touchscreen) (int, int)'. I am not quite sure why that happens..

Display.cpp

#include "Arduino.h"
#include "Display.h"

 // XPT2046_Touchscreen ts(CS_PIN); // Instanziierung eines ts Objekts der Klasse XPT2046_Touchscreen
// ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
#define TIRQ_PIN 2
#define CS_PIN 8
#define TFT_DC 9
#define TFT_CS 10

Display::Display()
{
  ts(CS_PIN);
  tft = ILI9341_t3(TFT_CS, TFT_DC);
}

float Display::getPoints()
{
  if (istouched)
  {
 /*   TS_Point p = ts.getPoint(); // point getter function
    p.x = _x;
    p.y = _y;
    return _x;
    return _y;  */
  }
  else
  {
    return 0;
  }
}

void Display::redrawButtons()
{
}

void Display::clear()
{
  tft.fillScreen(ILI9341_GREEN);
  redrawButtons();
}

void Display::start()
{
  Serial.begin(38600);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_GREEN);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000))
    ; // weiß nicht was das ist
}

boolean Display::pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH)
{
  boolean ret = false;
  if ((x >= rectX) && (x <= (rectX + rectW)) && (y >= rectY) && (y <= (rectY + rectH)))
  {
    ret = true;
  }
  return ret;
}

Display.h

#ifndef Display_h
#define Display_h
#include "Arduino.h"
#include <SPI.h>
#include <ILI9341_t3.h>
#include <font_Arial.h>
#include <XPT2046_Touchscreen.h>



/* extern XPT2046_Touchscreen ts; // declare the existence of global variable
#define TIRQ_PIN 2
extern ILI9341_t3 tft; // declare the existence of global variable */

class Display
{
public:
    Display();
    float getPoints();
    void clear();
    void redrawButtons();
    void start();
    boolean pointInRect(int x, float y, float rectX, float rectY, float rectW, float rectH);

private:
    XPT2046_Touchscreen ts;
    ILI9341_t3 tft;
    boolean istouched;
    float _x;
    float _y;
};

#endif

Hello John! Thank you for helping me for days, I finally solved it. :slight_smile: Thank you Todd too! I initialized ts and tft wrong all the time, but now, its working! :slight_smile:

Working code snippet:

Display::Display(): ts(CS_PIN), tft(TFT_CS, TFT_DC)
{
}