OPEN-SMART ILI9329 not working with MCUFRIEND_kbv

I bought an OPEN-SMART ILI9329 touchscreen LCD-TFT (3.2" 240X320) together with a (clone) Mega2560.
Issue:
I am trying to get it to work with MCUFRIEND_kbv original library but whatever I do, it does not display. Display stays completely white.
I am using Arduino IDE 1.8.19 (latest as of writing) and I installed the original MCUFRIEND_kbv and Adafruit_GFX libraries through the library manager.
Using the (old) provided libraries from the seller does work. These libraries seem to use a hacked version of an old MCUFRIEND library so I really do not prefer to use them.

The boards were ordered as a set (Mega2560 blue board and the 3.2" LCD touchscreen red board) from here:
https://nl.aliexpress.com/item/32756200704.html

On the board it says it uses driver chip ILI9329.

The pin-out on this board is not the default uno or mega pin-out so I redefined the pin-out in the LCD_ID_readreg.ino to use the following:

LCD_ID_readreg.ino:

#define LCD_RST A4
#define LCD_CS A3
#define LCD_RS A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_D0 8
#define LCD_D1 9
#define LCD_D2 10
#define LCD_D3 11
#define LCD_D4 4
#define LCD_D5 13
#define LCD_D6 6
#define LCD_D7 7

I am unsure as to why they used a non-default pinout. Maybe because the display shield has a SD
card reader and those altered pins are used for that.
This is what is stated in the graphictest.ino that I got with the library from the seller:

//***********************************************//
// If you use OPEN-SMART TFT breakout board                 //
// Reconmmend you to add 5V-3.3V level converting circuit.
// Of course you can use OPEN-SMART UNO Black version with 5V/3.3V power switch,
// you just need switch to 3.3V.
// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
//----------------------------------------|
// TFT Breakout  -- Arduino UNO / Mega2560 / OPEN-SMART UNO Black
// GND              -- GND
// 3V3               -- 3.3V
// CS                 -- A3
// RS                 -- A2
// WR                -- A1
// RD                 -- A0
// RST                -- RESET
// LED                -- GND
// DB0                -- 8
// DB1                -- 9
// DB2                -- 10
// DB3                -- 11
// DB4                -- 4
// DB5                -- 13
// DB6                -- 6
// DB7                -- 7

Just to be clear, this display board has a 5V to 3V3 converter.

As can be seen the reset is not connected to A4 but to the arduino reset? I left the A4 reference though in the altered pinout because I did not know how to define it otherwise.

I tried using the original MCUFRIEND_kbv library unaltered except for the pin definitions in LCD_ID_readreg.ino and when that was not working I tried using:
#define USE_SPECIAL (mcufriend_shield.h) together with
#define USE_OPENSMART_SHIELD_PINOUT_MEGA (mcufriend_special.h)

Both configurations do not change the outcome. Still white screen.

Running LCD_ID_readreg.ino with the altered pinout (see above) outputs the following:
Read Registers on MCUFRIEND UNO shield
controllers either read as single 16-bit
e.g. the ID is at readReg(0)
or as a sequence of 8-bit values
in special locations (first is dummy)

reg(0x0000) 00 00	ID: ILI9320, ILI9325, ILI9335, ...
reg(0x0004) 00 E3 00 00	Manufacturer ID
reg(0x0009) 00 00 61 00 00	Status Register
reg(0x000A) 00 08	Get Power Mode
reg(0x000C) 00 06	Get Pixel Format
reg(0x0061) 00 00	RDID1 HX8347-G
reg(0x0062) 00 00	RDID2 HX8347-G
reg(0x0063) 00 00	RDID3 HX8347-G
reg(0x0064) 00 00	RDID1 HX8347-A
reg(0x0065) 00 00	RDID2 HX8347-A
reg(0x0066) 00 00	RDID3 HX8347-A
reg(0x0067) 00 00	RDID Himax HX8347-A
reg(0x0070) 00 00	Panel Himax HX8347-A
reg(0x00A1) 00 00 00 00 00	RD_DDB SSD1963
reg(0x00B0) 00 00	RGB Interface Signal Control
reg(0x00B4) 00 02	Inversion Control
reg(0x00B6) 02 0A 82 27 04	Display Control
reg(0x00B7) 00 06	Entry Mode Set
reg(0x00BF) 06 02 02 02 02 02	ILI9481, HX8357-B
reg(0x00C0) 02 1A 16 16 16 16 16 16 16	Panel Control
reg(0x00C8) 16 16 16 16 16 16 16 16 16 16 16 16 16	GAMMA
reg(0x00CC) 16 2D	Panel Control
reg(0x00D0) 07 00 00	Power Control
reg(0x00D2) 00 00 00 02 02	NVM Read
reg(0x00D3) 02 00 93 29	ILI9341, ILI9488
reg(0x00D4) 29 29 29 29	Novatek ID
reg(0x00DA) 29 E3	RDID1
reg(0x00DB) 00 00	RDID2
reg(0x00DC) 00 00	RDID3
reg(0x00E0) 00 00 04 0F 04 16 08 37 69 47 47 0C 09 1A 1B 0F	GAMMA-P
reg(0x00E1) 00 06 24 28 01 0C 01 38 30 46 02 09 09 32 36 0F	GAMMA-N
reg(0x00EF) 00 04 2A 00 00 00	ILI9327
reg(0x00F2) 00 00 00 00 00 00 00 00 00 00 00 00	Adjust Control 2
reg(0x00F6) 00 41 00 00	Interface Control

So it seems from register 0xD3 that 93 29 is indeed being recognized.
But the ID (register 0) gives 00 00 ? Why? I do not understand.

Next I also tried using jumper wiring to wire all lines from the display to the MEGA as original wiring and I put back the original MCUFRIEND pinout. This also did not work with or without the additional use special defines.

When I try to run the example 'Font_simple.ino' and I watch the serial output I see

Without the display attached it says:
found ID = 0xD3D3

With the display attached it gives:
Example: Font_simple
found ID = 0x0

Is this the display ID? Is that maybe the problem? The display ID not being recognized here?

[EDIT] The graphictest.ino from the supplied library also reports the ID but the ID found is:
ID = 0x202
But that ID is subsequently not being used as there is a hardcoded
tft.begin(0x9329);
after.

When I use the library (old) that I got from the seller the display works and I can run the graphictest.ino from that. But I really prefer not to use that as it is old and not maintained. I really would like to use the MCUFRIEND_kbv original library as it is maintained, has more examples and I think might run quicker. I read something about rotating being done in a strange way in the hacked library.

I have the electrical schematic of the display shield. I will try to attach it to this thread.
I can also attach the library that I got from the seller if that helps.

Another very annoying issue with these boards is that I cannot upload sketches with the display attached. This is because the 6 In-Circuit-Serial-Programming ICSP are being connected. As soon as I use jumper wires to connect the display and not wire the 6 ICSP pins I can upload.
If the pins are connected I get a timeout error.

Ultimate goal is to use these boards to make a logging module for my solar panels power converter. logging serial message from the PV converter and being able to display PV solar graphs on the display while saving the data to the SD card on the display. For this I would really much like to use the original maintained MCUFRIEND library as it seems to be well made and well maintained and not the hacked old non-maintained library from the seller.

Any help is very much appreciated.
If I forgot to mention any information please let me know and I'll add it to this thread.

[edit] Just tried to upload the PDF but as I am a new user of this forum I am not allowed.. bummer.

Alwin

I compared the code of the supplied library with the latest code from MCUFRIEND_kbv and found the missing link that was hacked into the old library.

In mcufriend_shield.h definitions have been added to redefine write_8(), read_8(), setWriteDir() and setReadDir() macro functions for this specific display board (see below for the quite ugly hacked code).

After I added those definitions to the latest MCUFRIEND library the display is working fine.
I ran graphictest.ino from the mcufriend library examples to confirm its working.
The display update rate seems a lot faster than the graphictest provided in the library that came with the board. I found that the supplied mcufriend library was based on a pre-release version 2.9.1-beta according to the library.properties file:

name=MCUFRIEND_kbv
version=2.9.1-beta
author=David Prentice
maintainer=David Prentice
sentence=TFT Library for 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend UNO Shields
paragraph=TFT Library for 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend UNO Shields.  Must have /RD pin to be readable. 
category=Display
url=https://github.com/prenticedavid/MCUFRIEND_kbv
architectures=*

So in conclusion this setup with this 3.2" touchscreen display using Ili9329 with the 'clone' MEGA2560 board works with the following changes to mcufriend 2.9.9-Release version:

mcufriend_shield.h:

line 0:
#define USE_SPECIAL

line52 onward adding the code below in betwee '#ifdef USE_OPENSMART_SHIELD_PINOUT_MEGA' and the '#else' clause.
//################################### MEGA2560 ##############################
#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)       //regular UNO shield on MEGA2560
#define RD_PORT PORTF
#define RD_PIN  0
#define WR_PORT PORTF
#define WR_PIN  1
#define CD_PORT PORTF
#define CD_PIN  2
#define CS_PORT PORTF
#define CS_PIN  3
#define RESET_PORT PORTF
#define RESET_PIN  4

#ifdef USE_OPENSMART_SHIELD_PINOUT_MEGA

  #define write_8(x) {                                              \
    PORTH = (PORTH&B10000111)|(((x)&B11000000)>>3)|(((x)&B00000011)<<5); \
    PORTB = (PORTB&B01001111)|(((x)&B00101100)<<2);                      \
    PORTG = (PORTG&B11011111)|(((x)&B00010000)<<1);                      \
    }**
  #define read_8()(                                      \ 
  	((PINH & B00011000) << 3) | ((PINB & B10110000) >> 2) | \
  	((PING & B00100000) >> 1) | ((PINH & B01100000) >> 5) )
  #define setWriteDir() {                                   \
    DDRH |=  B01111000; DDRB |=  B10110000; DDRG |=  B00100000; }
  #define setReadDir()  {                                   \
    DDRH &= ~B01111000; DDRB &= ~B10110000; DDRG &= ~B00100000; }

 #else 

#define EMASK         0x38
#define GMASK         0x20
#define HMASK         0x78
#define write_8(x)   {  PORTH &= ~HMASK; PORTG &= ~GMASK; PORTE &= ~EMASK; \
                        PORTH |= (((x) & (3<<0)) << 5); \
                        PORTE |= (((x) & (3<<2)) << 2); \
                        PORTG |= (((x) & (1<<4)) << 1); \
                        PORTE |= (((x) & (1<<5)) >> 2); \
                        PORTH |= (((x) & (3<<6)) >> 3); \
					 }

#define read_8()      ( ((PINH & (3<<5)) >> 5)\
                      | ((PINE & (3<<4)) >> 2)\
                      | ((PING & (1<<5)) >> 1)\
                      | ((PINE & (1<<3)) << 2)\
                      | ((PINH & (3<<3)) << 3)\
                      )
#define setWriteDir() { DDRH |=  HMASK; DDRG |=  GMASK; DDRE |=  EMASK;  }
#define setReadDir()  { DDRH &= ~HMASK; DDRG &= ~GMASK; DDRE &= ~EMASK;  }
#endif

and at the end of the mcufriend_shield.h there is this addition:

#ifdef USE_OPENSMART_SHIELD_PINOUT
  #define CTL_INIT()   { RD_OUTPUT; WR_OUTPUT; CD_OUTPUT; CS_OUTPUT; }
#else  
  #define CTL_INIT()   { RD_OUTPUT; WR_OUTPUT; CD_OUTPUT; CS_OUTPUT; RESET_OUTPUT;  }
#endif

So the CTL_INIT() macro function is being redefined for the missing LCD reset pin (LCD reset is coupled to the arduino reset it seems from the supplied schematic).
Not sure if this redefinition of CTL_INIT() is actually needed though.

In the new mcufirend library the macro is defined as:
#define CTL_INIT() { GPIO_INIT(); RD_OUTPUT; WR_OUTPUT; CD_OUTPUT; CS_OUTPUT; RESET_OUTPUT; }

So in the old 2.9.1-beta version apparently the GPIO_INIT() macro was not part of CTL_INIT().

Then in mcufriend_special.h the following needs to be defined:
#define USE_OPENSMART_SHIELD_PINOUT_MEGA

Clearly, what I did to make it work in the mcufriend v2.9.9-Release is also hacked.
I would like to take the opportunity to ask David Prentice if what I did could have been done without this code addition in mcufriend_shield.h. If so please let me know how.
If not then I would like to ask if this board can be integrated in the next release version of the mcufriend library. I don't like using this hack and would like to be able to update mcufriend with newer releases without having to change this code obviously.
If I can provide relevant info needed to support this hardware I am happy to test and provide what I can.

Alwin

I followed the steps from the how-to in v2.9.9-Release

19. OPEN-SMART Shields have different wiring to regular Uno Shields:
    Edit utility/mcufriend_shield.h:  #define USE_SPECIAL
    Edit utility/mcufriend_special.h: #define USE_OPENSMART_SHIELD_PINOUT_MEGA
    Edit MCUFRIEND_kbv.cpp:           #define SUPPORT_8352B

And everything worked just fine with a HX8352B Shield on a MEGA2560.

I can only suggest that you delete any current library folder.
Install v2.9.9-Release via the IDE Library Manager.
Make the appropriate edits. (you do not need SUPPORT_8352B)

Report back.

David.

Just to make clear, this is not a HX8352B driver display. the display is using a ILI9329 driver chip. The displays look very similar in appearance but the driver chip is not the same nor is the way the TFT is actually fitted on the board. The TFT seems rotated or flipped if I compare the HX8352B images that I can find on the net with my board. Other than that the boards look very similar.

I did not mention it but deleting all libraries and setting only the two below defines was one of the first things I tried. Did not work. white screen.
#define USE_SPECIAL
#define USE_OPENSMART_SHIELD_PINOUT_MEGA

I just tried this again just to make sure. So deleted all libraries then used library manager to get mcufriend_kbv 2.9.2 and Adafruit_GFX 1.10.13.
Then added the above two defines and then tested by uploading the example graphictest_kbv.
I just get the white screen. nothing more.

I think there might be differences between the HX8352B shield and my display using the ILI9329.
As said with the above patches in the code it does work. I guess I need to find out what exactly those patches change w.r.t. the original routines to maybe understand the problem a bit better.

Alwin

Surely you should install v2.9.9-Release i.e. the one recommended by the IDE Library Manager.

I possess a HX8352B Open-Smart Shield and a RM68090 Open-Smart Shield. I do not have an ILI9329 Open-Smart Shield. (nor any ILI9329)

I would expect everything to work 100%.

David.

My mistake I typed 2.9.2 but I have 2.9.9 installed indeed through the library manager.
It does not work.
I will try to find out the root-cause by analysing the patches I included on the mcufriend library to see what are the differences.

You don't need any "patches".
You simply remove the // in front of the appropriate #defines.

As I said, I don't have an ILI9329. But I understand that it will start with minimal initialisation.

David.

As mentioned above I did define the two lines and it is not working.
And with those patches it is working.

For info:
tft.readID() finds: ID = 0x2929
And clearly states 'This ID is not supported'.

Also in the hacked mcufriend library from the seller the in graphictest_kbv.ino in the void setup(void) function the ID is forced:

void setup(void) {
Serial.begin(9600);
uint32_t when = millis();
// while (!Serial) ; //hangs a Leonardo until you connect a Serial
if (!Serial) delay(5000); //allow some time for Leonardo
Serial.println("Serial took " + String((millis() - when)) + "ms to start");
// tft.reset(); //hardware reset
uint16_t ID = tft.readID(); //
Serial.print("ID = 0x");
Serial.println(ID, HEX);
if (ID == 0xD3D3) ID = 0x9481; // write-only shield
ID = 0x9329; // force ID
tft.begin(ID);
}

So you see, I clearly do not believe it should just work.

I am pretty convinced they are not using the same pinout as you get when using the #define USE_OPENSMART_SHIELD_PINOUT_MEGA directive.

Ok, mystery solved.

The pinout is not different. I compared the BMASK, GMASK and HMASK bitfields that are used in the read and write functions and they are the same as you get with the #define USE_OPENSMART_SHIELD_PINOUT_MEGA directive.

Solution is really simple and actually already something I wrote before.
To get this display to work with 2.9.9 (for example graphictest_kbv.ino example) all you need to do is use the two define directives

    Edit utility/mcufriend_shield.h:  #define USE_SPECIAL
    Edit utility/mcufriend_special.h: #define USE_OPENSMART_SHIELD_PINOUT_MEGA

AND you need to force the ID in the void setup(void) routine when calling tft.begin(ID); i.e. you have to do:

void setup(void) {
...

...
ID = 0x9329; // force ID
tft.begin(ID);
}

tft.readID() should work fine on your Shield.
i.e. it works fine on LCD_ID_readreg.ino

reg(0x00D3) 02 00 93 29	ILI9341, ILI9488

If you got 0x2929 instead of 0x9329 there is something seriously wrong.
But if tft.begin(0x9329) produced a 100% working graphictest_kbv.ino something is very odd.

Please run graphictest_kbv.ino and observe colours, times, ID, rotations, directions, vertical scroll, software scroll, invert, ...
Take notes on paper.

Please report back which features are not working.

David.

It looks to me that indeed the graphictest_kbv.ino works 100% with the forced ID. All colors, scrolling, rotations, etc work fine.
But I do get a remark stating 'readPixel() should be 24-bit'. I'm not sure if this is just a remark or an error being displayed.
The total time reported is 11,78sec.

That means SOFTWARE SCROLL has failed.

What does it say for ID on the Adafruit_Tests Report screen ?

Please try this in MCUFRIEND_kbv.cpp

    case 0x9329:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | REV_SCREEN | READ_24BITS;

David.

The ID reported on the screen says:

ID: 0x9329
But maybe that is just because it is forced?

I tried

case 0x9329:
_lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | REV_SCREEN | READ_24BITS;

Now the software scroll works and I do not have the 'readPixel should be 24-bits' error anymore.

Alwin

Another side question that you might know the answer to:
is it normal that I have to unplug the display shield from the arduino before I can upload? If found that this is because of the 6pin header for the in-circuit-programming pins ICPS.
But is that as intended? It seems weird that I have to pull of the display each time.

Alwin

note: I edited the post #14 above where I stated that the readPixel error still apeared. This was because I had put the case 0x9329 at the beginning of the switch case not knowing there was already a 0x9329 case.

Then I tried again but now adapting the existing case 0x9329 as you asked.
That made the software scroll work and the readPixel error disappear.

Alwin

I just notice that not everything is ok apparently.
Because when it comes to display color grades the colors are wrong. :face_with_raised_eyebrow:-(
blue grades are displayed as yellow
green grades are displayed as magenta (purple)
red grades are displayed as blue

Also I am unsure if the background is supposed to be white most of the time?

Alwin

Please just take accurate notes. i.e. every mistake.

I can't believe that you can look at a Penguin screen with RED in big letters and not notice the colour is different. It definitely will not be BLUE.

This means INVERTED colours. So use this.

case 0x9329:
_lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | READ_24BITS;

Quite honestly, I think that I have displayed colours, directions, rotations, ... in obvious ways. The average human would spot if something was wrong.
They might not know how to put it into words. e.g. using correct colour names.

I am grateful for your feedback. Many punters don't report the problems i.e. some controllers are not common.

David.

Please be patient with me. I was hypnotized by looking at this Penguin. I thought Penguins ought to be countershaded (countershaded penguins)

But ok on topic: I tested the the flags without the REV_SCREEN:

_lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | MV_AXIS | INVERT_SS | READ_24BITS;

And that works nicely! Background is now black and the color names match the actual colors.

So I think everything seems to be working except that I still need to force the ID? Any idea why?

Alwin

No. tft.readID() should work at all times.

All the examples call tft.readID() to determine the correct ID.
Do you have to force the ID in every example ?

The Open-Smart Shield has a hardware Reset chip. This should work fine with your 5V MEGA2560.

Uploading with the Bootloader should work fine.
If you want to upload with an external programmer you need to remove the Shield to access the 3x2 ICSP header.

David.