controlling TFT screen with 4.1 - outsource to Mega?

Status
Not open for further replies.

garcho

Member
Greetings Forumites,

I've been programming a digital synthesizer on a Teensy 4.1. There are quite a few parameters the user has control over. I want some of these parameters to be displayed on a screen. There are a few encoders and such, and I'm using the audio shield, so pins are at a premium.

I would like a bigger screen than something like the 1" OLED i2c screens I've used in the past. I have a larger version, which is a significant improvement, but I'd still rather have a bigger screen, more like 3.5". I would also like color, although that's not a deal breaker.

I bought a `9486 3.5" TFT screen, on a Uno/Mega shield. It's exactly what I'm looking for. It also has touchscreen abilities. That interests me because it could mean some of the "deeper" functions could be touchscreen buttons instead of menu diving with an encoder, or something like that. I like the image quality, and smaller fonts are very easy to read. The default font is not transparent, which is great, because then I don't need to refresh the entire screen each time something changes. Because it's on a shield, I'm using it with an Arduino Mega. If I can control this with the Teensy, that would only require 1 pin for TX, or 2 if I figure out the touchscreen stuff. So far, so good.

Here is my question, having very little experience with µC and programming:

How realistic is my dream of sending display information from a Teensy 4.1 to a Arduino Mega, to be displayed on the TFT Mega shield?

I've dug around this and a few other forums for information, but I've had difficulty finding anything specific to Teensy 4.1. My idea as of now is to just use Serial, one of Teensy's TX to one of the Mega's RX that's not being used/blocked by the TFT shield. I'm a bit nervous of the Teensy 4.1's intolerance for 5V. The Mega's RX will never output 5V, correct? Is that something to worry about? I've read from Paul S, that the Arduino will "understand" the lower voltage from the Teensy, so I'm not concerned about that for now.

I mentioned touchscreen buttons earlier, I assume that would definitely need some finessing to deal with Mega 5V and T4.1 at 3V3, since the data would be going to the T4.1 instead of from it. This is from Paul S:

You must reduce Uno's transmit signal to 3.3V, before connecting to Teensy LC. A pair of resistors can be used. 2.2K and 3.3K will work.

Any reason to think that won't work in this case, from the Mega to the T4.1? Again, I'm assuming an easy way to do this is via serial from the Mega to the Teensy.

What I want to display are things like "OSC B Pitch Shift +7", or "VCF LFO Waveform: SINE", or a float like "SUSTAIN VAL: 0.45", to be updated when values change. I've done that before using i2c screens, like the aforementioned OLED, or old school LCDs. I plan on just plucking the data from the synth sketch and sending it over as text to be displayed on the TFT. Any thoughts, recommendations, advice? Is Serial the way to go? I'm playing with serial sketches now to learn more about parsing data and that kind of stuff, but this is new to me. Am I on the right path?

Thanks for your time, cheers
 
The MEGA would present 5V on the Rx pin so that is a concern. But using a resistor on that connect would seem to also drop the 3.3V from the Teensy to the MEGA so it may no longer see the digital HIGH?

Perhaps a suitable Level Shifter would be needed instead?
 
The usual Fet and two resistor level shifter works well in this situation.

I've found the Mega to be an electrically noisy board and displays can add their share of noise as well. Hooking 'em up to an audio project can introduce noise and cause some tail-chasing. Suggest using optocouplers and thinking of isolated power supply/s to design out noise from the outset.
 
Last edited:
^ yeah, I've run in to that before, especially with OLEDs. Decoupling caps helped a lot too. Thanks for the tip
 
As for if this is the right direction? Hard to say. There are lots of different displays that have touch screens and the like. Note: Normal caveat I am a retired software guy so not EE...

Example the one that PJRC sells, which is 2.8": https://www.pjrc.com/store/display_ili9341_touch.html
Adafruit also sells others with the ILI9341 as well.

Likewise the ILI9488 and HX8357 and the like that are in the 3.5

Then there are larger ones like RA8875 and RA8876...

As for is it better for your project to use two processor boards versus one? Again hard to say. I guess the Question is why the Mega? Are you trying to get faster speeds on the ILI9486 through parallel buss? Again if it is for the speed, will you have a bottleneck getting the data from T4 to Mega over Serial?


If going to two boards, as running out of pins. Not sure if there are better options?
Like maybe MUX for digital or analog inputs?
If things like buttons, can maybe arrange them in a keypad like matrix, where for example you can read in 16 buttons with 8 pins, with something like the KeyPad library

Again hard to know...
 
Mainly, my free pins are shrinking in number because of the Audio Shield, and using encoders. I plan on using shift registers for things like the push buttons, the encoder switches, any LED indicators, that kind of thing. As far as the display, it seems something along the lines of what you linked to (PJRC store) and the display I already have (this one) will require around 10 pins, if the audio shield uses about 13, then I'm already at 23 pins used, not including encoders (i'm hoping for 8), par/ser shifting, and anything else that needs a pin, hence the allure of using one TX pin. Like I said, I'm using the T4.1.

why the Mega? Are you trying to get faster speeds on the ILI9486 through parallel buss?
Well, I could use the Uno as well, but the Mega has accessible pins that aren't covered up by the shield. And it prints to the screen faster. I had the screen, I had the Mega (cheap generic one), so I figured, hey, why not try it. I'm not sure how else I would use this shield (i2c, spi?).

I have the Mega receiving serial from an Uno, and displaying that on the screen. It works fine so far, although this is all new territory for me and I can't imagine I'm doing it in a very wise fashion. I've attached the send and receive sketches, in case that sheds any light on what I'm trying to do. Right now the Uno is sending via SUART 3 pieces of data, a char array, a float, and an int. The char is the name of the parameter, the float is the value of the parameter, and the int is a tag, so that way the Mega knows where on the screen to print the data, depending on what parameter it is. The serial print has <> tags, and the '=' is used to separate the data. I barely understand this part. I'm cobbling things together from library examples, shooting in the dark. For instance, I noticed that 9600 baud and 112500 baud rates gave slightly glitchy results (data on screen and in the monitor would occasionally be off or not refresh). I randomly tried 57600 and all the glitchiness went away. Is that what you were talking about with bottleneck and speed? Serial communication is new to me, outside of good old MIDI. Thanks for your time!

SENDER CODE:

Code:
/////////////////
// Sender Code //
/////////////////
// 202012111338

#include <Bounce.h>
// made a button to test printing by changing values
Bounce updateButton = Bounce(12, 15);

#include <SoftwareSerial.h>  // for serial com
SoftwareSerial SUART(2, 3); //SRX = 2 of UNO

#include <PrintEx.h>  // library for serial com 
PrintEx myPrint = SUART;

//===========================================================================

int oscAFreqSpot = 1;
int oscBFreqSpot = 2;
int oscAWaveSpot = 3;

float oscAFreq = 220; 
float oscBFreq = 440;
float oscAWave = 2;

float oscAFreqOLD;
float oscBFreqOLD;
float oscAWaveOLD;

bool valueChange = false;

/////////////////////////////////////////////////////////////////////////////
                                                          
void setup(){                                             
  
  Serial.begin(57600); 
  SUART.begin(57600); // this baud rate produced no errors (the others did)

  pinMode(12, INPUT_PULLUP);
  myPrint.printf("<OscAFreq = %.2f, %.1d\n>", oscAFreq, oscAFreqSpot);
  myPrint.printf("<OscBFreq = %.2f, %.1d\n>", oscBFreq, oscBFreqSpot);
  myPrint.printf("<OscAWave = %.2f, %.1d\n>", oscAWave, oscAWaveSpot);
  
} // setup
                                                     
////////////////////////////////////////////////////////////////////////////
                                                        
void loop() {

  updateButton.update();
  if (updateButton.fallingEdge()){
    valueChange = !valueChange;
    Serial.println(valueChange);
    if (valueChange == true){
      oscAFreq = 333;
      oscBFreq = 111;
      oscAWave = 2;
    }
    if (valueChange == false){
      oscAFreq = 666;
      oscBFreq = 123;
      oscAWave = 3;
    }
  } // updateButton
  
  runDisplayUpdate();

} // loop

////////////////////////////////////////////////////////////////////////////

void runDisplayUpdate(){
 
  if (oscAFreqOLD != oscAFreq){
    myPrint.printf("<OscAFreq = %.2f, %.1d\n>", oscAFreq, oscAFreqSpot);
    oscAFreqOLD = oscAFreq;
  }
  if (oscBFreqOLD != oscBFreq){
    myPrint.printf("<OscBFreq = %.2f, %.1d\n>", oscBFreq, oscBFreqSpot);
    oscBFreqOLD = oscBFreq;
  }
  if (oscAWaveOLD != oscAWave){
    myPrint.printf("<OscAWave = %.2f, %.1d\n>", oscAWave, oscAWaveSpot);
    oscAWaveOLD = oscAWave;
  }

} // runDisplayUpdate



and here's the RECEIVER CODE:

Code:
///////////////////
// Receiver Code //
///////////////////
// 202012111338

#include <Adafruit_GFX.h>    // Core graphics library

#include <MCUFRIEND_kbv.h>   // Hardware-specific library
MCUFRIEND_kbv tft;

#include<SoftwareSerial.h>
SoftwareSerial  SUART(51, 53); // for MEGA

//===========================================================================

const byte numChars = 32;    // temporary array for use when parsing
char receivedChars[numChars];
char tempChars[numChars];        

char messageFromPC[numChars] = {0}; // variables to hold the parsed data
int integerFromPC = 0;
float floatFromPC = 0.00;

boolean newData = false;

#define BLACK   0x0000
#define RED     0xF800
#define GREEN   0x07E0
#define WHITE   0xFFFF
#define GREY    0x8410

int itemNum;
int positionNum;

//////////////////////////////////////////////////////////////////////////////

void setup() {
  
  Serial.begin(57600); 
  SUART.begin(57600);  /// this baud rate produced no errors (the others did)

  tft.begin(0x9486);
  tft.setRotation(0);
  tft.fillScreen(BLACK);
  tft.setFont(NULL);
  tft.setTextColor(WHITE, BLACK);
    
} // setup

//////////////////////////////////////////////////////////////////////////////

void loop() {
  
  recvWithStartEndMarkers();
  if (newData == true) {
    strcpy(tempChars, receivedChars);
    // this temporary copy is necessary to protect the original data
    // because strtok() used in parseData() replaces the commas with \0
    parseData();
    showParsedData();
    newData = false;
  }
    
} // loop

////////////////////////////////////////////////////////////////////////////////

void recvWithStartEndMarkers() {
    
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;

  while (SUART.available() > 0 && newData == false) {
    rc = SUART.read();
    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        ndx++;
          if (ndx >= numChars) ndx = numChars - 1;         
      }else{
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }else if (rc == startMarker) {
      recvInProgress = true;
    }
  } // while
  
} // recvWithStartEndMarkers

//===========================================================================

void parseData() {      // split the data into its parts

  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars," = ");  // get the first part - the string
  strcpy(messageFromPC, strtokIndx);     // copy it to messageFromPC
  //strtokIndx = strtok(NULL, " = ");    // this continues where the previous call left off
  //integerFromPC = atoi(strtokIndx);    // convert this part to an integer
  strtokIndx = strtok(NULL, " = ");
  floatFromPC = atof(strtokIndx);        // convert this part to a float
  strtokIndx = strtok(NULL, ",");
  integerFromPC = atoi(strtokIndx);
} // parseData

//===========================================================================

void showParsedData() {
  
  Serial.print(messageFromPC);
  Serial.print(" = ");
  Serial.println(floatFromPC);

  if (integerFromPC == 1){
    tft.setTextSize(2);
    tft.setCursor(0, 0);
    tft.print(messageFromPC);
    tft.setCursor(120, 0);
    tft.print(floatFromPC);
  }

  if (integerFromPC == 2){
    tft.setTextSize(2);
    tft.setCursor(0, 50);
    tft.print(messageFromPC);
    tft.setCursor(120, 50);
    tft.print(floatFromPC);
  }

  if (integerFromPC == 3){
    tft.setTextSize(2);
    tft.setCursor(0, 100);
    tft.print(messageFromPC);
    tft.setCursor(120, 100);
    if (floatFromPC > 1 && floatFromPC < 3){
      tft.print("SINE    ");  
    }
    if (floatFromPC > 2 && floatFromPC < 4){
      tft.print("SQUARE  ");  
    }  
  }

} // showParsedData
 
Status
Not open for further replies.
Back
Top