Forum Rule: Always post complete source code & details to reproduce any issue!
Page 6 of 6 FirstFirst ... 4 5 6
Results 126 to 135 of 135

Thread: ILI9341 and XPT2046 for Teensy Touchscreen 320x240 display

  1. #126
    Junior Member
    Join Date
    Jan 2019
    Posts
    4
    First off, thank you for following up. You're correct there is no evidence of any physical damage but I've been in electronics long enough to know ICs don't show damage often. Anyway, Wiring follows the documentation at PJRC site. VCC red, GND blk, CS TCS yel, RESET brn, DC org, SDI T_DIN grn, SCK pur, T_CLK grey, LED red, SDO T_DO blu, T_IRG org


    Click image for larger version. 

Name:	IMG_0678.jpg 
Views:	32 
Size:	112.6 KB 
ID:	15526

    I hope you see my error.

  2. #127
    Junior Member
    Join Date
    Jan 2019
    Posts
    4
    OK - Guess no one found an error. I discovered that the touch does work correctly after all but just not for Teensy 3.6. Soon as I put it on a Teensy 3.2 all example sketches starting working with problems. I am not sure why this is so but on person told me the CS pin pulse is so fast and short on the 3.6 he had to add a 47p cap to the pin to slow it down enough to work. I did not try this but it might offer why the 3.6 does not work while the 3.2 does.

    So I offer my findings and will stop banging my head against the wall with the 3.6! If someone has a code fix for the Teensy or other ideas to make it work I'd love to hear them.

  3. #128
    Junior Member
    Join Date
    Jan 2019
    Location
    Suburban Hell, AKA, Aloha, OR
    Posts
    8

    Mirrored X/Y Axis issue?

    Hi Everyone!

    I'm trying to build a "simple" encoder based measuring tool using a the IL9341 touch screen I bought from Paul.. I noticed his nifty breakout/test board, hopped over to OSH Park and ordered a set because they were just the thing I needed! Hooked it all up, added IR9341_t3 libraries to Arduino 1.8.7 and ran a few tests - all seems to work, happy days..

    Next step, plagiarize a smarter person's work to hack up a few simple touchscreen buttons.. (I'm building a G-Scale railroad car with speed and distance measuring capabilities.. Well, I'm going to TRY.. ) Anyway, a little googling around lead me to defragster's awesome examples base for the very work I want.. A modest TFT screen to display some formatted data from a capacitive encoder and a touch screen to implement a few buttons to calibrate, reset data and set units and such..

    But when I upload the code examples, they don't seem to work exactly as expected, and the issue SEEMS to be a mirroring of both X and Y axis the touch screen uses...

    IE:, when the "ROT" button is in the upper left corner, I have to touch the lower right corner to activate a rotation.. On a narrower scale, I can see the same effect on buttons in the center.. This is more pronounced on screens where the buttons are even number x even number, but it remains consistent at all times.

    If I touch "Rot", the serial console spits out:
    Code:
    button #20
    button #20
    button #20
    Okay, I pressed it THREE times there..

    It occurred to me as I wrote this that I said "everything works", but that doesn't mean I understand the correct value of "working"!! So, the photo shows the touch coordinates as generated by the "IL9341Test" example.. Is the "upper right" supposed to be the higher numbers and lower left the lowest numbers? I don't know if that's "correct" orientation or not.. The product photo is sort of conviently in the middle, so that's hard to use as a gauge..

    Click image for larger version. 

Name:	orientation.JPG 
Views:	15 
Size:	106.7 KB 
ID:	15756

    My display is version 1.2, the Teensy is a 3.2, the display TFT Display test board does not appear to have a revision. The code base in question is ColorButtonsMark3 pulled from github.

    I'll be upfront - my C-foo is weak at best.. I can see a few rotation key words, but I don't recognize anything that would appear to address my situation..

    So - did I miss something in the RTFM part that would fix this? I'm excited to see what I can come up with using this example base, but I pretty sure I need to understand why it's not working for me first..

    Thanks for any input!!

    Sincerely,

    -ET-
    Last edited by mtrcycllvr; 01-28-2019 at 10:07 AM.

  4. #129
    Junior Member
    Join Date
    Jan 2019
    Location
    Suburban Hell, AKA, Aloha, OR
    Posts
    8
    Quote Originally Posted by mtrcycllvr View Post
    The product photo is sort of conviently in the middle, so that's hard to use as a gauge.
    I so lie.. The product page INDEED shows that my numbers are backwards.. Paul's finger is at the lower left.



    My values for the same position are backwards?

    Click image for larger version. 

Name:	wrong.JPG 
Views:	9 
Size:	109.2 KB 
ID:	15757

    Okay, I answer one of my own questions - can someone suggest why I'm seeing reverse values?

    Thanks so much!!

  5. #130
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,739
    The numbers need to be changed with screen rotation. I did a cool map function that can move to any orientation. It looks like your screen is the same orientation there.

    Is this the 'ColorButtonsMark3' code used: Defragster/XPT2046_Touch_Examples … ColorButtonsMark3/ButtonMap.cpp#L31

    That link goes to the map with rotation I did, it needs to be oriented with the screen X,Y to map properly.

  6. #131
    Junior Member
    Join Date
    Jan 2019
    Location
    Suburban Hell, AKA, Aloha, OR
    Posts
    8
    Quote Originally Posted by defragster View Post
    The numbers need to be changed with screen rotation. I did a cool map function that can move to any orientation. It looks like your screen is the same orientation there.

    Is this the 'ColorButtonsMark3' code used: Defragster/XPT2046_Touch_Examples … ColorButtonsMark3/ButtonMap.cpp#L31

    That link goes to the map with rotation I did, it needs to be oriented with the screen X,Y to map properly.
    Ah! I see!

    Code:
    //TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    // wrong orientation for my screen!!
    TS_MAP tsMap[5] = { {3700, 200, 3670, 325 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    ...makes your example code run as expected on my screen! On to more hacking of examples!

    Thanks so much for your prompt response!!

    -ET-

  7. #132
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,739
    Quote Originally Posted by mtrcycllvr View Post
    Ah! I see!

    Code:
    //TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    // wrong orientation for my screen!!
    TS_MAP tsMap[5] = { {3700, 200, 3670, 325 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    ...makes your example code run as expected on my screen! On to more hacking of examples!

    Thanks so much for your prompt response!!

    -ET-
    @mtrcycllvr , hope you are still having Teensy fun - glad I saw your post quickly and you used it to work!

    Just looking back at this code myself and looking closer at this. The goal of the MAP array was to leave the first set of screen Min/Max values unchanged and then index the calculation from there 1,2,3,4 based on screen rotation.

    The swap you did should be the same as setting screen rotation to [3] = { 319, 0, 239, 0 } - that results in the swap of the direction.

    This should be the same if in the source a change of :: int16_t TS_Rotate = 1; to int16_t TS_Rotate = 3;

    Or at RunTime in setup:: ts.ButtonRotate( 3 );

    The goal was allowing the user to rotate the screen and touch with it one or more times after startup without code change.

  8. #133
    Junior Member
    Join Date
    Jan 2019
    Location
    Suburban Hell, AKA, Aloha, OR
    Posts
    8
    Quote Originally Posted by defragster View Post
    @mtrcycllvr , hope you are still having Teensy fun - glad I saw your post quickly and you used it to work!

    Just looking back at this code myself and looking closer at this. The goal of the MAP array was to leave the first set of screen Min/Max values unchanged and then index the calculation from there 1,2,3,4 based on screen rotation.

    The swap you did should be the same as setting screen rotation to [3] = { 319, 0, 239, 0 } - that results in the swap of the direction.

    This should be the same if in the source a change of :: int16_t TS_Rotate = 1; to int16_t TS_Rotate = 3;

    Or at RunTime in setup:: ts.ButtonRotate( 3 );

    The goal was allowing the user to rotate the screen and touch with it one or more times after startup without code change.
    Hey, thanks for the reply and the further distillation! Yeah, see that's the problem, my c-foo is so weak, I couldn't see that, which, well, read on... And I TOTALLY get that your trying to solve the very problem I'm currently facing...

    I'm sorry, I did build a thing, and no, I did not build it from your model.. Of course, now there are RFC's that actually make sense, and I'm kicking myself for not just buckling down and figuring out how to meld your library with my desires in the first place..

    Click image for larger version. 

Name:	IMG_3275.JPG 
Views:	15 
Size:	128.9 KB 
ID:	16193

    So, in the next few days I'm going to take another stab at using your library for a 'version' of my tool that has the sort of flexibility it really could use..

    Your clarification fits nicely with my recent notice of the sticker on the most recent display that suggested pairs of library "orientation" values that had previously escaped my notice..

    Ultimately it's all about me and my general lack of c++-foo.. ;-)

    I'll be sure to poke back here if I get in trouble - honestly, my goal is pretty simple:

    decode/track encoder data
    display data in user selectable scales in a few "formats"
    landscape/portrait mode for said display

    I just got intimidated as I didn't immediately understand much of your code and "thought" my requirements were so simple, they'd NEVER change, right? ;-)

    https://github.com/mtrcycllvr/g-scal...n_distance_car

    Again, thanks.. You may hear more lame questions from me shortly!! The latest circuit boards (not up on github yet) are out for fab, so updated FW is the next big step!

    -ET-

  9. #134
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    9,739
    Glad it is of some value to you - hopefully it will teach you something good. That looks like a very nice build!

    I'm not sure that code is the best example of anything - but it was working as I left it, and when I run it again now … only now looking at it again to integrate the map_code() to suggest inclusion in the lib because that same 2046 touch controller showed up on a new 320x480 display - except it doesn't seem to act as nicely … and my first attempt to port my own code for that has put me off it for a week.

  10. #135
    Junior Member
    Join Date
    Jan 2019
    Location
    Suburban Hell, AKA, Aloha, OR
    Posts
    8
    Hey, just a quick post to relate that I able to achieve my first goal - using abstracted button code to create a simple multi-screen menu system..

    I wanted to reach out with a big "THANK YOU" to Defragster and all who helped put this code together!

    I know that I saw at least one "how can I leverage this?" question that lead me to this post to begin with, so I thought I'd post my current project sketch so others can see how I adapted Defragster's button abstraction code to my relatively simple project and compare the two.. Again, my C-foo is weak, so no laughing at my work! ;-) Constructive criticism/suggestions always welcome, however..

    The goal of the project is to made a G-Scale "data" car that will measure speed and distance in both selected scales ("G-Guage", Garden Gauge, represents five possible scales!) and real world (1:1) scale... There are lots of examples of "a magnet or two on the wheel" approach to this, but when I started considering the SPEED aspect of this it became clear that more data would be required. Anyway, I wanted to share this project with other old train farts like me, which made me think this would be a good time to try integrating a touch screen into my project.

    That opened up a whole new can of worms... So, I actually found this thread, got started, but my c-foo failed me and I backed out to creating my own static button code for version 1. That worked great.. For version 1. Of course then came the RFC's, and I found myself wishing I'd spent more time trying to grok Defragster's button abstraction code.. Which ultimately lead to a few nights of intense study and experimentation..

    So here is my new start, version 2.x using ColorButtonsMark2.ino example provided.. I somehow could just NOT figure out how to get "Mark3" to correctly orient on my screen, and again, weak c-foo plays a role..

    BUT, I am VERY happy with the resulting code functionality - it made creating and fine tuning a multi-screen menu system that features flexible rotation options a simple evenings worth of coding and is SOO much simpler than manipulating static button code over and over again!! Still a work in progress, but it's a WORKING work in progress, which is thrilling..

    So.. THANK YOU!

    -ET-

    Code:
    /*
    
    Dialog only TEST derived from defragster button abstraction code..
    https://github.com/Defragster/XPT2046_Touch_Examples 
    Specifically, this is an adapted version of ColorButtonsMark2.ino
    (Thanks, Defragster!)
    
    Attempt number one - can I just implement an easy menu system
    based on this abstraction code..  
    
    Interweaving my own data collection from the encoder is easy-pie if
    I can get a handle on button management..
    
    Eric Timberlake, March 25th, 2019..
    */
    
    float VERSION = 2.3;
    
    /*
    Version 2.0 -
      - Just get basic abstraction code setup, create buttons for all the screens
        trigger actions on touch..   Still some work to debounce and de-double hit
        (button on screen 1 overlays button on screen 2) is a problem...
        Eric Timberlake, 3.25.2019
    
      - Next: wrap head around screen rotation and preserving rotation state..
              an "info" or "about" screen, perhaps an easter egg in the config
              screen?
    
    Version 2.1 -
      - something.....  Got Rotation and basic menu working, got rotation to
        store persistently, but THEN....
      - Dog gone it - SOMETHING effed up - this will not compile any more - I think
        I was tired and touched/altered something, but for the life of me, can't 
        find out why!!  Claims "ButtonInit" is previously delcared variable or field.
        I sure can't see how or why..   Very frustrating to have a working outline just 
        stop working..
    
    Version 2.2 - 
      - *(^) if I know - copy entire file - fails.  Cut and paste in pieces back into
        original code example and it works fine, just like it was..  WTF?  What follows
        is that reconstruction with NOT A CLUE IN THE WORLD what went wrong..  Obviously
        I created an unclosed brace or something of the sort somewhere..
      - So, we have basic rotation, but not all the required portrait screens and 
        button deffinitions..  We need to set a decision tree on when to be using 
        landscape vs. poitrait versions.
      - I need to figure a way to stop button re-trigger?
      DONE!  Well, done-ish for now..  I'll investigate superior button re-trigger
      detection later.  For now, time to start designing data output screens!
    
    Version 2.3 -
      - start working on calibration routine and various displays? Try actually attaching
        the encoder?  ;-)
    
    */
    
    #include <SPI.h>
    #include <Wire.h>
    
    //#define LC 1
    #if LC
    #include "Adafruit_ILI9341.h"
    #else
    #include <ILI9341_t3.h>
    #endif
    #include <XPT2046_Touchscreen.h>
    
    #define CS_PIN 8
    //XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts and TeensyDuino version 1.26 libs
    // Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
    #define TIRQ_PIN  2
    //XPT2046_Touchscreen ts(CS_PIN, 255);  // Param 2 - 255 - No interrupts
    XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling
    // Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
    
    #define TFT_CS 10
    #define TFT_DC  9
    // MOSI=11, MISO=12, SCK=13
    #ifdef LC
    Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
    // ADAFRUIT MISSING COLORS
    #define ILI9341_NAVY        0x000F      /*   0,   0, 128 */
    #define ILI9341_DARKCYAN    0x03EF      /*   0, 128, 128 */
    #define ILI9341_ORANGE      0xFD20      /* 255, 165,   0 */
    #define ILI9341_PINK        0xF81F
    #else
    ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
    #endif
    
    #include <font_Arial.h>                       // from ILI9341_t3, font
    #include <font_CourierNew.h>                  // from ILI9341_t3, font
    #include <font_CourierNewBold.h>              // from ILI9341_t3, font
    #include <font_AwesomeF100.h>                 // from ILI9341_t3 library - symbols font..
    #include <Encoder.h>                          // optimized encoder library to track motion easily!!
    #include <Adafruit_FRAM_SPI.h>                // access tools for FRAM storage where we store "stuff"..
    
    uint8_t FRAM_CS = 22;                         // use CS pin 22 for chip select / SS
    Adafruit_FRAM_SPI fram = Adafruit_FRAM_SPI(); // use hardware SPI 
    // a little FRAM address tracking...
    uint16_t SAVEDODO = 0x00;                     //FRAM address for long odometer 0x00, 01 02 and 03
    uint16_t SAVEDUNITS = 0x04;                   //FRAM addres for byte units     0x04
    uint16_t SAVEDTRIP = 0x05;                    //FRAM address for long trip     0x05. 06 07 and 08
    uint16_t SAVEDSCALE = 0x10;                   //FRAM address for long scale    0x10, 11 12 and 13
    uint16_t ALTSCALE = 0x20;                     //FRAM address for byte scale array pointer 0x20
    uint16_t TSROTATE = 0x30;                     //FRAM address for integer screen orientation, 0-3
    uint16_t SERIALNM = 0x40;                     //FRAM address for a permanent serial number - we only
                                                  // ever READ THIS a separate program sets it at prod time..
    
    
    // -----------------------------------------
    // --- Button Data Starts here
    // -----------------------------------------
    int16_t TS_Rotate = 1;  // INVALID until set on startup
    static int16_t TS_iiSlide = -1;
    #define TS_SLIDET 40  // Reject SLIDE buttons farther apart than this
    
    struct TS_MAP {
      int16_t xt;
      int16_t xb;
      int16_t yl;
      int16_t yr;
    };
    // Zero is calibration for mapping to pixel, 1-4 follow screen rotation for mapping math
    
    //TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    // restore original TS_MAP and use "ts.ButtonRotate( 3 );" in void setup()
    // re-restore - ts.ButtonRotate( 3 ); isn't working...
    TS_MAP tsMap[5] = { {3700, 200, 3670, 325 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
    int16_t TS_xMax = 0; // Current Screen orientation x,y Max values
    int16_t TS_yMax = 0;
    
    struct TS_BUTTON {
      char *text; // Literal string put into FLASH on compile leaving a pointer that is user changeable
      int16_t tx, ty; // Top Left X,Y
      int16_t ww, hh; // Width, Height
      uint16_t fgc; // forground text/frame color
      uint16_t bgc; // background color button or empty frame
      uint8_t btype;  // for toggle/slider two bytes TYPE & info PAIRING number
      uint8_t info;  // for toggle/slider two bytes TYPE & info PAIRING number
      byte bState; // button state
      byte fontsz; // font size
      byte bId; // Button ID
      uint8_t TS_data; // Toggle FRAME stores state value here
    };
    
    #define TS_JITTER 250 // ms Threshold for Toggle/Slider re-activate
    #define TS_FBUTN 0x01 // Frame Button
    #define TS_RBUTN 0x03 // Rounded Button
    #define TS_FRAME  0x10  // FRAME for two TOGGLE button areas
    #define TS_TOGOFF 0x20  // Off Toggle
    #define TS_TOGON  0x30
    #define TS_ASLIDE 0x40 // Slide Button : A position
    #define TS_BSLIDE 0x50 // Slide Button : B position
    int TS_bCount = 0;  // Set at run time from sizeof()
    // -----------------------------------------
    // --- Button Data Ends here
    // -----------------------------------------
    
    // -----------------------------------------
    // --- USER Button Data Starts here
    //        { text *, tx, ty, ww, hh, fgc, bgc, btype, info, bState, fontsz, bId, TS_data }    << Struct looks like this
    // REQUIRED LAST ITEM :: {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    // -----------------------------------------
    
    uint16_t gobuttonclr=0x34C4;
    uint16_t cancelclr=0xD165;
    //unsigned long menuclr=0x5E23;
    uint16_t menuclr=0xEFE0;
    int16_t stdbuttonwidth=147;
    int16_t stdLborder=7;
    
    // main screen buttons...
    TS_BUTTON mainscreen_l[] = {
      {(char *)"Reset", 10, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 1, 0} ,
      {(char *)" BIG", 105, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 2, 0} ,
      {(char *)"Config", 200, 195, 85, 40, menuclr, 325, TS_FBUTN, 0, 0, 2, 3, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON mainscreen_p[] = {
      {(char *)"Reset", 10, 225, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 1, 0} ,
      {(char *)" BIG", 104, 225, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 2, 0} ,
      {(char *)"Config", 10, 273, 85, 40, 65535, 325, TS_FBUTN, 0, 0, 2, 3, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // configuration choices selection dialog buttons - just rough form for now
    TS_BUTTON configscreen_l[] = {
      {(char *)"Rotation", stdLborder, 15, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 4, 0} ,
      {(char *)"Calibration", stdLborder, 60, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 5, 0} ,
      {(char *)"Scale", stdLborder, 105, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 6, 0} ,
      {(char *)"Units", stdLborder, 150, stdbuttonwidth, 35, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 7, 0} ,
      {(char *)"CANCEL", stdLborder, 195, stdbuttonwidth, 35, cancelclr, 325, TS_FBUTN, 0, 0, 2, 8, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON configscreen_p[] = {
      {(char *)"Rotation", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 4, 0} ,
      {(char *)"Calibration", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 5, 0} ,
      {(char *)"Scale", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 6, 0} ,
      {(char *)"Units", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 7, 0} ,
      {(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 3, 8, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // scale selection dialog buttons - just rough form for now
    TS_BUTTON scalescreen_l[] = {
      {(char *)"1:32 Scale", stdLborder, 5, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 9, 0} ,
      {(char *)"1:29 Scale", stdLborder, 44, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 10, 0} ,
      {(char *)"1:24 Scale", stdLborder, 83, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 11, 0} ,
      {(char *)"1:22.5 Scale", stdLborder, 122, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 12, 0} ,
      {(char *)"1:20.5 Scale", stdLborder, 161, stdbuttonwidth, 32, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 13, 0} ,
      {(char *)"CANCEL", stdLborder, 198, stdbuttonwidth, 32, cancelclr, 325, TS_FBUTN, 0, 0, 2, 14, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON scalescreen_p[] = {
      {(char *)"1:32 Scale", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 9, 0} ,
      {(char *)"1:29 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 10, 0} ,
      {(char *)"1:24 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 11, 0} ,
      {(char *)"1:22.5 ", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 12, 0} ,
      {(char *)"1:20.5", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 13, 0} ,
      {(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 14, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // Units selection dialog buttons - just rough form for now
    TS_BUTTON unitsscreen_l[] = {
      {(char *)"Imperial", stdLborder, 5, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 15, 0} ,
      {(char *)"Metric", stdLborder, 55, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 16, 0} ,
      {(char *)"CANCEL", stdLborder, 105, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 17, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON unitsscreen_p[] = {
      {(char *)"Ipmerial", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 15, 0} ,
      {(char *)"Metric", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 16, 0} ,
      {(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 17, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // Calibration start/help screen dialog
    TS_BUTTON calibrationstartscreen_l[] = {
      {(char *)"Start, 1 Meter", stdLborder, 5, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 18, 0} ,
      {(char *)"Start, 2 Meter", stdLborder, 55, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 19, 0} ,
      {(char *)"CANCEL", stdLborder, 105, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 20, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON calibrationstartscreen_p[] = {
      {(char *)"Start 1M", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 18, 0} ,
      {(char *)"Start 2M", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 19, 0} ,
      {(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 20, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // Calibration stop/set dialog
    TS_BUTTON calibrationstopscreen_l[] = {
      {(char *)"Set", stdLborder, 140, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 21, 0} ,
      {(char *)"CANCEL", stdLborder, 190, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 22, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON calibrationstopscreen_p[] = {
      {(char *)"Set", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 21, 0} ,
      {(char *)"CANCEL", stdLborder, 220, stdbuttonwidth, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 22, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    // Set rotation dialog!
    TS_BUTTON rotationscreen_l[] = {
      {(char *)"Rotate", stdLborder, 10, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 23, 0} ,
      {(char *)"Set", stdLborder, 60, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 2, 24, 0} ,
      {(char *)"CANCEL", stdLborder, 110, stdbuttonwidth, 40, cancelclr, 325, TS_FBUTN, 0, 0, 2, 25, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    TS_BUTTON rotationscreen_p[] = {
      {(char *)"Rotate", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 23, 0} ,
      {(char *)"Set", stdLborder, 220, stdbuttonwidth, 40, 65535, gobuttonclr, TS_FBUTN, 0, 0, 3, 24, 0} ,
      {(char *)"CANCEL", stdLborder , stdbuttonwidth, 220, 40, cancelclr, 319, TS_FBUTN, 0, 0, 3, 25, 0} ,
      {(char *)".", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0, 0, 0}
    };
    
    
    // -----------------------------------------
    // --- USER Button Data Ends here
    // -----------------------------------------
    
    
    uint16_t bg1 = ILI9341_BLUE;                  // define a background color in one place..
    int16_t beepPin = 23;                         // we have a 4KHz buzzer attached here - drive low for tone!
    int16_t beepTime = 50;                        // beep duration, longer is louder and more irritating..
    uint8_t prevTS_Rotate = 0;                    // when we cancel, what rotation do we cancel back to?
    
    
    void setup(void)
    {
    
      fram.begin(FRAM_CS, 2);                     // intialize fram instance to save various data to..  Testing reveils 2 byte addressing..
      fram.setAddressSize(2);                     // ... so we set that here.
    
      Serial.begin(9600);
      while ( !Serial && (millis() < 2000)) ;
      tft.begin();
      if (!ts.begin()) Serial.println("Unable to start touchscreen.");
      else Serial.println("Touchscreen started.");
      
      // doesnt' work - mark2 versus mark3?
      //ts.ButtonRotate( 3 );                       // set button to line up with DISPLAY - for some reason we're mirrored with my hardware?
    
      tft.setFont(Arial_16);                      // sort of globally affect the button fonts..  What happens after displaying data??
    
      TS_Rotate = framReadByte(TSROTATE);         // recall last set rotation from FRAM
    
      ButtonInit( 0 );
      tft.fillScreen(bg1);
      if ((TS_Rotate % 2)) {
        ButtonInit( &mainscreen_l[0] );
      }
      else {
        ButtonInit( &mainscreen_p[0] );
      }
      ButtonDraw( 0 );
      pinMode(beepPin, OUTPUT);                   // setup beeper driving pin
      digitalWrite(beepPin, HIGH);                // make sure we're not beeping!  ;-)
      beep(50);
    }
    
    
    
    void loop()
    {
    
       /* 
      We do stuff here - check encoder for changes, if so, update data, then appropriate
      display updates..  THEN, look to see if someone is pressing a button and act on it.
      */
    
    
      // See if there's any  touch data for us
      static elapsedMillis userTime;
      uint16_t userDebounce = 1555;
      static int16_t lastbValue;
      boolean istouched = false;
      int16_t bValue;
      int16_t x, y;
      istouched = TS_GetMap( x, y, true );
      if (istouched && ButtonHit(x , y, bValue))
      {
        if ( lastbValue == bValue ) userDebounce = userTime;
    
        // Main Screen...
        // buttons 1 2 3 are on main screen
        if ( 1 == bValue ) {  // reset trip meter data
          // do something that actually resets the trip meter here!
          beep(beepTime);
          Serial.println("Reset the trip meter data!!");
          delay(1000);  //stop button rehits crudely?
        }
        if ( 2 == bValue ) {  // full screen display
          // some sort of data only, press and hold for 3 seconds to return?
          beep(beepTime);
          Serial.println("Enter Full Screen Mode!!");
          delay(1000);  //stop button rehits crudely?
        }
        if ( 3 == bValue ) { // goto the sconfig screen..
          prevTS_Rotate = TS_Rotate;
          Serial.println("Go to the Configuration selection screen...");
          configscreen();                     // redraw the config screen
        }
    
        // Config Screen actions...
        // buttons 4, 5, 6, 7 and 8 are located on the config screen..  8 is cancel.
        if ( 4 == bValue ) {                   // goto rotation screen
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &rotationscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Goto rotation screen...");
        }
        if ( 5 == bValue ) {                  // goto calibration screen
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &calibrationstartscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Goto calibration screen...");
        }
        if ( 6 == bValue ) {                  // goto scale selection screen
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &scalescreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Goto scale selection...");
          delay(1500);
        }
        if ( 7 == bValue ) {                  // go to units
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &unitsscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Go to units selection...");
        } 
        if ( 8 == bValue ) {                  // cancel
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          if ((TS_Rotate % 2)) {
            ButtonInit( &mainscreen_l[0] );
          }
          else {
            ButtonInit( &mainscreen_p[0] );
          }
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Return from config screen unchanged...");
        }
    
        // Scale Select Screen actions...
        // buttons 9 - 14 are to scelect scale
        if ( 9 == bValue ) {                  // 1:32
          // do something to set scale to 1:32nd here
          configscreen();                     // redraw the config screen
          Serial.println("Select 1:32nd scale and return to main screen...");
        }
        if ( 10 == bValue ) {                 // 1:29
          // do something to set scale to 1:29th here
          configscreen();                     // redraw the config screen
          Serial.println("Select 1:29th scale and return to main screen...");
        }
        if ( 11 == bValue ) {                 // 1:24
          // do something to set scale to 1:24th here
          configscreen();                     // redraw the config screen
          Serial.println("Select 1:24th scale and return to main screen...");
        }
        if ( 12 == bValue ) {                 // 1:22.5
          // do something to set scale to 1:22.5 here
          configscreen();                     // redraw the config screen
          Serial.println("Select 1:22.5 scale and return to main screen...");
        }
        if ( 13 == bValue ) {                 // 1:20.5
          // do something to set scale to 1:20.5 here
          tft.fillScreen(bg1);
          configscreen();                     // redraw the config screen
          Serial.println("Select 1:20.5th scale and return to main screen...");
        }
        if ( 14 == bValue ) {                 // cancel
          // Don't do anything and return to the main screen...
          configscreen();                     // redraw the config screen
          Serial.println("cancel from select scale screen...");
        }
    
        // Units Select Screen actions...
        // units select are buttons 15, 16 and 17..
        if ( 15 == bValue ) {                 // imperial units select
          // do something to set units to Imperial here
          configscreen();                     // redraw the config screen
          Serial.println("Set units to Imperial measure...");
        }
        if ( 16 == bValue ) {                 // metric
          // do something to set units to Metric here
          configscreen();                     // redraw the config screen
          Serial.println("Set units to Metric measure...");
        }
        if ( 17 == bValue ) {                 // cancel
          // return to main screen without doing anything
          configscreen();                     // redraw the config screen
          Serial.println("Return to main screen from units select...");
        }
    
    
        // Calibration start screen...
        // Calibration start is button 18, cancel is 19..
        if ( 18 == bValue ) { // calibration start using 1M reference
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &calibrationstopscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Start calibration count using 1 meter reference...");
        }
        if ( 19 == bValue ) { // calibration start using 2m reference
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &calibrationstopscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Start calibration count using 2 meter reference...");
        }
        if ( 20 == bValue ) {                 // cancel
          // return to main screen without doing anything
          configscreen();                     // redraw the config screen
          Serial.println("Cancel from set units screen without saving changes...");
        }
    
        // Calibration stop screen...
        // Calibration stop is button 18, cancel is 19..
        if ( 21 == bValue ) {                  // calibration stop at reference distance..
          // do seomthing here to save encoder data!!
          configscreen();                     // redraw the config screen
          Serial.println("Stop calibration count using selected reference...");
        }
        if ( 22 == bValue ) {                 // cancel
          // return to main screen without doing anything
          configscreen();                     // redraw the config screen
          Serial.println("Cancel from set units setup without saving changes...");
        }
    
    
        // Rotation start screen...
        // Rotation is button 18, cancel is 19..
        if ( 23 == bValue ) {                 // Rotate the screen
          tft.fillScreen(bg1);
          ButtonRotate( 1 + TS_Rotate );
          ButtonInit( 0 );
          ButtonInit( &rotationscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Rotate the screen here...");
        }
        if ( 24 == bValue ) {                 // save the current rotation!
          // save rotation settings in some persistent fashion here.
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &configscreen_l[0] );
          prevTS_Rotate = TS_Rotate;
          framWriteByte(TSROTATE, TS_Rotate);
          ButtonDraw( 0 );
          beep(beepTime);
          Serial.println("Save rotation settings...");
        }
        if ( 25 == bValue ) {                 // cancel
          // return to main screen without doing anything
          tft.fillScreen(bg1);
          TS_Rotate = prevTS_Rotate;          // set back to original rotation
          configscreen();                     // redraw the config screen
          Serial.println("Cancel from set rotation screen without saving changes...");
        }
    
        lastbValue = bValue;
        userTime = 0;
      }
    }         // end void loop
    
    
    
    
    
    
    
    
    // -----------------------------------------
    // --- Button Code Starts here
    // -----------------------------------------
    TS_BUTTON TS_NoButton[] = { {(char *)"X", -1, 0, 0, 0, 0, 0, TS_FBUTN, 0, 0, 0} };
    TS_BUTTON *TS_pbtn = TS_NoButton;
    
    #define TS_LIMIT 10 // millisecond limit to check touch value
    #define TS_MINPRESS 800 // Z Pressure return minimum to use point
    #define TS_DEBOUNCE 3 // TX_Map() debounce factor
    boolean TS_GetMap( int16_t &xx, int16_t &yy, boolean twoHits )
    {
      static int16_t lastxx = 500, lastyy = 500; // if twoHits: require two hits same point
      static TS_Point pp;
      static elapsedMillis tsLimit;
      static int16_t xxo = 500, yyo = 500;  // Store old/last returned x,y point
      if ( tsLimit < TS_LIMIT ) return false;
      if (!ts.touched()) return false;
      if ( tsLimit >= TS_SLIDET ) TS_iiSlide = -1;
      tsLimit = 0;
      pp = ts.getPoint();
      if ( pp.z < TS_MINPRESS ) return false;
      xx = map(pp.x, tsMap[0].xt, tsMap[0].xb, tsMap[TS_Rotate].xt, tsMap[TS_Rotate].xb);
      yy = map(pp.y, tsMap[0].yl, tsMap[0].yr, tsMap[TS_Rotate].yl, tsMap[TS_Rotate].yr);
      if (!(TS_Rotate % 2)) {
        int16_t swap = xx;
        xx = yy;
        yy = swap;
      }
      // Debounce by +/-# pixel to minimize point jitter
      if ( ((xxo - TS_DEBOUNCE) <= xx) && ((xxo + TS_DEBOUNCE) >= xx) ) xx = xxo; else xxo = xx;
      if ( ((yyo - TS_DEBOUNCE) <= yy) && ((yyo + TS_DEBOUNCE) >= yy) ) yy = yyo; else yyo = yy;
      if (  twoHits && (xx != lastxx || yy != lastyy) ) {
        lastxx = xx; lastyy = yy;
      }
      if ( 500 == lastyy) TS_iiSlide = -1;
      lastxx = 500; lastyy = 500;
      return true;
    }
    
    // int8_t ButtonType( int16_t idBut ) {   return buttons[idBut].btype; }
    
    void ButtonDraw( int16_t idBut ) {
      int ii = 0;
      while ( ii < TS_bCount ) {
        if ((( TS_pbtn[ii].tx + TS_pbtn[ii].ww ) <= TS_xMax ) && (( TS_pbtn[ii].ty + TS_pbtn[ii].hh ) <= TS_yMax)) {
          if ( !idBut || idBut == TS_pbtn[ii].bId ) {
            if ( TS_TOGOFF == TS_pbtn[ii].btype || TS_FBUTN == TS_pbtn[ii].btype || TS_RBUTN == TS_pbtn[ii].btype || TS_BSLIDE == TS_pbtn[ii].btype ) {
              if (TS_RBUTN == TS_pbtn[ii].btype) {
                tft.fillRoundRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].hh / 2, TS_pbtn[ii].bgc);
              }
              else
                tft.fillRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].bgc);
              tft.setCursor(TS_pbtn[ii].tx + 6, TS_pbtn[ii].ty + (TS_pbtn[ii].hh / 3));
              tft.setTextColor(TS_pbtn[ii].fgc);  // ForeGround Text color same as Frame
              tft.setTextSize(TS_pbtn[ii].fontsz);
              tft.println(TS_pbtn[ii].text);
            }
            else if ( TS_TOGON == TS_pbtn[ii].btype || TS_ASLIDE == TS_pbtn[ii].btype )
              tft.fillRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].fgc);
          }
        }
        ii++;
      }
      ii = 0;
      while ( ii < TS_bCount ) {
        if ((( TS_pbtn[ii].tx + TS_pbtn[ii].ww ) <= TS_xMax ) && (( TS_pbtn[ii].ty + TS_pbtn[ii].hh ) <= TS_yMax)) {
          if ( !idBut || idBut == TS_pbtn[ii].bId ) {
            if ( TS_FRAME == TS_pbtn[ii].btype || TS_FBUTN == TS_pbtn[ii].btype )
              tft.drawRect(TS_pbtn[ii].tx, TS_pbtn[ii].ty, TS_pbtn[ii].ww, TS_pbtn[ii].hh, TS_pbtn[ii].fgc);
          }
        }
        ii++;
      }
    }
    
    boolean ButtonHit( int16_t xx, uint16_t yy, int16_t &bHit ) {
      static elapsedMillis toggleTime;  // Debounce/Jitter Toggle and Slider
      int16_t ii = 0, iiOn = -1, iiHit = -1, idTog = 0, iiFrame = -1;
      if ( toggleTime > 10000 ) toggleTime = 1000;
      while ( ii < TS_bCount ) {
        if  ( (xx >= TS_pbtn[ii].tx && xx <= TS_pbtn[ii].tx + TS_pbtn[ii].ww) && (yy >= TS_pbtn[ii].ty && yy <= TS_pbtn[ii].ty + TS_pbtn[ii].hh)) {
          if ( TS_ASLIDE == TS_pbtn[ii].btype ) {
            TS_iiSlide = TS_pbtn[ii].info; // track slide start - do nothing now
            return false;
          }
          else if ( (TS_FBUTN == TS_pbtn[ii].btype) || TS_RBUTN == TS_pbtn[ii].btype ) {
            bHit =  TS_pbtn[ii].bId;
            TS_iiSlide = -1;
            return true;
          }
          else if (TS_TOGOFF == TS_pbtn[ii].btype) {
            iiHit = ii;
            idTog = (TS_pbtn[ii].info);
            TS_iiSlide = -1;
          }
          else if ( (TS_iiSlide == TS_pbtn[ii].info) && (TS_BSLIDE == TS_pbtn[ii].btype)) {
            iiHit = ii;
            idTog = (TS_pbtn[ii].info);
          }
        }
        ii++;
      }
      ii = 0;
      while ( ii < TS_bCount ) {
        if ( ((TS_TOGON == TS_pbtn[ii].btype) || (TS_ASLIDE == TS_pbtn[ii].btype)) && (idTog == TS_pbtn[ii].info) )
          iiOn = ii;
        if ( (TS_FRAME == TS_pbtn[ii].btype) && (idTog == TS_pbtn[ii].info) )
          iiFrame = ii;
        ii++;
      }
    
      if ( -1 != iiOn && -1 != iiFrame ) {
        if ( toggleTime < TS_JITTER ) {
          TS_iiSlide = -1;
          return false;
        }
        TS_pbtn[iiFrame].TS_data = !TS_pbtn[iiFrame].TS_data;
        bHit = TS_pbtn[iiHit].bId;
        if ( TS_iiSlide == TS_pbtn[iiOn].info ) {
          TS_pbtn[iiOn].btype = TS_BSLIDE;
          TS_pbtn[iiHit].btype = TS_ASLIDE;
        }
        else {
          TS_pbtn[iiOn].btype = TS_TOGOFF;
          TS_pbtn[iiHit].btype = TS_TOGON;
        }
        ButtonDraw( TS_pbtn[iiOn].bId );  // Limit Redraw to Framed TS_pbtn - not all buttons
        ButtonDraw( TS_pbtn[iiHit].bId );
        ButtonDraw( TS_pbtn[iiFrame].bId );
        TS_iiSlide = -1;
        toggleTime = 0;
        return true;
      }
      return false;
    }
    
    void  ButtonRotate( int setrotate )
    {
      TS_Rotate = setrotate;
      if ( TS_Rotate > 4 ) TS_Rotate = 1;
      if ( TS_Rotate < 1 ) TS_Rotate = 4;
      tft.setRotation(TS_Rotate);
      if ((TS_Rotate % 2)) {
        TS_xMax = tsMap[1].xb;
        TS_yMax = tsMap[1].yr;
      }
      else {
        TS_xMax = tsMap[1].yr;
        TS_yMax = tsMap[1].xb;
      }
      /*Serial.print( "\nTS_xMax =" );
      Serial.println( TS_xMax );
      Serial.print( "TS_yMax =" );
      Serial.println( TS_yMax );*/
    }
    
    void ButtonInit( TS_BUTTON *userbuttons )
    {
      if ( 0 == userbuttons ) {
        TS_pbtn = TS_NoButton;
        tft.fillScreen(ILI9341_BLUE);
        ButtonRotate( TS_Rotate );
      }
      else TS_pbtn = userbuttons;
      TS_bCount = 0;
      while ( -1 != TS_pbtn[TS_bCount].tx ) {
        TS_bCount++;
      }
      /*Serial.print( "Buttons count =" );
      Serial.println( TS_bCount );
      Serial.println( sizeof( TS_BUTTON) );*/
      ButtonDraw( 0 );
    }
    // -----------------------------------------
    // --- Button Code Ends here
    // -----------------------------------------
    
    
    // Eric's datacar support routines start here...
    
    void configscreen(void) {                                   // a lot of routines return to config screen..
          tft.fillScreen(bg1);
          ButtonInit( 0 );
          ButtonInit( &configscreen_l[0] );
          ButtonDraw( 0 );
          beep(beepTime);
          delay(1000);  //stop button rehits crudely?
    }
    
    void beep(int beeptime) {                                     // Elemental Beep function - not much going on here anyway...
      digitalWrite(beepPin, LOW);
      delay(beeptime);                                            // ..cause we just don't care, just make it beep the old fashioned way...
      digitalWrite(beepPin, HIGH);
    }
    
    void framWritelong(uint16_t address, unsigned long value) {   // write a long to four consecutive bytes.
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);
      fram.writeEnable(true);                                     //Write the 4 bytes into the eeprom memory.
      fram.write8(address, four);
      fram.writeEnable(false);
      fram.writeEnable(true);
      fram.write8(address + 1, three);
      fram.writeEnable(false);
      fram.writeEnable(true);
      fram.write8(address + 2, two);
      fram.writeEnable(false);
      fram.writeEnable(true);
      fram.write8(address + 3, one);
      fram.writeEnable(false);
    }
    
    void framWriteByte(uint16_t address, uint8_t value) {         // write a single byte..
      fram.writeEnable(true);
      fram.write8(address, value);
      fram.writeEnable(false);
    }
    
    unsigned long framReadlong(uint16_t address) {                 //Read the 4 bytes from the eeprom memory.
      long four = fram.read8(address);
      long three = fram.read8(address + 1);
      long two = fram.read8(address + 2);
      long one = fram.read8(address + 3);
      //Return the recomposed long by using bitshift.
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
    }
    
    uint8_t framReadByte(uint16_t address) {                       // read single byte
      return fram.read8(address);
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •