cancel
Showing results for 
Search instead for 
Did you mean: 

SSD1963 with STM32F407 using FSMC

oleq96
Associate

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

 

 

 

1 REPLY 1
Toneski
Associate III

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.