A UBlox GPS Module Primer for beginners

Just wondering how are you connecting to u-Center Software
Using FTDI.

With Serial wired to Teensy - a Teensy sketch turns it into a PROXY for Serial#
Tried that - works for reading data from u-center but haven't been able to get it to work to change settings from ucenter to teensy to gps
 
Yeah this is the reason i asked because inside the UBLOX library on last update i did try to implement this functionality with simple gps.USE_Ucenter(true); Command, Unfortunately i was running into issues.
If you look closely in UBLOX.h library you will see this:
Code:
//TODO: add pre-processor ifdef
///> void USE_Ucenter(bool u_c);//# experimental Bridge between u-center and teensy UBLOX #
 
I used it no problem with u-center to make updates to baud - to 10 Hz and back to 5 Hz ( when I saw 10 Hz just did dupes of the 5 Hz data ).

posted in AHRS thread?

It takes dedicated effort to not mess the timing up - I thought about saving the transcript for replay and review and anything but fast read>write left it not working on a quick edit - so I left it alone.

Code Here ...
 
I've been using this code, that triggers from a command from the loop (the loop breaks and runs until I toggle the flag back):
Code:
void passThroughMode(){

  int val;
  while(1){
    if(cout.available() > 0) {
      val = cout.read();  //read telem input commands  

    switch(val)
    {
    case 'n': 
        passThrough_toggle = 1;
        toggleGPS();
        return;
    }
   }
  if (cout.available()) {      // If anything comes in Serial (USB),
    GPS_PORT.write(cout.read());   // read it and send it out Serial1 (pins 0 & 1)
  }

  if (GPS_PORT.available()) {     
    cout.write(GPS_PORT.read());   // read it and send it out Serial (USB)
  }
  }
}
I tried the inchar method as well but to the same effect. Could read but not send. I am just doing it from one teensy instead of 2.
 
Hi Chris - don't know if you are still awake but all is working at least as far as the screen is concerned so far. Problem having GPS tracked to the baudrate. I just fixed it 921600 and it works fine. Except now when I tried to change the freq I get the following:
Code:
Setting CFG-TP5 (0x06 0x31) Time Pulse 0 Parameters	(FreqLocked) 2001Hz  (DutyLocked) 50.000000% map(2147483648)  (antCableDelay) 50ns
 Poll_CFG_TP5, Time Pulse 0 Parameters
UBX_ACK_ACK: Message Acknowledged - CFG-TP5 (0x06 0x31) Set Time Pulse 0 Parameters
_gpsPayload[_payloadSize] array error:160

Making progress. But of course now I don't have any fixes.
 
Oh you must have other GPS messages running like maybe NMEA?

in UBLOX.c :
Code:
      // prevent _gpsPayload[_payloadSize] array overrun error, currently set @ 150
      if (c < _payloadSize) {
        _fpos++;
      } else {
        Serial.print("_gpsPayload[_payloadSize] array error:"), Serial.println(c);
        _fpos = 0;
      }
    }
I think I'm going to order the GPS you have, I'm guessing the one you're using is in post #30

Edit:
ok
Your order was placed.
Estimated delivery: Apr 27 – Jun 1
 
Last edited:
you have to change the solution rate as well which is right below the update rate.

Missed that - so many pages of options - Must have quit reading when I thought I found half the solution.

If you Proxy isn't working ? - make a dedicated sketch with no option check to exit - just a tight loop efficiently doing only Rx<>Tx?
 
you ever try running teensythreads on them using separate threads? my other project uses 4 threads and is blazing faster than a single loop

i say this because i have one thread on Wire, one on Serial1, and one on Serial2, plus main loop for processing and SPI1&2 polling, the 2 uart displays i have ran at full speed, never possible to reach these speeds before teensythreads came out :)
 
Last edited:
Hi Chris

Guess what - finally it all works. Put some longer wires on to the GPS to move further away from the screen and teensy, change the max payload length to 168 (last I checked I didn't all messages were disabled). And last but not least finally got a good fix.

Was fun watching the little red light fix rate blink faster as I increased the frequency on the display :) Hey blinking lights always make me happy. :)

Just one question the frequency locked on the screen comes from polling the TP message? or is the freq when it turns yellow?
 
Hi Chris.

Know I haven't worked this for awhile since I was doing other tests but today I decided to get back to it. First I did incorporate you version of the lib in the uNavAHRS code and it works like a charm, love that I set the RATE right from the sketch :)

Anyway, now for the reason of the post. Since I don't have a frequency counter I decided to hook up the PPS wire to a T3.5 and run the FreqCount library and it works, finally got something to work out of the box. Here are some results for you:
Code:
Set                       Measured
1,024,000               1,024,017
1                            1
10,000                    10,000
100,000                  100,001 -100,002
500,000                  500,008 - 500,009

Slight difference, probably the library. Is there another lib that is better?

Mike
 
Hey Mike glad you are having fun.
Slight difference, probably the library. Is there another lib that is better?
The touch is probably part of the issue, I bet if you use the T_IRQ pin it will look a bit better.
 
Thanks Chris - will check it out next go around. Playing around with getting the M8N to read a NTRIP server.
 
Don't ignore the T_IRQ code - it is awesome ...
;) I love it so far.

TFT TIRQ interrupt signal must be used for this example.

v1.2
Addition: TFT TIRQ interrupt signal.
v1.1
Addition: set up touch rotation independent from the screen rotation.
//Rotations 1 or 3 = Landscape mode only ~ 1->TFT conn. Pins on right side: 3->TFT conn. Pins on left side
const int rotation = 3;//(1 or 3 only)
const int TouchRotation = 1;//(1 or 3 only)

Code:
// ***********************************************************************************************************
// *(c) Chris O 2018/4 - License: MIT
// * U-Blox UBX-CFG-TP5 (0x06 0x31) Quick configuration editor - ILI9341 TFT + Touch interface
// * v1.2 - TFT TIRQ interrupt signal must be used for this example.
// *
// * Permission is hereby granted, free of charge, to any person obtaining
// * a copy of this software and associated documentation files (the
// * "Software"), to deal in the Software without restriction, including
// * without limitation the rights to use, copy, modify, merge, publish,
// * distribute, sublicense, and/or sell copies of the Software, and to
// * permit persons to whom the Software is furnished to do so, subject to
// * the following conditions:
// *
// * 1. The above copyright notice and this permission notice shall be
// * included in all copies or substantial portions of the Software.
// *
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// * SOFTWARE.
// ***********************************************************************************************************

// ***********************************************************************************************************
// *                            UBLOX GPS - Important set this to the GPS hardware serial port
// ***********************************************************************************************************
#include "UBLOX.h" // Update #4 U-BLOX lib v1.0.3  https://forum.pjrc.com/threads/36103-uBlox-Library/page2
// Set this to the GPS hardware serial port you wish to use
#define GPShwSERIAL 3 // 1 = Serial1, 2 = Serial2, 3 = Serial3, 4 = Serial4 ....

// ***********************************************************************************************************
// *                            RUN TFT Touch Calibration
// ***********************************************************************************************************
// comment or uncomment me.
#define TFTCalibration  // calibrate the touch screen.
//

// This is calibration data for the raw touch data to the screen coordinates
int TS_MINX = 367;
int TS_MINY = 226;
int TS_MAXX = 3920;
int TS_MAXY = 3809;

// Rotations 1 or 3 = Landscape mode only ~ 1->TFT conn. pins on right side  : 3->TFT conn. pins on left side
const int rotation = 3; //(1 or 3 only)
const int TouchRotation = 1; //(1 or 3 only) #### NOTE: if its mirrored and flipped USE # 3

uint32_t const BaudDefault = 9600; // default settings
// a uBlox object, which is on Teensy hardware
// GPS serial port
UBLOX gps(GPShwSERIAL);
// the uBlox data structure
gpsData uBloxData;

// ***********************************************************************************************************
// *                            TFT
// ***********************************************************************************************************
#include <SPI.h>
#include <Wire.h>      // this is needed even tho we aren't using it
#include <ILI9341_t3.h>
#include <XPT2046_Touchscreen.h>
//#include <Adafruit_STMPE610.h>

// https://www.pjrc.com/store/display_ili9341_touch.html
// Connections For optimized ILI9341_t3 library + XPT2046 Touch library
// ---------------------------------------------------------------------------------------------------------------------
// ILI9341 Pin | - Teensy 3.x - | - Notes -
// VCC         |           VIN  | Power: 3.6 to 5.5 volts
// GND         |           GND  |
// CS          |            20  | Alternate Pins: 9, 10, 15, 20, 21
// RESET       |         +3.3V  | Optional; #define TFT_RST 255, = unused, connect to 3.3V
// D/C         |            15  | Alternate Pins: 9, 10, 15, 20, 21
// SDI   (MOSI)|(DOUT~MOSI) 11  | Alternate Pin:  7 [SPI.setMOSI(7); - Use befor tft.begin()]
// SCK   (SCK0)|     (SCK0) 13  | Alternate Pin: 14 [SPI.setSCK(14); - Use befor tft.begin()]
// LED         |           VIN  | Use 100 ohm resistor, TFT dependent I'm not using any.
// SDO   (MISO)| (DIN~MISO) 12  | Alternate Pin:  8 [SPI.setMISO(8); - Use befor tft.begin()]
// T_CLK (SCK0)|     (SCK0) 13  | Alternate Pin: 14 [SPI.setSCK(14); - Use befor tft.begin()]
// T_CS        |            16  | Alternate: can use any digital pin  e.g. 6
// T_DIN (MOSI)|(DOUT~MOSI) 11  | Alternate Pin:  7 [SPI.setMOSI(7); - Use befor tft.begin()]
// T_DO  (MISO)| (DIN~MISO) 12  | Alternate Pin:  8 [SPI.setMISO(8); - Use befor tft.begin()]
// T_IRQ       |             2  | Optional: can use any digital pin, TIRQ interrupt signal must be used for this example.
// ----------------------------------------------------------------------------------------------------------------------

#define TOUCH_CS  16 // 8
// The TIRQ interrupt signal must be used for this example.
#define TIRQ_PIN  2

//Adafruit_STMPE610 ts = Adafruit_STMPE610(TOUCH_CS);
//XPT2046_Touchscreen ts(TOUCH_CS);
XPT2046_Touchscreen ts(TOUCH_CS, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

// For optimized ILI9341_t3 library
#define TFT_DC      15
#define TFT_CS      20
#define TFT_RST    255  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

#include "font_Arial.h"

int t_x; // Retrieve point x
int t_y; // Retrieve point y
int Tx = 0;
int Ty = 0;
byte touch_event_detected = 0;
#define MINPRESSURE 5   // 10
#define MAXPRESSURE 3000  // this was 1000

// Slider value editor
uint32_t xFreq = 1; // Hz, Maps the values
uint32_t xAnt = 50; // ns
float xDuty = 50.0000; // %
float xR = 29; // Slider

// The elapsedMillis feature is built into Teensyduino.
// For non-Teensy boards, it is available as a library.
elapsedMillis BLINK;
uint8_t Toggle = 1; // Toggle
uint8_t Select = 22; // 22 ant ,39 freq, 55 duty

// ***********************************************************************************************************
// *
// *                                Setup()
// *
// ***********************************************************************************************************
void setup(void) {
  tft.begin();
  tft.setRotation(rotation); // TFT Rotation 0~3

  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_16);
  byte i = 0;
  while (!Serial && millis() < 5000) { // wait for Arduino Serial Monitor
    if (i >= 240) {
      i = 255;
    }
    tft.fillRect(250, 5, 42, 18, ILI9341_BLACK);
    tft.setCursor(250, 5);
    tft.print((5000.0 - (float)millis()) / 1000.0, 1);
    tft.print(" sec");

    delay(100);
    // BackLight
    if (i <= 254) {
      i += 10;
    }
  }

  if (!ts.begin()) {
    Serial.println("Couldn't start touchscreen controller");
    while (1);
  }
  Serial.println("U-Blox UBX-CFG-TP5 (0x06 0x31), TFT + Touch interface");
  Serial.println("Touchscreen started");

#ifdef TFTCalibration
  //int Tx = 0;
  //int Ty = 0;
  bool EXIT = true;
  unsigned long y = 10000;
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_9);
  tft.drawRoundRect(250, 140, 70, 40, 3, ILI9341_ORANGE);
  tft.setCursor(273, 155);
  tft.print("EXIT");

  tft.drawRoundRect(250, 200, 70, 40, 3, ILI9341_ORANGE);
  tft.setCursor(273, 208);
  tft.print("RUN");
  tft.setCursor(255, 222);
  tft.print("Calibration");

  tft.setTextColor(ILI9341_WHITE);
  tft.setCursor(2, 2);
  tft.print("Click on screen to draw Pixel");
  tft.setFont(Arial_16);
  while (millis() < y) { // wait for
    tft.fillRect(250, 5, 42, 18, ILI9341_BLACK);
    tft.setCursor(250, 5);
    tft.print((y - (float)millis()) / 1000.0, 1);
    tft.print(" sec");
    delay(10);

    TS_Point p = ts.getPoint();
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
      // Retrieve a point
      TS_Point p = ts.getPoint();
      Tx = p.x;
      Ty = p.y;

      Touchrot();

      tft.drawPixel(t_x, t_y, ILI9341_BLUE);
      // EXIT
      if (t_x > 250 && t_x < 320 && t_y > 140 && t_y < 180) {
        tft.fillScreen(ILI9341_BLACK);
        y = 0;
        EXIT = true;
        delay(300);
      }
      if (t_x > 250 && t_x < 320 && t_y > 200 && t_y < 240) {
        tft.fillScreen(ILI9341_BLACK);
        y = 0;
        EXIT = false;
        delay(300);
      }
    }
  }
  if (EXIT == false) {
    TS_MINX = 450;
    TS_MINY = 450;
    TS_MAXX = 3700;
    TS_MAXY = 3700;
    TFTCali(); // Run TFT Touch Calibration
  }
#endif

  tft.fillScreen(ILI9341_BLACK);
  ResetScreen();
  // ***********************************************************************************************************
  // *                            UBLOX GPS setup
  // ***********************************************************************************************************
  // serial to display data
  Serial.begin(9600); // Teensy Serial object always communicates at 12 Mbit/sec USB speed.
  CPUspecs();
  /*
    // -- AutoBauding test -- experimental baud rate 1500000
    // Try communication with the GPS receiver at 9600 baud, default settings
    // then set GPS UART Baud to 1500000
    gps.begin(BaudDefault);                   // Enable Teensy serial communication @ 9600 baud, default settings.
    gps.SetGPSbaud(1500000, false);           // Set GPS Port Baud, Possible Baud Rate Configurations 4800~9600~19200~38400~57600~115200~230400~460800-921600
    gps.end();                                // Disables Teensy serial communication, to re-enable serial communication, call gps.begin(Baud, bool);.
    gps.begin(19200);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(38400);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(57600);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(115200);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(230400);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(460800);
    gps.SetGPSbaud(1500000, false);
    gps.end();
    gps.begin(921600);
    gps.SetGPSbaud(1500000, true);
    gps.end();
    // now start communication with the GPS
    // receiver at 1500000 baud,
    gps.begin(1500000);                       // Enable Teensy serial communication @ given baud rate
  */

  // -- AutoBauding test -- baud rate 921600
  // Try communication with the GPS receiver at 9600 baud, default settings
  // then set GPS UART Baud to 921600
  gps.begin(BaudDefault);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(19200);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(38400);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(57600);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(115200);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(230400);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(460800);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(921600);
  gps.SetGPSbaud(921600, false);
  gps.end();
  gps.begin(1500000);
  gps.SetGPSbaud(921600, true);
  gps.end();
  // now start communication with the GPS
  // receiver at 921600 baud,
  gps.begin(921600);                        // Enable Teensy serial communication @ given baud rate
  if (gps.read(&uBloxData) ) {}             // reading data clears the hw serial port.

  gps.SetRATE(1000, false);                 // Navigation/Measurement Rate Settings, e.g. 100ms => 10Hz, 200 => 5.00Hz, 1000ms => 1Hz, 10000ms => 0.1Hz
  // Possible Configurations:
  // 60=>16.67Hz, 64=>15.63Hz, 72=>13.89Hz, 80=>12.50Hz, 100=>10.00Hz, 125=>8.00Hz, 200=>5.00Hz, 250=>4.00Hz, 500=>2.00Hz
  // 800=>1.25Hz, 1000=>1.00Hz, 2000=>0.50Hz, 4000=>0.25Hz, 10000=>0.10Hz, 20000=>0.05Hz, 50000=>0.02Hz

  // NOTE: Dis_all_NMEA -strongly suggest changing RX buffer to 255 or more,*otherwise you will miss ACKs*on serial monitor
  gps.Dis_all_NMEA_Child_MSGs(false);       // Disable All NMEA Child Messages Command

  gps.SetNAV5(3, false);                    // Set Dynamic platform model Navigation Engine Settings (0:portable, 2: stationary, 3:pedestrian, Etc)
  // Possible Configurations
  // 0: portable, 2: stationary, 3: pedestrian, 4: automotive, 5: sea, 6: airborne with <1g, 7: airborne with <2g
  // 8: airborne with <4g, 9: wrist worn watch (not supported in protocol v.less than 18)

  // ### Periodic auto update ON,OFF Command ###
  gps.Ena_NAV_PVT(false);                    // Enable periodic auto update NAV_PVT
  //gps.Dis_NAV_PVT(false);                  // Disable periodic auto update NAV_PVT

  //gps.Ena_NAV_ATT(true);                   // Enable periodic auto update NAV_ATT ~ U-blox M8 from protocol version 19
  //gps.Dis_NAV_ATT(false);                  // Disable periodic auto update NAV_ATT ~ ---^

  //gps.Ena_NAV_POSLLH(true);                // Enable periodic auto update NAV_POSLLH
  //gps.Dis_NAV_POSLLH(false);               // Disable periodic auto update NAV_POSLLH

  gps.Ena_Dis_MON_IO(true, false);           // Ena/Dis periodic auto update I/O Subsystem Status, bytes(received, sent), parity errors, framing errors, overrun errors)

  gps.Poll_MON_IO(false);                   // Polls UBX-MON-IO (0x0A 0x02) I/O Subsystem Status
  gps.Poll_MON_VER(false);                  // Polls UBX-MON-VER (0x0A 0x04) Receiver/Software Version

  // A UBlox GPS Module Primer for beginners https://forum.pjrc.com/threads/46058-A-UBlox-GPS-Module-Primer-for-beginners
  gps.SetCFG_TP5(1, 50.0000, 50, true);    // UBX-CFG-TP5 (0x06 0x31) - Set Time Pulse 0 Parameters.
  //          (1Hz,50%,ant50ns,print usb)
  // Possible Configurations:
  // SetCFG_TP5(FreqLocked- 1Hz ~ 24000000Hz, DutyLocked- 0.000000% ~ 100.000000%, antCableDelay- 0~32767ns, print usb ACK- true or false);

  gps.Poll_CFG_TP5(false);                 // Polls CFG-TP5        (0x06 0x31) Poll Time Pulse 0 Parameters
}

// ***********************************************************************************************************
// *
// *                                Loop()
// *
// ***********************************************************************************************************
byte buffer[255];

void loop()
{
  if (BLINK > 500) {
    BLINK = 0; // reset since
    Toggle = ! Toggle;
    if (Toggle == 0) {
      tft.setFont(Arial_12);
      tft.setTextColor(ILI9341_YELLOW);
      tft.setCursor(10, Select); //
      tft.print(">");

      tft.setFont(Arial_11); // Arial, Arial
      if (Select == 22) {
        tft.setCursor(85, 100);  // 22
        tft.print("Ant");
      } else if (Select == 39) {
        tft.setCursor(85, 115);  // 22
        tft.print("Freq");
      } else if (Select == 55) {
        tft.setCursor(85, 130);  // 22
        tft.print("Duty");
      }
    } else {
      tft.setFont(Arial_12);
      tft.setTextColor(ILI9341_BLACK);
      tft.setCursor(10, Select); //
      tft.print(">");

      tft.setFont(Arial_11);
      tft.setCursor(85, 100);
      tft.print("Ant");
      tft.setCursor(85, 115);
      tft.print("Freq");
      tft.setCursor(85, 130);
      tft.print("Duty");
    }
  }

  // ***********************************************************************************************************
  // *                            UBLOX GPS read
  // ***********************************************************************************************************
  if (gps.read(&uBloxData) ) {

    //numSV
    tft.setFont(Arial_9);
    tft.setTextColor(ILI9341_CYAN);
    tft.setCursor(265, 6);
    tft.fillRect(297 , 6 , 18, 10, ILI9341_BLACK);
    tft.print("#SV: ");
    tft.print(uBloxData.numSV);

    tft.setCursor(263, 20);
    tft.print("Fix Type:");
    tft.setCursor(263, 35);
    tft.fillRect(263 , 35 , 55, 10, ILI9341_BLACK);
    //fixType;///< [ND], GNSSfix Type: 0: no fix, 1: dead reckoning only, 2: 2D-fix, 3: 3D-fix, 4: GNSS + dead reckoning combined, 5: time only fix
    switch (uBloxData.fixType) { // fixType
      case 0:    // 0: no-fix
        tft.setTextColor(ILI9341_RED);
        tft.print(" NO-fix");
        break;
      case 1:    // 1: dead reckoning only
        tft.print("dead rec");
        break;
      case 2:    // 2: 2D-fix
        tft.setTextColor(ILI9341_BLUE);
        tft.print(" 2D-fix");
        break;
      case 3:    // 3: 3D-fix
        tft.setTextColor(ILI9341_GREEN);
        tft.print(" 3D-fix");
        break;
      case 4:    //  4: GNSS + dead reckoning combined
        tft.print("GNSS+d");
        break;
      case 5:    //  5: time only fix
        tft.print("Time only");
        break;
      default:
        // Not Supported
        tft.print("Not Sup:"), tft.print(uBloxData.fixType);
        break;
    }

    // UBX-CFG-TP5 (0x06 0x31) - Set Time Pulse 0 Parameters.
    //tft.setTextSize(2);
    tft.setFont(Arial_11);
    tft.setTextColor(ILI9341_GREEN);
    tft.fillRect(185 , 23 , 60, 11,  ILI9341_BLACK);
    tft.setCursor(25, 23);
    tft.print("Ant Cable Delay");
    tft.setTextColor(ILI9341_YELLOW);
    tft.setCursor(163, 23);
    tft.print(" ns: ");
    tft.print(uBloxData.antCableDelay);  // antCableDelay

    tft.setTextColor(ILI9341_GREEN);
    tft.fillRect(185 , 40 , 75, 11, ILI9341_BLACK);
    tft.setCursor(25, 40);
    tft.print("Freq Locked");
    tft.setTextColor(ILI9341_YELLOW);
    tft.setCursor(161, 40);
    tft.print(" Hz: ");
    tft.println(uBloxData.freqPeriodL);  // freqPeriodL

    tft.setTextColor(ILI9341_GREEN);
    // CurrentfreqPeriodL = uBloxData.freqPeriodL; //TODO REMOVE?
    tft.fillRect(181 , 58 , 68, 11, ILI9341_BLACK);
    tft.setCursor(25, 58);
    tft.print("Duty Cycle Locked");
    tft.setTextColor(ILI9341_YELLOW);
    tft.setCursor(165, 58);
    tft.print(" %: ");
    tft.print(uBloxData.dutycycleL, 4);  // duty cycle%

    //tft.setTextSize(0);
    tft.setFont(Arial_8);
    tft.setTextColor(ILI9341_CYAN);
    tft.setCursor(0, 200);
    tft.print("I/O Subsystem Status");
    tft.setTextColor(ILI9341_WHITE);
    tft.setCursor(0, 210);
    tft.fillRect(47 , 210 , 70, 8, ILI9341_BLACK);
    tft.print("RX Bytes: "), tft.print(uBloxData.rxBytes); ///< [B], Number of bytes ever received
    tft.setCursor(0, 220);
    tft.fillRect(45 , 220 , 70, 8, ILI9341_BLACK);
    tft.print("TX Bytes: "), tft.print(uBloxData.txBytes); ///< [B], Number of bytes ever sent
    tft.setCursor(0, 230);
    tft.fillRect(66 , 230 , 70, 8, ILI9341_BLACK);
    tft.print("Overrun Errs: "), tft.print(uBloxData.overrunErrs); ///< [ms], Number of 100ms timeslots with overrun errors

    tft.setTextColor(ILI9341_CYAN);
    tft.setCursor(90, 158);
    tft.fillRect(180 , 158 , 30, 8, 0x31C7);
    tft.print("UBlox SW Version: "), tft.print(uBloxData.swVersion); ///< Software Version
    tft.setCursor(140, 168);
    tft.fillRect(165 , 168 , 50, 8, 0x31C7);
    tft.print("Rev# "), tft.print(uBloxData.revVersion); ///< Rev#
    tft.setCursor(121, 178);
    tft.fillRect(180 , 178 , 16, 8, 0x31C7);
    tft.print("HW Version: "), tft.print(uBloxData.hwVersion); ///< Hardware Version, 7 = u-blox 7
    tft.setCursor(121, 188);
    tft.fillRect(164 , 188 , 32, 8, 0x31C7);
    tft.print("Protocol: "), tft.print(uBloxData.extension1); ///< Protocol version, e.g. 14.00

    tft.drawRoundRect(180, 200, 120, 40, 6, ILI9341_CYAN); // SEND BTN
    tft.setFont(Arial_20);
    tft.setTextColor(ILI9341_GREEN);
    tft.setCursor(208, 210);
    tft.print("SEND");

    ScreenUpdate ();
  }
  // ***********************************************************************************************************
  // *                            TFT
  // ***********************************************************************************************************
  // See if there's any touch data for us
  TouchData();
  if (touch_event_detected == 1) {
    // SEND BUTTON
    if (t_x > 180 && t_x < 300 && t_y > 200 && t_y < 240) {
      tft.drawRoundRect(180, 200, 120, 40, 6, ILI9341_BLUE);
      tft.setFont(Arial_20);
      tft.setTextColor(ILI9341_RED);
      tft.setCursor(208, 210);
      tft.print("SEND");
      gps.SetCFG_TP5(xFreq, xDuty, xAnt, true);  // UBX-CFG-TP5   (0x06 0x31) - Set Time Pulse 0 Parameters.
      gps.Poll_CFG_TP5(true);                  // Polls CFG-TP5 (0x06 0x31) - Poll Time Pulse 0 Parameters
      gps.Poll_MON_VER(true);                 // Polls UBX-MON-VER (0x0A 0x04) Receiver/Software Version
    }
    // Select cur. ant, freq, duty
    byte temp = Select; // clear
    if (t_x > 0 && t_x < 320 && t_y > 20 && t_y < 34) {
      Select = 22; // y = 22
      tft.drawRoundRect(20, 21, 140, 17, 3, ILI9341_ORANGE);

      tft.drawRoundRect(20, 38, 140, 17, 3, ILI9341_BLACK);
      tft.drawRoundRect(20, 56, 140, 17, 3, ILI9341_BLACK);
    }
    if (t_x > 0 && t_x < 320 && t_y > 40 && t_y < 50) {
      Select = 39;
      tft.drawRoundRect(20, 38, 140, 17, 3, ILI9341_ORANGE);

      tft.drawRoundRect(20, 21, 140, 17, 3, ILI9341_BLACK);
      tft.drawRoundRect(20, 56, 140, 17, 3, ILI9341_BLACK);
    }
    if (t_x > 0 && t_x < 320 && t_y > 60 && t_y < 70) {
      Select = 55;
      tft.drawRoundRect(20, 56, 140, 17, 3, ILI9341_ORANGE);

      tft.drawRoundRect(20, 21, 140, 17, 3, ILI9341_BLACK);
      tft.drawRoundRect(20, 38, 140, 17, 3, ILI9341_BLACK);
    }
    tft.setFont(Arial_12);
    tft.setTextColor(ILI9341_BLACK); // clear old
    tft.setCursor(10, temp);
    tft.print(">");
  }
}

void ScreenUpdate () {
  if (Select == 22) { // Ant
    xR = modifiedMap(xAnt, 0, 32767, 29, 285); // 0~32767, default 50ns
    // Draws the positioners
    tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
    tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
    tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
    // Draws the positioner outside box
    tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
    tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);
  } // Ant
  tft.setCursor(125, 100);
  if (xAnt == uBloxData.antCableDelay) {
    tft.setTextColor(ILI9341_YELLOW);
  }  else {
    tft.setTextColor(ILI9341_RED);
  }
  // print the new value in the slider bar
  tft.setFont(Arial_12);
  tft.fillRect(125, 100, 100, 12, ILI9341_BLACK); // Clear
  tft.print(xAnt);

  if (Select == 39) { // Freq
    xR = modifiedMap(xFreq, 1, 24000000, 29, 285); // 1Hz ~ 24000000Hz
    // Draws the positioners
    tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
    tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
    tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
    // Draws the positioner outside box
    tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
    tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);
  } // Freq
  tft.setCursor(125, 115);
  if (xFreq == uBloxData.freqPeriodL) {
    tft.setTextColor(ILI9341_YELLOW);
  }  else {
    tft.setTextColor(ILI9341_RED);
  }
  // print the new value in the slider bar
  tft.setFont(Arial_12);
  tft.fillRect(125, 115, 100, 12, ILI9341_BLACK); // Clear
  tft.print(xFreq);

  if (Select == 55) { // Duty
    xR = map(xDuty, 0 , 100, 29, 285);
    // Draws the positioners
    tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
    tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
    tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
    // Draws the positioner outside box
    tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
    tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);
  } // Duty

  tft.setCursor(125, 130);
  if (xDuty == uBloxData.dutycycleL) {
    tft.setTextColor(ILI9341_YELLOW);
  }  else {
    tft.setTextColor(ILI9341_RED);
  }
  // print the new value in the slider bar
  tft.setFont(Arial_12);
  tft.fillRect(125, 130, 100, 12, ILI9341_BLACK); // Clear
  tft.print(xDuty, 4);
}

void ResetScreen () {
  tft.fillScreen(ILI9341_BLACK);
  tft.fillRoundRect(5, 1, 256, 73, 3, 0x1000); // 0x52AA

  tft.setCursor(6, 6);
  tft.setTextColor(ILI9341_BLUE);
  tft.setFont(Arial_8);
  tft.print("UBX-CFG-TP5 Current Time Pulse Configuration");

  // Select = 22; // y = 22
  tft.drawRoundRect(20, 21, 140, 17, 3, ILI9341_ORANGE);

  tft.drawRoundRect(20, 38, 140, 17, 3, ILI9341_BLACK);
  tft.drawRoundRect(20, 56, 140, 17, 3, ILI9341_BLACK);

  //http://www.barth-dev.de/online/rgb565-color-picker/
  //COLOR GRAY 0x52AA
  //DK GRY 0x31C7
  //DK BLUE 0x006F
  tft.fillRoundRect(0, 75, 320, 123, 5, 0x31C7); // frame around slider and black rear axle msg. box
  tft.drawRoundRect(0, 75, 320, 124, 5, ILI9341_GREEN); //
  tft.fillRoundRect(20, 76, 274, 52, 5, ILI9341_BLACK); // frame around slider and - + bottons
  tft.fillRoundRect(20, 125, 64, 72, 5, ILI9341_BLACK); // blue side
  tft.fillRoundRect(230, 125, 64, 72, 5, ILI9341_BLACK); // red side
  tft.fillRoundRect(81, 98, 152, 60, 5, ILI9341_GREEN); // red side
  tft.fillRoundRect(82, 99, 150, 58, 5, ILI9341_BLACK); // red side
  tft.fillRoundRect(83, 100, 35, 56, 5, 0x31C7); // red side

  tft.drawRoundRect(0, 0, 320, 75, 5, ILI9341_YELLOW); //

  tft.drawRoundRect(28, 97, 51, 29, 5, ILI9341_BLUE); // - botton
  tft.setCursor( 50, 105);
  tft.setTextColor(ILI9341_BLUE);
  tft.setFont(Arial_16);
  tft.print("-");
  tft.drawRoundRect(284 - 48, 97, 53, 29, 5, ILI9341_RED); // + botton
  tft.setCursor(284 - 28, 105);
  tft.setTextColor(ILI9341_RED);
  tft.setFont(Arial_16);
  tft.print("+");

  tft.drawRoundRect(28, 130, 51, 29, 5, ILI9341_BLUE); // - botton
  tft.setCursor( 30, 137);
  tft.setTextColor(ILI9341_BLUE);
  tft.setFont(Arial_16);
  tft.print("-500");
  tft.drawRoundRect(284 - 48, 130, 53, 29, 5, ILI9341_RED); // + botton
  tft.setCursor(284 - 48, 137);
  tft.setTextColor(ILI9341_RED);
  tft.setFont(Arial_16);
  tft.print("+500");

  tft.drawRoundRect(28, 165, 51, 29, 5, ILI9341_BLUE); // - botton
  tft.setCursor( 30, 173);
  tft.setTextColor(ILI9341_BLUE);
  tft.setFont(Arial_13);
  tft.print("-5000");
  tft.drawRoundRect(284 - 48, 165, 53, 29, 5, ILI9341_RED); // + botton
  tft.setCursor(284 - 48, 173);
  tft.setTextColor(ILI9341_RED);
  tft.setFont(Arial_13);
  tft.print("+5000");

  Draw_Slider(); // Draw Slider
}

void TouchData()
{
  touch_event_detected = 0; // reset flag

  // See if there's any touch data for us
  if (ts.touched())
  {

    // Retrieve a point
    TS_Point p = ts.getPoint();

    // we have some minimum pressure we consider 'valid'
    // pressure of 0 means no pressing!
    if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
      // Wait for end of the touch event before continuing
      while (ts.touched()) { //
        Touchrot();

        // drawPixel
        //  if ((t_x) && ((t_y) < tft.height())) {
        //    tft.drawPixel(t_x, t_y, currentcolor);
        //  }

        if (gps.read(&uBloxData)) {
        }

        // Area of the slider
        if ( (t_y >= 80) && (t_y <= 95)) {
          xR = t_x; // Stores the X value where the screen has been pressed in to variable xR
          if (xR <= 29) { // Confines the area of the slider to be above 38 pixels
            xR = 29;
          }
          if (xR >= 285) { /// Confines the area of the slider to be under 310 pixels
            xR = 285;
          }

          if (Select == 22) { // Ant
            xAnt = modifiedMap(xR, 29, 285, 0, 32767); // 0~32767
            // Draws the positioners
            tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
            tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
            tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
            // Draws the positioner outside box
            tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
            tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);

            tft.setCursor(125, 100);
            if (xAnt == uBloxData.antCableDelay) {
              tft.setTextColor(ILI9341_YELLOW);
            }  else {
              tft.setTextColor(ILI9341_RED);
            }
            // print the new value in the slider bar
            tft.setFont(Arial_12);
            tft.fillRect(125, 100, 100, 12, ILI9341_BLACK); // Clear
            tft.print(xAnt);
          } // Ant

          if (Select == 39) { // Freq
            xFreq = modifiedMap(xR, 29, 285, 1, 24000000);
            // Draws the positioners
            tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
            tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
            tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
            // Draws the positioner outside box
            tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
            tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);

            tft.setCursor(125, 115);
            if (xFreq == uBloxData.freqPeriodL) {
              tft.setTextColor(ILI9341_YELLOW);
            }  else {
              tft.setTextColor(ILI9341_RED);
            }
            // print the new value in the slider bar
            tft.setFont(Arial_12);
            tft.fillRect(125, 115, 100, 12, ILI9341_BLACK); // Clear
            tft.print(xFreq);
          } // Freq

          if (Select == 55) { // Duty
            //xDuty = modifiedMap(xR, 29, 285, (0 - 0.125), (100 - 0.125)); // 100% 4294967295
            xDuty = map(xR, 29, 285, 0 , 100); // 100% 4294967295
            // Draws the positioners
            tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
            tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
            tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
            // Draws the positioner outside box
            tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
            tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);

            tft.setCursor(125, 130);
            if (xDuty == uBloxData.dutycycleL) {
              tft.setTextColor(ILI9341_YELLOW);
            }  else {
              tft.setTextColor(ILI9341_RED);
            }
            // print the new value in the slider bar
            tft.setFont(Arial_12);
            tft.fillRect(125, 130, 100, 12, ILI9341_BLACK); // Clear
            tft.print(xDuty, 4);
          }
        }
      } // while
      touch_event_detected = 1; // reset flag
    }
    Draw_Slider(); // Draw Slider
    Touchrot();
    touch_event_detected = 1; // set flag
  }
}

void Draw_Slider() { // Slider
  if (Select == 22) { // antCableDelay, 0~32767, default 50ns
    // If we press the [-] Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 97) && (t_y <= 126)) {
      xAnt = xAnt - 1;
    }
    // If we press the [+] Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 97) && (t_y <= 126)) {
      xAnt = xAnt + 1;
    }

    // If we press the [-]500 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 140) && (t_y <= 165)) {
      if (xAnt < 502) {
        xAnt = 1;
      } else {
        xAnt = xAnt - 500;
      }
    }
    // If we press the [+]500 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 140) && (t_y <= 165)) {
      xAnt = xAnt + 500;
    }

    // If we press the [-]5000 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 170) && (t_y <= 190)) {
      if (xAnt < 5002) {
        xAnt = 1;
      } else {
        xAnt = xAnt - 5000;
      }
    }
    // If we press the [+]5000 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 170) && (t_y <= 190)) {
      xAnt = xAnt + 5000;
    }
    if (xAnt == 0) {
      xAnt = 0;
      xR = modifiedMap(xAnt, 0, 32767, 29, 285); // Confines for the draw slider
    }  else if (xAnt >= 32767) {
      xAnt = 32767;
      xR = modifiedMap(xAnt, 0, 32767, 29, 285); // Confines for the draw slider
    }
    // curr Ant
    tft.setCursor(125, 100);
    if (xAnt == uBloxData.antCableDelay) {
      tft.setTextColor(ILI9341_YELLOW);
    }  else {
      tft.setTextColor(ILI9341_RED);
    }
    // print the new value in the slider bar
    tft.setFont(Arial_12);
    tft.fillRect(125, 100, 100, 12, ILI9341_BLACK); // Clear
    tft.print(xAnt);
    xR = modifiedMap(xAnt, 0, 32767, 29, 285);
  }

  if (Select == 39) { // freqPeriodLock, 24000000Hz ~ 1Hz
    // If we press the [-] Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 97) && (t_y <= 126)) {
      xFreq = xFreq - 1;
    }
    // If we press the [+] Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 97) && (t_y <= 126)) {
      xFreq = xFreq + 1;
    }

    // If we press the [-]500 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 140) && (t_y <= 165)) {
      if (xFreq < 502) {
        xFreq = 1;
      } else {
        xFreq = xFreq - 500;
      }
    }
    // If we press the [+]500 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 140) && (t_y <= 165)) {
      xFreq = xFreq + 500;
    }

    // If we press the [-]5000 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 170) && (t_y <= 190)) {
      if (xFreq < 5002) {
        xFreq = 1;
      } else {
        xFreq = xFreq - 5000;
      }
    }
    // If we press the [+]5000 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 170) && (t_y <= 190)) {
      xFreq = xFreq + 5000;
    }
    if (xFreq == 0) {
      xFreq = 1;
      xR = modifiedMap(xFreq, 1, 24000000, 29, 285); // Confines for the draw slider
    }  else if (xFreq >= 24000000) {
      xFreq = 24000000;
      xR = modifiedMap(xFreq, 1, 24000000, 29, 285); // Confines for the draw slider
    }
    // curr Freq
    tft.setCursor(125, 115);
    if (xFreq == uBloxData.freqPeriodL) {
      tft.setTextColor(ILI9341_YELLOW);
    }  else {
      tft.setTextColor(ILI9341_RED);
    }
    // print the new value in the slider bar
    tft.setFont(Arial_12);
    tft.fillRect(125, 115, 100, 12, ILI9341_BLACK); // Clear
    tft.print(xFreq);
    xR = modifiedMap(xFreq, 1, 24000000, 29, 285);
  }

  if (Select == 55) { // Duty, 100% 4294967295
    // If we press the [-] Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 97) && (t_y <= 126)) {
      if (xDuty < 0.0001) {
        xDuty = 0;
      } else {
        xDuty = xDuty - 0.0001;
      }
    }
    // If we press the [+] Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 97) && (t_y <= 126)) {
      xDuty = xDuty + 0.0001;
    }

    // If we press the [-]500 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 140) && (t_y <= 165)) {
      if (xDuty < 0.5) {
        xDuty = 0;
      } else {
        xDuty = xDuty - 0.0500;
      }
    }
    // If we press the [+]500 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 140) && (t_y <= 165)) {
      xDuty = xDuty + 0.0500;
    }

    // If we press the [-]5000 Button
    if ((t_x >= 28) && (t_x <= 78) && (t_y >= 170) && (t_y <= 190)) {
      if (xDuty < 0.5001) {
        xDuty = 0;
      } else {
        xDuty = xDuty - 0.5000;
      }
    }
    // If we press the [+]5000 Button
    if ((t_x >= 284 - 48) && (t_x <= 286) && (t_y >= 170) && (t_y <= 190)) {
      xDuty = xDuty + 0.5000;
    }

    if (xDuty <= 0) {
      xDuty = 0;
      xR = modifiedMap(xDuty, 0 , 100, 29, 285); // Confines for the draw slider //(xDuty, (0 - 0.125), (100 - 0.125), 29, 285);
    }  else if (xDuty >= 100) {
      xDuty = 100;
      xR = modifiedMap(xDuty, 0 , 100, 29, 285); // Confines for the draw slider
    }
    // curr Duty
    tft.setCursor(125, 130);
    if (xDuty == uBloxData.dutycycleL) {
      tft.setTextColor(ILI9341_YELLOW);
    }  else {
      tft.setTextColor(ILI9341_RED);
    }
    // print the new value in the slider bar
    tft.setFont(Arial_12);
    tft.fillRect(125, 130, 100, 12, ILI9341_BLACK); // Clear
    tft.print(xDuty, 4);
    xR = map(xDuty, 0 , 100, 29, 285);
  }
  // Draws the positioners
  tft.fillRoundRect(29, 80, xR - 28 , 15, 1, ILI9341_BLUE);
  tft.fillRoundRect(xR + 2 , 80, 285 - xR , 15, 1, ILI9341_BLACK);
  tft.fillRoundRect(xR - 1, 80, 4, 15, 3, ILI9341_RED);
  // Draws the positioner outside box
  tft.drawRoundRect(28, 79, 285 - 25, 17, 1, ILI9341_GREEN);
  tft.drawRoundRect(27, 78, 285 - 25, 19, 3, ILI9341_CYAN);
}

// ***********************************************************************************************************
// *
// *                            Modified Map
// * ARDUINO "map" function have problems with large numbers, rolling my own "Modified Map"
// ***********************************************************************************************************
double modifiedMap(double x, double in_min, double in_max, double out_min, double out_max)
{
  double temp = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  temp = (double) (4 * temp + .5);
  return (double) temp / 4;
}

// ***********************************************************************************************************
// *
// *                                TFT Touch Calibration ()
// * based on http://cyaninfinite.com/tutorials/2-8-tft-lcd-touchscreen-shield/
// ***********************************************************************************************************
#ifdef TFTCalibration
void TFTCali ()
{
  byte count = 0;
  bool tft_y = false;

  tft.fillScreen(ILI9341_BLACK);
  Serial.println("TFT Calibration");
  //Splash
  tft.setCursor(30, (tft.height() / 2) - 20);
  //tft.setTextSize(2);
  tft.setFont(Arial_18);
  tft.println("TFT Calibration v1.1");
  tft.setCursor(30, tft.height() / 2 + 10);
  tft.setFont(Arial_9);
  tft.setTextColor(ILI9341_WHITE);
  tft.print("Screen size:");
  tft.print(tft.width());
  tft.print("x");
  tft.println(tft.height());
  tft.setCursor(30, (tft.height() / 2) + 30);
  tft.println("Test wil begin in 2s...");
  delay(2000);
  tft.fillScreen(ILI9341_BLACK);
  //TFT Calibration
  tft.setCursor(30, (tft.height() / 2) - 20);
  tft.setFont(Arial_14);
  tft.println("TFT Calibration");
  tft.setCursor(30, (tft.height() / 2));
  tft.setFont(Arial_9);
  tft.setTextColor(ILI9341_WHITE);
  tft.print("Click on screen to begin...");
  tft_y = true;

  tft.setTextColor(ILI9341_WHITE);
  tft.setFont(Arial_9);

  while (count < 5) {
    // Retrieve a point
    TS_Point p = ts.getPoint();
    Tx = 0;
    Ty = 0;

    if (tft_y == true) {
      delay(200);
      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        TS_Point p = ts.getPoint();
        Tx = p.x;
        Ty = p.y;
        Touchrot();
        switch (count) {
          case 0:
            tft.fillRect(30, (tft.height() / 2), 180, (tft.height() / 2) + 10, ILI9341_BLACK);
            tft.setCursor(30, (tft.height() / 2));
            tft.print("Press the dots on the corners of the screen.");
            //drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
            tft.setCursor(tft.width() / 2, 10);
            tft.print(count);
            tft.fillCircle(0, 0, 16, ILI9341_YELLOW);
            getMinMax(Tx, Ty);
            count++;
            break;
          case 1:
            tft.fillCircle(tft.width(), 0, 16, ILI9341_YELLOW);
            tft.fillRect(tft.width() / 2, 10, 10, 10, ILI9341_BLACK);
            tft.setCursor(tft.width() / 2, 10);
            tft.print(count);
            getMinMax(Tx, Ty);
            count++;
            break;
          case 2:
            tft.fillCircle(tft.width(), tft.height(), 16, ILI9341_YELLOW);
            tft.fillRect(tft.width() / 2, 10, 10, 10, ILI9341_BLACK);
            tft.setCursor(tft.width() / 2, 10);
            tft.print(count);
            getMinMax(Tx, Ty);
            count++;
            break;
          case 3:
            tft.fillCircle(0, tft.height(), 16, ILI9341_YELLOW);
            tft.fillRect(tft.width() / 2, 10, 10, 10, ILI9341_BLACK);
            tft.setCursor(tft.width() / 2, 10);
            tft.print(count);
            getMinMax(Tx, Ty);
            count++;
            break;
          case 4:
            tft.fillRect(tft.width() / 2, 10, 10, 10, ILI9341_BLACK);
            tft.setCursor(tft.width() / 2, 10);
            tft.print(count);
            tft.fillRect(30, (tft.height() / 2), 300, (tft.height() / 2) + 10, ILI9341_BLACK);
            tft.setCursor(30, tft.height() / 2);
            tft.print("Calibration completed!");
            tft.setCursor(30, (tft.height() / 2) + 20);
            tft.print("TS_MINX:");
            tft.print(TS_MINX);
            tft.setCursor(130, (tft.height() / 2) + 20);
            tft.print("TS_MINY:");
            tft.print(TS_MINY);
            tft.setCursor(30, (tft.height() / 2) + 40);
            tft.print("TS_MAXX:");
            tft.print(TS_MAXX);
            tft.setCursor(130, (tft.height() / 2) + 40);
            tft.print("TS_MAXY:");
            tft.print(TS_MAXY);
            tft.setCursor(30, (tft.height() / 2) + 75);
            tft.setTextColor(ILI9341_OLIVE);
            tft.print("Press Try Again or Exit...");
            tft.setCursor(30, (tft.height() / 2) + 60);
            tft.print("Click on screen to draw Pixel");
            tft.setTextColor(ILI9341_WHITE);

            tft.drawRoundRect(270, 200, 50, 40, 3, ILI9341_ORANGE);
            tft.setCursor(285, 208);
            tft.print("Try");
            tft.setCursor(278, 222);
            tft.print("Again");

            tft.drawRoundRect(270, 140, 50, 40, 3, ILI9341_ORANGE);
            tft.setCursor(283, 155);
            tft.print("EXIT");
            tft_y = false;
            break;
        }
        delay(200);
      }
    } else {
      //tft.setRotation(0);

      if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
        TS_Point p = ts.getPoint();
        Tx = p.x;
        Ty = p.y;

        tft.fillRect(52, 50, 30, 10, ILI9341_BLACK);
        tft.setCursor(30, 50);
        tft.print("X = "); tft.print(Tx);
        tft.fillRect(52, 65, 30, 10, ILI9341_BLACK);
        tft.setCursor(30, 65);
        tft.print("Y = "); tft.print(Ty);
        tft.fillRect(97, 82, 30, 10, ILI9341_BLACK);
        tft.setCursor(30, 82);
        tft.print("Pressure = "); tft.println(p.z);

        Touchrot();

        tft.drawPixel(t_x, t_y, ILI9341_BLUE);

        tft.fillRect(132, 50, 25, 10, ILI9341_BLACK);
        tft.setCursor(100, 50);
        tft.print("t_x = "); tft.print(t_x);
        tft.fillRect(132, 65, 25, 10, ILI9341_BLACK);
        tft.setCursor(100, 65);
        tft.print("t_y = "); tft.print(t_y);

        tft.setCursor(30, tft.height() / 2);
        tft.print("Calibration completed!");
        tft.setCursor(30, (tft.height() / 2) + 20);
        tft.print("TS_MINX:");
        tft.print(TS_MINX);
        tft.setCursor(130, (tft.height() / 2) + 20);
        tft.print("TS_MINY:");
        tft.print(TS_MINY);
        tft.setCursor(30, (tft.height() / 2) + 40);
        tft.print("TS_MAXX:");
        tft.print(TS_MAXX);
        tft.setCursor(130, (tft.height() / 2) + 40);
        tft.print("TS_MAXY:");
        tft.print(TS_MAXY);


        // EXIT
        if (t_x > 270 && t_x < 320 && t_y > 140 && t_y < 180) {
          tft.fillScreen(ILI9341_BLACK);
          count = 5; // exit while()
          delay(300);
        }
        // Try Again
        if (t_x > 270 && t_x < 320 && t_y > 200 && t_y < 240) { // tft 320 x 240
          tft.fillScreen(ILI9341_BLACK);
          tft_y = true;
          count = 0; // reset
          tft.setCursor(30, (tft.height() / 2));
          //tft.setFont(Arial_9);
          tft.setTextColor(ILI9341_WHITE);
          tft.print("Click on screen to begin...");
          TS_MINX = 450;
          TS_MINY = 450;
          TS_MAXX = 3600;
          TS_MAXY = 3600;
          delay(300);
        }
      }
    }
  }
}
void getMinMax(int Tx, int Ty) {
  if (Tx < TS_MINX) {
    TS_MINX = Tx;
  }
  if (Ty < TS_MINY) {
    TS_MINY = Ty;
  }
  if (Tx > TS_MAXX) {
    TS_MAXX = Tx;
  }
  if (Ty > TS_MAXY) {
    TS_MAXY = Ty;
  }
}
#endif

void Touchrot() {
  if (ts.tirqTouched()) {
    TS_Point p = ts.getPoint();
    Tx = p.x;
    Ty = p.y;

    if (TouchRotation == 3) { // 3
      t_y = map(Ty, TS_MINY, TS_MAXY, 0, tft.height());
      t_x = map(Tx, TS_MINX, TS_MAXX, 0, tft.width());
    } else { // 1
      t_y = map(Ty, TS_MINY, TS_MAXY, tft.height(), 0);
      t_x = map(Tx, TS_MAXX, TS_MINX, 0, tft.width());
    }
    //Serial.print("X = "); Serial.print(Tx);
    //Serial.print("  Y = "); Serial.print(Ty);
    //Serial.print("  Pressure = "); Serial.println(p.z);
  }
}


// ***********************************************************************************************************
// *
// *                            CPU specs
// * Thanks defragster ):
// ***********************************************************************************************************
void CPUspecs() {
  Serial.println();
#if defined(__MK20DX128__)
  Serial.println( "CPU is T_LC");
#elif defined(__MK20DX256__)
  Serial.println( "CPU is T_3.1/3.2");
#elif defined(__MKL26Z64__)
  Serial.println( "CPU is T_3.0");
#elif defined(__MK64FX512__)
  Serial.println( "CPU is T_3.5");
#elif defined(__MK66FX1M0__)
  Serial.println( "CPU is T_3.6");
#endif
  Serial.print( "F_CPU =");   Serial.println( F_CPU );
  Serial.print( "ARDUINO =");   Serial.println( ARDUINO );
  Serial.print( "F_PLL =");   Serial.println( F_PLL );
  Serial.print( "F_BUS =");   Serial.println( F_BUS );
  Serial.print( "F_MEM =");   Serial.println( F_MEM );
  Serial.print( "NVIC_NUM_INTERRUPTS =");   Serial.println( NVIC_NUM_INTERRUPTS );
  Serial.print( "DMA_NUM_CHANNELS =");   Serial.println( DMA_NUM_CHANNELS );
  Serial.print( "CORE_NUM_TOTAL_PINS =");   Serial.println( CORE_NUM_TOTAL_PINS );
  Serial.print( "CORE_NUM_DIGITAL =");   Serial.println( CORE_NUM_DIGITAL );
  Serial.print( "CORE_NUM_INTERRUPT =");   Serial.println( CORE_NUM_INTERRUPT );
  Serial.print( "CORE_NUM_ANALOG =");   Serial.println( CORE_NUM_ANALOG );
  Serial.print( "CORE_NUM_PWM =");   Serial.println( CORE_NUM_PWM );
  Serial.println("");
}
 
Cool - I should order one of those SFun MPU9250's and connect up a display and give it a try. ... if only to give a fully functional map function done a cool array way :)

The view I saw of your UI was very nice - I'll have to read the rest of this thread ... need another uBlox too - I only got one ... last one shipped quick from US for about $15 ... have to find another one.
 
Hi Chris
Just gave your new sketch a try and T_IRQ doesn't seem to want to work on the T3.2. I did try changing the IRQ pin but still no luck. It does work fine without the IRQ. Not sure what the problem is?

Mike
 
Odd with this: #include <XPT2046_Touchscreen.h>
and this: #define TIRQ_PIN 2
as a param here: XPT2046_Touchscreen ts(TOUCH_CS, TIRQ_PIN);

It should set up to work - as long as that pin is not used or controlled by anything else and redefined. And of course given a well wired connection between display TIRQ output and the right pin spot on the Teensy.
 
A quick question. I did a quick swap out of screens to make sure I had good connection with the breadboard and switch pins to 22. Waiting now for a GPS fix. Bad time of day for quick fix :(. Anyway found out by accident that if the T_IRQ pin was wrong, i.e., plug it into the pin on the teensy by accident, the touchscreen would not work. Will update as I go.

EDIT: Ok found the problem, my fault. Forgot I changed the clock pin to 14. Now it works not problem. Check the FreqCount sketch against what was set but there is still a difference - at about 22.5Mhz the readings from the FreqCount sketch is about 350Hz higher. Now is when I wish I had a frequency counter :)

Mike
 
Last edited:
Well I'm busy now fixing my truck leaking water pump, by the way i did quick test with no wire connected to T_IRQ pin.
Screen starts up and work correctly other than no touch of course.:confused:
 
Well I'm busy now fixing my truck leaking water pump, by the way i did quick test with no wire connected to T_IRQ pin.
Screen starts up and work correctly other than no touch of course.:confused:

Indeed - when specified the T_IRQ disables touch until the INT fires to enable a transfer. So rather than some bytes of SPI transfer to read the touch Pressure is < MIN and reporting no touch { though I did drop a few bytes and exit early when no touch not using the T_IRQ } it just does immediate return with T_IRQ and no INT detected - and doesn't touch SPI to ask. So overpolling the Touch is much faster with no SPI - and can give less delay after the start of the Touch.

With standard call when touch is found it immediately reads the data and returns the tested value {best 2 avg out of three reads}. Once set the INT indicator stays set until a position request detects Pressure is < MIN, then off it goes - and No_Touch is returned.

A new call was added to just find out if T_IRQ was triggered and won't do a read until asked, this helps when the display is on DMA auto-refresh as the Touch test would collide if DMA not stopped first.

In glancing at code {i.e. may have misread?} in p#92 it seemed a few extra calls to get touch point were made? Each call that returns was tested for MIN pressure and will already be 'fail' if no T_IRQ ( when used ) or if under MIN pressure { based on the threshold of the units I tested }. Doing a second read without keeping the data from prior reads could lead to a missed touch if touch detect ends between calls - so if a point is returned don't throw it away. Not sure why I saw a test for MIN and MAX pressure? If alternate MIN pressures can happen on alternate displays that needs to be accounted for because two values are hardcoded - First Min pressure and another lesser # for Min to disable of INT detected { because a moving touch pressure can drop enough for reporting No_Touch - but not low enough for display to fire another interrupt when it increases without going below the hardware detected threshold }. I'm not sure what a MAX pressure would be?
 
Chris,
Looking at your Example and cpp code. Am trying to figure out what the Poll_CFG_TP5 does. Does it simply just grab the current GPS time, or can it create an interrupt (or time pulse) kind of like a PPS signal?

Don
 
Back
Top