aboutsummaryrefslogtreecommitdiffstats
path: root/boards/base/STM32F469i-Discovery/CubeHAL/board_STM32LTDC.h
blob: 1571966b06bb28083efb93b00f7b4532f907f53a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*
 * This file is subject to the terms of the GFX License. If a copy of
 * the license was not distributed with this file, you can obtain one at:
 *
 *              http://ugfx.io/license.html
 */

#ifndef _GDISP_LLD_BOARD_H
#define _GDISP_LLD_BOARD_H

/* Avoid naming collisions with CubeHAL. */
#if GFX_COMPAT_V2 && GFX_COMPAT_OLDCOLORS
	#undef Red
	#undef Green
	#undef Blue
#endif

/* HAL drivers needed for configuration. */
#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_rcc.h"
#include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_hal_dsi.h"
/* sdram driver provided by ST. */
#include "stm32f469i_discovery_sdram.h"
/* OTM8009A driver provided by ST. */
#include "otm8009a.h"

/** Manually set the LTDC timing. */
#ifndef GFX_LTDC_TIMING_SET
  #define GFX_LTDC_TIMING_SET
#endif

/** Most boards will be revision A. */
#ifndef USE_STM32469I_DISCO_REVA
  #define USE_STM32469I_DISCO_REVA
#endif

/** @brief Panel parameters
 *
 * This panel is a KoD KM-040TMP-02-0621 DSI LCD Display.
 */

static const ltdcConfig driverCfg = {
	800, 480,								// Width, Height (pixels)
	1, 2,									  // Horizontal, Vertical sync (pixels)
	15, 34,									// Horizontal, Vertical back porch (pixels)
	16, 34,									// Horizontal, Vertical front porch (pixels)
	0,										  // Sync flags
	0x000000,								// Clear color (RGB888)

	{										                  // Background layer config
		(LLDCOLOR_TYPE *)SDRAM_DEVICE_ADDR, // Frame buffer address
		800, 480,							              // Width, Height (pixels)
		800 * LTDC_PIXELBYTES,				      // Line pitch (bytes)
		LTDC_PIXELFORMAT,					          // Pixel format
		0, 0,								                // Start pixel position (x, y)
		800, 480,							              // Size of virtual layer (cx, cy)
		LTDC_COLOR_FUCHSIA,					        // Default color (ARGB8888)
		0x980088,							              // Color key (RGB888)
		LTDC_BLEND_FIX1_FIX2,				        // Blending factors
		0,									                // Palette (RGB888, can be NULL)
		0,									                // Palette length
		0xFF,								                // Constant alpha factor
		LTDC_LEF_ENABLE						          // Layer configuration flags
	},

	LTDC_UNUSED_LAYER_CONFIG				      // Foreground layer config
};

/** Display timing setting */
#define KoD_FREQUENCY_DIVIDER 7

/** Global DSI handle to hold DSI parameters. */
DSI_HandleTypeDef dsiHandle;

static GFXINLINE void reset_lcd(GDisplay* g);

/**
 * @brief  Function to intialize the STM32F46i-DISCO board.
 *
 * @param  g: Structure holding display parameters.
 */
static GFXINLINE void init_board(GDisplay *g) {

  // As we are not using multiple displays we set g->board to NULL as we don't use it
  g->board = 0;

#ifdef GFX_LTDC_TIMING_SET
  // KoD LCD clock configuration
  // PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz
  // PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 384 Mhz
  // PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 384/7 = 54.857 Mhz
  // LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_2 = 54.857/2 = 27.429Mhz
  #define STM32_SAISRC_NOCLOCK    (0 << 23)   /**< No clock.                  */
  #define STM32_SAISRC_PLL        (1 << 23)   /**< SAI_CKIN is PLL.           */
  #define STM32_SAIR_DIV2         (0 << 16)   /**< R divided by 2.            */
  #define STM32_SAIR_DIV4         (1 << 16)   /**< R divided by 4.            */
  #define STM32_SAIR_DIV8         (2 << 16)   /**< R divided by 8.            */
  #define STM32_SAIR_DIV16        (3 << 16)   /**< R divided by 16.           */

  #define STM32_PLLSAIN_VALUE                 384
  #define STM32_PLLSAIQ_VALUE                 4
  #define STM32_PLLSAIR_VALUE                 KoD_FREQUENCY_DIVIDER
  #define STM32_PLLSAIR_POST                  STM32_SAIR_DIV2

  RCC->PLLSAICFGR = (STM32_PLLSAIN_VALUE << 6) | (STM32_PLLSAIR_VALUE << 28) | (STM32_PLLSAIQ_VALUE << 24);
  RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | STM32_PLLSAIR_POST;
  RCC->CR |= RCC_CR_PLLSAION;
  while(!(RCC->CR & RCC_CR_PLLSAIRDY));			// wait for PLLSAI to lock
#endif

  __HAL_RCC_DSI_CLK_ENABLE();

  DSI_PLLInitTypeDef  dsiPllInit;
  DSI_CmdCfgTypeDef   dsiCmdMode;
  DSI_LPCmdTypeDef    dsiAPBCmd;
  /* Filling the DSI intialization struct. */
  dsiHandle.Instance                       = DSI;                            // There is only one DSI interface
  dsiHandle.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_ENABLE;  // Automatic clock lane control: powers down the clock lane when not in use
  /* Highest speed = 500MHz. */
  gU16 laneByteClk_kHz = 62500; /* 500 MHz / 8 = 62.5 MHz = 62500 kHz */
  /* TXEscapeCkdiv = f(LaneByteClk)/15.62 = 4 -> 500MHz/4 = 25MHz datasheet says around 20MHz */
  dsiHandle.Init.TXEscapeCkdiv             = laneByteClk_kHz/15620;          // Low power clock relative to the laneByteClock
  dsiHandle.Init.NumberOfLanes             = DSI_TWO_DATA_LANES;             // Two data lines for the fastest transfer speed

  /* Fill in the command mode struct. */
  dsiCmdMode.VirtualChannelID              = 0;                              // The first virtual channel

  /* Select the appropriate color coding. */
#ifdef GDISP_PIXELFORMAT_RGB565
  dsiCmdMode.ColorCoding = DSI_RGB565;
#else
  dsiCmdMode.ColorCoding = DSI_RGB888;
#endif

  dsiCmdMode.CommandSize            = driverCfg.width;             // Amount of pixels sent at once -> one line at a time
  dsiCmdMode.TearingEffectSource    = DSI_TE_EXTERNAL;             // Use pin PJ2
  dsiCmdMode.TearingEffectPolarity  = DSI_TE_RISING_EDGE;
  dsiCmdMode.HSPolarity             = DSI_HSYNC_ACTIVE_HIGH;
  dsiCmdMode.VSPolarity             = DSI_VSYNC_ACTIVE_HIGH;
  dsiCmdMode.DEPolarity             = DSI_DATA_ENABLE_ACTIVE_HIGH;
  dsiCmdMode.VSyncPol               = DSI_VSYNC_FALLING;
  dsiCmdMode.AutomaticRefresh       = DSI_AR_ENABLE;               // Use the automatic refresh mode
  dsiCmdMode.TEAcknowledgeRequest   = DSI_TE_ACKNOWLEDGE_DISABLE;  // Not needed when using TE through GPIO

  /* GPIO configuration. */
  GPIO_InitTypeDef  gpioInit;
  /* PH7  LCD_RESET */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  gpioInit.Pin   = GPIO_PIN_7;
  gpioInit.Mode  = GPIO_MODE_OUTPUT_OD;
  gpioInit.Pull  = GPIO_NOPULL;
  gpioInit.Speed = GPIO_SPEED_HIGH;
  HAL_GPIO_Init(GPIOH, &gpioInit);

  /* PJ2  DSIHOST_TE */
  __HAL_RCC_GPIOJ_CLK_ENABLE();
  gpioInit.Pin        = GPIO_PIN_2;
  gpioInit.Mode       = GPIO_MODE_AF_PP;
  gpioInit.Alternate  = GPIO_AF13_DSI;
  HAL_GPIO_Init(GPIOJ, &gpioInit);

  /* PA3  LCD_BL_CTRL This pin is not physically connected. */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  gpioInit.Pin        = GPIO_PIN_3;
  gpioInit.Mode       = GPIO_MODE_OUTPUT_OD;
  HAL_GPIO_Init(GPIOA, &gpioInit);

  /* Fvco = f(CLKin/IDF) * 2 * NDIV;  fPHI = Fvco/(2*ODF) */
#if !defined(USE_STM32469I_DISCO_REVA)
  /* fPHI = CLKin*62.5;  Fvco = CLKin*125 */
  dsiPllInit.PLLNDIV  = 125;
  dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV2;
#else
  /* fPHI = CLKin*20;   Fvco = CLKin*40 */
  dsiPllInit.PLLNDIV  = 100;
  dsiPllInit.PLLIDF   = DSI_PLL_IN_DIV5;
#endif
  dsiPllInit.PLLODF   = DSI_PLL_OUT_DIV1;

  /* Initialize the DSI peripheral. */
  HAL_DSI_Init(&dsiHandle, &dsiPllInit);

  DSI_PHY_TimerTypeDef  PhyTimings;
  /* Configure DSI PHY HS2LP and LP2HS timings. Datasheet says 95ns max */
  PhyTimings.ClockLaneHS2LPTime   = 35;
  PhyTimings.ClockLaneLP2HSTime   = 35;
  PhyTimings.DataLaneHS2LPTime    = 35;
  PhyTimings.DataLaneLP2HSTime    = 35;
  PhyTimings.DataLaneMaxReadTime  = 0;
  PhyTimings.StopWaitTime         = 10;
  HAL_DSI_ConfigPhyTimer(&dsiHandle, &PhyTimings);

  /* Configure adapted command mode. */
  HAL_DSI_ConfigAdaptedCommandMode(&dsiHandle, &dsiCmdMode);

  /* Hardware reset LCD */
  reset_lcd(g);

  /* Initialize the SDRAM */
  BSP_SDRAM_Init();
}

static GFXINLINE void set_backlight(GDisplay* g, gU8 percent)
{
	(void)g;
	(void)percent;
}

/**
 * @brief  Perform a hardware reset on the LCD.
 *
 * @param  g: Display parameter structure.
 */
static GFXINLINE void reset_lcd(GDisplay* g)
{
  (void)g;
  /* Hardware display reset. */
  HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_RESET);
  gfxSleepMilliseconds(20);
  HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_SET);
  gfxSleepMilliseconds(10);
  /* Turn on backlight. */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
}

/**
 * @brief  Extra initialization that is performed after the LTDC intialization.
 *
 * @param  g: Display paramter structure.
 */
static GFXINLINE void post_init_board(GDisplay* g)
{
  (void)g;
  DSI_LPCmdTypeDef dsiAPBCmd;

  /* Enable the DSI host and wrapper after the LTDC initialization
  To avoid any synchronization issue, the DSI shall be started after enabling the LTDC */
  HAL_DSI_Start(&dsiHandle);

  /* The configuration commands for the LCD have to be send through the dsiAPBCmd
  * interface as the adapted command mode only supports DCS, WMS and WMC commands. */
  dsiAPBCmd.LPGenShortWriteNoP    = DSI_LP_GSW0P_ENABLE;  // Put everything in low power mode
  dsiAPBCmd.LPGenShortWriteOneP   = DSI_LP_GSW1P_ENABLE;
  dsiAPBCmd.LPGenShortWriteTwoP   = DSI_LP_GSW2P_ENABLE;
  dsiAPBCmd.LPGenShortReadNoP     = DSI_LP_GSR0P_ENABLE;
  dsiAPBCmd.LPGenShortReadOneP    = DSI_LP_GSR1P_ENABLE;
  dsiAPBCmd.LPGenShortReadTwoP    = DSI_LP_GSR2P_ENABLE;
  dsiAPBCmd.LPGenLongWrite        = DSI_LP_GLW_ENABLE;
  dsiAPBCmd.LPDcsShortWriteNoP    = DSI_LP_DSW0P_ENABLE;
  dsiAPBCmd.LPDcsShortWriteOneP   = DSI_LP_DSW1P_ENABLE;
  dsiAPBCmd.LPDcsShortReadNoP     = DSI_LP_DSR0P_ENABLE;
  dsiAPBCmd.LPDcsLongWrite        = DSI_LP_DLW_ENABLE;
  HAL_DSI_ConfigCommand(&dsiHandle, &dsiAPBCmd);

  /* Configure the LCD. */
#ifdef GDISP_PIXELFORMAT_RGB565
  OTM8009A_Init(OTM8009A_FORMAT_RBG565, 1);
#else
  OTM8009A_Init(OTM8009A_FORMAT_RGB888, 1);
#endif

  /* Enable the tearing effect line. */
  HAL_DSI_ShortWrite(&dsiHandle, 0, DSI_DCS_SHORT_PKT_WRITE_P1, DSI_SET_TEAR_ON, 0);  // Only V-Blanking info

  /* Disable the APB command mode again to go into adapted command mode. (going into high speed mode) */
  dsiAPBCmd.LPGenShortWriteNoP    = DSI_LP_GSW0P_DISABLE;
  dsiAPBCmd.LPGenShortWriteOneP   = DSI_LP_GSW1P_DISABLE;
  dsiAPBCmd.LPGenShortWriteTwoP   = DSI_LP_GSW2P_DISABLE;
  dsiAPBCmd.LPGenShortReadNoP     = DSI_LP_GSR0P_DISABLE;
  dsiAPBCmd.LPGenShortReadOneP    = DSI_LP_GSR1P_DISABLE;
  dsiAPBCmd.LPGenShortReadTwoP    = DSI_LP_GSR2P_DISABLE;
  dsiAPBCmd.LPGenLongWrite        = DSI_LP_GLW_DISABLE;
  dsiAPBCmd.LPDcsShortWriteNoP    = DSI_LP_DSW0P_DISABLE;
  dsiAPBCmd.LPDcsShortWriteOneP   = DSI_LP_DSW1P_DISABLE;
  dsiAPBCmd.LPDcsShortReadNoP     = DSI_LP_DSR0P_DISABLE;
  dsiAPBCmd.LPDcsLongWrite        = DSI_LP_DLW_DISABLE;
  HAL_DSI_ConfigCommand(&dsiHandle, &dsiAPBCmd);

  HAL_DSI_Refresh(&dsiHandle);
}

/**
  * @brief  DCS or Generic short/long write command
  * @param  NbrParams: Number of parameters. It indicates the write command mode:
  *                 If inferior to 2, a long write command is performed else short.
  * @param  pParams: Pointer to parameter values table.
  * @retval HAL status
  */
void DSI_IO_WriteCmd(gU32 NbrParams, gU8 *pParams)
{
  if(NbrParams <= 1)
  {
   HAL_DSI_ShortWrite(&dsiHandle, 0, DSI_DCS_SHORT_PKT_WRITE_P1, pParams[0], pParams[1]);
  }
  else
  {
   HAL_DSI_LongWrite(&dsiHandle,  0, DSI_DCS_LONG_PKT_WRITE, NbrParams, pParams[NbrParams], pParams);
  }
}

/**
 * @brief  Delay function for the OTM8009A driver.
 *
 * @param  Delay: The requested delay in ms.
 */
void OTM8009A_IO_Delay(gU32 Delay)
{
  gfxSleepMilliseconds(Delay);
}

#endif /* _GDISP_LLD_BOARD_H */