cancel
Showing results for 
Search instead for 
Did you mean: 

SPI, LTDC and TouchGFX init of Adafruit 4" Round LCD HD40015C40-Y

SkeleSt
Associate II

Hi Everyone I have a some difficulties with bringing up the HD40015C40-Y display with TouchGFX or even at all:

1. I used the init code provided by adafruit, I set up my SPI with 9bit words and sent it to the display as per the datasheet for the NV3052CRGB datasheet.

2. TouchGFX is already setup and LTDC is setup to the timings described in the  https://www.adafruit.com/product/5793 init code. 


3. I have very strange rainbow lines behaviour
Currently I am running a 35Mhz clock. The 35Mhz clock was derived from the linux device tree overlay for the HD40015C40-Y display. 

SkeleSt_0-1720762206550.png

 

4. Things I do know: SPI transmission definitely works. There are physical signals for the LTDC pins coming from the STM chip as I checked with an oscilloscope.

 

Interestingly if you read the Circuit Python code from Adafruit, they only have 16Mhz frequency.

I have no idea if this is a software problem, hardware problem or a combination of both. 

 

 

void Wrt_Reg_3052(uint8_t Par1,uint8_t Par2)
{
	// 9 bit mode
	command = 0;
	command|= Par1;

	parameter = 256;
	parameter |= Par1;

	HAL_GPIO_WritePin(CS_PIN_GPIO_Port, CS_PIN_Pin ,GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, (uint8_t*)&command,1, 1000);
	HAL_SPI_Transmit(&hspi1, (uint8_t*)&parameter,1, 1000);
	HAL_GPIO_WritePin(CS_PIN_GPIO_Port, CS_PIN_Pin, GPIO_PIN_SET);
}
uint8_t NV3051D_Init()
{
	Wrt_Reg_3052(0xFF,0x30);
	Wrt_Reg_3052(0xFF,0x52);
	Wrt_Reg_3052(0xFF,0x01);
	Wrt_Reg_3052(0xE3,0x00);
	Wrt_Reg_3052(0x0A,0x11);
	Wrt_Reg_3052(0x23,0xA0);//A2
	Wrt_Reg_3052(0x24,0x32);
	Wrt_Reg_3052(0x25,0x12);
	Wrt_Reg_3052(0x26,0x2E);
	Wrt_Reg_3052(0x27,0x2E);

	Wrt_Reg_3052(0x29,0x02);
	Wrt_Reg_3052(0x2A,0xCF);
	Wrt_Reg_3052(0x32,0x34);
	Wrt_Reg_3052(0x38,0x9C);
	Wrt_Reg_3052(0x39,0xA7);
	Wrt_Reg_3052(0x3A,0x27);
	Wrt_Reg_3052(0x3B,0x94);
	Wrt_Reg_3052(0x42,0x6D);
	Wrt_Reg_3052(0x43,0x83);
	Wrt_Reg_3052(0x81,0x00);
	Wrt_Reg_3052(0x91,0x67);
	Wrt_Reg_3052(0x92,0x67);
	Wrt_Reg_3052(0xA0,0x52);
	Wrt_Reg_3052(0xA1,0x50);
	Wrt_Reg_3052(0xA4,0x9C);
	Wrt_Reg_3052(0xA7,0x02);
	Wrt_Reg_3052(0xA8,0x02);
	Wrt_Reg_3052(0xA9,0x02);
	Wrt_Reg_3052(0xAA,0xA8);
	Wrt_Reg_3052(0xAB,0x28);
	Wrt_Reg_3052(0xAE,0xD2);
	Wrt_Reg_3052(0xAF,0x02);
	Wrt_Reg_3052(0xB0,0xD2);
	Wrt_Reg_3052(0xB2,0x26);
	Wrt_Reg_3052(0xB3,0x26);
	Wrt_Reg_3052(0xFF,0x30);
	Wrt_Reg_3052(0xFF,0x52);
	Wrt_Reg_3052(0xFF,0x02);
	Wrt_Reg_3052(0xB1,0x0A);
	Wrt_Reg_3052(0xD1,0x0E);
	Wrt_Reg_3052(0xB4,0x2F);
	Wrt_Reg_3052(0xD4,0x2D);
	Wrt_Reg_3052(0xB2,0x0C);
	Wrt_Reg_3052(0xD2,0x0C);
	Wrt_Reg_3052(0xB3,0x30);
	Wrt_Reg_3052(0xD3,0x2A);
	Wrt_Reg_3052(0xB6,0x1E);
	Wrt_Reg_3052(0xD6,0x16);
	Wrt_Reg_3052(0xB7,0x3B);
	Wrt_Reg_3052(0xD7,0x35);
	Wrt_Reg_3052(0xC1,0x08);
	Wrt_Reg_3052(0xE1,0x08);
	Wrt_Reg_3052(0xB8,0x0D);
	Wrt_Reg_3052(0xD8,0x0D);
	Wrt_Reg_3052(0xB9,0x05);
	Wrt_Reg_3052(0xD9,0x05);
	Wrt_Reg_3052(0xBD,0x15);
	Wrt_Reg_3052(0xDD,0x15);
	Wrt_Reg_3052(0xBC,0x13);
	Wrt_Reg_3052(0xDC,0x13);
	Wrt_Reg_3052(0xBB,0x12);
	Wrt_Reg_3052(0xDB,0x10);
	Wrt_Reg_3052(0xBA,0x11);
	Wrt_Reg_3052(0xDA,0x11);
	Wrt_Reg_3052(0xBE,0x17);
	Wrt_Reg_3052(0xDE,0x17);
	Wrt_Reg_3052(0xBF,0x0F);
	Wrt_Reg_3052(0xDF,0x0F);
	Wrt_Reg_3052(0xC0,0x16);
	Wrt_Reg_3052(0xE0,0x16);
	Wrt_Reg_3052(0xB5,0x2E);
	Wrt_Reg_3052(0xD5,0x3F);
	Wrt_Reg_3052(0xB0,0x03);
	Wrt_Reg_3052(0xD0,0x02);
	Wrt_Reg_3052(0xFF,0x30);
	Wrt_Reg_3052(0xFF,0x52);
	Wrt_Reg_3052(0xFF,0x03);
	Wrt_Reg_3052(0x08,0x09);
	Wrt_Reg_3052(0x09,0x0A);
	Wrt_Reg_3052(0x0A,0x0B);
	Wrt_Reg_3052(0x0B,0x0C);
	Wrt_Reg_3052(0x28,0x22);
	Wrt_Reg_3052(0x2A,0xE9);
	Wrt_Reg_3052(0x2B,0xE9);
	Wrt_Reg_3052(0x34,0x51);
	Wrt_Reg_3052(0x35,0x01);
	Wrt_Reg_3052(0x36,0x26);
	Wrt_Reg_3052(0x37,0x13);
	Wrt_Reg_3052(0x40,0x07);
	Wrt_Reg_3052(0x41,0x08);
	Wrt_Reg_3052(0x42,0x09);
	Wrt_Reg_3052(0x43,0x0A);
	Wrt_Reg_3052(0x44,0x22);
	Wrt_Reg_3052(0x45,0xDB);
	Wrt_Reg_3052(0x46,0xdC);
	Wrt_Reg_3052(0x47,0x22);
	Wrt_Reg_3052(0x48,0xDD);
	Wrt_Reg_3052(0x49,0xDE);
	Wrt_Reg_3052(0x50,0x0B);
	Wrt_Reg_3052(0x51,0x0C);
	Wrt_Reg_3052(0x52,0x0D);
	Wrt_Reg_3052(0x53,0x0E);
	Wrt_Reg_3052(0x54,0x22);
	Wrt_Reg_3052(0x55,0xDF);
	Wrt_Reg_3052(0x56,0xE0);
	Wrt_Reg_3052(0x57,0x22);
	Wrt_Reg_3052(0x58,0xE1);
	Wrt_Reg_3052(0x59,0xE2);
	Wrt_Reg_3052(0x80,0x1E);
	Wrt_Reg_3052(0x81,0x1E);
	Wrt_Reg_3052(0x82,0x1F);
	Wrt_Reg_3052(0x83,0x1F);
	Wrt_Reg_3052(0x84,0x05);
	Wrt_Reg_3052(0x85,0x0A);
	Wrt_Reg_3052(0x86,0x0A);
	Wrt_Reg_3052(0x87,0x0C);
	Wrt_Reg_3052(0x88,0x0C);
	Wrt_Reg_3052(0x89,0x0E);
	Wrt_Reg_3052(0x8A,0x0E);
	Wrt_Reg_3052(0x8B,0x10);
	Wrt_Reg_3052(0x8C,0x10);
	Wrt_Reg_3052(0x8D,0x00);
	Wrt_Reg_3052(0x8E,0x00);
	Wrt_Reg_3052(0x8F,0x1F);
	Wrt_Reg_3052(0x90,0x1F);
	Wrt_Reg_3052(0x91,0x1E);
	Wrt_Reg_3052(0x92,0x1E);
	Wrt_Reg_3052(0x93,0x02);
	Wrt_Reg_3052(0x94,0x04);
	Wrt_Reg_3052(0x96,0x1E);
	Wrt_Reg_3052(0x97,0x1E);
	Wrt_Reg_3052(0x98,0x1F);
	Wrt_Reg_3052(0x99,0x1F);
	Wrt_Reg_3052(0x9A,0x05);
	Wrt_Reg_3052(0x9B,0x09);
	Wrt_Reg_3052(0x9C,0x09);
	Wrt_Reg_3052(0x9D,0x0B);
	Wrt_Reg_3052(0x9E,0x0B);
	Wrt_Reg_3052(0x9F,0x0D);
	Wrt_Reg_3052(0xA0,0x0D);
	Wrt_Reg_3052(0xA1,0x0F);
	Wrt_Reg_3052(0xA2,0x0F);
	Wrt_Reg_3052(0xA3,0x00);
	Wrt_Reg_3052(0xA4,0x00);
	Wrt_Reg_3052(0xA5,0x1F);
	Wrt_Reg_3052(0xA6,0x1F);
	Wrt_Reg_3052(0xA7,0x1E);
	Wrt_Reg_3052(0xA8,0x1E);
	Wrt_Reg_3052(0xA9,0x01);
	Wrt_Reg_3052(0xAA,0x03);

	Wrt_Reg_3052(0xFF,0x30);
	Wrt_Reg_3052(0xFF,0x52);
	Wrt_Reg_3052(0xFF,0x00);
	Wrt_Reg_3052(0x36,0x0A);
	Wrt_Reg_3052(0x11,0x00);
	HAL_Delay(200);
	Wrt_Reg_3052(0x29,0x00);
	HAL_Delay(100);

	for (int i = 0; i < 50; i++){
		HAL_GPIO_TogglePin(GPIOD, USER_LD2_RED_Pin|USER_LD3_GREEN_Pin);
		HAL_Delay(30);
	}
	return 1;
}

 

SkeleSt_1-1720762471699.pngSkeleSt_2-1720762480100.png

 

 

14 REPLIES 14
SkeleSt
Associate II

 have realized an error in my function. I have changed the Par1 to Par2 for the parameter. I have progressed to a different screen. 

 

void Wrt_Reg_3052(uint8_t Par1,uint8_t Par2)
{
	// 9 bit mode
	command = 0;
	command|= Par1;

	parameter = 256;
	parameter |= Par1;

	HAL_GPIO_WritePin(CS_PIN_GPIO_Port, CS_PIN_Pin ,GPIO_PIN_RESET);
	HAL_SPI_Transmit(&hspi1, (uint8_t*)&command,1, 1000);
	HAL_SPI_Transmit(&hspi1, (uint8_t*)&parameter,1, 1000);
	HAL_GPIO_WritePin(CS_PIN_GPIO_Port, CS_PIN_Pin, GPIO_PIN_SET);
}

SkeleSt_1-1721201505278.png

I've had different permutations and combinations of Vsync and it has yielded different artefacts such as the number of lines appearing. However none of this reflects what my GUI design is supposed to look like.

SkeleSt_4-1721201548711.png

 

 

I have the image even TouchGFX GUI animating in the simulator but there is no change on the display.

So it seems to be stuck somewhere between SPI initialization and LTDC? If I turn off the power, it will lose this state. So SPI init seems to be working to an extent, however I cannot see the desired image. Anyone have any ideas?

 

 

Hi SkeleSt ,,

I played with 5inch TFT having NV3052 chip with 720x1280 resolution.

The interface was SPI+RGB

Instead of Hardware SPI , I used software SPI function for Initialized .

Here is TouchGFX , running on 5.0" ,, 720X1280 ,, RGB + SPI TFT with STM32F429i-DISCOVERY
LCD PART No. TL050HDV31CT5-H1206A
The lcd driver chip/COG is NV3052

_legacyfs_online_stmicro_images_0693W00000dDSwFQAW.png

Let me know if you need help , fixing errors.

regards

I.N

 

GPaga
Associate

Hi Skele,

I'm doing a very similar activity and I am currently in the middle of the debug.

I have an MPU board that is not able to light up the display properly (even if the signals are correct), and for this reason, I've bought a complete adafruit kit, and I'm currently doing some tests on it.

I won't mention here the microcontroller that came with the display in this kit, but after having flashed the associated binary image, the display is running properly.

 

Here is what I've discovered until now:

This microcontroller is running the pixelclock at 16MHz, but if I raise it to 35MHz the display is still lighted up; there is a lot of flickering and the image is not stable but it is always present. See below pictures (on the left pixelclock = 16MHz, on the right 35MHz)

 

WhatsApp Image 2024-07-20 at 22.25.05.jpeg

 16 MHz

WhatsApp Image 2024-07-20 at 22.23.27.jpeg

 

 

 

 

 

Moreover, I verified that the following register initialization works properly after having mounted the kit:

https://cdn-shop.adafruit.com/product-files/5793/5793_initcode.txt

To do better debugging I reduced that list of registers initialization, and I verified that the minimal registers initialization to have the display working properly is the following one (register, datalen, value):

tmp_init_sequence = [

0xff, 0x01, 0x30,
0xff, 0x01, 0x52,
0xff, 0x01, 0x01, // Page 1
0x0a, 0x01, 0x11,
0x23, 0x01, 0xa0,
0x29, 0x01, 0x02,
0x2a, 0x01, 0xcf,

0xff, 0x01, 0x30,
0xff, 0x01, 0x52,
0xff, 0x01, 0x03, // Page 3
0x82, 0x01, 0x1f,
0x83, 0x01, 0x1f,
0x85, 0x01, 0x0a,
0x86, 0x01, 0x0a,
0x87, 0x01, 0x0c,
0x88, 0x01, 0x0c,
0x89, 0x01, 0x0e,
0x8a, 0x01, 0x0e,
0x8b, 0x01, 0x10,
0x8c, 0x01, 0x10,
0x8f, 0x01, 0x1f,
0x90, 0x01, 0x1f,
0x93, 0x01, 0x02,
0x94, 0x01, 0x04,
0x9a, 0x01, 0x05,

0xff, 0x01, 0x30,
0xff, 0x01, 0x52,
0xff, 0x01, 0x00,  // Page 0
0x36, 0x01, 0x0a,
0x11, 0x01, 0x00,
0x29, 0x01, 0x00]

I cannot shrink the list more than this, in particular, if I comment out the PANELU2D1~44:80H~ABH on Page 3, there is an effect similar to the one you showed in your photo.

I'll let you be aware of any progress.

Cheers

Giuseppe

Hi Guiseppe and I.N,

thanks for replying. Regarding, 35Mhz is it possible that is due to signal integrity? The data should not be any different correct? Theorhetically if you try 18Mhz, 20Mhz etc. The data should be stable?
I read App note AN4861 and to get 60fps for 720x720 at 18bit we need at least 35Mhz clock.

 

Also see Lady Ada from Adafruit achieve high fps with ICN6211 here: https://www.tiktok.com/@adafruit/video/7301032769637993770

https://www.youtube.com/watch?v=CZ8xDk7Tw4g 

 

From my understanding the Adafruit Microcontroller only updates at around 30fps which is a primary reason I wanted to move to a STM32U5 based system with Neochrom.

 

Regarding, the minimal init sequence you are sending the bytes with 9 bit words in STM32?

9bit cmd + 9bit parameter? + 9bit parameter? How is this achieved?

SkeleSt_0-1721612110673.png

 compared to the Write_Reg_3052(cmd,param);

 

Regards,

Skele.

 

Hi SkeleSt ,,

at first look , i suspect the init codes are not properly transmitting to NV3052.

As i mentioned before , I used software spi solution of 9-bit frame .

 

below is my nv3052c.h

#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_gpio.h"
//#include "stdint.h"

/* Define for connection, redefine if needed */

/* Define for module SPI */

/* Define the pins tp connect */

/* Define for Chip Select Pin */
#define CS_PORT						GPIOC
#define CS_PIN						GPIO_PIN_8

/* Define for Data/Command Pin */
#define SCL_PORT					GPIOE
#define SCL_PIN						GPIO_PIN_2

/* Define for Data/Command Pin */
#define SDA_PORT					GPIOE
#define SDA_PIN						GPIO_PIN_6

/* Define for Backlite Pin */
#define BL_PORT						GPIOG
#define BL_PIN						GPIO_PIN_3

/* End Define For Connection */

/* Define private useful macro */
#define SPI_ENABLE	HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_RESET);
#define SPI_DISABLE     HAL_GPIO_WritePin(CS_PORT,CS_PIN,GPIO_PIN_SET);

/* Define private useful macro */
#define BL_ENABLE		HAL_GPIO_WritePin(BL_PORT,BL_PIN,GPIO_PIN_SET)
#define BL_DISABLE   	HAL_GPIO_WritePin(BL_PORT,BL_PIN,GPIO_PIN_RESET)

#define LCD_SDA0   		HAL_GPIO_WritePin(SDA_PORT,SDA_PIN,GPIO_PIN_RESET);
#define LCD_SDA1   		HAL_GPIO_WritePin(SDA_PORT,SDA_PIN,GPIO_PIN_SET);

#define LCD_SCL0   		HAL_GPIO_WritePin(SCL_PORT,SCL_PIN,GPIO_PIN_RESET);
#define LCD_SCL1   		HAL_GPIO_WritePin(SCL_PORT,SCL_PIN,GPIO_PIN_SET);

/* Define For TFT */
#define LCD_W 1280
#define LCD_H 720

/* Define string mode for tft_puts */
#define TFT_STRING_MODE_NO_BACKGROUND		0x01
#define TFT_STRING_MODE_BACKGROUND			0x00

extern uint16_t BACK_COLOR, POINT_COLOR;

/* Control Registers and constant codes */
#define NOP     0x00
#define SWRESET 0x01
#define RDDID   0x04
#define RDDST   0x09

#define SLPIN   0x10
#define SLPOUT  0x11
#define PTLON   0x12
#define NORON   0x13

#define INVOFF  0x20
#define INVON   0x21
#define DISPOFF 0x28
#define DISPON  0x29
#define CASET   0x2A
#define PASET   0x2B
#define RAMWR   0x2C
#define RAMRD   0x2E

#define PTLAR   0x30
#define COLMOD  0x3A
#define MADCTL  0x36


/** 
 * Memory Data Access Control Register (0x36H)
 * MAP:     D7  D6  D5  D4  D3  D2  D1  D0 
 * param:   MY  MX  MV  ML  RGB MH  -   -
 * 
 */ 

/* Page Address Order ('0': Top to Bottom, '1': the opposite) */
#define NV3052C_MADCTL_MY  0x02
/* Column Address Order ('0': Left to Right, '1': the opposite) */
#define NV3052C_MADCTL_MX  0x01
/* Page/Column Order ('0' = Normal Mode, '1' = Reverse Mode) */
/* RGB/BGR Order ('0' = RGB, '1' = BGR) */
#define NV3052C_MADCTL_RGB 0x08

#define NV3052C_RDID1   0xDA
#define NV3052C_RDID2   0xDB
#define NV3052C_RDID3   0xDC
#define NV3052C_RDID4   0xDD

/* Choose a display rotation you want to use: (0-3) */
//#define NV3052C_ROTATION 0
//#define NV3052C_ROTATION 1       
//#define NV3052C_ROTATION 2				//  use Normally on 240x240
#define NV3052C_ROTATION 3


#define NV3052C_COLOR_MODE_16bit 0x55    //  RGB565 (16bit)
#define NV3052C_COLOR_MODE_18bit 0x66    //  RGB666 (18bit)

/* Declaring Function Prototype */

/***************************************************** User Function ************************************************************/
/********************************************************************************************************************************/
/********************************************************************************************************************************/
/********************************************************************************************************************************/

void NV3052C_Init(void); 
void NV3052C_SetRotation(uint8_t m);

/******************************************************** Private Function ******************************************************/
/********************************************************************************************************************************/
/********************************************************************************************************************************/
/********************************************************************************************************************************/
/* Private Function Do Not Use In User Program */
void tft_add_set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);
void NV3052C_WriteSmallData(uint8_t data);
void tft_write_data(uint16_t data);
void NV3052C_WriteCommand(int8_t data);
void LCDSetXY(int x, int y);
void LCDSetCircle(int x0, int y0, int radius, int color);
void LCDSetPixel(int x, int y, int color);
void LCDSetLine(int x1, int y1, int x2, int y2, int color);
void LCDSetRect(int x0, int y0, int x1, int y1, unsigned char fill, int color);
void DefaultAxis(void);

void LCDPutChar(char c, int x, int y, int size, int fcolor, int bcolor);
void LCDPutString(char *pString, int x, int y, int Size, int fColor, int bColor);
void LCD_Clear (unsigned short color);

void LCDWriteWiFiLogo(unsigned int x, unsigned int y,unsigned int size_x, unsigned int size_y, unsigned int state);
void FIVE_inch_init(void);
void WriteSpiCommand(volatile unsigned int command);
void WriteSpiData(volatile unsigned int data);
void shiftBits(char b);
void write_Reg_3052(unsigned int command,unsigned int data);

below is my nv3052c.c

#include "nv3052c.h"


void write_Reg_3052(unsigned int command,unsigned int data);

/*---------------------- Graphic LCD size definitions ------------------------*/
#define WIDTH       1280                 /* Screen Width (in pixels)           */
#define HEIGHT      720                 /* Screen Hight (in pixels)           */
/******************************************************************************/

// *****************************************************************************
// 	function.c
// *****************************************************************************
/***************************************************** User Function ************************************************************/
void FIVE_inch_init(void)
{	
	BL_ENABLE;

  write_Reg_3052(0xFF,0x30);
  write_Reg_3052(0xFF,0x52);
  write_Reg_3052(0xFF,0x01); //page1 
  write_Reg_3052(0xE3,0x00);
  write_Reg_3052(0xf6,0xc0);
  write_Reg_3052(0xf0,0x00);
  write_Reg_3052(0xf3,0x00);
  write_Reg_3052(0xf5,0x00);
  write_Reg_3052(0x40,0x0a); 
  write_Reg_3052(0x32,0x34);
  write_Reg_3052(0x23,0xa2); 
  write_Reg_3052(0x43,0x83);
  write_Reg_3052(0x42,0x6d);
  write_Reg_3052(0x24,0x10);
  write_Reg_3052(0x25,0x10);
  write_Reg_3052(0x26,0x2e);
  write_Reg_3052(0x27,0x2e);
  write_Reg_3052(0x81,0x00);
  write_Reg_3052(0x91,0x55);
  write_Reg_3052(0x92,0x66);
  write_Reg_3052(0xaa,0xa8);
  write_Reg_3052(0xab,0x28);
  write_Reg_3052(0xae,0xd2);
  write_Reg_3052(0xaf,0x02);
  write_Reg_3052(0xb0,0xd2);
  write_Reg_3052(0xb2,0x26);
  write_Reg_3052(0xb3,0x26);
  write_Reg_3052(0xA0,0x52); 
  write_Reg_3052(0xA1,0x50); 
  write_Reg_3052(0x3b,0x94); 
  write_Reg_3052(0xA4,0x9C); 
  write_Reg_3052(0x3a,0x30);
  write_Reg_3052(0x38,0x9c);
  write_Reg_3052(0x39,0xa7);
  //Gamma
  write_Reg_3052(0xFF,0x30);
  write_Reg_3052(0xFF,0x52);
  write_Reg_3052(0xFF,0x02);
  //VRP0~VRP5
  write_Reg_3052(0xB0,0x07);
  write_Reg_3052(0xB1,0x04);
  write_Reg_3052(0xB2,0x03);
  write_Reg_3052(0xB3,0x23);
  write_Reg_3052(0xB4,0x21);
  write_Reg_3052(0xB5,0x2b);
  //PRP0,0xPRP1
  write_Reg_3052(0xB6,0x08);
  write_Reg_3052(0xB7,0x2b);
  //PKP0~PKP9
  write_Reg_3052(0xB8,0x0a);
  write_Reg_3052(0xB9,0x01);
  write_Reg_3052(0xBA,0x11);
  write_Reg_3052(0xBB,0x0f);
  write_Reg_3052(0xBC,0x12);
  write_Reg_3052(0xBD,0x13);
  write_Reg_3052(0xBE,0x17);
  write_Reg_3052(0xBF,0x0f);
  write_Reg_3052(0xC0,0x16);
  write_Reg_3052(0xC1,0x06);
  //VRN0~VRN5
  write_Reg_3052(0xD0,0x02);
  write_Reg_3052(0xD1,0x0a);
  write_Reg_3052(0xD2,0x05);
  write_Reg_3052(0xD3,0x2f);
  write_Reg_3052(0xD4,0x35);
  write_Reg_3052(0xD5,0x3e);
  //PRN0,0xPRN1
  write_Reg_3052(0xD6,0x0d);
  write_Reg_3052(0xD7,0x33);
  //PKN0~PKN9
  write_Reg_3052(0xD8,0x0c);
  write_Reg_3052(0xD9,0x02);
  write_Reg_3052(0xDA,0x11);
  write_Reg_3052(0xDB,0x0f);
  write_Reg_3052(0xDC,0x12);
  write_Reg_3052(0xDD,0x14);
  write_Reg_3052(0xDE,0x18);
  write_Reg_3052(0xDF,0x0e);
  write_Reg_3052(0xE0,0x16);
  write_Reg_3052(0xE1,0x07);
  write_Reg_3052(0xFF,0x30);
  write_Reg_3052(0xFF,0x52);
  write_Reg_3052(0xFF,0x03); //page3
  write_Reg_3052(0x05,0x00); //gip_vst_tchop low
  write_Reg_3052(0x06,0x00); //gip_vst_tglue low
  write_Reg_3052(0x07,0x02); //gip_vst_width
  write_Reg_3052(0x08,0x07); //gip_vst_shift1 07
  write_Reg_3052(0x09,0x08); //gip_vst_shift2 08
  write_Reg_3052(0x0a,0x09); //gip_vst_shift3 09
  write_Reg_3052(0x0b,0x0a); //gip_vst_shift4 0a
  //ECLK
  write_Reg_3052(0x70,0x0f); //eclk_width
  write_Reg_3052(0x71,0xc0); //eclk_tchop
  write_Reg_3052(0x34,0xb1); //gip_clk_tchop high
  write_Reg_3052(0x35,0x77);   
  write_Reg_3052(0x36,0x20); ///gip_clk_tchop low80
  write_Reg_3052(0x37,0x13); ///gip_clk_width
  //GCLKA1/2/3/4
  write_Reg_3052(0x40,0x09); //clk_start  0a
  write_Reg_3052(0x41,0x0a); //clk_start  0b
  write_Reg_3052(0x42,0x0b); //clk_start  0c
  write_Reg_3052(0x43,0x0c); //clk_start  0d
  write_Reg_3052(0x45,0x11); //clk_stop   0e
  write_Reg_3052(0x46,0x12); //clk_stop   0f
  write_Reg_3052(0x48,0x13); //clk_stop   10
  write_Reg_3052(0x49,0x14); //clk_stop   11
  //GCLKB1/2/3/4
  write_Reg_3052(0x50,0x0d); //clk_start  0e
  write_Reg_3052(0x51,0x0e); //clk_start  0f
  write_Reg_3052(0x52,0x0f); //clk_start  10
  write_Reg_3052(0x53,0x10); //clk_start  11
  write_Reg_3052(0x55,0x15); //clk_stop   12
  write_Reg_3052(0x56,0x16); //clk_stop   13
  write_Reg_3052(0x58,0x17); //clk_stop   14
  write_Reg_3052(0x59,0x18); //clk_stop   15
  write_Reg_3052(0x80,0x1f); //FW
  write_Reg_3052(0x81,0x00); //BW
  write_Reg_3052(0x82,0x15); //GPWR1
  write_Reg_3052(0x83,0x16); //GPWR2
  write_Reg_3052(0x84,0x0e); //clkb2,0xclk1_l
  write_Reg_3052(0x85,0x10); //clkb4,0xclk2_l
  write_Reg_3052(0x86,0x0a); //clka2,0xclk3_l
  write_Reg_3052(0x87,0x0c); //clka4,0xclk4_l
  write_Reg_3052(0x88,0x02); //vst2,0xstv1_l
  write_Reg_3052(0x8A,0x04); //vst4,0xstv2_l
  write_Reg_3052(0x96,0x1f); //FW
  write_Reg_3052(0x97,0x00); //BW
  write_Reg_3052(0x98,0x17); //GPWR1
  write_Reg_3052(0x99,0x18); //GPWR2
  write_Reg_3052(0x9a,0x0d); //clkb1,0xclk1_r
  write_Reg_3052(0x9b,0x0f); //clkb3,0xclk2_r
  write_Reg_3052(0x9c,0x09); //clka1,0xclk3_r
  write_Reg_3052(0x9d,0x0b); //clka3,0xclk4_r
  write_Reg_3052(0x9e,0x01); //vst1,0xstv1_r
  write_Reg_3052(0xA0,0x03); //vst3,0xstv2_r
  write_Reg_3052(0xb0,0x00);
  write_Reg_3052(0xb1,0x1f);
  write_Reg_3052(0xb2,0x15);
  write_Reg_3052(0xb3,0x16);
  write_Reg_3052(0xb4,0x0b);
  write_Reg_3052(0xb5,0x09);
  write_Reg_3052(0xb6,0x0f);
  write_Reg_3052(0xb7,0x0d);
  write_Reg_3052(0xb8,0x03);
  write_Reg_3052(0xba,0x01);
  write_Reg_3052(0xc6,0x00);
  write_Reg_3052(0xc7,0x1f);
  write_Reg_3052(0xc8,0x17);
  write_Reg_3052(0xc9,0x18);
  write_Reg_3052(0xca,0x0c);
  write_Reg_3052(0xcb,0x0a);
  write_Reg_3052(0xcc,0x10);
  write_Reg_3052(0xcd,0x0e);
  write_Reg_3052(0xce,0x04);
  write_Reg_3052(0xd0,0x02);
	
  write_Reg_3052(0xFF,0x30);
  write_Reg_3052(0xFF,0x52);
  write_Reg_3052(0xFF,0x00);
//  write_Reg_3052(0x36,0x03);

  NV3052C_SetRotation(1);

  write_Reg_3052(0x35,0x01);
  write_Reg_3052(0x11,0x00);
  HAL_Delay(120);	

  write_Reg_3052(0x29,0x00);
  HAL_Delay(120);



} 
// *****************************************************************************
// 	function.c
// *****************************************************************************
void NV3052C_SetRotation(uint8_t m)
{
	
	switch (m) {
	case 0:
		write_Reg_3052(MADCTL,NV3052C_MADCTL_MX );
		break;
	case 1:
		write_Reg_3052(MADCTL,NV3052C_MADCTL_MY );
		break;
	case 2:
		write_Reg_3052(MADCTL,NV3052C_MADCTL_MX | NV3052C_MADCTL_MY );
		break;
	case 3:
		write_Reg_3052(MADCTL,NV3052C_MADCTL_MX | NV3052C_MADCTL_MY | NV3052C_MADCTL_RGB);
		break;
	default:
		break;
	}
}
// *****************************************************************************
// WriteSpiCommand.c
// *****************************************************************************
void WriteSpiCommand(volatile unsigned int command)
{
  LCD_SCL0;
  LCD_SDA0;                                                 //0 for cmd
  LCD_SCL1;
  shiftBits(command);
  
}
// *****************************************************************************
// WriteSpiData.c
// *****************************************************************************
void WriteSpiData(volatile unsigned int data)
{
  LCD_SCL0;
  LCD_SDA1;                                                 //1 for param
  LCD_SCL1;
  shiftBits(data);
}
// *****************************************************************************
// shiftBits
// *****************************************************************************
void shiftBits(char b)
{
  LCD_SCL0;
  if ((b&128)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&64)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&32)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&16)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&8)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&4)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&2)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;
  LCD_SCL0;

  if ((b&1)!=0) {LCD_SDA1;} else LCD_SDA0;
  LCD_SCL1;

}
// *****************************************************************************
// 	function.c
// *****************************************************************************
void write_Reg_3052(unsigned int command,unsigned int data)
{
	SPI_ENABLE;
	WriteSpiCommand(command);
	WriteSpiData(data);
	SPI_DISABLE;
}

 

You need to define your software SPI's Clock & Data Pins in MX.

You also need to bit modify the above codes as per your resolution.

I hop , after proper initialization , you will get the proper display .

regarding the Pixel Clock frequency ,, first use lower frequencies to test the display but display (complete frame) will flicker due to low refresh rate but don't worry.:face_with_tears_of_joy:

let me know the outcomes of your test with 9-bit software SPI.

 

regards

I.N

CommanderCloud
Associate II

Hello,

 

I have been working on a similar screen, and I have had similar lines. I doubt that it is the initialization code, because it wasn't for me. I tested it two ways - I found that the display controller has an onboard register that displays a white screen when set, and another which displays a test image (if your display controller is a Sitronix ST7701S, the code in the file attached can display those images). If you can get those, your initialization code is arriving properly. The other way I tested it was as follows. I bought an HDMI converter board which can correctly initialize the display and run it, so I hooked up a logic analyzer to the relevant SPI pins and was able to capture the initialization code, and it was identical to what the manufacturer for the display provided. This leads to what I think is the problem: I hooked up the logic analyzer to the HDMI board and was able to get the sync timings, porches and polarities. The signals that came out of the HDMI board were completely different to the signals from my custom board, and the polarities were not what I expected from what the labels suggest (Active High did not mean what I thought it did). So, the polarities and timings were wrong.

 

Hope it helps :)

Kind regards, Cloud

Hi Gpaga,

I attempted your minimal init code on the STM32 and there's still vertical line artefacts. Although they are different in behavior. 

uint8_t NV3051C_Init_Minimal()
{
	Wrt_Reg_3052(0xff, 0x30);
	Wrt_Reg_3052(0xff, 0x52);
	Wrt_Reg_3052(0xff, 0x01);
	Wrt_Reg_3052(0x0a, 0x11);
	Wrt_Reg_3052(0x23, 0xa0);
	Wrt_Reg_3052(0x29, 0x02);
	Wrt_Reg_3052(0x2a, 0xcf);
	Wrt_Reg_3052(0xff, 0x30);
	Wrt_Reg_3052(0xff, 0x52);
	Wrt_Reg_3052(0xff, 0x03);
	Wrt_Reg_3052(0x82, 0x1f);
	Wrt_Reg_3052(0x83, 0x1f);
	Wrt_Reg_3052(0x85, 0x0a);
	Wrt_Reg_3052(0x86, 0x0a);
	Wrt_Reg_3052(0x87, 0x0c);
	Wrt_Reg_3052(0x88, 0x0c);
	Wrt_Reg_3052(0x89, 0x0e);
	Wrt_Reg_3052(0x8a, 0x0e);
	Wrt_Reg_3052(0x8b, 0x10);
	Wrt_Reg_3052(0x8c, 0x10);
	Wrt_Reg_3052(0x8f, 0x1f);
	Wrt_Reg_3052(0x90, 0x1f);
	Wrt_Reg_3052(0x93, 0x02);
	Wrt_Reg_3052(0x94, 0x04);
	Wrt_Reg_3052(0x9a, 0x05);
	Wrt_Reg_3052(0xff, 0x30);
	Wrt_Reg_3052(0xff, 0x52);
	Wrt_Reg_3052(0xff, 0x00);
	Wrt_Reg_3052(0x36, 0x0a);
	Wrt_Reg_3052(0x11, 0x00);
	HAL_Delay(200);
	Wrt_Reg_3052(0x29, 0x00);
	HAL_Delay(120);

	HAL_Delay(1000);
	Wrt_Reg_3052(0x28,0x00); // Display Off
	HAL_Delay(1000);
	Wrt_Reg_3052(0x29,0x00); // Display On
	HAL_Delay(50);
	Wrt_Reg_3052(0x23,0x00); // All Pixels On(23H)
	HAL_Delay(1000);
	Wrt_Reg_3052(0x28,0x00); // Display Off
	HAL_Delay(1000);
	Wrt_Reg_3052(0x29,0x00); // Display On
	HAL_Delay(50);
	Wrt_Reg_3052(0x13,0x00);//Normal Display Mode On(13H)


	return 1;
}

 

Hi INaee,

thank you for your reply. I've turned my LTDC clock down to 4Mhz to ensure a stable signal.

My logic analyzer confirm the SPI is correct even with hardware based SPI1 configuration in CubeMX. My SPI is 100% correct, I can use Display ON, All pixels on commands etc.

SkeleSt_1-1721695738425.png

This means that either the init code is incorrect, or the display timings are incorrect which is consistent with what @CommanderCloud has said.

 

I have one question however regarding my specific display. There seems to be a inconsistency in the code provided by Adafruit. The init code refers to the NV3052CGRB driver IC. However the manual provided on their website is the NV3052C. These have different datasheets.

https://www.buydisplay.com/download/ic/NV3052CGRB.pdf

https://www.phoenixdisplay.com/wp-content/uploads/2019/05/NV3052C-Datasheet-V0.2.pdf

Of course I am using 18bit + SPI in either case.


@GPaga is it possible to use logic analyser on the VS, HS, porch timings of the ESP32-S3? Maybe there is inconsistency between STM32 and ESP32?

 

In green are the permutations of cubemx settings I tried for LTDC:

SkeleSt_1-1721704243675.png

I haven't tested different timings yet however.

All behavior on my screen so far has only led to different combinations of "white lines" on my display. But always white lines.

 

Kind Regards,

Skele.

 

 

 

 

 

 

Hi S.

you asked me the meaning of the initialization sequence.

This is how the adafruit code process it:

https://git.kfayun.com/xpstem/circuitpython/-/blob/9.1.0/shared-module/dotclockframebuffer/__init__.c#L89

        ioexpander_bus_send(bus, true, cmd, 1);
        ioexpander_bus_send(bus, false, data, data_size);

   cmd is in the first column

   data_size in the second column

   data in the third column 

Today I will do some tests changing the polarity of then synchronism signals (VS, HS, DE).

It is really difficult to understand what is wrong with your or mine setting, what I realized is that a single error bit in the page 3 register configuration leads to the vertical leads artifacts (small changes in many of the other registers generates bad synchronism or flickering).

I'll keep you up to date.

 

Cheers

Giuseppe