Problem of overriding touches in menus selection - TFT display

AntiLoop

Well-known member
Hello,
I would like to select different menus with buttons that are same dimensions and at the same coordonnates,
of course,i set a different state for each menu,but when i touch one of the menus,the twice are selected with a very small delay,
so i stuck on the first menu but the serial monitor shows: MENU1 MENU2 at the same time.
Of course if i use different touch coordonates,the problem does'n exist but i need a lot of buttons at the same coordonates in all the menus.
I show you a simple example with only 2 menus:

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <RA8875.h>
#include <Adafruit_FT6206.h>

// The FT6206 uses hardware I2C (SCL 19/SDA 18)
Adafruit_FT6206 ts = Adafruit_FT6206();


#define RA8875_CS         36
#define RA8875_RESET      255                                                                                                                                                                                     23                 
#define RA8875_INT        41

 RA8875 tft = RA8875(RA8875_CS, RA8875_RESET);

int state = 0;


void setup() {
 
  Serial.begin(38400);

  //  begin display: Choose from: RA8875_480x272, RA8875_800x480, RA8875_800x480ALT, Adafruit_480x272, Adafruit_800x480
  tft.begin(RA8875_800x480);

   if (!ts.begin(40)) {
    Serial.println("Unable to start touchscreen.");
  }
  else {
    Serial.println("Touchscreen started.");
  }
 
   tft.setRotation(0);
  tft.fillWindow(RA8875_BLACK);//fill window black
 
  //tft.setTextColor(RA8875_WHITE,RA8875_BLACK);
  tft.setFontScale(1);
    
 
 drawMenu1();
 
}

boolean wastouched = true;
elapsedMillis msecs;

void loop() {
 
 
  boolean istouched = ts.touched();
 
  if (istouched) {
    TS_Point p = ts.getPoint();

    // rotate coordinate system
    // flip it around to match the screen.
    p.x = map(p.x, 0, 800,0,800);
    p.y = map(p.y, 0, 480, 480,0);
    //int y = tft.height() - p.y;   
    //int x = p.x;

    int y = tft.height() - p.y;   
    int x = p.x;
    
    if (!wastouched) {
    
    }
    
        
    if(state == 0){
    if(p.x>=0 && p.x<=400 && p.y>=90 && p.y<=480)
    {Serial.println("MENU2");
      drawMenu2();}
    }

    if(state == 1){
    if(p.x>=0 && p.x<=400 && p.y>=90 && p.y<=480)
    {Serial.println("MENU1");
      drawMenu1();}
    }
    
  else {
    if (wastouched) {
      
                      
    }
    Serial.println("no touch");
  }
  wastouched = istouched;
  delay(100);

  }
}

void drawMenu1(){
  state = 0;
  tft.fillWindow(RA8875_BLACK);
tft.fillRect(0,0,400,400,RA8875_BLUE);
      tft.setTextColor(RA8875_WHITE);
      tft.setFontScale(3);
      
      tft.setCursor(125, 160);
      tft.print("MENU1"); 
}

void drawMenu2(){
  state = 1;
  tft.fillWindow(RA8875_BLACK);
tft.fillRect(0,0,400,400,RA8875_GREEN);
      tft.setTextColor(RA8875_WHITE);
      tft.setFontScale(3);
      
      tft.setCursor(125, 160);
      tft.print("MENU2");   
}

Maybe it's basic for you but i'm stucking here :unsure:
 
I had the same problem using multiple row and column menus. The solution is to have a handler for each menu so that the same position can be used for several menus but only the correct one. Use the code at the top of the loop() statement as a model. You can also use only the loop() occurrence for all menus but you will have to create a boolean flag that is active for each menu. A sequence of if---else if statements will determine which one is active and direct it to the appropriate handler. Each handler will still need a touch detector.
 
With your code:
Code:
    if(state == 0){
        if(p.x>=0 && p.x<=400 && p.y>=90 && p.y<=480)
        {
            Serial.println("MENU2");
              drawMenu2();
        }
    }

    if(state == 1){
        if(p.x>=0 && p.x<=400 && p.y>=90 && p.y<=480)
        {
            Serial.println("MENU1");
            drawMenu1();
        }
    }
Note I re-indented the code.
Couple of things:

1) in your state == 1 state, it will always drawmenu1 as where your {} is.
EDIT : Never mind on this one, I misread your code

2) Suppose drawMenu2 changes the variable state... from 0 to 1, your next if will pick up the updated value...
You might want to change to else if (state == 1)

Hope that helps
 
Hello, Arctic_Eddie and KurtE, it's new for me this kind of handling menus, i have also in each menu many others buttons
witch coordonates are included in the menu select areas of course not in the same menu :)
I use always down screen buttons to navigate and switch to every menu,but in the principal menu,the buttons are bigger.
Of course it's a non-sense to have 3 choices on the same areas,2 choices make the two menu to flip each other,
i say that because my example is only for 2 menus.
I will study your suggestions and be back...Thank you for your help :)
 
@AntiLoop:

[ EDITED ] Not sure if the attached template will help you with your current challenge, but I wrote this template as a simple example of how I support a state-driven menu system (for example, with buttons at identical locations supporting different functions and/or initiating different actions, depending upon which "state" the system is currently in . . . similarly, common buttons are used to change between the different states - this example demonstrates four different menu states and the unique buttons associated with each state).

Let me know if this helps and/or if you have any other questions WRT this example template for the 7" RA8875 TFT touchscreen display.

Code:
//
//  Teensy 4.1 RA8875 template - version 1.0 dated 20240921-2100
//
//    - designed & written by Mark J Culross (KD5RXT)
//
//    - controlled via buttons/sliders displayed on a 7" RA8875 800x480 display w/ touchscreen from here:
//
//         https://www.buydisplay.com/7-inch-lcd-module-capacitive-touch-screen-panel-i2c-spi-serial
//
//         Display options (ER-TFTM070-5):
//            Interface:               Pin Header Connection-4-wire SPI
//            VDD:                     5.0V (can always change the jumper later to power from 3.3VDC)
//            Touch Panel:             7" Capacitive Touch Panel with Controller
//            MicroSD Card Interface:  Pin Header Connection (not useable - see display docs)
//            Font Chip:               (none selected)
//
//         Make sure to edit C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\RA8875\_settings\RA8875UserSettings.h
//            - uncomment the following line: #define USE_FT5206_TOUCH//capacitive touch screen
//
//  Arduino IDE Configuration (last built with Arduino 1.8.19 + Teensyduino 1.59):
//     Tools/Board:           "Teensy 4.1"
//     Tools/USB Type:        "Serial"
//     Tools/CPU Speed:       "600MHz"
//     Tools/Optimize:        "Faster"
//     Tools/Keyboard Layout: "US English"
//     Tools/Port:            "COMx Serial (Teensy 4.1)"
//
//

const String VERSION0  = "1.0";
const String VERSION1  = ">> Teensy RA8875 template <<";
const String VERSION2  = "version " + VERSION0 + " dated 09/21/2024 @2100";
const String VERSION3  = "designed & written by Mark J Culross (KD5RXT)";

//#define DISABLE_BACKLIGHT_CONTROL       // uncomment to disable backlight control (NOTE: enabling may induce 230Hz tone in LINE OUT audio)
//#define DEBUG_TOUCHSCREEN               // uncomment to print touchscreen coordinates & touch state to SerialMonitor
//#define DEBUG_SLIDER_BUMP               // uncomment to print slider bump up/down calculations & intermediate values to SerialMonitor


#include <SPI.h>    // to avoid unnecessary compile errors, this *must* appear in the list of includes *before* RA8875
#include <RA8875.h>

// when used w/ Audio Adapter, must use an alternate CS pin for the display
const int RA8875_CHIP_SELECT     =  38;       // Teensy 38 (A14) -to- RA8875 05
const int RA8875_RESET           =   3;       // Teensy 03 (D03) -to -RA8875 11
const int RA8875_MISO            =  39;       // Teensy 39 (A15) -to- RA8875 06
const int RA8875_MOSI            =  26;       // Teensy 26 (A12) -to- RA8875 07
const int RA8875_SCLK            =  27;       // Teensy 27 (A13) -to- RA8875 08
const int RA8875_TS_INT          =   2;       // Teensy 02 (D02) -to- RA8875 33

const int RA8875_MAX_TOUCH_LIMIT =   1;

RA8875 tft = RA8875(RA8875_CHIP_SELECT, RA8875_RESET, RA8875_MOSI, RA8875_SCLK, RA8875_MISO);

//
// The following pins are used in this project:
//
// PIN D0       = (not used)
// PIN D1       = (not used)
// PIN D2       = RA8875 Touchscreen INT
// PIN D3       = RA8875 Touchscreen RESET
// PIN D4       = CHECK_BATTERY_PIN
// PIN D5       = (not used)
// PIN D6       = (not used)
// PIN D7       = (not used)
// PIN D8       = (not used)
// PIN D9       = (not used)
// PIN D10      = (not used)
// PIN D11      = (not used)
// PIN D12      = (not used)
// PIN D13      = (not used)
// PIN D14/A0   = (not used)
// PIN D15/A1   = (not used)
// PIN D16/A2   = (not used)
// PIN D17/A3   = (not used)
// PIN D18/A4   = (not used)
// PIN D19/A5   = (not used)
// PIN D20/A6   = (not used)
// PIN D21/A7   = (not used)
// PIN D22/A8   = (not used)
// PIN D23/A9   = (not used)
// PIN D24/A10  = (not used)
// PIN D25/A11  = (not used)
// PIN D26/A12  = RA8875 Touchscreen MOSI (MOSI1)
// PIN D27/A13  = RA8875 Touchscreen SCLK (SCK1)
// PIN D28      = (not used)
// PIN D29      = (not used)
// PIN D30      = (not used)
// PIN D31      = (not used)
// PIN D32      = (not used)
// PIN D33      = (not used)
// PIN D34      = (not used)
// PIN D35      = (not used)
// PIN D36      = (not used)
// PIN D37      = (not used)
// PIN D38/A14  = RA8875 Touchscreen CS (CS1)
// PIN D39/A15  = RA8875 Touchscreen MISO (MISO1)
// PIN D40/A16  = (not used)
// PIN D41/A17  = (not used)

// onboard LED on pin 13
#define LED_PIN 13
#define LED_PIN_ON 16
#define LED_PIN_OFF 0

// keep track of splash screen delay
const int CHECK_SPLASH_MILLIS = 4000;
unsigned long check_splash_time;

// keep track of when the screen needs to be updated
boolean screen_update_required = false;

// keep track of how often to check touchscreen
const int CHECK_TOUCHSCREEN_MILLIS = 20;
unsigned long check_touchscreen_time = millis();

// custom RA8875 TFT colors (5-bit RED, 6-bit GREEN, 5-bit BLUE)
#define RA8875_DIMGREY     0x6B4D
#define RA8875_MDGREY      0x8410
#define RA8875_ASHGREY     0xB5F6
#define RA8875_ORANGE      0xFB00


typedef enum
{
   CONFIG_MODE_SPLASH = 0, CONFIG_MODE_INIT_SCREEN,
   CONFIG_MODE_MENU1, CONFIG_MODE_MENU2, CONFIG_MODE_MENU3, CONFIG_MODE_MENU4,
}  CONFIG_MODE;

CONFIG_MODE config_mode = CONFIG_MODE_SPLASH;

boolean previously_touched = false;
boolean touch_triggered = false;

// global touchscreen coordinates (in pixels) where touched
int16_t BtnX = -1, BtnY = -1;

struct BUTTON_TYPE
{
   unsigned int   xCenterLoc;
   unsigned int   yCenterLoc;
   unsigned int   xSize;
   unsigned int   ySize;
   const String*  textPtr;
   uint16_t       textColor;
   uint16_t       buttonColor;
   uint16_t       borderColor;
   boolean        activated;
};

// create button objects, passing in the display object

// UNIQUE PORTION OF THE DISPLAY SCREEN (only used for clearing the bottom portion of the screen & detecting touches)
const String uniqueScreenAreaText         = "";
BUTTON_TYPE uniqueScreenArea              = {400, 270, 800, 420,     &uniqueScreenAreaText,  RA8875_BLACK,  RA8875_BLACK,  RA8875_BLACK,  true};

// CHANGING BUTTON PORTION OF THE DISPLAY SCREEN (only used for clearing/redrawing buttons when changing menus)
const String buttonScreenAreaText         = "";
BUTTON_TYPE buttonScreenArea              = {400,  81, 630,  50,     &buttonScreenAreaText,  RA8875_BLACK,  RA8875_BLACK,  RA8875_BLACK,  true};


// PRIMARY BUTTONS
const String menu1ButtonText              = "MENU 1";
BUTTON_TYPE menu1Button                   = {120,  48, 70, 36,            &menu1ButtonText,  RA8875_BLACK,  RA8875_GREEN, RA8875_ORANGE, false};

const String menu2ButtonText              = "MENU 2";
BUTTON_TYPE menu2Button                   = {195,  48, 70, 36,            &menu2ButtonText,  RA8875_BLACK,  RA8875_GREEN, RA8875_ORANGE, false};

const String menu3ButtonText              = "MENU 3";
BUTTON_TYPE menu3Button                   = {270,  48, 70, 36,            &menu3ButtonText,  RA8875_BLACK,  RA8875_GREEN, RA8875_ORANGE, false};

const String menu4ButtonText              = "MENU 4";
BUTTON_TYPE menu4Button                   = {345,  48, 70, 36,            &menu4ButtonText,  RA8875_BLACK,  RA8875_GREEN, RA8875_ORANGE, false};



// MENU 1 BUTTONS
const String menu1BacklightButtonTextV    = "BACKLIGHT";
BUTTON_TYPE menu1BacklightButtonV         = {750, 91, 90, 30,  &menu1BacklightButtonTextV,  RA8875_GREEN,  RA8875_BLACK,    RA8875_RED,  true};

const String menu1BacklightButtonTextH    = "BACKLIGHT";
BUTTON_TYPE menu1BacklightButtonH         = {400, 240, 90, 30,  &menu1BacklightButtonTextH,  RA8875_GREEN,  RA8875_BLACK,    RA8875_RED,  true};

const String menu1Button1Text             = "BUTTON 1-1";
BUTTON_TYPE menu1Button1                  = {100, 200, 90, 30,           &menu1Button1Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu1Button2Text             = "BUTTON 1-2";
BUTTON_TYPE menu1Button2                  = {100, 250, 90, 30,           &menu1Button2Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu1Button3Text             = "BUTTON 1-3";
BUTTON_TYPE menu1Button3                  = {100, 300, 90, 30,           &menu1Button3Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu1Button4Text             = "BUTTON 1-4";
BUTTON_TYPE menu1Button4                  = {100, 350, 90, 30,           &menu1Button4Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};


// MENU 2 BUTTONS
const String menu2Button1Text             = "BUTTON 2-1";
BUTTON_TYPE menu2Button1                  = {100, 200, 90, 30,           &menu2Button1Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu2Button2Text             = "BUTTON 2-2";
BUTTON_TYPE menu2Button2                  = {100, 250, 90, 30,           &menu2Button2Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu2Button3Text             = "BUTTON 2-3";
BUTTON_TYPE menu2Button3                  = {100, 300, 90, 30,           &menu2Button3Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu2Button4Text             = "BUTTON 2-4";
BUTTON_TYPE menu2Button4                  = {100, 350, 90, 30,           &menu2Button4Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};


// MENU 3 BUTTONS
const String menu3Button1Text             = "BUTTON 3-1";
BUTTON_TYPE menu3Button1                  = {100, 200, 90, 30,           &menu3Button1Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu3Button2Text             = "BUTTON 3-2";
BUTTON_TYPE menu3Button2                  = {100, 250, 90, 30,           &menu3Button2Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu3Button3Text             = "BUTTON 3-3";
BUTTON_TYPE menu3Button3                  = {100, 300, 90, 30,           &menu3Button3Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu3Button4Text             = "BUTTON 3-4";
BUTTON_TYPE menu3Button4                  = {100, 350, 90, 30,           &menu3Button4Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};


// MENU 4 BUTTONS
const String menu4Button1Text             = "BUTTON 4-1";
BUTTON_TYPE menu4Button1                  = {100, 200, 90, 30,           &menu4Button1Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu4Button2Text             = "BUTTON 4-2";
BUTTON_TYPE menu4Button2                  = {100, 250, 90, 30,           &menu4Button2Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu4Button3Text             = "BUTTON 4-3";
BUTTON_TYPE menu4Button3                  = {100, 300, 90, 30,           &menu4Button3Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};

const String menu4Button4Text             = "BUTTON 4-4";
BUTTON_TYPE menu4Button4                  = {100, 350, 90, 30,           &menu4Button4Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};


#define BUMP_REPEAT_START_DELAY_MILLISECONDS 750

typedef enum
{
   SLIDER_MODE_HORIZONTAL = 0, SLIDER_MODE_VERTICAL
}  SLIDER_MODE;

struct SLIDER_TYPE
{
   unsigned int   xCenterLoc;
   unsigned int   yCenterLoc;
   unsigned int   xSize;
   unsigned int   ySize;
   float          value;
   unsigned int   minorTickSections;  // normally = 10
   unsigned int   majorTickSections;  // normally =  2
   unsigned int   placesBeforeTheDecimal;
   unsigned int   placesAfterTheDecimal;
   boolean        showPlusMinusSign;
   float          minValue;  // for HORIZONTAL = all the way to the left, for VERTICAL, all the way up
   float          maxValue;  // for HORIZONTAL = all the way to the right, for VERTICAL, all the way down
   boolean        withBumpUpArrow;
   boolean        withBumpDownArrow;
   float          bumpValue;
   unsigned int   xValueCenterLoc;
   unsigned int   yValueCenterLoc;
   uint16_t       valueColor;
   uint16_t       backgroundColor;
   uint16_t       borderColor;
   uint16_t       scaleColor;
   uint16_t       handleColor;
   uint16_t       handleBorderColor;
   uint16_t       backgroundColorDisabled;
   uint16_t       borderColorDisabled;
   uint16_t       scaleColorDisabled;
   uint16_t       handleColorDisabled;
   uint16_t       handleBorderColorDisabled;
   uint16_t       bumpBackgroundColor;
   boolean        activated;
   boolean        repeatEnabled;
   boolean        previouslyTouched;
   unsigned long  touchStartMillis;
   unsigned int   repeatMilliseconds;
   SLIDER_MODE    orientation;
};

SLIDER_TYPE  menu1BacklightSliderV    = { 750,  305,  30, 255, 127.00, 16, 2, 3, 0, false,     1.0,    255.0,  true, true, 1.00, 750, 115, RA8875_WHITE, RA8875_MDGREY, RA8875_GREEN, RA8875_BLACK,   RA8875_GREEN, RA8875_BLACK,   RA8875_BLACK, RA8875_MDGREY, RA8875_MDGREY, RA8875_MDGREY, RA8875_BLACK, RA8875_BLACK, true,  true, false, 0, 250, SLIDER_MODE_VERTICAL };
SLIDER_TYPE  menu1BacklightSliderH    = { 400,  305, 255,  30, 127.00, 16, 2, 3, 0, false,     1.0,    255.0,  true, true, 1.00, 400, 265, RA8875_WHITE, RA8875_MDGREY, RA8875_GREEN, RA8875_BLACK,   RA8875_GREEN, RA8875_BLACK,   RA8875_BLACK, RA8875_MDGREY, RA8875_MDGREY, RA8875_MDGREY, RA8875_BLACK, RA8875_BLACK, true,  true, false, 0, 250, SLIDER_MODE_HORIZONTAL };




// function headers
void centerDrawText(const String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground);
boolean checkButton(BUTTON_TYPE thisButton);
boolean checkSlider(SLIDER_TYPE* thisSlider);
boolean checkSliderBumpDown(SLIDER_TYPE* thisSlider);
boolean checkSliderBumpUp(SLIDER_TYPE* thisSlider);
void drawButton(BUTTON_TYPE thisButton);
void drawScreen(void);
void drawSlider(SLIDER_TYPE thisSlider);
void loop();
boolean processTouchscreen(void);
void setup();



// draw text, centered around xLoc & yLoc
void centerDrawText(const String text, unsigned int xCenterLoc, unsigned int yCenterLoc, uint16_t textColor, uint16_t textBackground)
{
   unsigned int xOffset = (text.length() * 8) / 2;
   unsigned int yOffset = 8;

   tft.setTextColor(textColor, textBackground);
   tft.setTextSize(1);

   tft.setCursor(xCenterLoc - xOffset, yCenterLoc - yOffset);
   tft.print(text);
}  // centerDrawText


// check if a button was pressed
boolean checkButton(BUTTON_TYPE thisButton)
{
   boolean retVal = false;

   // if touched most recently in thisButton
   if ((BtnX >= (uint16_t)(thisButton.xCenterLoc - (thisButton.xSize / 2))) &&
         (BtnX <= (uint16_t)(thisButton.xCenterLoc + (thisButton.xSize / 2))) &&
         (BtnY >= (uint16_t)(thisButton.yCenterLoc - (thisButton.ySize / 2))) &&
         (BtnY <= (uint16_t)(thisButton.yCenterLoc + (thisButton.ySize / 2))))
   {
      retVal = true;
   }

   return (retVal);
}  // checkButton()


// check if a slider has changed
boolean checkSlider(SLIDER_TYPE* thisSlider)
{
   boolean retVal = false;
   float newValue = 0.0f;

   // if thisSlider is active & touched most recently in thisSlider
   if (thisSlider->activated)
   {
      if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
      {
         // if touched most recently in thisSlider
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 15))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 15))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
         {
            if (BtnX < (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)))
            {
               BtnX = (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2));
            }

            if (BtnX > (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)))
            {
               BtnX = (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2));
            }

            if (BtnY < (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)))
            {
               BtnY = (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2));
            }

            if (BtnY > (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)))
            {
               BtnY = (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2));
            }

            newValue = (float)map((float)BtnY, (float)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)), (float)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)), thisSlider->maxValue, thisSlider->minValue);

            if (newValue != thisSlider->value)
            {
               thisSlider->value = newValue;

               retVal = true;
            }
         } else {
            // if thisSlider is active & has either bump arrow & has been held & was touched most recently in thisSlider's bump arrow area
            if ((thisSlider->withBumpDownArrow || thisSlider->withBumpUpArrow) && (thisSlider->repeatEnabled))
            {
               // if touched most recently in thisSlider's bump up arrow
               if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
                     (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
                     (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2) + 50))) &&
                     (BtnY <= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))))
               {

#ifdef DEBUG_SLIDER_BUMP
                  Serial.print("initial slider value:   ");
                  Serial.println(thisSlider->value);
                  Serial.print("slider bump up value:   ");
                  Serial.println(thisSlider->bumpValue);
#endif

                  if (!(thisSlider->previouslyTouched))
                  {
                     thisSlider->previouslyTouched = true;
                     thisSlider->touchStartMillis = millis();
                  } else {
                     if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
                     {
                        if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
                        {
                           thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
                           thisSlider->value += thisSlider->bumpValue;
                        } else {
                           thisSlider->value = thisSlider->maxValue;
                        }

#ifdef DEBUG_SLIDER_BUMP
                        Serial.print("resulting slider value: ");
                        Serial.println(thisSlider->value);
                        Serial.println("");
#endif

                        retVal = true;
                     }
                  }
               } else {
                  // if touched most recently in thisSlider's bump down arrow
                  if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
                        (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
                        (BtnY >= (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2))) &&
                        (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2) + 50))))
                  {

#ifdef DEBUG_SLIDER_BUMP
                     Serial.print("initial slider value:   ");
                     Serial.println(thisSlider->value);
                     Serial.print("slider bump down value:   ");
                     Serial.println(thisSlider->bumpValue);
#endif

                     if (!(thisSlider->previouslyTouched))
                     {
                        thisSlider->previouslyTouched = true;
                        thisSlider->touchStartMillis = millis();
                     } else {
                        if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
                        {
                           if ((thisSlider->value - thisSlider->bumpValue) > thisSlider->minValue)
                           {
                              thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
                              thisSlider->value -= thisSlider->bumpValue;
                           } else {
                              thisSlider->value = thisSlider->minValue;
                           }

#ifdef DEBUG_SLIDER_BUMP
                           Serial.print("resulting slider value: ");
                           Serial.println(thisSlider->value);
                           Serial.println("");
#endif

                           retVal = true;
                        }
                     }
                  } else {
                     // force another wait delay before repeat
                     thisSlider->previouslyTouched = false;
                  }
               }
            } else {
               // force another wait delay before repeat
               thisSlider->previouslyTouched = false;
            }
         }
      } else {  // SLIDER_MODE_HORIZONTAL
         // if touched most recently in thisSlider
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 15))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 15))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
         {
            if (BtnX < (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)))
            {
               BtnX = (uint16_t)(thisSlider->xCenterLoc - (thisSlider->xSize / 2));
            }

            if (BtnX > (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)))
            {
               BtnX = (uint16_t)(thisSlider->xCenterLoc + (thisSlider->xSize / 2));
            }

            if (BtnY < (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2)))
            {
               BtnY = (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2));
            }

            if (BtnY > (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2)))
            {
               BtnY = (uint16_t)(thisSlider->yCenterLoc + (thisSlider->ySize / 2));
            }

            newValue = (float)map((float)BtnX, (float)(thisSlider->xCenterLoc - (thisSlider->xSize / 2)), (float)(thisSlider->xCenterLoc + (thisSlider->xSize / 2)), thisSlider->minValue, thisSlider->maxValue);

            if (newValue != thisSlider->value)
            {
               thisSlider->value = newValue;

               retVal = true;
            }
         } else {
            // if thisSlider is active & has either bump arrow & has been held & was touched most recently in thisSlider's bump arrow area
            if ((thisSlider->withBumpDownArrow || thisSlider->withBumpUpArrow) && (thisSlider->repeatEnabled))
            {
               // if touched most recently in thisSlider's bump up arrow
               if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
                     (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 50))) &&
                     (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
                     (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
               {

#ifdef DEBUG_SLIDER_BUMP
                  Serial.print("initial slider value:   ");
                  Serial.println(thisSlider->value);
                  Serial.print("slider bump up value:   ");
                  Serial.println(thisSlider->bumpValue);
#endif

                  if (!(thisSlider->previouslyTouched))
                  {
                     thisSlider->previouslyTouched = true;
                     thisSlider->touchStartMillis = millis();
                  } else {
                     if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
                     {
                        if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
                        {
                           thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
                           thisSlider->value += thisSlider->bumpValue;
                        } else {
                           thisSlider->value = thisSlider->maxValue;
                        }

#ifdef DEBUG_SLIDER_BUMP
                        Serial.print("resulting slider value: ");
                        Serial.println(thisSlider->value);
                        Serial.println("");
#endif

                        retVal = true;
                     }
                  }
               } else {
                  // if touched most recently in thisSlider's bump down arrow
                  if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 50))) &&
                        (BtnX <= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
                        (BtnY >= (uint16_t)(thisSlider->yCenterLoc - (thisSlider->ySize / 2))) &&
                        (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
                  {
#ifdef DEBUG_SLIDER_BUMP
                     Serial.print("initial slider value:   ");
                     Serial.println(thisSlider->value);
                     Serial.print("slider bump down value:   ");
                     Serial.println(thisSlider->bumpValue);
#endif

                     if (!(thisSlider->previouslyTouched))
                     {
                        thisSlider->previouslyTouched = true;
                        thisSlider->touchStartMillis = millis();
                     } else {
                        if ((millis() - thisSlider->touchStartMillis) > BUMP_REPEAT_START_DELAY_MILLISECONDS)
                        {
                           if ((thisSlider->value - thisSlider->bumpValue) > thisSlider->minValue)
                           {
                              thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
                              thisSlider->value -= thisSlider->bumpValue;
                           } else {
                              thisSlider->value = thisSlider->minValue;
                           }

#ifdef DEBUG_SLIDER_BUMP
                           Serial.print("resulting slider value: ");
                           Serial.println(thisSlider->value);
                           Serial.println("");
#endif

                           retVal = true;
                        }
                     }
                  } else {
                     // force another wait delay before repeat
                     thisSlider->previouslyTouched = false;
                  }
               }
            } else {
               // force another wait delay before repeat
               thisSlider->previouslyTouched = false;
            }
         }
      }
   }

   return (retVal);
}  // checkSlider()


// check if a slider bump down arrow has been pressed
boolean checkSliderBumpDown(SLIDER_TYPE * thisSlider)
{
   boolean retVal = false;

   // if thisSlider is active & has a bump down arrow & was touched most recently in thisSlider's bump down arrow area
   if ((thisSlider->activated) && (thisSlider->withBumpDownArrow))
   {
      if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
      {
         // if touched most recently in thisSlider's bump down arrow
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2) + 50))))
         {

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("initial slider value:   ");
            Serial.println(thisSlider->value);
            Serial.print("slider bump down value:   ");
            Serial.println(thisSlider->bumpValue);
#endif

            if ((thisSlider->value - thisSlider->bumpValue) > (thisSlider->minValue))
            {
               thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
               thisSlider->value -= thisSlider->bumpValue;
            } else {
               thisSlider->value = thisSlider->minValue;
            }

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("resulting slider value: ");
            Serial.println(thisSlider->value);
            Serial.println("");
#endif

            retVal = true;

            // force another wait delay before repeat
            thisSlider->previouslyTouched = false;
         }
      } else {   // SLIDER_MODE_HORIZONTAL
         // if touched most recently in thisSlider's bump down arrow
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2) + 50))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
         {

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("initial slider value:   ");
            Serial.println(thisSlider->value);
            Serial.print("slider bump down value:   ");
            Serial.println(thisSlider->bumpValue);
#endif

            if ((thisSlider->value - thisSlider->bumpValue) > (thisSlider->minValue))
            {
               thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
               thisSlider->value -= thisSlider->bumpValue;
            } else {
               thisSlider->value = thisSlider->minValue;
            }

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("resulting slider value: ");
            Serial.println(thisSlider->value);
            Serial.println("");
#endif

            retVal = true;

            // force another wait delay before repeat
            thisSlider->previouslyTouched = false;
         }
      }
   }

   return (retVal);
}  // checkSliderBumpDown()


// check if a slider bump up arrow has been pressed
boolean checkSliderBumpUp(SLIDER_TYPE * thisSlider)
{
   boolean retVal = false;

   // if thisSlider is active & has a bump up arrow & was touched most recently in thisSlider's bump up arrow area
   if ((thisSlider->activated) && (thisSlider->withBumpUpArrow))
   {
      if (thisSlider->orientation == SLIDER_MODE_VERTICAL)
      {
         // if touched most recently in thisSlider's bump up arrow
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc - ((thisSlider->xSize / 2)))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2) + 50))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))))
         {

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("initial slider value:   ");
            Serial.println(thisSlider->value);
            Serial.print("slider bump up value:   ");
            Serial.println(thisSlider->bumpValue);
#endif

            if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
            {
               thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
               thisSlider->value += thisSlider->bumpValue;
            } else {
               thisSlider->value = thisSlider->maxValue;
            }

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("resulting slider value: ");
            Serial.println(thisSlider->value);
            Serial.println("");
#endif

            retVal = true;

            // force another wait delay before repeat
            thisSlider->previouslyTouched = false;
         }
      } else {
         // if touched most recently in thisSlider's bump up arrow
         if ((BtnX >= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2)))) &&
               (BtnX <= (uint16_t)(thisSlider->xCenterLoc + ((thisSlider->xSize / 2) + 50))) &&
               (BtnY >= (uint16_t)(thisSlider->yCenterLoc - ((thisSlider->ySize / 2)))) &&
               (BtnY <= (uint16_t)(thisSlider->yCenterLoc + ((thisSlider->ySize / 2)))))
         {

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("initial slider value:   ");
            Serial.println(thisSlider->value);
            Serial.print("slider bump up value:   ");
            Serial.println(thisSlider->bumpValue);
#endif

            if ((thisSlider->value + thisSlider->bumpValue) < thisSlider->maxValue)
            {
               thisSlider->value = (float)((round)(thisSlider->value / thisSlider->bumpValue)) * thisSlider->bumpValue;
               thisSlider->value += thisSlider->bumpValue;
            } else {
               thisSlider->value = thisSlider->maxValue;
            }

#ifdef DEBUG_SLIDER_BUMP
            Serial.print("resulting slider value: ");
            Serial.println(thisSlider->value);
            Serial.println("");
#endif

            retVal = true;

            // force another wait delay before repeat
            thisSlider->previouslyTouched = false;
         }
      }
   }

   return (retVal);
}  // checkSliderBumpUp()


// draw a button
void drawButton(BUTTON_TYPE thisButton)
{
   if (thisButton.activated)
   {
      tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.buttonColor);
      tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.borderColor);

      centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.buttonColor);
   } else {
      tft.fillRect(thisButton.xCenterLoc - (thisButton.xSize / 2) + 1, thisButton.yCenterLoc - (thisButton.ySize / 2) + 1, thisButton.xSize - 2, thisButton.ySize - 2, thisButton.borderColor);
      tft.drawRect(thisButton.xCenterLoc - (thisButton.xSize / 2), thisButton.yCenterLoc - (thisButton.ySize / 2), thisButton.xSize, thisButton.ySize, thisButton.buttonColor);

      centerDrawText(*(thisButton.textPtr), thisButton.xCenterLoc, thisButton.yCenterLoc, thisButton.textColor, thisButton.borderColor);
   }
}  // drawButton()


// update the screen based upon the current mode
void drawScreen(void)
{
   if (config_mode != CONFIG_MODE_SPLASH)
   {
      // clear the unique portion of the display screen
      drawButton(uniqueScreenArea);

      menu1Button.activated       = false;
      menu2Button.activated       = false;
      menu3Button.activated       = false;
      menu4Button.activated       = false;
   }

   switch (config_mode)
   {
      case CONFIG_MODE_SPLASH:
         {
            tft.clearScreen(RA8875_BLACK);

            // NOTE: first character printed to TFT after restart is lost (so print a "don't care" space character)
            centerDrawText(" ", tft.width() / 2, tft.height() / 2 - 100, RA8875_GREEN, RA8875_BLACK);

            centerDrawText(VERSION1, tft.width() / 2, tft.height() / 2 - 50, RA8875_GREEN, RA8875_BLACK);
            centerDrawText(VERSION2, tft.width() / 2, tft.height() / 2, RA8875_YELLOW, RA8875_BLACK);
            centerDrawText(VERSION3, tft.width() / 2, tft.height() / 2 + 50, RA8875_RED, RA8875_BLACK);
         }
         break;

      case CONFIG_MODE_INIT_SCREEN:
         {
            tft.clearScreen(RA8875_BLACK);

            tft.setTextColor(RA8875_GREEN, RA8875_BLACK);
            tft.setCursor(95, 6);
            tft.print(VERSION1);
            tft.setCursor(405, 6);
            tft.print(" [");
            tft.print(VERSION2);
            tft.print("]");
         }
         break;

      case CONFIG_MODE_MENU1:
         {
            menu1Button.activated    = true;
         }
         break;

      case CONFIG_MODE_MENU2:
         {
            menu2Button.activated   = true;
         }
         break;

      case CONFIG_MODE_MENU3:
         {
            menu3Button.activated    = true;
         }
         break;

      case CONFIG_MODE_MENU4:
         {
            menu4Button.activated   = true;
         }
         break;
   }


   if (config_mode > CONFIG_MODE_INIT_SCREEN)
   {
      // clear the button portion of the display screen
      drawButton(buttonScreenArea);


      drawButton(menu1Button);
      drawButton(menu2Button);
      drawButton(menu3Button);
      drawButton(menu4Button);
   }

   // update screen using the current config mode
   switch (config_mode)
   {
      case CONFIG_MODE_SPLASH:
      case CONFIG_MODE_INIT_SCREEN:
         {
         }
         break;

      case CONFIG_MODE_MENU1:
         {
            tft.setTextSize(1);
            tft.setTextColor(RA8875_WHITE);

#ifndef DISABLE_BACKLIGHT_CONTROL
            drawSlider(menu1BacklightSliderV);
            drawButton(menu1BacklightButtonV);
            drawSlider(menu1BacklightSliderH);
            drawButton(menu1BacklightButtonH);

            drawButton(menu1Button1);
            drawButton(menu1Button2);
            drawButton(menu1Button3);
            drawButton(menu1Button4);
#endif
         }
         break;

      case CONFIG_MODE_MENU2:
         {
            drawButton(menu2Button1);
            drawButton(menu2Button2);
            drawButton(menu2Button3);
            drawButton(menu2Button4);
         }
         break;

      case CONFIG_MODE_MENU3:
         {
            drawButton(menu3Button1);
            drawButton(menu3Button2);
            drawButton(menu3Button3);
            drawButton(menu3Button4);
         }
         break;

      case CONFIG_MODE_MENU4:
         {
            drawButton(menu4Button1);
            drawButton(menu4Button2);
            drawButton(menu4Button3);
            drawButton(menu4Button4);
         }
         break;
   }
}  // drawScreen()


// draw a slider
void drawSlider(SLIDER_TYPE thisSlider)
{
   int characterCount = 0;
   String outString = "";

   if (thisSlider.value < thisSlider.minValue)
   {
      thisSlider.value = thisSlider.minValue;
   }

   if (thisSlider.value > thisSlider.maxValue)
   {
      thisSlider.value = thisSlider.maxValue;
   }

   if (thisSlider.orientation == SLIDER_MODE_HORIZONTAL)
   {
      if (thisSlider.activated)
      {
         // clear the bump down arrow area if enabled
         if (thisSlider.withBumpDownArrow)
         {
            // clear the slider bump down arrow area
            tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 42, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.bumpBackgroundColor);

            // draw the slider bump down arrow outline
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 42, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.borderColor);
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 40, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 1, 31, thisSlider.ySize + 2, thisSlider.borderColor);

            // draw the slider bump down arrow
            for (int i = 0; i < 7; i++)
            {
               tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 23 - i, thisSlider.yCenterLoc - (7 - i), thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 23 - i, thisSlider.yCenterLoc + (7 - i), thisSlider.handleColor);
            }
         }

         // clear the bump up arrow area if enabled
         if (thisSlider.withBumpUpArrow)
         {
            // clear the slider bump up arrow area
            tft.fillRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 9, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.bumpBackgroundColor);

            // draw the slider bump up arrow outline
            tft.drawRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 9, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, 35, thisSlider.ySize + 6, thisSlider.borderColor);
            tft.drawRect(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 11, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 1, 31, thisSlider.ySize + 2, thisSlider.borderColor);

            // draw the slider bump up arrow
            for (int i = 0; i < 7; i++)
            {
               tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 30 - i, thisSlider.yCenterLoc - i - 1, thisSlider.xCenterLoc + (thisSlider.xSize / 2) + 30 - i, thisSlider.yCenterLoc + i + 1, thisSlider.handleColor);
            }
         }

         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColor);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColor);

         // draw the slider handle
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColor);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColor);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor);  // left end
         tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColor);  // right end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColor);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColor);      // major tick lines
         }
      } else {
         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.backgroundColorDisabled);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 3, thisSlider.xSize + 15, thisSlider.ySize + 6, thisSlider.borderColorDisabled);

         // draw the slider handle
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 6, thisSlider.yCenterLoc - (2 + thisSlider.ySize * 4 / 10), 13, (thisSlider.ySize * 8 / 10) + 4, RA8875_BLACK);
         tft.fillRect((int)map(thisSlider.value, thisSlider.minValue, thisSlider.maxValue, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.xCenterLoc + (thisSlider.xSize / 2)) - 4, thisSlider.yCenterLoc - thisSlider.ySize * 4 / 10, 9, thisSlider.ySize * 8 / 10, thisSlider.handleColorDisabled);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc, thisSlider.scaleColorDisabled);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc - (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled);  // left end
         tft.drawLine(thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc - 7, thisSlider.xCenterLoc + (thisSlider.xSize / 2), thisSlider.yCenterLoc + 7, thisSlider.scaleColorDisabled);  // right end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc - 2, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.minorTickSections), thisSlider.yCenterLoc + 2, thisSlider.scaleColorDisabled);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc - 4, thisSlider.xCenterLoc - thisSlider.xSize / 2 + (thisSlider.xSize * i / thisSlider.majorTickSections), thisSlider.yCenterLoc + 4, thisSlider.scaleColorDisabled);      // major tick lines
         }
      }
   } else {  // SLIDER_MODE_VERTICAL
      if (thisSlider.activated)
      {
         // clear the bump down arrow area if enabled
         if (thisSlider.withBumpDownArrow)
         {
            // clear the slider bump down arrow area
            tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 8, thisSlider.xSize + 6, 40, thisSlider.bumpBackgroundColor);

            // draw the slider bump down arrow outline
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 8, thisSlider.xSize + 6, 40, thisSlider.borderColor);
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc + (thisSlider.ySize / 2) + 10, thisSlider.xSize + 2, 36, thisSlider.borderColor);

            // draw the slider bump down arrow
            for (int i = 0; i < 7; i++)
            {
               tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc + (thisSlider.ySize / 2) + i + 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc + (thisSlider.ySize / 2) + i + 24, thisSlider.handleColor);
            }
         }

         // clear the bump up arrow area if enabled
         if (thisSlider.withBumpUpArrow)
         {
            // clear the slider bump up arrow area
            tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.bumpBackgroundColor);

            // draw the slider bump up arrow outline
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.borderColor);
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 44, thisSlider.xSize + 2, 36, thisSlider.borderColor);

            // draw the slider bump up arrow
            for (int i = 0; i < 7; i++)
            {
               tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.handleColor);
            }
         }

         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColor);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColor);

         // draw the slider handle
         tft.fillRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 6, (thisSlider.xSize * 8 / 10) + 4, 13, RA8875_BLACK);
         tft.fillRect(thisSlider.xCenterLoc - thisSlider.xSize * 4 / 10, (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, thisSlider.xSize * 8 / 10, 9, thisSlider.handleColor);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColor);  // top end
         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColor);  // bottom end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColor);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColor);      // major tick lines
         }
      } else {
         // clear the bump uparrow area if enabled
         if (thisSlider.withBumpUpArrow)
         {
            // clear the slider bump up arrow area
            tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.backgroundColorDisabled);

            // draw the slider bump up arrow outline
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 46, thisSlider.xSize + 6, 40, thisSlider.borderColorDisabled);
            tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 1, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 44, thisSlider.xSize + 2, 36, thisSlider.borderColorDisabled);

            // draw the slider bump up arrow
            for (int i = 0; i < 7; i++)
            {
               tft.drawLine(thisSlider.xCenterLoc - (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.xCenterLoc + (7 - i), thisSlider.yCenterLoc - (thisSlider.ySize / 2) - i - 24, thisSlider.borderColorDisabled);
            }
         }

         // clear the entire slider
         tft.fillRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.backgroundColorDisabled);

         // draw the slider outline
         tft.drawRect(thisSlider.xCenterLoc - (thisSlider.xSize / 2) - 3, thisSlider.yCenterLoc - (thisSlider.ySize / 2) - 7, thisSlider.xSize + 6, thisSlider.ySize + 15, thisSlider.borderColorDisabled);

         // draw the slider handle
         tft.drawRect(thisSlider.xCenterLoc - (2 + thisSlider.xSize * 4 / 10), (int)map(thisSlider.value, thisSlider.maxValue, thisSlider.minValue, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.yCenterLoc + (thisSlider.ySize / 2)) - 4, (thisSlider.xSize * 8 / 10) + 4, 9, thisSlider.borderColorDisabled);

         // draw the slider guide line
         tft.drawLine(thisSlider.xCenterLoc, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);          // guide line

         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc - (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);  // top end
         tft.drawLine(thisSlider.xCenterLoc - 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.xCenterLoc + 7, thisSlider.yCenterLoc + (thisSlider.ySize / 2), thisSlider.scaleColorDisabled);  // bottom end

         // draw the slider minor tick lines
         for (unsigned int i = 1; i < thisSlider.minorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.xCenterLoc + 2, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.minorTickSections), thisSlider.scaleColorDisabled);      // minor tick lines
         }

         // draw the slider major tick lines
         for (unsigned int i = 1; i < thisSlider.majorTickSections; i++)
         {
            tft.drawLine(thisSlider.xCenterLoc - 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.xCenterLoc + 4, thisSlider.yCenterLoc - thisSlider.ySize / 2 + (thisSlider.ySize * i / thisSlider.majorTickSections), thisSlider.scaleColorDisabled);      // major tick lines
         }
      }
   }

   characterCount = thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal;
   if (thisSlider.placesAfterTheDecimal != 0)
   {
      // add one character for the decimal point
      characterCount++;
   }
   if (thisSlider.showPlusMinusSign)
   {
      // add one for the +/- sign
      characterCount++;

      if (thisSlider.value >= 0.0)
      {
         outString = outString + "+";
      } else {
         outString = outString + "-";
      }
   }

   switch (thisSlider.placesBeforeTheDecimal)
   {
      case 5:
         {
            if (abs(thisSlider.value) >= 10000.0)
            {
               outString = outString + (char)(((int)(abs(thisSlider.value)) / 10000) + 0x30);
            }
         }
      // no break, so fall-thru

      case 4:
         {
            if (abs(thisSlider.value) >= 1000)
            {
               outString = outString + (char)((((int)(abs(thisSlider.value)) % 10000) / 1000) + 0x30);
            }
         }
      // no break, so fall-thru

      case 3:
         {
            if (abs(thisSlider.value) >= 100)
            {
               outString = outString + (char)((((int)(abs(thisSlider.value)) % 1000) / 100) + 0x30);
            }
         }
      // no break, so fall-thru

      case 2:
         {
            if (abs(thisSlider.value) >= 10)
            {
               outString = outString + (char)((((int)(abs(thisSlider.value)) % 100) / 10) + 0x30);
            }
         }
         // no break, so fall-thru
   }

   outString = outString + (char)(((int)(abs(thisSlider.value)) % 10) + 0x30);

   if (thisSlider.placesAfterTheDecimal != 0)
   {
      outString = outString + ".";
   }

   switch (thisSlider.placesAfterTheDecimal)
   {
      case 1:
         {
            outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
         }
         break;

      case 2:
         {
            outString = outString + (char)(((int)((abs(thisSlider.value) * 10.0f)) % 10) + 0x30);
            outString = outString + (char)(((int)((abs(thisSlider.value) * 100.0f)) % 10) + 0x30);
         }
         break;
   }

   tft.fillRect(thisSlider.xValueCenterLoc - ((thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 4), thisSlider.yValueCenterLoc - 4, (thisSlider.placesBeforeTheDecimal + thisSlider.placesAfterTheDecimal + 2) * 8, 10, RA8875_BLACK);

   centerDrawText(outString, thisSlider.xValueCenterLoc + 1, thisSlider.yValueCenterLoc, thisSlider.valueColor, RA8875_BLACK);
}  // drawSlider()


// main loop
void loop()
{
   if ((config_mode == CONFIG_MODE_SPLASH) && (millis() > (check_splash_time + CHECK_SPLASH_MILLIS)))
   {
      config_mode = CONFIG_MODE_INIT_SCREEN;

      drawScreen();

      config_mode = CONFIG_MODE_MENU1;

      drawScreen();
   }

   // if the touchscreen is being touched anywhere
   if ((config_mode > CONFIG_MODE_INIT_SCREEN) && ((millis() - check_touchscreen_time) > CHECK_TOUCHSCREEN_MILLIS) && processTouchscreen())
   {
      check_touchscreen_time = millis();

      switch (config_mode)
      {
         case CONFIG_MODE_SPLASH:
         case CONFIG_MODE_INIT_SCREEN:
            {
            }
            break;

         case CONFIG_MODE_MENU1:
            {
#ifndef DISABLE_BACKLIGHT_CONTROL
               if (checkSlider(&menu1BacklightSliderV))
               {
                  menu1BacklightSliderH.value = menu1BacklightSliderV.value;

                  drawSlider(menu1BacklightSliderV);
                  drawSlider(menu1BacklightSliderH);

                  tft.brightness(menu1BacklightSliderV.value);
               }

               if (checkSlider(&menu1BacklightSliderH))
               {
                  menu1BacklightSliderV.value = menu1BacklightSliderH.value;

                  drawSlider(menu1BacklightSliderV);
                  drawSlider(menu1BacklightSliderH);

                  tft.brightness(menu1BacklightSliderV.value);
               }
#endif
            }
            break;

         case CONFIG_MODE_MENU2:
            {
            }
            break;

         case CONFIG_MODE_MENU3:
            {
            }
            break;

         case CONFIG_MODE_MENU4:
            {
            }
            break;
      }
   } else {
      // if the touchscreen was touched, but is no longer being touched
      if (touch_triggered)
      {
         touch_triggered = false;


         // if the touchscreen was last touched within menu1Button
         if (checkButton(menu1Button))
         {
            config_mode = CONFIG_MODE_MENU1;

            screen_update_required = true;
         }

         // if the touchscreen was last touched within menu2Button
         if (checkButton(menu2Button))
         {
            config_mode = CONFIG_MODE_MENU2;

            screen_update_required = true;
         }

         // if the touchscreen was last touched within menu3Button
         if (checkButton(menu3Button))
         {
            config_mode = CONFIG_MODE_MENU3;

            screen_update_required = true;
         }

         // if the touchscreen was last touched within menu4Button
         if (checkButton(menu4Button))
         {
            config_mode = CONFIG_MODE_MENU4;

            screen_update_required = true;
         }


         switch (config_mode)
         {
            case CONFIG_MODE_SPLASH:
            case CONFIG_MODE_INIT_SCREEN:
               {
               }
               break;

            case CONFIG_MODE_MENU1:
               {
#ifndef DISABLE_BACKLIGHT_CONTROL
                  if (checkButton(menu1BacklightButtonV) || checkButton(menu1BacklightButtonH))
                  {
                     if (menu1BacklightSliderV.value != 127)
                     {
                        menu1BacklightSliderV.value = 127;
                        menu1BacklightSliderH.value = 127;
                     } else {
                        menu1BacklightSliderV.value = 255;
                        menu1BacklightSliderH.value = 255;
                     }

                     drawSlider(menu1BacklightSliderV);
                     drawSlider(menu1BacklightSliderH);

                     tft.brightness(menu1BacklightSliderV.value);
                  }
#endif

                  if (checkSliderBumpDown(&menu1BacklightSliderV))
                  {
                     menu1BacklightSliderH.value = menu1BacklightSliderV.value;

                     drawSlider(menu1BacklightSliderV);
                     drawSlider(menu1BacklightSliderH);
                  }

                  if (checkSliderBumpUp(&menu1BacklightSliderV))
                  {
                     menu1BacklightSliderH.value = menu1BacklightSliderV.value;

                     drawSlider(menu1BacklightSliderV);
                     drawSlider(menu1BacklightSliderH);
                  }

                  if (checkSliderBumpDown(&menu1BacklightSliderH))
                  {
                     menu1BacklightSliderV.value = menu1BacklightSliderH.value;

                     drawSlider(menu1BacklightSliderV);
                     drawSlider(menu1BacklightSliderH);
                  }

                  if (checkSliderBumpUp(&menu1BacklightSliderH))
                  {
                     menu1BacklightSliderV.value = menu1BacklightSliderH.value;

                     drawSlider(menu1BacklightSliderV);
                     drawSlider(menu1BacklightSliderH);
                  }


                  if (checkButton(menu1Button1))
                  {
                     menu1Button1.activated = !menu1Button1.activated;
                     drawButton(menu1Button1);

                     if (menu1Button1.activated)
                     {
                        Serial.println("...activated BUTTON 1 in MENU 1...");
                     } else {
                        Serial.println("...deactivated BUTTON 1 in MENU 1...");
                     }
                  }

                  if (checkButton(menu1Button2))
                  {
                     menu1Button2.activated = !menu1Button2.activated;
                     drawButton(menu1Button2);

                     if (menu1Button2.activated)
                     {
                        Serial.println("...activated BUTTON 2 in MENU 1...");
                     } else {
                        Serial.println("...deactivated BUTTON 2 in MENU 1...");
                     }
                  }

                  if (checkButton(menu1Button3))
                  {
                     menu1Button3.activated = !menu1Button3.activated;
                     drawButton(menu1Button3);

                     if (menu1Button3.activated)
                     {
                        Serial.println("...activated BUTTON 3 in MENU 1...");
                     } else {
                        Serial.println("...deactivated BUTTON 3 in MENU 1...");
                     }
                  }

                  if (checkButton(menu1Button4))
                  {
                     menu1Button4.activated = !menu1Button4.activated;
                     drawButton(menu1Button4);

                     if (menu1Button4.activated)
                     {
                        Serial.println("...activated BUTTON 4 in MENU 1...");
                     } else {
                        Serial.println("...deactivated BUTTON 4 in MENU 1...");
                     }
                  }
               }
               break;

            case CONFIG_MODE_MENU2:
               {
                  if (checkButton(menu2Button1))
                  {
                     menu2Button1.activated = !menu2Button1.activated;
                     drawButton(menu2Button1);

                     if (menu2Button1.activated)
                     {
                        Serial.println("...activated BUTTON 1 in MENU 2...");
                     } else {
                        Serial.println("...deactivated BUTTON 1 in MENU 2...");
                     }
                  }

                  if (checkButton(menu2Button2))
                  {
                     menu2Button2.activated = !menu2Button2.activated;
                     drawButton(menu2Button2);

                     if (menu2Button2.activated)
                     {
                        Serial.println("...activated BUTTON 2 in MENU 2...");
                     } else {
                        Serial.println("...deactivated BUTTON 2 in MENU 2...");
                     }
                  }

                  if (checkButton(menu2Button3))
                  {
                     menu2Button3.activated = !menu2Button3.activated;
                     drawButton(menu2Button3);

                     if (menu2Button3.activated)
                     {
                        Serial.println("...activated BUTTON 3 in MENU 2...");
                     } else {
                        Serial.println("...deactivated BUTTON 3 in MENU 2...");
                     }
                  }

                  if (checkButton(menu2Button4))
                  {
                     menu2Button4.activated = !menu2Button4.activated;
                     drawButton(menu2Button4);

                     if (menu2Button4.activated)
                     {
                        Serial.println("...activated BUTTON 4 in MENU 2...");
                     } else {
                        Serial.println("...deactivated BUTTON 4 in MENU 2...");
                     }
                  }
               }
               break;

            case CONFIG_MODE_MENU3:
               {
                  if (checkButton(menu3Button1))
                  {
                     menu3Button1.activated = !menu3Button1.activated;
                     drawButton(menu3Button1);

                     if (menu3Button1.activated)
                     {
                        Serial.println("...activated BUTTON 1 in MENU 3...");
                     } else {
                        Serial.println("...deactivated BUTTON 1 in MENU 3...");
                     }
                  }

                  if (checkButton(menu3Button2))
                  {
                     menu3Button2.activated = !menu3Button2.activated;
                     drawButton(menu3Button2);

                     if (menu3Button2.activated)
                     {
                        Serial.println("...activated BUTTON 2 in MENU 3...");
                     } else {
                        Serial.println("...deactivated BUTTON 2 in MENU 3...");
                     }
                  }

                  if (checkButton(menu3Button3))
                  {
                     menu3Button3.activated = !menu3Button3.activated;
                     drawButton(menu3Button3);

                     if (menu3Button3.activated)
                     {
                        Serial.println("...activated BUTTON 3 in MENU 3...");
                     } else {
                        Serial.println("...deactivated BUTTON 3 in MENU 3...");
                     }
                  }

                  if (checkButton(menu3Button4))
                  {
                     menu3Button4.activated = !menu3Button4.activated;
                     drawButton(menu3Button4);

                     if (menu3Button4.activated)
                     {
                        Serial.println("...activated BUTTON 4 in MENU 3...");
                     } else {
                        Serial.println("...deactivated BUTTON 4 in MENU 3...");
                     }
                  }
               }
               break;

            case CONFIG_MODE_MENU4:
               {
                  if (checkButton(menu4Button1))
                  {
                     menu4Button1.activated = !menu4Button1.activated;
                     drawButton(menu4Button1);

                     if (menu4Button1.activated)
                     {
                        Serial.println("...activated BUTTON 1 in MENU 4...");
                     } else {
                        Serial.println("...deactivated BUTTON 1 in MENU 4...");
                     }
                  }

                  if (checkButton(menu4Button2))
                  {
                     menu4Button2.activated = !menu4Button2.activated;
                     drawButton(menu4Button2);

                     if (menu4Button2.activated)
                     {
                        Serial.println("...activated BUTTON 2 in MENU 4...");
                     } else {
                        Serial.println("...deactivated BUTTON 2 in MENU 4...");
                     }
                  }

                  if (checkButton(menu4Button3))
                  {
                     menu4Button3.activated = !menu4Button3.activated;
                     drawButton(menu4Button3);

                     if (menu4Button3.activated)
                     {
                        Serial.println("...activated BUTTON 3 in MENU 4...");
                     } else {
                        Serial.println("...deactivated BUTTON 3 in MENU 4...");
                     }
                  }

                  if (checkButton(menu4Button4))
                  {
                     menu4Button4.activated = !menu4Button4.activated;
                     drawButton(menu4Button4);

                     if (menu4Button4.activated)
                     {
                        Serial.println("...activated BUTTON 4 in MENU 4...");
                     } else {
                        Serial.println("...deactivated BUTTON 4 in MENU 4...");
                     }
                  }
               }
               break;
         }

         if (screen_update_required)
         {
            drawScreen();

            screen_update_required = false;
         }
      }
   }
}  // loop()


// process any touchscreen activity
boolean processTouchscreen(void)
{
   uint16_t coordinates[RA8875_MAX_TOUCH_LIMIT][2];   // array to hold the touch coordinates
   boolean currently_touched = false;

   // fill the FT5206 registers to get access to the data inside the library...
   tft.updateTS();

   currently_touched = tft.getTouches();

   if (!currently_touched && previously_touched)
   {
      touch_triggered = true;
   }

   if (currently_touched)
   {
      tft.getTScoordinates(coordinates);

      // range-check the values before using them
      if ((coordinates[0][0] > 0) && (coordinates[0][0] < tft.width()) && (coordinates[0][1] > 0) && (coordinates[0][1] < tft.height()))
      {
         BtnX = coordinates[0][0];
         BtnY = coordinates[0][1];
      }

      previously_touched = true;

#ifdef DEBUG_TOUCHSCREEN
      Serial.print("X : ");
      Serial.print(BtnX);
      Serial.print("     Y : ");
      Serial.println(BtnY);
#endif
   } else {
      previously_touched = false;
   }

   return (currently_touched);  // whether the touchscreen is being touched or not
}  // processTouchscreen()


// one-time setup
void setup()
{
   unsigned long check_time;

   pinMode(RA8875_CHIP_SELECT, OUTPUT);
   digitalWrite(RA8875_CHIP_SELECT, HIGH);

   pinMode(RA8875_RESET, OUTPUT);
   digitalWrite(RA8875_RESET, LOW);

   check_time = millis();
   while ((millis() - check_time) <= 100);

   digitalWrite(RA8875_RESET, HIGH);

   Serial.begin(57600);

   check_time = millis();
   while (!Serial && ((millis() - check_time) <= 2000));

   Serial.println("===================================================");
   Serial.print("           ");
   Serial.println(VERSION1);
   Serial.print("        ");
   Serial.println(VERSION2);
   Serial.print("   ");
   Serial.println(VERSION3);
   Serial.println("===================================================");
   Serial.println("");
   Serial.println("");

   if (CrashReport) {
      Serial.print(CrashReport);
   }

   tft.begin(RA8875_800x480);

   tft.DMA_enable();

   tft.setRotation(2);

   tft.clearScreen(RA8875_BLACK);

#ifdef DISABLE_BACKLIGHT_CONTROL
   menu1BacklightSliderV.value = 127;
   menu1BacklightSliderH.value = 127;
#endif

   tft.brightness(menu1BacklightSliderV.value);

   tft.useCapINT(RA8875_TS_INT);   // use the FT5206 chip interrupt

   tft.setTouchLimit(RA8875_MAX_TOUCH_LIMIT);

   tft.enableCapISR(true);         // capacitive touch screen interrupt it's armed

   tft.writeTo(L1);                // write to layer 1

   check_splash_time = millis();

   drawScreen();

   pinMode(LED_PIN, OUTPUT);
}  // setup()


// EOF placeholder
EDITED: Sorry, original template code posted primarily demonstrated slider operations. Updated to demonstrate both buttons and sliders. MJC
 
Last edited:
Hello,kd5rxt-mark

I didn't expect such a piece of sketch!
A lot to learn from this and takes time to be analyzed,i'm almost a beginner and i'll take an opportunity
to grow up my basic level.
I like the way you declare and initialize the buttons like:
Code:
// MENU 3 BUTTONS
const String menu3Button1Text             = "BUTTON 3-1";
BUTTON_TYPE menu3Button1                  = {100, 200, 90, 30,           &menu3Button1Text,  RA8875_BLACK,  RA8875_GREEN,    RA8875_RED,  true};
It's new for me,i like it ,it's very handy :)
I will take some time and test it, thank you very much :)
 
@AntiLoop:

I developed this button & slider approach to a user interface while creating the latest version of my TeensyMIDIPolySynth (TMPS), which is a (work-in-progress) digital synthesizer built around the Teensy 4 & the Audio Adapter, mostly for my own personal enjoyment. I needed the ability to selectively enable/disable multiple functions (oscillators, modulators, filters, effects, voices, etc.), as well as the ability to individually control the level(s) of these same functions. I knew from the beginning that I would have multiple screens with a variety of buttons & sliders, so I slowly developed this approach (allowing me to define buttons, using those buttons to control capabilities, and to be able to define sliders, using those sliders to control levels, and to easily manage the specific capabilities on any given screen using a state variable, etc.). This approach has proven to be quite effective in my particular application. Because of this (& to allow my future use of the same fundamental capabilities without having to re-invent the wheel, and/or to start from scratch again), I saved off this simple template to serve as a starting point for any future application that may need these same types of controls. I hope that this short example conveys enough of the methods of applying these capabilities that it may help with your current and/or future needs as well.

Good luck & have fun (& let me know if you have any other questions) !!

Mark J Culross
KD5RXT

P.S. In the simple template, alternating the slider value between two "pre-defined" values by pressing the associated button is demonstrated. In my TMPS application, the button associated with a slider is more typically used to enable/disable the functionality of that slider by tapping its button (e.g. enable/disable a particular oscillator type: sine, square, triangle, ramp, etc.). I tried to avoid putting too much capability into the simple template to keep it from being too overwhelming. If you need help in creating a specific capability, please feel free to ask. Hope that helps . . . MJC
 
That's very kind of you,Mark
i didn't know you were in the work of synthetizers,my goal is probably primary an audio concept to be like
a kind of inputs,outputs,usb_oct capabilities to be designed as a multimedia center with recordings with
Goldwave,but between inputs and outputs i'd like to have patchcords buttons and effects,this mean a lot of routings.
Have you tried to build your works with nextion displays? i know they are expensive but can save a lot of memory
with drawing objects
 
@AntiLoop:

I have not used the Nextion displays in any of my projects so far. For my larger projects (i.e. needing more display area and/or larger readbility), I primarily use the RA8875 7" 800x480 display. For my smaller projects, I have been using the PJRC 3.2" 320x240 touchscreen display very successfully. However, there are other members here on this forum who have lots of experience with the Nextion family of displays, if you need help in that area.

Mark J Culross
KD5RXT
 
I'm stuck at the splashscreen of your template, i've installed FT5206 touch,but nothing respond
before this,i was using RA8875-RA8875_t4 and Adafruit_FT6206_Library for my sketches,and all was alright.
 
@AntiLoop:

Not sure what may be going on with your hardware setup, but independent of that, the example template transitions from the splash screen to the operational screen automatically after a 4-second delay (not touch dependent). You'll notice that the example template indicates in the comments at the beginning of the sketch source that it was tested using the ER-TFTM070-5 from buydisplay.com, specifically with the capacitive touchscreen attached. Is this the same display & touchscreen that you have (and are you using the example template sketch without any modifications) ?? With the specific display/touchscreen combo that I have, I use the RA8875 driver included with the Teensyduino installation, which does not require a separate touchscreen driver (it uses the one built into the RA8875 driver).

To troubleshoot your setup, I'd suggest that you start adding "Serial.println("");" lines (with unique indicator strings between the quotes to be printed on the SerialConsole) into the source to try & narrow down where your sketch might be hanging.

Let us know what you find . . .

Mark J Culross
KD5RXT
 
Last edited:
@AntiLoop:

Since you specifically mentioned using the Adafruit libraries in your earlier messages, I did some independent checking on the Adafruit website. Based upon what I saw, it seems like you may be using one of the displays with a touchpanel attached, but without an integrated controller. I don't have any of those specific Adafruit products myself. However, with the possibility that someone else may have the same items that you have, & can possibly provide more direct support, could you please identify the specific hardware that you are using (part number and/or description) ?? My example template may need some modification to work with anything other than the specific ER-TFTM070-5 from buydisplay.com that I have, since that is what it has specifically worked on here.

Thanks,

Mark J Culross
KD5RXT
 
Hey Mark, it's no ambiguity that i have the same buydisplay 4 - wires as you,same reference,
So i adaptated the pin settings to make it work,and the display showed your splashscreen with no problem.
I did uncomment all the monitor debugs,but it only shows your personnal presentation and after i can't see anything else,no touch results.
You see,i'm using the RA8875_t4 library (don't remember where i took it),and you seems to use the RA8875 lib
wich is in the teensy folder,but the settings look to be the same,i'm now using the RA8875 from the teensy folder
to have the same libs as you.
There is one thing i want to point to is the LED =13 include in your sketch,i use pin 13 for the SCK of the display,i don't know
if it does do anything in the stuck i have,but it doesn't perturb the display.
 
That's very kind of you,Mark
i didn't know you were in the work of synthetizers,my goal is probably primary an audio concept to be like
a kind of inputs,outputs,usb_oct capabilities to be designed as a multimedia center with recordings with
Goldwave,but between inputs and outputs i'd like to have patchcords buttons and effects,this mean a lot of routings.
Have you tried to build your works with nextion displays? i know they are expensive but can save a lot of memory
with drawing objects
I use the Nextion display on a number of my projects.
I find them excellent, you can even offload simple routines to the display whilst the Teensy get's on with more complex stuff.
I have written a skeletal driver, now up to version 2, for them which can be seen here.

I did a write up on this forum some time ago, look here.

What I think you want to do would be quite easy. Draw your buttons on page 0.
Copy Page 0 to Page 1...you now have another level, repeat as needed changing the text on the buttons ass you go.
When a button is pressed send a numeric value to Teensy, it's what I do. Look at my demo and the Nextion2 Library I wrote.
 
I should have said that you can experience using a Nextion before buying one.
You use the Nextion Editor to create your display/code. Once you have done that you can run your code in debug mode on the PC. This allows you to modify your code if necessary, but also to see how it will look/perform.
The editor can be downloaded from here.
You will also need the details of the Nextion instruction set from here and editor guide from here.
 
I BriComp, thanks to point us about nextion,with teensy audio/midi it's a speed up creativity,more flexible than any other display.
i know nextion,i've been a user for a couple of years,it's a very handy display where you can
load a nice picture and put what you want over it by transparancy, i've been thinking about mixer tables or bar levels or a patch bays
with nice apparences.
Mark also thought that my question was to know about nextion,i only wanted to know if he had experience with it because
it can save many procedures,like my problems of overriding touches in menus.
It will be a pleasure to test some examples of yours,i wonder why nextion did not expand by I2C port,it doesn't need so much speed
to talk with a mcu like teensy? Or maybe I2C could speed up the transactions,i will search in ali express if they have
serial-I2C converters to see if it's more flexible.
 
Hey Mark, it's no ambiguity that i have the same buydisplay 4 - wires as you,same reference,
So i adaptated the pin settings to make it work,and the display showed your splashscreen with no problem.
I did uncomment all the monitor debugs,but it only shows your personnal presentation and after i can't see anything else,no touch results.
You see,i'm using the RA8875_t4 library (don't remember where i took it),and you seems to use the RA8875 lib
wich is in the teensy folder,but the settings look to be the same,i'm now using the RA8875 from the teensy folder
to have the same libs as you.
There is one thing i want to point to is the LED =13 include in your sketch,i use pin 13 for the SCK of the display,i don't know
if it does do anything in the stuck i have,but it doesn't perturb the display.

@AntiLoop:

OK, good that you've confirmed to have the same ER-TFTM070-5 from buydisplay.com. Since you are troubleshooting problems with the touch, did you select the "capacitive touchscreen" (as opposed to the "resistive touchscreen") when ordering (I don't want to make any incorrect assumptions on my part) ?? If so, did you also uncomment the line activating the capacitive touchscreen support in the RA8875 library (as instructed at the top of the sketch) ??

When you say "So i adaptated the pin settings to make it work,and the display showed your splashscreen with no problem. I did uncomment all the monitor debugs, but it only shows your personnal presentation and after i can't see anything else,no touch results.", does that mean that you do, or that you do not see the first operational screen with the "MENU 1" thru "MENU 4" buttons, the "BUTTON 1-1" thru "BUTTON 1-4" buttons, & the two sliders with their respective buttons (you should not uncomment the "#define DISABLE_BACKLIGHT_CONTROL") displayed ??

To make 100% certain that you are using the RA8875 library installed with TD, you should turn on verbose output during compile in Arduino IDE's File > Preferences, then check to confirm which libraries are being included. When I do that, here's the portion of interest in the report that I get:

Code:
Memory Usage on Teensy 4.1:
  FLASH: code:53288, data:13496, headers:8988   free for files:8050692
   RAM1: variables:15136, code:48136, padding:17400   free for local variables:443616
   RAM2: variables:12416  free for malloc/new:511872
"C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/stdout_redirect" "C:\\Users\\mjcul\\AppData\\Local\\Temp\\arduino_build_268111/Teensy-RA8875-template.ino.lst" "C:\\Program Files (x86)\\Arduino\\hardware\\teensy/../tools/arm/bin/arm-none-eabi-objdump" -d -S -C "C:\\Users\\mjcul\\AppData\\Local\\Temp\\arduino_build_268111/Teensy-RA8875-template.ino.elf"
Using library SPI at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\SPI
Using library RA8875 at version 0.7.11 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\RA8875
Using library Wire at version 1.0 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Wire


Please post the exact sketch that you are using to test (use the </> button at the top of the message composition area to include your sketch in CODE tags). Also, if you can, please post pictures of your setup such that someone else can easily trace your wiring.

Thanks & we'll continue working to the best of our ability in order to get this resolved, so that you can get on with your actual project !!

Mark J Culross
KD5RXT
 
Last edited:
There is one thing i want to point to is the LED =13 include in your sketch,i use pin 13 for the SCK of the display,i don't know
if it does do anything in the stuck i have,but it doesn't perturb the display.

Sorry, I forgot to answer your other question . . . nothing in the example template sketch should cause any adverse effects with respect to PIN 13. If you are getting something/anything on the display (& you indicated earlier that you are seeing the splash screen), then the Teensy is able to talk to the display successfully. Touchscreen processing is handled by the same RA8875 library that is installed with TD. So, as long as you have enabled support for the proper type of touchscreen (capacitive vs. resistive) in the library, then you should also be able to see results when you activate any of the custom buttons drawn on the display.

Here's what is shown (with "#define DEBUG_TOUCHSCREEN" uncommented in the sketch) in the SerialMonitor when I toggle "BUTTON 1-1" OFF then ON (BUTTON 1-1 is active by default when the sketch starts, so the first touch deactivates it, then the second touch re-activates it, toggling as enabled/disabled with each touch):

Code:
===================================================
           >> Teensy RA8875 template <<
        version 1.0 dated 09/21/2024 @2100
   designed & written by Mark J Culross (KD5RXT)
===================================================


X : -1     Y : -1 [ trimmed - this line will be displayed continuously until the first touch anywhere ]
X : 116     Y : 198
X : 116     Y : 198
X : 116     Y : 198
...deactivated BUTTON 1 in MENU 1...
X : 121     Y : 197
X : 121     Y : 197
X : 121     Y : 197
X : 121     Y : 197
X : 121     Y : 197
...activated BUTTON 1 in MENU 1...

Hope that helps . . .

Mark J Culross
KD5RXT
 
Last edited:
Using library RA8875 at version 0.7.11 in folder: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\RA8875
Sorry to jump in here again. It has been a while since I played with the RA8875, been playing more with 76...

Wondering if you still need to edit the user settings file to enable the touch code within the RA8875.

For example, with my current install, I am looking at the ....\0.60.1\libraries\RA8875\src\_settings\RA8875UserSettings.h

And I see:
Code:
/* [CHOOSE YOUR TOUCH SCREEN TYPE] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This library supports the RA8875 internal resistive touch screen driver or a FT5206
based capacitive touch screen driver. Below, you have to choose one of them.
The Resistive Touch screen it's drived directly by RA8875.
The Capacitive Touch Screen use a I2C chip called FT5206 (hardwired to address 0x38).
Please choose at list one (NOT both), if you comment both it's the same as _AVOID_TOUCHSCREEN*/

//#define USE_RA8875_TOUCH//resistive touch screen
//#define USE_FT5206_TOUCH//capacitive touch screen
Where it looks like neither is enabled by default...
 
Wondering if you still need to edit the user settings file to enable the touch code within the RA8875.

For example, with my current install, I am looking at the ....\0.60.1\libraries\RA8875\src\_settings\RA8875UserSettings.h

And I see:
Code:
/* [CHOOSE YOUR TOUCH SCREEN TYPE] +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This library supports the RA8875 internal resistive touch screen driver or a FT5206
based capacitive touch screen driver. Below, you have to choose one of them.
The Resistive Touch screen it's drived directly by RA8875.
The Capacitive Touch Screen use a I2C chip called FT5206 (hardwired to address 0x38).
Please choose at list one (NOT both), if you comment both it's the same as _AVOID_TOUCHSCREEN*/

//#define USE_RA8875_TOUCH//resistive touch screen
//#define USE_FT5206_TOUCH//capacitive touch screen
Where it looks like neither is enabled by default...

@KurtE:

Yes, you remember correctly, and yes, one of those two lines needs to be uncommented in order to support the respective touchscreen (& I have included instructions at the top of my example template sketch on the necessity for doing so). Your point is a very valid one.

If neither of the two support lines is uncommented in the library, then a warning is generated when the sketch is built (& the build fails), as the example template sketch is making calls specifically for the capacitive touchscreen.

Mark J Culross
KD5RXT
 
So,Mark,let's get into that problem,
Yes i have a capacitive one like you,i use normally the FT6206 driver,and in the RA8875 settings,FT5206 is uncommented ,i never cared with it
maybe because those drivers are compatible.
ra8875 settings.png

I remember i had problem to make the touch working with FT5206,so i switched to FT6026,
I only see the presentation screen but not the operationnal screen with the menus,buttons or sliders

Here is the verbose:

verbose.png


My RA8875 settings:

#define RA8875_CS 36
#define RA8875_RESET 255 23
#define RA8875_INT 41
MOSI=11,MISO=12,SCK=13
SDA=18,SCL=19
I2C ADRESS: 0x38

The debugs choices:

debug.png


What i only see on the monitor:

===================================================
>> Teensy RA8875 template <<
version 1.0 dated 09/21/2024 @2100
designed & written by Mark J Culross (KD5RXT)
===================================================

Don't know what infos more i can give you...
Maybe an adaptation of your sketch with FT6206?
 
More infos:
i was using &wire1 -> I2C1 (17,16) in the FT6206 setup,but when i change to &wire -> I2C (18,19) it's the same,of course
the FT6206 settings don't interfere with FT5206 one,so if i take I2C or I2C1,same result,stucking at splashscreen.
 
So,Mark,let's get into that problem,
Yes i have a capacitive one like you,i use normally the FT6206 driver,and in the RA8875 settings,FT5206 is uncommented ,i never cared with it
maybe because those drivers are compatible.
View attachment 35873
I remember i had problem to make the touch working with FT5206,so i switched to FT6026,
I only see the presentation screen but not the operationnal screen with the menus,buttons or sliders

Here is the verbose:

View attachment 35874

My RA8875 settings:

#define RA8875_CS 36
#define RA8875_RESET 255 23
#define RA8875_INT 41
MOSI=11,MISO=12,SCK=13
SDA=18,SCL=19
I2C ADRESS: 0x38

The debugs choices:

View attachment 35875

What i only see on the monitor:

===================================================
>> Teensy RA8875 template <<
version 1.0 dated 09/21/2024 @2100
designed & written by Mark J Culross (KD5RXT)
===================================================

Don't know what infos more i can give you...
Maybe an adaptation of your sketch with FT6206?

@AntiLoop:

OK, thanks for those details. Here are a few things that I can't tell for certain:

1) have you tried connecting your display & Teensy exactly as indicated in the example template sketch & running the example template sketch exactly as is (with no modifications) ??

2) If you have different wiring (which your last post indicates), have you made only the changes to the example template sketch to accommodate the differences in your wiring (without any other changes/additions, for example, to which libraries are included in the example template sketch, etc.) ??

3) we still need to see the exact sketch that you are testing with.


The things that I know for certain:

1) if you have the exact same display with the exact same touchscreen, and you wire this display to the Teensy exactly as indicated in the example template sketch, then it should work exactly as mine does (if not, then you may potentially have some unexpected hardware problem: Teensy (damaged/wrong pins), display (double-check that all of the on-board PCB options are soldered to match what you ordered), and/or wiring).

2) if you have the exact same display with the exact same touchscreen, I can say with absolute certainty that no additional libraries beyond that provided by the RA8875 support included with the TD installation (if/when configured correctly) are needed and/or required to allow the touchscreen to work (i.e. you should not be installing an/or trying to make use of any additional FT6206 libraries !!).

Looking forward to your reply . . .

Mark J Culross
KD5RXT

P.S. The hope/intent here is for you to start with a configuration that is known to work correctly. Once you have that successfully working (which confirms that all of your hardware & wiring is correct & working), then you can start making changes (wiring, etc.) with confidence that everything was working previously. MJC
 
Mark,
using RA8875 with FT6206 has always worked for me and doesn't frighten me at all,i assume it,used it for about one year with no problem,
but if you want me to have exactly the same configutation,so i'll take out of my stock another teensy 4.1
and wire exactly like it is in you template,and pull away for a while the FT6206.
The reason i adapted your sketch to my settings is because i was using a pcb board that i made specially with those settings
for a TDM concept,using 2X cs42448 + 1 Sd card + 1 display RA8875,so it was impossible to move the wiring.
After i made the tests,with your wiring, i will tell you the results.
 
Mark,
using RA8875 with FT6206 has always worked for me and doesn't frighten me at all,i assume it,used it for about one year with no problem,
but if you want me to have exactly the same configutation,so i'll take out of my stock another teensy 4.1
and wire exactly like it is in you template,and pull away for a while the FT6206.
The reason i adapted your sketch to my settings is because i was using a pcb board that i made specially with those settings
for a TDM concept,using 2X cs42448 + 1 Sd card + 1 display RA8875,so it was impossible to move the wiring.
After i made the tests,with your wiring, i will tell you the results.
Is this a new board? Or has it been working for you for a while?

Are there other SPI devices on the same SPI buss as the RA8875?

Why I am asking, If I remember correctly the RA8875 does not play nicely with other devices, in particular the MISO pin.
On my own boards, I setup it up with a buffer chip between the MISO and the display like:
1727116831870.png


U1 is the buffer. note there is also a solder jumper (SJ0MISOB) that I can solder to close if I don't care

Sorry if I am barking up the wrong tree
 
Back
Top