kd5rxt-mark
Well-known member
I have a PJRC ILI9341 touchscreen connected to a Teensy 4.0. I use an #ifdef statement to switch between the default pins & the alternate pins (for when using the ILI9341 touchscreen display & the Audio Adapter on the same Teensy) as follows"
Both the display & touchscreen work as expected when making use of the default/standard pin definitions. I am now attempting to make use the ILI9341 touchscreen using the alternate pins so I can use the Teensy 4.0 + ILI9341 touchscreen + Audio Adapter Rev D. I must be overlooking something simple as I am not able to get the same program (w/ alternate pins defined & rewired) to display anything. In addition, the onboard LED is still blinking (which appears like something is still using PIN 13 as a clock) as it did before the pin changes.
Here's the full program that I am playing with (including the pin modifications in place):
Code:
// uncomment the next line to make use of the alternate pins (when used w/ Audio Adapter) for the display & touchscreen
#define USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
#ifndef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// By default, the display uses hardware SPI, with pin #9 as DataCommand & pin #10 as ChipSelect
// MOSI=11, MISO=12, SCK=13
const int TFT_CHIP_SELECT = 10;
const int TFT_DATA_COMMAND = 9;
ILI9341_t3 tft = ILI9341_t3(TFT_CHIP_SELECT, TFT_DATA_COMMAND);
#endif
#ifdef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// Alternate ILI9341 display pins (when used w/ Audio Adapter) for optimized ILI9341_t3 library
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
#endif
#ifndef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// By default, the touchscreen uses hardware SPI, with pin #9 as DataCommand & pin #8 as ChipSelect
// MOSI=11, MISO=12, SCK=13
#define TS_CS_PIN 8
#endif
#ifdef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// Alternate touchscreen pins (when used w/ Audio Adapter)
#define TS_CS_PIN 5
#endif
XPT2046_Touchscreen ts(TS_CS_PIN, 255);
Both the display & touchscreen work as expected when making use of the default/standard pin definitions. I am now attempting to make use the ILI9341 touchscreen using the alternate pins so I can use the Teensy 4.0 + ILI9341 touchscreen + Audio Adapter Rev D. I must be overlooking something simple as I am not able to get the same program (w/ alternate pins defined & rewired) to display anything. In addition, the onboard LED is still blinking (which appears like something is still using PIN 13 as a clock) as it did before the pin changes.
Here's the full program that I am playing with (including the pin modifications in place):
Code:
//
// TeensyChristmasTFT version 1.0 dated 12/24/2200 @1350
// written by Mark J Culross, KD5RXT (kd5rxt@arrl.net)
//
// Teensy 4.0/4.1 Configuration:
// Tools/Board: "Teensy 4.0"
// Tools/USB Type: "Serial"
// Tools/CPU Speed: "600MHz"
// Tools/Optimize: "Fastest"
// Tools/Keyboard Layout: "US English"
// Tools/Port: "COMx Serial (Teensy 4.0)"
//
//
#define VERSION1 F("TeensyChristmasTFT: Christmas tree & fireplace")
#define VERSION2 F("written by Mark J Culross (KD5RXT)")
#define VERSION3 F("version 1.0 dated 12/24/2020 @1350")
#include <ILI9341_t3.h>
#include <font_Arial.h> // from ILI9341_t3
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
// This is calibration data for the raw touch data to the screen coordinates
// (NOTE: run the TFTcal-Teensy.ino sketch to determine the calibration values
// for your specific touchscreen display, by touching the top-left
// corner to find TS_MINX & TS_MINY, then rouching the bottom-right
// corner to find TX_MAXX & TS_MAXY)
const int TS_MINX = 260;
const int TS_MINY = 220;
const int TS_MAXX = 3750;
const int TS_MAXY = 3740;
// uncomment the next line to make use of the alternate pins (when used w/ Audio Adapter) for the display & touchscreen
#define USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
#ifndef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// By default, the display uses hardware SPI, with pin #9 as DataCommand & pin #10 as ChipSelect
// MOSI=11, MISO=12, SCK=13
const int TFT_CHIP_SELECT = 10;
const int TFT_DATA_COMMAND = 9;
ILI9341_t3 tft = ILI9341_t3(TFT_CHIP_SELECT, TFT_DATA_COMMAND);
#endif
#ifdef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// Alternate ILI9341 display pins (when used w/ Audio Adapter) for optimized ILI9341_t3 library
#define TFT_DC 20
#define TFT_CS 21
#define TFT_RST 255 // 255 = unused, connect to 3.3V
#define TFT_MOSI 7
#define TFT_SCLK 14
#define TFT_MISO 12
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);
#endif
#ifndef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// By default, the touchscreen uses hardware SPI, with pin #9 as DataCommand & pin #8 as ChipSelect
// MOSI=11, MISO=12, SCK=13
#define TS_CS_PIN 8
#endif
#ifdef USE_ALTERNATE_PINS_FOR_ILI9341_TOUCHSCREEN
// Alternate touchscreen pins (when used w/ Audio Adapter)
#define TS_CS_PIN 5
#endif
XPT2046_Touchscreen ts(TS_CS_PIN, 255);
//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
//
// The following pins are used in this project:
//
// PIN D1 = (not used)
// PIN D2 = (not used)
// PIN D3 = (not used)
// PIN D4 = (not used)
// PIN D5 = (not used)
// PIN D6 = (not used)
// PIN D7 = (not used)
// PIN D8 = TouchScreen chip select
// PIN D9 = TFT/TS data/command select
// PIN D10 = TFT chip select
// PIN D11 = SPI MOSI (data in)
// PIN D12 = SPI MISO (data out)
// PIN D13 = SPI serial clock + on-board LED
// PIN A0 = (not used)
// PIN A1 = (not used)
// PIN A2 = (not used)
// PIN A3 = (not used)
// PIN A4 = (not used)
// PIN A5 = (not used)
// onboard LED on pin 13
#define LED_PIN 13
// keep track of whether the fireplace is ON or OFF
bool fire_on = true;
// The display size to use for the Christmas tree
const unsigned int tree_width = 220;
const unsigned int tree_height = 300;
unsigned int y_offset_tree = (320 - tree_height) / 2;
unsigned int x_offset_tree = (240 - tree_width) / 2;
// The display size to use for the fireplace
const unsigned int fire_width = 100;
const unsigned int fire_height = 100;
unsigned int x_offset_fire = (320 - fire_width) / 4;
unsigned int y_offset_fire = (240 - fire_height) / 2;
// These parameters control the fire appearance
#define HEAT_DEFAULT 50
#define COOL_DEFAULT 35 // 60 (coolest) to 10 (hottest)
#define FOCUS_DEFAULT 30
#define SPARK_DEFAULT 50
#define MAX_COOLING 10
#define MIN_COOLING 60
unsigned int heat = HEAT_DEFAULT;
unsigned int focus = FOCUS_DEFAULT;
unsigned int cool = COOL_DEFAULT;
unsigned int spark_color = SPARK_DEFAULT;
// Arrays for fire animation
unsigned char canvas[fire_width * fire_height];
extern const unsigned int fireColor[100];
boolean previously_touched = false;
boolean touch_triggered = false;
#define CUSTOM_FOREST_GREEN ILI9341_GREEN & 0xf1ff // 0x006E33
#define NOT_FIRST_PASS false
#define FIRST_PASS true
typedef enum
{
MODE_TREE=0, MODE_FIRE
} OP_MODE;
OP_MODE mode = MODE_TREE;
void animateFire();
void drawTree(bool first_pass);
void draw_fire_spot(unsigned int x, unsigned int y, uint32_t firecolor);
void draw_tree_spot(unsigned int x, unsigned int y, unsigned int color_rgb);
void loop();
void setup();
void animateFire()
{
unsigned int i, c, n, x, y;
if (fire_on == true)
{
// Step 1: move all data up one line
memmove(canvas + fire_width, canvas, fire_width * (fire_height - 1));
memset(canvas, 0, fire_width);
// Step 2: draw random heatspots on bottom line
i = heat;
if (i > fire_width-8) i = fire_width-8;
while (i > 0) {
x = random(fire_width - 2) + 1;
if (canvas[x] == 0) {
canvas[x] = spark_color;
i--;
}
}
// Step 3: interpolate
for (y=0; y < fire_height; y++) {
for (x=0; x < fire_width; x++) {
c = canvas[y * fire_width + x] * focus;
n = focus;
if (x > 0) {
c = c + canvas[y * fire_width + (x - 1)];
n = n + 1;
}
if (x < fire_width-1) {
c = c + canvas[y * fire_width + (x + 1)];
n = n + 1;
}
if (y > 0) {
c = c + canvas[(y -1) * fire_width + x];
n = n + 1;
}
if (y < fire_height-1) {
c = c + canvas[(y + 1) * fire_width + x];
n = n + 1;
}
c = (c + (n / 2)) / n;
i = (random(1000) * cool) / 10000;
if (c > i) {
c = c - i;
} else {
c = 0;
}
canvas[y * fire_width + x] = c;
}
}
// Step 4: render canvas to LEDs
for (y=0; y < fire_height; y++) {
for (x=0; x < fire_width; x++) {
c = canvas[((fire_height - 1) - y) * fire_width + x];
draw_fire_spot(x, y, fireColor[c * 3]);
}
}
} else {
// turn off all LEDs
for (y=0; y < fire_height; y++) {
for (x=0; x < fire_width; x++) {
draw_fire_spot(x, y, ILI9341_BLACK);
}
}
}
} // animateFire()
//
// draw a fireplace spot on the TFT & takes care of GRB32 to TFT_RGB conversion
//
void draw_fire_spot(unsigned int x, unsigned int y, uint32_t color_rgb32)
{
// 32-bit GRB for LED = 8-bits GREEN + 8-bits RED + 8-bits BLUE
// 16-bit RGB for TFT = 5-bits RED + 6-bits GREEN + 5-bits BLUE
int tft_color_rgb = (((color_rgb32 & 0x1f0000) >> 5) + ((color_rgb32 & 0x003f00) >> 3) + (color_rgb32 & 0x00001f)) & 0x00ffff;
tft.drawPixel(x * 2 + x_offset_fire, y + y_offset_fire, tft_color_rgb);
}
//
// draw a spot on the TFT tree
//
void draw_tree_spot(unsigned int x, unsigned int y, unsigned int color_rgb)
{
tft.drawPixel(x + x_offset_tree, y + y_offset_tree, color_rgb);
tft.drawPixel(x + x_offset_tree + 1, y + y_offset_tree, color_rgb);
tft.drawPixel(x + x_offset_tree, y + y_offset_tree + 1, color_rgb);
tft.drawPixel(x + x_offset_tree + 1, y + y_offset_tree + 1, color_rgb);
}
// Draw the underlying tree
void drawTree(bool first_pass)
{
for (unsigned int x = 0; x < tree_width; x++)
{
for (unsigned int y = 0; y < tree_height; y++)
{
unsigned int leftside;
unsigned int rightside;
if (y < (tree_height - 16))
{
leftside = (float)(tree_width / 2) - (((float)(tree_height - y) / 2.5) * tree_width / tree_height) - ((tree_height - y) % ((tree_height - y) / 17));
rightside = (float)(tree_width / 2) + (((float)(tree_height - y) / 2.5) * tree_width / tree_height) + ((tree_height - y) % ((tree_height - y) / 17));
} else {
leftside = (float)(tree_width / 2) - (((float)(tree_height - y) / 2.5) * tree_width / tree_height);
rightside = (float)(tree_width / 2) + (((float)(tree_height - y) / 2.5) * tree_width / tree_height);
}
if ((x >= leftside) && (x <= rightside))
{
if (first_pass == true)
{
if (random(5) == 0)
{
draw_tree_spot(x, y, CUSTOM_FOREST_GREEN);
}
} else {
if (random(5000) == 0)
{
switch(random(100))
{
case 0:
{
draw_tree_spot(x, y, ILI9341_RED);
}
break;
case 1:
{
draw_tree_spot(x, y, ILI9341_ORANGE);
}
break;
case 2:
{
draw_tree_spot(x, y, ILI9341_YELLOW);
}
break;
case 3:
{
draw_tree_spot(x, y, ILI9341_GREEN);
}
break;
case 4:
{
draw_tree_spot(x, y, ILI9341_BLUE);
}
break;
case 5:
{
draw_tree_spot(x, y, ILI9341_PURPLE);
}
break;
case 6:
{
draw_tree_spot(x, y, ILI9341_WHITE);
}
break;
default:
{
if (random(5) == 0)
{
draw_tree_spot(x, y, CUSTOM_FOREST_GREEN);
} else {
draw_tree_spot(x, y, ILI9341_BLACK);
}
}
break;
}
}
}
} else {
if (first_pass == true)
{
draw_tree_spot(x, y, ILI9341_BLACK);
}
}
}
}
} // drawTree()
// Run repetitively
void loop()
{
TS_Point p = ts.getPoint();
// Scale from raw to tft values to expected width & height using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
if ((ts.touched() == false) && (previously_touched == true))
{
touch_triggered = true;
}
if (ts.touched() == true)
{
previously_touched = true;
} else {
previously_touched = false;
}
switch (mode)
{
case MODE_TREE:
{
drawTree(NOT_FIRST_PASS);
if ((p.x >= 160) && (p.x <= 220) && (p.y >= 10) && (p.y <= 50))
{
if (touch_triggered == true)
{
touch_triggered = false;
switch (mode)
{
case MODE_TREE:
{
mode = MODE_FIRE;
}
break;
case MODE_FIRE:
{
mode = MODE_TREE;
}
break;
}
setup();
}
}
}
break;
case MODE_FIRE:
{
animateFire();
if ((p.x >= 0) && (p.x <= 40) && (p.y >= 100) && (p.y <= 140))
{
if (touch_triggered == true)
{
touch_triggered = false;
fire_on = !fire_on;
}
} else {
if ((p.x >= 260) && (p.x <= 300) && (p.y >= 100) && (p.y <= 140))
{
if (touch_triggered == true)
{
touch_triggered = false;
switch (mode)
{
case MODE_TREE:
{
mode = MODE_FIRE;
}
break;
case MODE_FIRE:
{
mode = MODE_TREE;
}
break;
}
setup();
}
} else {
if ((ts.touched() == true) & (p.y >= 180))
{
cool = map(p.x, 0, 320, MIN_COOLING, MAX_COOLING);
tft.fillRect(0, 210, 320, 10, ILI9341_BLACK);
tft.fillRect(0, 221, 320, 10, ILI9341_BLACK);
tft.fillCircle(p.x, 220, 10, ILI9341_YELLOW);
tft.drawLine(0, 220, 320, 220, ILI9341_YELLOW);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(p.x - 8, 216);
tft.print(map(cool, 60, 10, 0, 100));
tft.print("%");
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(5, 230);
tft.print("COOLER");
tft.setTextColor(ILI9341_RED);
tft.setCursor(280, 230);
tft.print("HOTTER");
}
}
}
}
break;
}
} // loop()
// Run setup once
void setup()
{
// initialize the serial port, then send out the firmware version string
Serial.begin(9600);
while (!Serial && (millis() <= 1000));
Serial.println(VERSION1);
Serial.println(VERSION2);
Serial.println(VERSION3);
Serial.println("");
switch(mode)
{
case MODE_TREE:
{
delay(500);
tft.begin();
tft.setRotation(0);
delay(100);
ts.begin();
ts.setRotation(0);
tft.fillScreen(ILI9341_BLACK);
drawTree(FIRST_PASS);
tft.setRotation(2);
tft.drawRect(170, 17, 50, 24, ILI9341_GREEN);
tft.drawRect(172, 19, 46, 20, ILI9341_GREEN);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(178, 25);
tft.print("SWITCH");
tft.setRotation(0);
tft.drawRect(x_offset_tree - 1, y_offset_tree - 1, tree_width + 3, tree_height + 3, ILI9341_WHITE);
tft.drawRect(x_offset_tree - 3, y_offset_tree - 3, tree_width + 7, tree_height + 7, ILI9341_WHITE);
}
break;
case MODE_FIRE:
{
delay(500);
tft.begin();
tft.setRotation(1);
delay(100);
ts.begin();
ts.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(1);
tft.setCursor(22, 10);
tft.print(VERSION1);
tft.setTextColor(ILI9341_RED);
tft.setCursor(52, 25);
tft.print(VERSION2);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(52, 40);
tft.print(VERSION3);
tft.drawRect(x_offset_fire - 1, y_offset_fire - 1, fire_width * 2 + 2, fire_height + 2, ILI9341_WHITE);
tft.drawRect(x_offset_fire - 3, y_offset_fire - 3, fire_width * 2 + 6, fire_height + 6, ILI9341_WHITE);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(52, 40);
tft.print(VERSION3);
tft.drawRect(0, 107, 50, 24, ILI9341_GREEN);
tft.drawRect(2, 109, 46, 20, ILI9341_GREEN);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(8, 115);
tft.print("ON/OFF");
tft.drawRect(260, 107, 50, 24, ILI9341_GREEN);
tft.drawRect(262, 109, 46, 20, ILI9341_GREEN);
tft.setTextColor(ILI9341_YELLOW);
tft.setCursor(268, 115);
tft.print("SWITCH");
tft.drawLine(0, 220, 320, 220, ILI9341_YELLOW);
tft.fillCircle(map (cool, MIN_COOLING, MAX_COOLING, 0, 320), 220, 10, ILI9341_YELLOW);
tft.setTextColor(ILI9341_BLACK);
tft.setCursor(map(cool, 60, 10, 0, 320) - 8, 216);
tft.print(map(cool, 60, 10, 0, 100));
tft.print("%");
tft.setTextColor(ILI9341_GREEN);
tft.setCursor(5, 230);
tft.print("COOLER");
tft.setTextColor(ILI9341_RED);
tft.setCursor(280, 230);
tft.print("HOTTER");
}
break;
}
} // setup()
// EOF PLACEHOLDER