Home » Projects » Electronics Projects » TJCTM24024 Module Up and Running

TJCTM24024 Module Up and Running

TJCTM24024 Module Up and Running

This is the final article about getting my TJCTM24024 up and running with the Arduino.

As previously described, I bought a few mystery modules from China which contained a TFT display and touchscreen similar to what you have on your mobile phone. The process I went through required some learning and experimenting. This included understanding the ILI9341 display driver chip and the XPT2046 touch driver chip. Eventually, I wrote my own software for the XPT2046, and just used a well known version of the Adafruit GFX library for the display.

This process could be used with almost any display module, especially if it is not supported by a retail vendor. The time it took to get the TJCTM24024 module up and running was worthwhile as a learning experience. Otherwise, you would probably be better off buying some display module which is well supported by an online retailer such as Adafruit or Sparkfun. There are lots to choose between.

Eventually, I want to use this project as the basis for controlling a signal generator using a touch screen rather than pushbuttons. Remember, if you want to do something similar, that these touchscreens require 3.3V not 5.0V. This means using level shifters or an Arduino Pro Mini running at 3.3V. Otherwise, getting your TJCTM24024 module up and running could turn into an “up and burning out” project.

Arduino Test Program for TJCTM24024 module up and running

The following test program brings together a graphics library, my XPT2046 driver and 3 point calibration. You could easily adapt this program to use other Arduino graphics libraries. You can download the PDQ_GFX library here. The XPT2046 code is in my previous article.

In its basic form, this test program simply lets you draw on the screen with a touch pen. But is has a couple of extra features which you can trigger using #define statements.

  • By un-commenting #define CALIBRATION, the program will first run its calibration routine before moving on to display activities in the main loop.
  • By un-commenting #define DEBUG, the program will present data over the serial port while it is running. This is particularly useful if you want to write down the calibration parameters and then apply them as defaults in the XPT2046.h file. I expect that every different TJCTM24024 module up and running will require individual calibration.

The use of these #define statements is a great example of using pre-processing in Arduino C code to turn optional features on and off by simply commenting-uncommenting a single line of code.

 

/*
	Test program to calibrate and demonstrate
	TJCTM24024-SPI TFT Touchpad Module which uses
	- ILI9341 Graphics Driver
	- XPT2046 Touch Driver
	Uncomment #define CALIBRATE to do calibration first
	Uncomment #define DEBUG to send details by serial port
*/

#include <SPI.h>
#include <PDQ_GFX.h>
#include <PDQ_FastPin.h>
#include "PDQ_ILI9341_config.h" 
#include <PDQ_ILI9341.h>
#include "XPT2046A.h"
#include "XPT2046A_calib.h"

//#define DEBUG
//#define CALIBRATE

#ifdef DEBUG
	#define DEBUG_PRINT(x)     Serial.print (x)
	#define DEBUG_PRINTDEC(x)     Serial.print (x, DEC)
	#define DEBUG_PRINTLN(x)  Serial.println (x)
#else
	#define DEBUG_PRINT(x)
	#define DEBUG_PRINTDEC(x)
	#define DEBUG_PRINTLN(x) 
#endif

/* Both devices use Hardware SPI and are both wired to the
   dedicated Arduino SPI pins (MOSI=11, MISO=12 and SCK=13)
   as described on https://www.arduino.cc/en/Reference/SPI.
   Each uses a different Slave Select (cs) pin. */
PDQ_ILI9341 tft; /* pins set in PDQ_ILI9341_config*/
XPT2046A touch(/*cs=*/ 3, /*irq=*/ 6);

cal_params cp;
Point m;
int Width, Height;

void setup()
{
#if defined(ILI9341_RST_PIN)
	FastPin<ILI9341_RST_PIN>::setOutput();
	FastPin<ILI9341_RST_PIN>::hi();
	FastPin<ILI9341_RST_PIN>::lo();
	delay(1);
	FastPin<ILI9341_RST_PIN>::hi();
#endif
#ifdef DEBUG
	Serial.begin(115200);
	delay(3000);
#endif

	tft.begin();
	/* Set Rotations to ROT0 to do calibration! */
	tft.setRotation(touch.ROT270);

	Width = tft.ILI9341_TFTWIDTH;
	Height = tft.ILI9341_TFTHEIGHT;

	touch.init(Width, Height);
	/* Set Rotations to ROT0 to do calibration! */
	touch.setRotation(touch.ROT270);

#ifdef CALIBRATE
	if (Calibrate()) {
		/* load the calibration parameters cp into touch driver */
		touch.setCalibration(cp);
		tft.setCursor(0, 0);
		tft.println("Calibration Okay");
		/* Print the calibration parameters so you can write them down 
		   and  set them as defaults in XPT2014.h */
		DEBUG_PRINTLN(cp.An);
		DEBUG_PRINTLN(cp.Bn);
		DEBUG_PRINTLN(cp.Cn);
		DEBUG_PRINTLN(cp.Dn);
		DEBUG_PRINTLN(cp.En);
		DEBUG_PRINTLN(cp.Fn);
		DEBUG_PRINTLN(cp.V);
	}
	else
	{
		tft.setCursor(0, 0);
		tft.println("Calibration Failed");
	}
#endif

	delay(1000);
	tft.fillScreen(ILI9341_BLUE);
	tft.setCursor(0, 0);
	tft.print("Ready");
}

static uint16_t prev_x = 0xffff, prev_y = 0xffff;
void loop()
{
	/* Assuming calibration has been set, the main loop
	   just lets you draw on the screen with a touch pen */
	if (touch.isTouching()) {

		touch.getLCDPosition(m);
		DEBUG_PRINT(m.x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(m.y);
		if (prev_x == 0xffff) {
			tft.drawPixel(m.x, m.y, ILI9341_YELLOW);
		}
		else {
			tft.drawLine(prev_x, prev_y, m.x, m.y, ILI9341_YELLOW);
		}
		prev_x = m.x;
		prev_y = m.y;
	}
	else {
		prev_x = prev_y = 0xffff;
	}
	delay(20);
}

bool Calibrate() {
	/* DisplayPoints array contains the three unrelated screen Points
	   to be used for calibration */
	Point DisplayPoints[] = { { 36,48 },{ 120,272 },{ 204,160 } };
	/* TouchPoints array will contain the touchpad values
	   corresponding to the above display points */
	Point TouchPoints[] = { { 0,0 },{ 0,0 },{ 0,0 } };

	tft.setCursor(0, 0);
	tft.fillScreen(ILI9341_BLACK);

	DrawCross(DisplayPoints[0], true);
	while (!touch.isTouching()) { delay(10); }
	touch.getADCData(TouchPoints[0]);
	DrawCross(DisplayPoints[0], false);
	DEBUG_PRINT(DisplayPoints[0].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(DisplayPoints[0].y);
	DEBUG_PRINT(TouchPoints[0].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(TouchPoints[0].y);
	DEBUG_PRINTLN();
	delay(500);

	DrawCross(DisplayPoints[1], true);
	while (!touch.isTouching()) { delay(10); }
	touch.getADCData(TouchPoints[1]);
	DrawCross(DisplayPoints[1], false);
	DEBUG_PRINT(DisplayPoints[1].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(DisplayPoints[1].y);
	DEBUG_PRINT(TouchPoints[1].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(TouchPoints[1].y);
	DEBUG_PRINTLN();
	delay(500);

	DrawCross(DisplayPoints[2], true);
	while (!touch.isTouching()) { delay(10); }
	touch.getADCData(TouchPoints[2]);
	DrawCross(DisplayPoints[2], false);
	DEBUG_PRINT(DisplayPoints[2].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(DisplayPoints[2].y);
	DEBUG_PRINT(TouchPoints[2].x); DEBUG_PRINT(" - "); DEBUG_PRINTLN(TouchPoints[2].y);
	DEBUG_PRINTLN();
	delay(500);
	
	/* After you have the three pairs of points, MakeCalibrationParams returns the
	   struct containing the seven calibration parameters in cp */
	return MakeCalibrationParams(DisplayPoints, TouchPoints, cp);
}

void DrawCross(Point cr, bool Show) {
	uint16_t color;

	if (Show)
		color = ILI9341_WHITE;
	else
		color = ILI9341_BLACK;
	tft.drawFastHLine(cr.x - 8, cr.y, 16, color);
	tft.drawFastVLine(cr.x, cr.y - 8, 16, color);
}

// PDQ_ILI9341_config.h
#define	ILI9341_CS_PIN		2
#define	ILI9341_DC_PIN		5
#define	ILI9341_RST_PIN		4

#define	ST7735_SAVE_SPCR	1

2 comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.