playSdWav1.stop (on btn1) doesn't work - what do I wrong?!

ACME

Active member
Hi Pals

I use the T4.1 Audio Shield Rev D with ILI9341 TFT Display and was following (mostly) the steps in the Tutorials by Alysia and Paul.
Unfortunately I do anything wrong because the STOP Function won't work by pressing Button1. Actually I won't stop the File, I want to pause/play
the Audio. I was looking for Posts which contains this issue but didn't found any with THIS issue.

C++:
// read pushbuttons
  button0.update();
  if (button0.fallingEdge()) {
    playSdWav1.stop();
  }

while (button1.update())
      playSdWav1.stop();
 

  button2.update();
  if (button2.fallingEdge()) {
    playSdWav1.stop();
    filenumber = filenumber - 2;
    if (filenumber < 0) filenumber = filenumber + 4;
  }

The Buttons 0 and 2 works perfectly as they should. Also Knob A2 for Volume Ramping.
As long I keep btn1 pushed, it will do the fallingEdge variable (and plays the prev or next file, even I release the btn) . If I don't push the btn1, the Player starts repeatly in loop.

Please forgive me Paul for this critical question, but why you havn't written a simple [stop] / [play] / [pause] variable in the .h File? playSdWav1.stop is declared by "stop(); Stop playing. If not playing, this function has no effect.". But how to make it work within the void loop?

Further there is a small problem on the TFT, I don't know how to code the screen update (destroy) to show the next filename on the Top of the Meters.

Dear Friends, I would be apprechiated for any help - I know I have a long way to go until I become the right understanding
❤️
 
Hi,ACME
Why don't you use an " if condition " like: if( !playSdWav1.stop())
I'm not sure if there is a boolean you can use inside playSdWav1.stop(bool?)
 
Hi,ACME
Why don't you use an " if condition " like: if( !playSdWav1.stop())
I'm not sure if there is a boolean you can use inside playSdWav1.stop(bool?)
Hi AntiLoop,

thanks for your reply.

As I mentioned above, it won't work - the same with a "if" condition. If I try to put something in the void, the compiler tells me, that he can't convert a void to bool. To me it's absolutely unclear how I can stop the player because there is no clear functions declared to use for

But I think, @Paul surely can give me the solution, he's the creator, but at first he need to read my post at first if he's online. Also I bet the variables for it will be simple - if you know which.

I will replyr later, I didn't sleep last night and pillow screams for me...
 
I scratched my head too,
but i made a simple button test in the loop:

Code:
// read pushbuttons


  button0.update();

  if (button0.fallingEdge()) {

    playSdWav1.play("sdtest1.wav");

  }


button2.update();

  if (button2.fallingEdge()) {

    playSdWav1.stop();   

  }

That works because of the antinomy between play() and stop()
i think the bad stuff is in the

Code:
if (playSdWav1.isPlaying() == false) {

    const char *filename = filelist[filenumber];

    filenumber = filenumber + 1;

    if (filenumber >= 2) filenumber = 0;

    Serial.print("Start playing ");

    Serial.println(filename);

    playSdWav1.play(filename);

    delay(10); // wait for library to parse WAV info

  }

Please Paul helps us,have pity on us :cry:
 
I scratched my head too,
but i made a simple button test in the loop:

Code:
// read pushbuttons


  button0.update();

  if (button0.fallingEdge()) {

    playSdWav1.play("sdtest1.wav");

  }


button2.update();

  if (button2.fallingEdge()) {

    playSdWav1.stop();  

  }
That's the point. It is the original code from the Tutorial. May be I'm too stupid... But in my opinion the .stop does its job and also it depends on .fallingEdge (pushed) and .risingEdge (released) for switching the state. I'm testing right now several code snippets to get the wanted results.

@Paul I feel pittiful due this happening and I don't get it...
 
This is a modified version of the Part_1_05_Do_More_While_Playing audio tutorial example.


button0 stops the current file and plays the next one
button1 is a toggle which pauses the current file or resumes playing it
button2 stops the current file and plays the previous one

Pete

Code:
// https://forum.pjrc.com/index.php?threads/playsdwav1-stop-on-btn1-doesnt-work-what-do-i-wrong.75600/

// Advanced Microcontroller-based Audio Workshop
//
// http://www.pjrc.com/store/audio_tutorial_kit.html
// https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015
// 
// Part 1-5: Respond to Pushbuttons & Volume Knob
//
// Do more while playing.  Monitor pushbuttons and adjust
// the volume.  When the buttons are pressed, stop playing
// the current file and skip to the next or previous.

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <Bounce.h>

AudioPlaySdWav           playSdWav1;
AudioOutputI2S           i2s1;
AudioConnection          patchCord1(playSdWav1, 0, i2s1, 0);
AudioConnection          patchCord2(playSdWav1, 1, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;

// button0 is STOP current file and play the next in sequence
Bounce button0 = Bounce(0, 15);
// button1 is PAUSE/RESUME current one
Bounce button1 = Bounce(1, 15);
// Button2 is STOP current one and play the previous one 
Bounce button2 = Bounce(2, 15);  // 15 = 15 ms debounce time

// Use these with the Teensy Audio Shield
#define SDCARD_CS_PIN    10
#define SDCARD_MOSI_PIN  7   // Teensy 4 ignores this, uses pin 11
#define SDCARD_SCK_PIN   14  // Teensy 4 ignores this, uses pin 13

// Use these with the Teensy 3.5 & 3.6 & 4.1 SD card
//#define SDCARD_CS_PIN    BUILTIN_SDCARD
//#define SDCARD_MOSI_PIN  11  // not actually used
//#define SDCARD_SCK_PIN   13  // not actually used

// Use these for the SD+Wiz820 or other adaptors
//#define SDCARD_CS_PIN    4
//#define SDCARD_MOSI_PIN  11
//#define SDCARD_SCK_PIN   13

#define LED_PIN    5
//#define LED_PIN LED_BUILTIN

void setup() {
  Serial.begin(9600);
  AudioMemory(8);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.15);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }
  pinMode(LED_PIN, OUTPUT);
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  delay(1000);
}

int filenumber = 0;  // while file to play

const char * filelist[4] = {
  "SDTEST1.WAV", "SDTEST2.WAV", "SDTEST3.WAV", "SDTEST4.WAV"
};

elapsedMillis blinkTime;

void loop() {
  /*
   * Play the next file in sequence if the current one is
   * not playing and is not paused  
   */
  if (!playSdWav1.isPaused() && (playSdWav1.isPlaying() == false)) {
    const char *filename = filelist[filenumber];
    filenumber = filenumber + 1;
    if (filenumber >= 4) filenumber = 0;
    Serial.print("Start playing ");
    Serial.println(filename);
    playSdWav1.play(filename);
    delay(150); // wait for library to parse WAV info
    while(playSdWav1.isPlaying() == false);
  }
  
  // blink the LED without delays
  if (blinkTime < 250) {
    digitalWrite(LED_PIN, LOW);
  } else if (blinkTime < 500) {
    digitalWrite(LED_PIN, HIGH);
  } else {
    blinkTime = 0; // start blink cycle over again
  }
  
  // read pushbuttons
  button0.update();
  if (button0.fallingEdge()) {
    playSdWav1.stop();
    Serial.printf("button0 NEXT\n");
  }
  button1.update();
  if (button1.fallingEdge()) {
    Serial.printf("button1 PAUSE\n");
    playSdWav1.togglePlayPause();
  }
  button2.update();
  if (button2.fallingEdge()) {
    playSdWav1.stop();
    filenumber = filenumber - 2;
    if (filenumber < 0) filenumber = filenumber + 4;
    Serial.printf("button2 PREV\n");
  }
  
  // read the knob position (analog input A2)

  int knob = analogRead(A2);
  float vol = (float)knob / 1280.0;
  sgtl5000_1.volume(vol);

  //Serial.print("volume = ");
  //Serial.println(vol);
}
 
Pete, thanks a thousand times! As I saw the Update-Section, it was like a fall into cold water... So obviously the conditions - I was several times that close, I could bit myself right now. A bit more on it than met the eyes.

Might be that I will have soon a couple more questions this Project, perhaps if it goes into the Synth part. Also may I ask your for advices by PM if it must be?

There's just one more tine issue... As I mentioned above, I have no clue how to make the Caption for the file change, f.g. the filename from filelist (on Top Line of the ILI9341 TFT where normally the "Peak Meter" as Caption is. I'm trying right now and play around with it.

What I've done is this (at bottom) and it works great (the position for "Left" and "Right" below the Meter gets shown): However, trough the tft.fillRect (as placeholder) the position of the previous print gets always destroyed - actually this is exactly what I need to show up the new filname if the Songtitle changes. So, I'm on it, but in spite it would be nice and I hope you can give me an advice or code snippet to speed up that whole.



C++:
if (msecs > 15) {
    if (peak1.available() && peak2.available()) {
      msecs = 0;
      float leftNumber = peak1.read();
      float rightNumber = peak2.read();
      Serial.print(leftNumber);
      Serial.print(", ");
      Serial.print(rightNumber);
      Serial.println();

      // draw the verticle bars
      int height = leftNumber * 240;
      tft.fillRect(60, 280 - height, 40, height, ILI9341_GREEN);
      tft.fillRect(60, 280 - 240, 40, 240 - height, ILI9341_BLACK);
      height = rightNumber * 240;
      tft.fillRect(140, 280 - height, 40, height, ILI9341_GREEN);
      tft.fillRect(140, 280 - 240, 40, 240 - height, ILI9341_BLACK);
      // a smarter approach would redraw only the changed portion...

      // draw numbers underneath each bar
      tft.setFont(Arial_14);
      tft.fillRect(60, 284, 40, 16, ILI9341_BLACK);
      tft.setCursor(60, 284);
      tft.print(leftNumber);
      tft.fillRect(140, 284, 40, 16, ILI9341_BLACK);
      tft.setCursor(140, 284);
      tft.print(rightNumber);
----------------------------------------------------------------
      tft.fillRect(61, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(61, 300);
      tft.print("Left");

      tft.fillRect(138, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(138, 300);
      tft.print("Right");
-----------------------------------------------------------------
    }
  }
}

And here a Picture how it looks right now with L and R

TFT.png


Also thanks to AntiLoop for the suggestions ;)


John
 
Last edited:
I think in principe you have to redraw all what is changing at a particular place,numbers,vertical lines,song names...
but i 'm not sure what you really want,i can't see where should be the filename,song title,under left & right numbers?
 
but i 'm not sure what you really want,i can't see where should be the filename,song title,under left & right numbers?
Sorry Bro, what's so unclear? Meanwhile I did the whole arrangement new. Guess what? YEAH Baby it works! And it's still lots of space left for more Text and Graphics (f.g. Play Status like Play, Pause, FWD, REV - and... all with touch (up next).

(It will take a couple seconds until the Picuture gets focused)

And here is the Code:
C++:
// Advanced Microcontroller-based Audio Workshop
//
// http://www.pjrc.com/store/audio_tutorial_kit.html
// https://hackaday.io/project/8292-microcontroller-audio-workshop-had-supercon-2015
//
// Part 3-3: Add a TFT Display (!)MODIFIED(!)
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
#include <ILI9341_t3.h>
#include <font_Arial.h> // from ILI9341_t3
#include <Bounce.h>

///////////////////////////////////
// copy the Design Tool code here
///////////////////////////////////
// GUItool: begin automatically generated code
AudioPlaySdWav           playSdWav1;     //xy=666,178
AudioOutputI2S           i2s1;           //xy=939,147
AudioAnalyzePeak         peak1;          //xy=942,216
AudioAnalyzePeak         peak2;          //xy=943,264
AudioConnection          patchCord1(playSdWav1, 0, peak1, 0);
AudioConnection          patchCord2(playSdWav1, 0, i2s1, 0);
AudioConnection          patchCord3(playSdWav1, 1, peak2, 0);
AudioConnection          patchCord4(playSdWav1, 1, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=622,329
// GUItool: end automatically generated code

// button0 is STOP current file and play the next in sequence
Bounce button0 = Bounce(0, 15);
// button1 is PAUSE/RESUME current one
Bounce button1 = Bounce(1, 15);
// Button2 is STOP current one and play the previous one
Bounce button2 = Bounce(2, 15);  // 15 = 15 ms debounce time

// Use these with the Teensy 4.x and Audio Shield Rev D or D2
#define TFT_DC       9
#define TFT_CS      22
#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);

// Use these with the Teensy Audio Shield
//#define SDCARD_CS_PIN    10
//#define SDCARD_MOSI_PIN  7   // Teensy 4 ignores this, uses pin 11
//#define SDCARD_SCK_PIN   14  // Teensy 4 ignores this, uses pin 13

// Use these with the Teensy 3.5 & 3.6 & 4.1 SD card
#define SDCARD_CS_PIN    BUILTIN_SDCARD
#define SDCARD_MOSI_PIN  11  // not actually used
#define SDCARD_SCK_PIN   13  // not actually used

#define LED_PIN    13//BUILDIN_LED
//#define LED_PIN LED_BUILTIN

void setup() {
  Serial.begin(9600);
  delay(500);
  tft.setClock(16000000);
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setFont(Arial_28);
  //tft.setTextSize(1);
  tft.setCursor(25, 8); //L and R on 68, 8 is center with Arial_28
  tft.println("X-PLAYER");
  //tft.setFont(Arial_16);
  //tft.setCursor(55, 50);
  //tft.println("FILE_NAME");

  AudioMemory(10);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  SPI.setMOSI(SDCARD_MOSI_PIN);
  SPI.setSCK(SDCARD_SCK_PIN);
  if (!(SD.begin(SDCARD_CS_PIN))) {
    while (1) {
      Serial.println("Hey dude... SD-Card not found!");
      delay(500);
    }
  }
  pinMode(0, INPUT_PULLUP);
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  delay(1000);
}

int filenumber = 0;  // while file to play

const char * filelist[4] = {
  "SDTEST1.WAV", "SDTEST2.WAV", "SDTEST3.WAV", "SDTEST4.WAV"
};

elapsedMillis msecs;
elapsedMillis blinkTime;

void loop() {

//if (playSdWav1.isPlaying() == false) {
  if (!playSdWav1.isPaused() && (playSdWav1.isPlaying() == false)) {
    const char *filename = filelist[filenumber];
    filenumber = filenumber + 1;
    if (filenumber >= 4) filenumber = 0;
    Serial.print("Start playing ");
    Serial.println(filename);
 
    if (msecs > 15) {
     // if (peak1.available() && peak2.available()) {
      msecs = 0;
     // float leftNumber = peak1.read();
     // float rightNumber = peak2.read();
    //  Serial.print(leftNumber);
    tft.setCursor(1, 50);
    tft.fillRect(1, 50, 240, 60, ILI9341_BLACK);
    tft.setFont(Arial_14);
    tft.print("Playing: "), tft.print(filename);
    }
 
    playSdWav1.play(filename);
    delay(10); // wait for library to parse WAV info
  }
 
  // blink the LED without delays
  if (blinkTime < 250) {
    digitalWrite(LED_PIN, LOW);
  } else if (blinkTime < 500) {
    digitalWrite(LED_PIN, HIGH);
  } else {
    blinkTime = 0; // start blink cycle over again
  }

// read pushbuttons
  button2.update();
  if (button2.fallingEdge()) {
    playSdWav1.stop();
    Serial.printf("button2 NEXT\n");
  }
  button1.update();
  if (button1.fallingEdge()) {
    Serial.printf("button1 PAUSE\n");
    playSdWav1.togglePlayPause();
  }
  button0.update();
  if (button0.fallingEdge()) {
    playSdWav1.stop();
    filenumber = filenumber - 2;
    if (filenumber < 0) filenumber = filenumber + 4;
    Serial.printf("button0 PREV\n");
  }

  // read the knob position (analog input A2)
  int knob = analogRead(A2);
  float vol = (float)knob / 1280;
  sgtl5000_1.volume(vol);
  //Serial.print("volume = ");
  //Serial.println(vol);

  if (msecs > 15) {
    if (peak1.available() && peak2.available()) {
      msecs = 0;
      float leftNumber = peak1.read();
      float rightNumber = peak2.read();
      Serial.print(leftNumber);
      Serial.print(", ");
      Serial.print(rightNumber);
      Serial.println();

      // draw the verticle bars
      int height = leftNumber * 200;
      tft.fillRect(20, 280 - height, 40, height, ILI9341_GREEN);
      tft.fillRect(20, 280 - 200, 40, 200 - height, ILI9341_BLACK);
      height = rightNumber * 200;
      tft.fillRect(65, 280 - height, 40, height, ILI9341_GREEN);
      tft.fillRect(65, 280 - 200, 40, 200 - height, ILI9341_BLACK);
      // a smarter approach would redraw only the changed portion...

      // draw numbers underneath each bar
      tft.setFont(Arial_14);
      tft.fillRect(20, 284, 40, 16, ILI9341_BLACK);
      tft.setCursor(20, 284);
      tft.print(leftNumber);
      tft.fillRect(65, 284, 40, 16, ILI9341_BLACK);
      tft.setCursor(65, 284);
      tft.print(rightNumber);

      /*tft.fillRect(140, 284, 40, 16, ILI9341_BLACK);
      tft.setCursor(140, 284);
      tft.print(filename);
*/
      tft.fillRect(18, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(18, 300);
      tft.print("Left");
      tft.fillRect(60, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(60, 300);
      tft.print("Right");

      //tft.fillRect(120, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(120, 300);
      tft.print("Volume: ");
      tft.fillRect(190, 300, 40, 16, ILI9341_BLACK);
      tft.setCursor(190, 300);
      tft.println(vol);
    }
  }
}

What be would interesting is how to remap the Vol Percentage in the print output. Instead of 0.xx it would be nice to get a scale from 0 to 100
further suggestions anybody?

So, thanks again and cheers!
John
 
Last edited:
hey i like it ! ,very reactive display animation (y)

I'd better see the peak meters level 0->100 but upon the meters and keep the left & right under,
and why not orange - red colors for the max volumes,it would be a firework!
i think in the examples of ILI9341_t3 library there is such peak meters.
felicitations!
 
For your scale problem ,i finally found a typecast float->string and multiplication to adapt the left ,right,volume
Here are the exerpts:

Code:
tft.print(String(leftNumber*100,0));
 .
 .
tft.print(String(rightNumber*100,0));
.
.
.
tft.println(String(vol*100,0));

the String(number,x) gives you nothing after the number if x=0,if x=2,you have 2 decimals (don't know the english name) after the number

It seems peak.read doesn't like byte or int,with typecast from String you can tft.print() almost what you want i think
edit: uint8_t could work with peak.read,if you look at "peak meter stereo" example
:)
 
Last edited:
For your scale problem ,i finally found a typecast float->string and multiplication to adapt the left ,right,volume
Here are the exerpts:

Code:
tft.print(String(leftNumber*100,0));
 .
 .
tft.print(String(rightNumber*100,0));
.
.
.
tft.println(String(vol*100,0));

the String(number,x) gives you nothing after the number if x=0,if x=2,you have 2 decimals (don't know the english name) after the number

It seems peak.read doesn't like byte or int,with typecast from String you can tft.print() almost what you want i think
edit: uint8_t could work with peak.read,if you look at "peak meter stereo" example
:)
Will give it a shot at the next opportunity, sounds interesting :cool:
 
Personally, I avoid using String objects...
Have you tried simply multiplying by 100? Like:
Code:
tft.print((int)(leftNumber * 100), DEC);
 
I just don't like String objects. They work if you need them, but the way the malloc/realloc... I just normally avoid them.
With Teensy 4.x, probably is not that critical, but with Atmega328 or the like...
 
Personally, I avoid using String objects...
Have you tried simply multiplying by 100? Like:
Code:
tft.print((int)(leftNumber * 100), DEC);
Hi and welcome to this Post, Kurt

So, no I didn't do that yet - but I will. Right now on it to try the TFT's touch to get running but it won't work yet. Could you help me with that?
This is the ILI9341_t3n Code (untouched):
C++:
#include <SPI.h>
#include <Wire.h>      // this is needed even tho we aren't using it
#include <ILI9341_t3n.h>
#include <Adafruit_STMPE610.h>

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000

// The STMPE610 uses hardware SPI on the shield, and #8
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);

// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 10
#define TFT_DC  9
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC);
I did just a few PIN changes to the T4.1 - TFT_CS was wired to PIN 22 before, now it's on PIN 10
The STMPE_CS is on PIN 8

I took off the Audioshield for that - and it doesn't work, I get always (Serial Monitor):
"Couldn't start touchscreen controller"

So... I was wondering if anything would be functional within the 1st try ever... But it isn't like that of course.
That makes me... not angry, but it's conquering always my expectations. Any Ideas?

John
 
What display are you using?

Why I ask:

Adafruit display you use or at least used to use the Adafruit_STMPE610 library and the like.
I have not looked in awhile if Adafruit still sells boards using the ILI9341 and if they are, are they still using
the same touch controller.

The ones sold by PJRC (and many like it on ebay/Amazon) use a different touch controller.
The PJRC ones use XPT2046_Touchscreen.h

There is an example sketch in my library: touchpaint_xpt2046 that was setup to use this controller...
 
#1 ILI9341
Yes it must be a XPT2046, the red one... or "new Generation" of TFT Displays - didn't thoght about that ;)
 
NOTE: the Adafruit resistive touchscreen TFT displays (Product #1651) no longer use the STMPE610 as the touch controller. . . they now use the TSC2007 as the touch controller.

Mark J Culross
KD5RXT
 
NOTE: the Adafruit resistive touchscreen TFT displays (Product #1651) no longer use the STMPE610 as the touch controller. . . they now use the TSC2007 as the touch controller.

Mark J Culross
KD5RXT
Don't worry, this is not the STMPE610 - it's as mentioned it's the XPT2046 ;)


For testing purposes I used the TouchTest.ino by CPT2046 Library and made this for the first

C++:
#include <XPT2046_Touchscreen.h>
#include <Wire.h>
#include <SPI.h>
#include <SerialFlash.h>
#include <ILI9341_t3.h>

#define CS_PIN  8
#define MOSI    11
#define MISO    12
#define SCLK     13

//XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN  2
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, 255);  // Param 2 - 255 - No interrupts


#define TFT_DC       9
#define TFT_CS      22
#define TFT_RST    255  // 255 = unused, connect to 3.3V
#define TFT_MOSI    11
#define TFT_SCLK    13
#define TFT_MISO    12

XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

void setup() {
  Serial.begin(38400);
  ts.begin();
  // ts.begin(SPI1); // use alternate SPI port
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

void loop() {
  if (ts.touched()) {
    TS_Point p = ts.getPoint();
    Serial.print("Pressure = ");
    Serial.print(p.z);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.print(p.y);
    delay(30);
    Serial.println();
  }
}

But I get this:


Pressure = 4095, x = 0, y = 0

Pressure = 4095, x = 0, y = 0

Pressure = 4095, x = 0, y = 0

Pressure = 4095, x = 0, y = 0

Pressure = 4095, x = 0, y = 0

Pressure = 4095, x = 0, y = 0

in the Serial Monitor


John
 
Last edited:
Sometimes I find you need to set all of the CS pins on the SPI bus to high before you try to init them. Some displays have built in PU resistors on their CS pins, but some of these cheap ones do not.

Something like:
CoffeeScript:
void setup() {
  Serial.begin(38400);
  pinMode(TFT_CS , OUTPUT);
  digitalWrite(TFT_CS, HIGH);
  ts.begin();
  // ts.begin(SPI1); // use alternate SPI port
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

Otherwise the display may be trying to intercept some of the messages going to/from the Touch part of the device
 
hey,ACME,how is it going with your display touch?
Have a try with that simple sketch:

Code:
//TESTING WITH AUDIO BOARD REV C & TEENSY 3.2 REV D & TEENSY 4X

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

#define CS_PIN  8//Touch CS
#define TFT_DC  9
#define TFT_CS 10
// MOSI=11, MISO=12, SCK=13,RST=3,3V

XPT2046_Touchscreen ts(CS_PIN);
#define TIRQ_PIN  2
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
//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

ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

void setup() {
  Serial.begin(115200);
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

boolean wastouched = true;

void loop() {
  boolean istouched = ts.touched();
  if (istouched) {
    TS_Point p = ts.getPoint();
    if (!wastouched) {
      tft.fillScreen(ILI9341_BLACK);
      tft.setTextColor(ILI9341_YELLOW);
      tft.setFont(Arial_60);
      tft.setCursor(60, 80);
      tft.print("Touch");
    }
    tft.fillRect(100, 150, 140, 60, ILI9341_BLACK);
    tft.setTextColor(ILI9341_GREEN);
    tft.setFont(Arial_24);
    tft.setCursor(100, 150);
    tft.print("X = ");
    tft.print(p.x);
    tft.setCursor(100, 180);
    tft.print("Y = ");
    tft.print(p.y);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.println(p.y);
  } else {
    if (wastouched) {
      tft.fillScreen(ILI9341_BLACK);
      tft.setTextColor(ILI9341_RED);
      tft.setFont(Arial_48);
      tft.setCursor(120, 50);
      tft.print("No");
      tft.setCursor(80, 120);
      tft.print("Touch");
    }
    Serial.println("no touch");
  }
  wastouched = istouched;
  delay(100);
}
 
Right now on it to install T4.1 libs for KiCad 7.0.7 also Symbols (weird to made this)
BTW - have opened Kurts FLEXSPI and trying all instances - Color Bars are there, but...
--------------------------------
Touch Paint!
Using SPI1 for Touch


Touchscreen started
--------------------------------

touch still won't work... I'm gonna to wire up all on teensy and ILI9341 without breadboards, just wire by wire to have a look if there is any issue with the touch panel itself... I'll hope not


John
 
Okay, now it have arrived new qualities: drawing works now but everything is flipside. If I draw upper left to right, it comes on the lower side right flipside to left on screen... desperate...

@KurtE


C++:
//#define KURTS_FLEXI

//****************************************************************************
// Touch options, Defaults to SPI
//****************************************************************************
// uncomment to try Touch on SPI1 pins
#define TOUCH_SPI1
// FlexSPI on SPI1 pins
//#define TOUCH_FLEXSPI


//****************************************************************************
// Includes
//****************************************************************************
#include <XPT2046_Touchscreen.h>
#include <ILI9341_t3n.h>

#ifdef TOUCH_FLEXSPI
#include <FlexIOSPI.h>
#include <FlexIO_t4.h>
#endif


//****************************************************************************
// This is calibration data for the raw touch data to the screen coordinates
//****************************************************************************
// Warning, These are
#define TS_MINX 337
#define TS_MINY 529
#define TS_MAXX 3729
#define TS_MAXY 3711

//****************************************************************************
// Settings and objects
//****************************************************************************
#if defined(KURTS_FLEXI)
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#define TOUCH_CS  8
#else
// *************** Change to your Pin numbers ***************
// VCC 3.3v PIN 1 red
//GND PIN 2 blk
#define TFT_CS 22 //3 CS orange
#define TFT_RST 8 //4 RESET blue
#define TFT_DC  9 //5 D/C yellow
#define TFT_MOSI 11 //6 SDI green
#define TFT_SCK 13 //7 SCK purple
// LED PIN 8 grey
#define TFT_MISO 12 //9 SDO white
//#define TOUCH_CS 6 //11
#endif

// If using SPI1 you can optionally setup to use other MISO pin on T4.1

#ifdef TOUCH_SPI1
#define TOUCH_SCK  27 //10 T_CLK blk2
#undef TOUCH_CS
#define TOUCH_CS  38 //11 T_CS whte2
#define TOUCH_MOSI 26 //12 T_DIN pple2
#define TOUCH_MISO 39 //13 T_OUT gry2
#endif

// Setup flexSPI on same pins as SPI1
#ifdef TOUCH_FLEXSPI
#define TOUCH_MOSI 26
#define TOUCH_MISO 39
#define TOUCH_SCK  27
#undef TOUCH_CS
#define TOUCH_CS  38
FlexIOSPI  flexspi(TOUCH_MOSI, TOUCH_MISO, TOUCH_SCK);
#endif

XPT2046_Touchscreen ts(TOUCH_CS);
ILI9341_t3n tft = ILI9341_t3n(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);

// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 2
int oldcolor, currentcolor;

//****************************************************************************
// Setup
//****************************************************************************
void setup(void) {
  while (!Serial && (millis() <= 1000));

  Serial.begin(9600);
  Serial.println(F("Touch Paint!"));

  tft.begin();

#if defined (TOUCH_SPI1)
  Serial.println("Using SPI1 for Touch\n");
  // Can setup to use SPI1
  #ifdef TOUCH_MISO 
  SPI1.setMISO(TOUCH_MISO);
  #endif
  if (!ts.begin(SPI1)) {
#elif defined(TOUCH_FLEXSPI)
  Serial.println("Using flexSPI for Touch\n");
  if (!ts.begin(flexspi)) {
#else
  // Or by default use SPI
  if (!ts.begin()) {
#endif
    Serial.println("Couldn't start touchscreen controller");
    while (1);
  }
  Serial.println("Touchscreen started");

  tft.fillScreen(ILI9341_BLACK);

  // make the color selection boxes
  tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
  tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
  tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
  tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
  tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
  tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);

  // select the current color 'red'
  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
  currentcolor = ILI9341_RED;
}


void loop()
{
  // See if there's any  touch data for us
  if (ts.bufferEmpty()) {
    return;
  }

  // You can also wait for a touch
  /*
  if (! ts.touched()) {
    return;
  }
*/

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

  // p is in ILI9341_t3 setOrientation 1 settings. so we need to map x and y differently.
/*
  Serial.print("X = "); Serial.print(p.x);
  Serial.print("\tY = "); Serial.print(p.y);
  Serial.print("\tPressure = "); Serial.print(p.z);
*/

  // Scale from ~0->4000 to tft.width using the calibration #'s
#ifdef SCREEN_ORIENTATION_1
  p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
#else
 
  uint16_t px = map(p.y, TS_MAXY, TS_MINY, 0, tft.width());
  p.y = map(p.x, TS_MINX, TS_MAXX, 0, tft.height());
  p.x = px;
#endif
/* 
    Serial.print(" ("); Serial.print(p.x);
    Serial.print(", "); Serial.print(p.y);
    Serial.println(")");
*/ 

  if (p.y < BOXSIZE) {
    oldcolor = currentcolor;

    if (p.x < BOXSIZE) {
      currentcolor = ILI9341_RED;
      tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 2) {
      currentcolor = ILI9341_YELLOW;
      tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 3) {
      currentcolor = ILI9341_GREEN;
      tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 4) {
      currentcolor = ILI9341_CYAN;
      tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 5) {
      currentcolor = ILI9341_BLUE;
      tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    } else if (p.x < BOXSIZE * 6) {
      currentcolor = ILI9341_MAGENTA;
      tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
    }

    if (oldcolor != currentcolor) {
      if (oldcolor == ILI9341_RED)
        tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
      if (oldcolor == ILI9341_YELLOW)
        tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
      if (oldcolor == ILI9341_GREEN)
        tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
      if (oldcolor == ILI9341_CYAN)
        tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
      if (oldcolor == ILI9341_BLUE)
        tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
      if (oldcolor == ILI9341_MAGENTA)
        tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
    }
  }
  if (((p.y - PENRADIUS) > BOXSIZE) && ((p.y + PENRADIUS) < tft.height())) {
    tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
  }
}

John
 
Typically, what I do, is to uncomment the lines in the sketch:

Code:
/*
  Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.print(p.z);
*/
and likewise:
Code:
/*
    Serial.print(" ("); Serial.print(p.x);
    Serial.print(", "); Serial.print(p.y);
    Serial.println(")");
*/

The touch screen knows nothing about display under it. That is it could care less what rotation you set the display code to.
So you set it up to print out the data coming in from it You then go to the 4 edges and get an idea of the Min and Max in both horizontal and vertical directions. And then setup mapping code that works for the direction you are going...

For example if you move the touch all the way to the left on the display in the orientation you want, and record the X, and y reported. Then move all the way to the right and do the same. and is it the Touch X or Y that mainly changed:
You can then use the map function to map it into screen orientation.

Suppose in your horizontal orientation, you found it was the Y that changed and Left was 3750 and at the right it was 500,
you can probably map it by saying x = map(p.x, 3750, 500, 0, 320);
And see how close it is...

I believe at one point @defragster had a more complete mapping for his display, that was setup to handle all 4 rotations.
 
Back
Top