Arduino DUE and NT35510 tft screen

​Good evening all,
I foolishly invested in a DUE ( based on the Atmel SAM3X8E ARM Cortex-M3 CPU) due to the pin compatibility with a Mega and wanting a bit more processing power (i know 3.5v versus 5v) and I am finding it hard to find libraries for it.
​I have a 4inch 800x480 MAR4018 display with a NT35510 driver and really struggling to find a library to use a high definition screen on a fast Due.
Does any one know if such library exists?
Thanks for your help.

Hi,

From your post I assume your display is a 16bit parallel shield for Arduino MEGA.
A link or picture would confirm that.

MCUFRIEND_kbv can be used with this combination. It is known by Library Manager.
In mcufriend_special.h you need to enable this parallel interface by uncommenting line 11:

//#define USE_DUE_16BIT_SHIELD        //RD on PA15 (D24) 

And uncomment //#define USE_SPECIAL at line 1 in mcufriend_shield.h

It will be slower than with MEGA, because of the bit shuffling needed.
You may need to force ID (0x5310) if your shield doesn't support read.

An alternative would be to use Arduino_GFX.
This library is also available through Library Manager, known as GFX Library for Arduino
It has a generic 16bit parallel IO driver Arduino_SWPAR16.cpp that implements the bit shuffling needed with Arduino DUE. You would specify each data pin to IO pin mapping in the constructor.

Please fix the spelling of NT35310 in both your topics! For users to find them.
Please cross-link your two topics, if related to the same display. Then we need less guessing!

Hi JM,

As ever, thanks for your assistance.
You are correct, my posts are related.
My original post is here: https://forum.arduino.cc/t/mcufriend-library-with-3-97inch-16bit-tft-nt35510/1129181/3?u=hml_2

With regards to " Please fix the spelling of NT35310 in both your topics!"
The documentation of the screens I use is quite specific: Driver IC NT35510
Here are the screens:

Screen_1

Both screens use the NT35510 controller (according to the manufacturer documentation).
My aim was/is to try to get them to work with an Arduino DUE.

Both screens/shields appear to be" read only" (the functions getReg, getGram used in readID and readPixel) always return the same values, making me conclude that the shields are read only.

McuFriend library tests:
I configured the library so that:

  • in the file "mcufriend_shield.h" I uncommented the "#define USE_SPECIAL" line
  • in the file ""HL_mcufriend_special.h I did various tests uncommenting the various options of shields available.
    The only shield option that resulted in any form of results was "#define USE_MEGA_8BIT_SHIELD"
    Surprisingly, the "USE_ELECHOUSE_DUE_16BIT_SHIELD" did not get the screen to provide any response.
    As suggested I had to force the ID of the screen:
 uint16_t ID = tft.readID();
   if (ID == 0xD3D3)
   {
       ID = 0x5310; // write-only shield
       Serial.print(F("Try to force ID = 0x"));
       Serial.println(ID, HEX);
   }
   tft.begin(ID);

The screen reacted to this by displaying mostly a green surface but that was it.
Looking into the body of the library, I fioud that the initialization section for the NT35310 controller is quite short and mentions a screen of size of 320x480.

    case 0x5310:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | INVERT_RGB | READ_24BITS;
        static const uint8_t NT35310_regValues[] PROGMEM = {        //
            TFTLCD_DELAY8, 10,    //just some dummy
        };
        table8_ads = NT35310_regValues, table_size = sizeof(NT35310_regValues);
        p16 = (int16_t *) & HEIGHT;
        *p16 = 480;
        p16 = (int16_t *) & WIDTH;
        *p16 = 320;
        break;

However, the screen I have are 800 x 480 (so I wonder if the initialization function works for such large screens ; or it is a case of controller NT35310 versus NT35510).

The library that I did eventually find and that works well with these screen but on an arduino MEGA 2560 http://www.lcdwiki.com/4.0inch_Arduino_Display-Mega2560_NT35510 has a much longer initialization function (see: "void LCDWIKI_GUI::start(uint16_t ID)")

So I switched my efforts to make the LDCWIKI library compile for an Arduino DUE.
I had to edit a few lines in the file: "mcu_16bit_magic.h"

For the people interested these are:
Here:

......
#elif defined(__SAM3X8E__)                              // For DUE
    // configure macros for data bus  
 #define AMASK         ((1<<7)|(3<<14))          //PA7, PA14-PA15                  // Added by HML
 #define BMASK         (1<<26)                   //PB26                            // Added by HML
 #define CMASK         (31<<1)                   //PC1-PC5                         // Added by HML
 #define DMASK         ((15<<0)|(1<<6)|(3<<9))   //PD0-PD3, PD6, PD9-PD10          // Added by HML
  #ifdef USE_ADAFRUIT_SHIELD_PIN
	  #define RD_PORT PIOA
	  #define WR_PORT PIOC
.....

And here:

   #define read_16(dst)  { RD_STROBE;dst=(0\
							|((PIOC->PIO_PDSR & (1<<5))>>5)\
							|((PIOC->PIO_PDSR & (1<<4))>>3)\
							|((PIOC->PIO_PDSR & (1<<3))>>1)\
							|((PIOC->PIO_PDSR & (1<<2))<<1)\
							|((PIOC->PIO_PDSR & (1<<1))<<3)\
							|((PIOD->PIO_PDSR & (1<<10))>>5)\
							|((PIOA->PIO_PDSR & (1<<7))>>1)\
							|((PIOD->PIO_PDSR & (1<<9))>>2)\
							|((PIOB->PIO_PDSR & (1<<26))>>18)\
							|((PIOA->PIO_PDSR & (3<<14))>>5)\
							|((PIOD->PIO_PDSR & (15<<0))<<11)\
							|((PIOD->PIO_PDSR & (1<<6))<<9))\
    	                 ;}  // Added the ";" before the "}" to fix compile error

I was then able to compile the various examples and the screens (both) worked well.

I am now attempting to get the touch screen to work.
It does work well on the mega 2560.
I had to make further edits in the file "LCDWIKI_TOUCH.CPP" to make it compile:
The changes are at the top of the file:

// IMPORTANT: LIBRARY MUST BE SPECIFICALLY CONFIGURED FOR EITHER TFT SHIELD
// OR BREAKOUT BOARD USAGE.

// Lcdwiki TOUCH library
// MIT license

#include "LCDWIKI_TOUCH.h"

// HML moved the content of mcu_touch_magic in and replaced the port manipulation with standard digitalread/Write functions (based on the known pins used by the screen)
//#########################include "mcu_touch_magic.h"########################
#define TCLK_LOW    digitalWrite(52,LOW)                     // *tclkPort &= ~tclkPinSet
#define TCLK_HIGH   digitalWrite(52,HIGH)                     // *tclkPort |= tclkPinSet
#define TCS_LOW     digitalWrite(53,LOW)                     // *tcsPort &= ~tcsPinSet
#define TCS_HIGH    digitalWrite(53,HIGH)                    // *tcsPort |= tcsPinSet
#define TDIN_LOW    digitalWrite(51,LOW)                     // *tdinPort &= ~tdinPinSet
#define TDIN_HIGH   digitalWrite(51,HIGH)                    // *tdinPort |= tdinPinSet
#define TDOUT_STATE digitalRead(50)                          // ((*tdoutPort) & tdoutPinSet)
#define TIRQ_STATE  digitalRead(44)                          // ((*tirqPort) & tirqPinSet)
//####################################################################

// HML moved cali_para in but this has no bearing in results other than calibration
//###################include "cali_para.h" ##########################
//for resolution 240x320,the calibration parameter is 663,-13,894,-30
//for resolution 320x480,the calibration parameter is 852,-14,1284,-30
//for resolution 480x800,the calibration parameter is 1344,-33,2156,-45
#define XFAC      1307 //663 //852
#define XOFFSET   -30//(-13) //(-14)
#define YFAC      2062//894 //1284
#define YOFFSET   -17//(-30) 
//####################################################################


static void delay_us(uint32_t us)  // HML replaced u32 by uint32_t
{
    uint32_t time=100*us/7;    
    while(--time);   
}

// This is how the touch screen is declared on the MEGA 2560 and this works
//            LCDWIKI_TOUCH my_touch(53,        52,          50,           51,          44);     //tcs,tclk,tdout,tdin,tirq
LCDWIKI_TOUCH::LCDWIKI_TOUCH(int8_t tcs, int8_t tclk, int8_t tdout, int8_t tdin, int8_t tirq)
........

From what I can assess, some of this is working.
The function TP_Scan used to detect if the screen is touched detects that the screen is pressed (the TIRQ_STATE now replaced by digitalread(44) return LOW/0 when the screen is pressed)

uint8_t LCDWIKI_TOUCH::TP_Scan(uint8_t mode)
{
#ifdef HL_VERBOSE
Serial.print("LCDWIKI_TOUCH::TP_Scan [");
Serial.print(TIRQ_STATE);
Serial.println("]");
#endif
	if(TIRQ_STATE==0)                                 // 0 (OR low) means screen is pressed!!
	{
		if(mode)                                        //Physical coordinates
		{
			TP_Read_Coordinate2(&x,&y);
		}
		else if(TP_Read_Coordinate2(&x,&y))             //screen coordinate
		{
		/*
			long temp;
			temp = (long)XFAC*x/10000;
			x=temp+XOFFSET;
			temp = (long)YFAC*y/10000;
		    y=temp+YOFFSET;
	   */
			x=((long)XFAC*x)/10000+XOFFSET;
		    y=((long)YFAC*y)/10000+YOFFSET;
			switch(touch_rotation)
			{
				case 0:
					if(lcd_rotation == 0)
					{
						break;
					}
					else if(lcd_rotation == 1)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						y = heig - y;
					}
					else if(lcd_rotation == 2)
					{
						x = wid-x;
						y = heig - y;
					}
					else if(lcd_rotation == 3)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						x = wid-x;
					}
					break;
				case 1:
					if(lcd_rotation == 0)
					{
						x = wid-x;
					}
					else if(lcd_rotation == 1)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
					}
					else if(lcd_rotation == 2)
					{
						y = heig - y;
					}
					else if(lcd_rotation == 3)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						x = wid-x;
						y = heig - y;
					}
					break;
				case 2:
					if(lcd_rotation == 0)
					{
						x = wid-x;
						y = heig - y;
					}
					else if(lcd_rotation == 1)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						x = wid-x;
					}
					else if(lcd_rotation == 2)
					{
						break;
					}
					else if(lcd_rotation == 3)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						y = heig - y;
					}
					break;
				case 3:
					if(lcd_rotation == 0)
					{
						y = heig - y;
					}
					else if(lcd_rotation == 1)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
						x = wid-x;
						y = heig - y;
					}
					else if(lcd_rotation == 2)
					{
						x = wid-x;;
					}
					else if(lcd_rotation == 3)
					{
						uint16_t tmp;
						tmp = x;
						x=y;
						y=tmp;
					}
					break;
				default:
					break;
			}
	 	}
		if((touch_statue&TP_PRES_DOWN)==0)
		{		 
			touch_statue=TP_PRES_DOWN|TP_CATH_PRES; 
			x0=x;
			y0=y;  	   			 
		}			   
	}
	else
	{
		if(touch_statue&TP_PRES_DOWN)
		{
			touch_statue&=~(1<<7);
		}
		else
		{
			x0=0;
			y0=0;
			x=0xffff;
			y=0xffff;
		}	    
	}
	return touch_statue&TP_PRES_DOWN;
}

What is not working is the reading of the X & Y coordinates.

The function TP_Scan(uint8_t mode)
calls TP_Read_Coordinate2(&x,&y);
that calls TP_Read_Coordinate(&x1,&y1);
that calls TP_Read_XY(CMD_RDX); // defined as #define CMD_RDX 0XD0
that calls TP_Read_ADC(xy)

Read_ADC is where the work is done:

uint16_t LCDWIKI_TOUCH::TP_Read_ADC(uint8_t cmd)
{
	uint16_t num=0; 
	uint8_t count=0; 
	TCS_LOW; 
	TCLK_LOW;           
	TDIN_LOW;
	TP_Write_Byte(cmd);
	//delay_us(6);              
	TCLK_LOW; 
	delay_us(1); 
	TCLK_HIGH;
	TCLK_LOW;
	for(count=0;count<16;count++)  
	{   
	    num<<=1;          
	    TCLK_LOW;                         
	    TCLK_HIGH;
	    if(TDOUT_STATE)  { num += 1; } 
		  else 		         { num += 0; }
	}
	num>>=4;   // the high 12 bits is valid
  TCS_HIGH;
  return num; 
}

What I don't understand is why this function works on the MEGA2560 with these definitions:

#define TCLK_LOW    *tclkPort &= ~tclkPinSet
#define TCLK_HIGH   *tclkPort |= tclkPinSet
......

but does not work on the DUE with these definitions

#define TCLK_LOW    digitalWrite(52,LOW)                     // *tclkPort &= ~tclkPinSet
#define TCLK_HIGH   digitalWrite(52,HIGH)                     // *tclkPort |= tclkPinSet

Could it be a problem of timing on the SPI wires?

Regards
H

Hi @hml_2,

Now I understand, you have two different displays with the same controller NT35510.
And I found both on AliExpress:
4.0 inch TFT color touch LCD Display Screen Module 800*480 XP12046 Touch IC 5V NT35510 Support for Arduino Mega2560 In-line

3.97 / 4 inch 480*800 16.7M HD MCU Parallel IPS TFT LCD Module Display Screen Resistive Touch Panel NT35510 for Alientek STM32

I will take a closer look at both and at your question(s) tomorrow.

I don't think so, as digitalWrite() is slower than direct port write.
You could try to use double TCLK_LOW. That's what I use to try.
-jz-

pin numbers for SPI are different on DUE: irrelevant

#define SPI_INTERFACE        SPI0
#define SPI_INTERFACE_ID     ID_SPI0
#define SPI_CHANNELS_NUM 4
#define PIN_SPI_SS0          (77u)
#define PIN_SPI_SS1          (87u)
#define PIN_SPI_SS2          (86u)
#define PIN_SPI_SS3          (78u)
#define PIN_SPI_MOSI         (75u)
#define PIN_SPI_MISO         (74u)
#define PIN_SPI_SCK          (76u)
#define BOARD_SPI_SS0        (10u)
#define BOARD_SPI_SS1        (4u)
#define BOARD_SPI_SS2        (52u)
#define BOARD_SPI_SS3        PIN_SPI_SS3
#define BOARD_SPI_DEFAULT_SS BOARD_SPI_SS3

HW SPI on DUE is on ICSP header only. Thus irrelevant for MEGA shield.

Good Evening JM,

Thanks again for a very fast answer.
I am not sure I understand what you mean by "try to use double TCLK_LOW"
Do you mean using TCLK_LOW twice each time?
Something like:

uint16_t LCDWIKI_TOUCH::TP_Read_ADC(uint8_t cmd)
{
	uint16_t num=0; 
	uint8_t count=0; 
	TCS_LOW; 
	TCLK_LOW; TCLK_LOW; // doubling up the TCLK_LOW;           
	TDIN_LOW;
	TP_Write_Byte(cmd);

I understand that the MOSI pins could be different on a DUE, but on the DUE board the digital pins have the same numbers than on any other MEGA:

Mage and DUE

Therefore I was assuming that if I replaced the code used on the UNO to trigger the SPI Pins

#define TCLK_LOW    *tclkPort &= ~tclkPinSet
#define TCLK_HIGH   *tclkPort |= tclkPinSet

With this code on the DUE to activate the same digital pins 50, 51, 52 & 53

#define TCLK_LOW    digitalWrite(52,LOW)                     // *tclkPort &= ~tclkPinSet
#define TCLK_HIGH   digitalWrite(52,HIGH)                     // *tclkPort |= tclkPinSet

The screen would behave in the same manner......but it does not.
So I am confused.

Regards
H

Ok, so you have a solution for display. MCUFriend_kbv is not an option, as it doesn't support NT35510. I don't like the LCDWIKI library, because of the strangely spelled methods.
I can't help you with the touch function.

Yes, that's what I meant.

Thanks JM,

Yes I did get the LCDWiki library to work with these NT35510 screens on the Arduino DUE.
Like you I don't like much the method's names so, as I was tinkering with the library, I took the opportunity to amend most of the names to make then "McuFriend library alike".
I shall continue trying to make the touch screen work.
I suspect this is a speed issue.
According to my measures, the DUE is approx 20 times faster than the MEGA so I suspect it may be too fast for the screen and the communication breaks.
Even though this is not an issue on the "display side" (only the touch screen).
Are the Touch Screen handled y another type of controller?
Adding a few "delays" may help, I need to try.

Have a great day
Regards
H

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.