2024-11-17 03:41 AM
Hello,
I am trying to configure STM32F407VGT6 discovery to work with 800x480 LCD with SSD1963 onboard. In the end i would like to use TouchGFX to run the GUI.
I was testing several configurations to display anything manually first. It looks like the command buffer works fine (in the end of Init function driver reacts on "LCD on" command), but nothing happens when I send anything to data buffer and pixels remains with random color values. I checked the wiring and it is fine.
I attached the .ioc file and my main.c. What could be the problem?
Regards,
Oliwer
#include "main.h"
#include "app_touchgfx.h"
CRC_HandleTypeDef hcrc;
SRAM_HandleTypeDef hsram1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_FSMC_Init(void);
static void MX_CRC_Init(void);
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_COMMAND (*((volatile uint16_t *) 0x60000000))
#define LCD_DATA (*((volatile uint16_t *) 0x60020000))
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_FSMC_Init();
MX_CRC_Init();
MX_TouchGFX_Init();
SSD1963_Init();
HAL_GPIO_WritePin(LCD_BACKLIGHT_GPIO_Port, LCD_BACKLIGHT_Pin, GPIO_PIN_SET);
SSD1963_FillScreen(0xF800);
while (1)
{
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV4;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_CRC_Init(void)
{
hcrc.Instance = CRC;
if (HAL_CRC_Init(&hcrc) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOC, LCD_RESET_Pin|LCD_BACKLIGHT_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = LCD_RESET_Pin|LCD_BACKLIGHT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
static void MX_FSMC_Init(void)
{
FSMC_NORSRAM_TimingTypeDef Timing = {0};
hsram1.Instance = FSMC_NORSRAM_DEVICE;
hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
hsram1.Init.NSBank = FSMC_NORSRAM_BANK1;
hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;
hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE;
Timing.AddressSetupTime = 15;
Timing.AddressHoldTime = 15;
Timing.DataSetupTime = 255;
Timing.BusTurnAroundDuration = 15;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FSMC_ACCESS_MODE_A;
if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
{
Error_Handler( );
}
}
void SSD1963_SendCommand(uint16_t cmd) {
LCD_COMMAND = cmd;
}
void SSD1963_SendData(uint16_t data) {
LCD_DATA = data;
}
void SSD1963_Init(void) {
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port,LCD_RESET_Pin, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(LCD_RESET_GPIO_Port,LCD_RESET_Pin, GPIO_PIN_SET);
HAL_Delay(100);
SSD1963_SendCommand(0x01); // Software reset
HAL_Delay(10);
SSD1963_SendCommand(0xE2); // PLL configuration
SSD1963_SendData(0x23); // M = 35
SSD1963_SendData(0x02); // N = 2
SSD1963_SendData(0x04); // PLL frequency = (M+1)*REF / (N+1)
SSD1963_SendCommand(0xE0); // Start PLL
SSD1963_SendData(0x01); // Enable PLL
HAL_Delay(10);
SSD1963_SendCommand(0xE0); // Lock PLL
SSD1963_SendData(0x03); // Now PLL is locked
HAL_Delay(10);
SSD1963_SendCommand(0xB0); // Set LCD mode
SSD1963_SendData(0x00); // TFT mode, no reverse scan
SSD1963_SendData(0x00); // TFT mode
SSD1963_SendData(0x03); // Horizontal width high byte (800 = 0x0320)
SSD1963_SendData(0x20); // Horizontal width low byte
SSD1963_SendData(0x01); // Vertical height high byte (480 = 0x01E0)
SSD1963_SendData(0xE0); // Vertical height low byte
SSD1963_SendData(0x00); // RGB565 format
SSD1963_SendCommand(0xF0); // Set pixel data interface
SSD1963_SendData(0x03); // 16-bit (RGB565)
SSD1963_SendCommand(0xB4); // Set horizontal period
SSD1963_SendData(0x03); // HT high byte (928 = 0x03A0)
SSD1963_SendData(0xA0); // HT low byte
SSD1963_SendData(0x00); // HPS high byte (40 = 0x28)
SSD1963_SendData(0x28); // HPS low byte
SSD1963_SendData(0x0A); // HPW (10)
SSD1963_SendData(0x00); // LPS high byte (88 = 0x58)
SSD1963_SendData(0x58); // LPS low byte
SSD1963_SendData(0x00); // Horizontal polarity
SSD1963_SendCommand(0xB6); // Set vertical period
SSD1963_SendData(0x01); // VT high byte (525 = 0x020D)
SSD1963_SendData(0x0D); // VT low byte
SSD1963_SendData(0x00); // VPS high byte (13 = 0x0D)
SSD1963_SendData(0x0D); // VPS low byte
SSD1963_SendData(0x02); // VPW (2)
SSD1963_SendData(0x00); // FPS high byte (10)
SSD1963_SendData(0x0A); // FPS low byte
SSD1963_SendData(0x00); // Vertical polarity
SSD1963_SendCommand(0x36); // Set address mode
SSD1963_SendData(0x00); // Default orientation
SSD1963_SendCommand(0x29); // Turn on the display
HAL_Delay(10);
}
void SSD1963_FillScreen(uint16_t color) {
SSD1963_SendCommand(0x2C); // Write Memory Start
for (int i = 0; i < LCD_WIDTH * LCD_HEIGHT; i++) {
SSD1963_SendData(color);
}
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
}
#endif
2024-11-18 09:17 PM
Hi oleq96,
We need more information.
1. I always worry when people state "I checked the wiring and it is fine.". Can we see how you've connected your display? - Please upload a schematic (a JPG will do, but must include connection detail - capture it from your schematic capture software).
2. Does the display do anything when you run this code? Does it light up with the backlight? - Can you see anything on the display even though nothing sensible is there? (Like a display full of random stuff/noise?).
3. Are you using some sort of frame buffer between your CPU and the display - something like the "Microchip Technology SSD1963"?.
FYI - Usually when driving displays you usually need to worry about the Whole picture - not just the data bit - this means that you need to wait for the correct timings for Horizontal/vertical blanking, the sync pulses (vertical and horizontal) and finally the data. The display data need to be sent to the display with the correct timings and synchronised to the LCD data clock. Usually I would use DMA to deliver the data at the required rate & quantity, with perhaps a timer to two to manage the SYNC/timings.
Show us what you've got...
Regards,
Toneski.