diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5445861278ef6f8fe6dedd99a58a85aaf5e3b6f9..60b7abb5e556a44585e06b18a232dd5ffc3d05d2 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -123,6 +123,7 @@
"addfilter",
"ADON",
"aelf",
+ "AHBP",
"airbrakes",
"Airbrakes",
"Alain",
@@ -131,18 +132,29 @@
"AMSL",
"apbclk",
"atthr",
+ "AVBP",
"AVDD",
+ "AWCR",
"awum",
"Baro",
+ "BCBLUE",
+ "BCCR",
+ "BCGREEN",
+ "BCRED",
"bittiming",
"boardcore",
"Boardcorev",
"boudrate",
+ "BPCR",
"Canbus",
"canprotocol",
"Carlucci",
"CCMDATAR",
"CCMDATARAMEN",
+ "CLCR",
+ "CMDM",
+ "COLC",
+ "COLMUX",
"compid",
"Corigliano",
"CORTEXM",
@@ -154,11 +166,16 @@
"cyaw",
"DATABUS",
"datasheet",
+ "DCKCFGR",
"deleteme",
"DMEIE",
"Doxyfile",
"doxygen",
"DRDY",
+ "DRST",
+ "DSIEN",
+ "DSIM",
+ "DSIRST",
"Duca",
"Ecompass",
"Eigen",
@@ -173,6 +190,7 @@
"FOVR",
"FRLVL",
"FRXTH",
+ "FUIE",
"Gatttr",
"getdetahstate",
"Ghirardini",
@@ -192,6 +210,7 @@
"GPIOK",
"GPIOS",
"gpstr",
+ "HACT",
"Hatt",
"HCLK",
"HIFCR",
@@ -215,12 +234,24 @@
"Katt",
"kbps",
"LBKM",
+ "LCOLCR",
"ldrex",
"leds",
"LIFCR",
"LISR",
"logdecoder",
+ "LPCE",
+ "LPHBPE",
+ "LPHFPE",
+ "LPMCR",
+ "LPSIZE",
+ "LPVAE",
+ "LPVFPE",
+ "LPVSAE",
"LSBFIRST",
+ "LTDC",
+ "LTDCEN",
+ "LTDCRST",
"Luca",
"Mandelli",
"Matteo",
@@ -230,6 +261,7 @@
"microcontrollers",
"MINC",
"miosix",
+ "MIPI",
"mkdir",
"MODER",
"mosfet",
@@ -239,6 +271,7 @@
"nart",
"NATT",
"NBAR",
+ "NDIV",
"NDTR",
"NGPS",
"Nidasio",
@@ -251,11 +284,23 @@
"OUTX",
"OUTY",
"OUTZ",
+ "PCONFR",
+ "PCTLR",
"peripehral",
"Piazzolla",
"PINC",
"Pitot",
"Plin",
+ "PLLEN",
+ "PLLLS",
+ "PLLM",
+ "PLLSAI",
+ "PLLSAICFGR",
+ "PLLSAIDIVR",
+ "PLLSAIN",
+ "PLLSAIR",
+ "PLLSAIRDY",
+ "PLLSAIRDYIE",
"prescaler",
"PUPDR",
"Qgbw",
@@ -267,10 +312,12 @@
"RDHR",
"RDLR",
"RDTR",
+ "REGEN",
"rflm",
"RFOM",
"Riccardo",
"RQCP",
+ "RSTR",
"RXCRCR",
"RXIRQ",
"RXNE",
@@ -303,9 +350,12 @@
"testsuite",
"THID",
"TMEIE",
+ "TOTALH",
+ "TOTALW",
"tparam",
"TSCPP",
"TSVREFE",
+ "TWCR",
"Tweakable",
"TXCRCR",
"txfp",
@@ -319,11 +369,27 @@
"Unsync",
"upcounter",
"USART",
+ "VACT",
"vbat",
"VBATE",
"velnord",
+ "VHBPCR",
+ "VHSACR",
+ "VLCR",
+ "VLPSIZE",
+ "VMCR",
+ "VNPCR",
"vout",
+ "VPCR",
"vsense",
+ "VVACR",
+ "VVBPCR",
+ "VVFPCR",
+ "VVSACR",
+ "WCFGR",
+ "WISR",
+ "WPCR",
+ "WRPCR",
"WSPI",
"Xbee",
"xnord",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0772a8044ff94f4963e019909be41fbb2e2a8603..2e1a85b9542c5ef5f5b7c00d748aa530d4380e14 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,9 @@ add_executable(sx1278lora-serial src/entrypoints/sx1278-serial.cpp)
target_compile_definitions(sx1278lora-serial PRIVATE SX1278_IS_LORA)
sbs_target(sx1278lora-serial stm32f429zi_skyward_groundstation_v2)
+add_executable(f769-discovery-display src/entrypoints/f769-discovery-display.cpp)
+sbs_target(f769-discovery-display stm32f769ni_discovery)
+
#-----------------------------------------------------------------------------#
# Tests #
#-----------------------------------------------------------------------------#
diff --git a/src/entrypoints/f769-discovery-display.cpp b/src/entrypoints/f769-discovery-display.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3fad02653f307637f655d2d5c84db2a2454ef791
--- /dev/null
+++ b/src/entrypoints/f769-discovery-display.cpp
@@ -0,0 +1,988 @@
+#include <miosix.h>
+
+/**
+ * The 4-inch 800x480 LCD-TFT color display with capacitive touch panel is
+ * connected to the MIPI DSI interface of the STM32F769NIH6.
+ *
+ * RGB vertical stripe of pixel arrangement.
+ *
+ * Up to two lanes of MIPI/DSI data.
+ *
+ * The self-capacitive touch panel on LCD has an I2C interface whose address is
+ * 0x1010100. It also provides an interrupt signal.
+ *
+ * Acronyms:
+ * - DSI: Display Serial Interface
+ * - MIPI: Mobile Industry Processor Interface
+ *
+ * MIPI had defined 3 sets of standards:
+ * - DBI: Display Bus Interface
+ * For displays with integrated display controller and frame buffer
+ * - DCS: Display Command Set
+ * Set of commands to be used with display supporting the MIPI-DBI interface.
+ * - DPI: Display Pixel Interface
+ * Standards for displays without controller nor frame buffer.
+ *
+ * To decrease the number of wires between MCU and displays, the MIPI display
+ * working group has defined the DSI (Display Serial Interface).
+ * The DSI encapsulates either DBI commands (called command mode) or DPI signals
+ * (called video mode) and transmits them to the display in a serial manner.
+ * This enables getting interfaced with a standard display using only four or
+ * six pins, and achieving the same performance than a DPI.
+ *
+ * The DSI standard defines two operating modes for the DSI host and the DSI
+ * display:
+ * - The command mode: Transactions sends commands and data to the display. The
+ * display needs to incorporate a controller and a frame buffer.
+ * - The video mode: A real time pixel stream. The display module relies on the
+ * host processor to provide the image data at a sufficient bandwidth to avoid
+ * flicker or other visible artifacts in the displayed image.
+ *
+ * The DSI is a packet based protocol. The parallel data and the commands are
+ * encapsulated into packets and upended with packet-protocol information and
+ * headers.
+ *
+ * There are two types of packets: short packets and long packets.
+ *
+ * The LCD on the Discovery 769 uses a DSI interface in video mode (the display
+ * does not have an integrated frame buffer).
+ *
+ * The LCD controller is one of:
+ * - ST7701S
+ * - ILI9806E
+ * - OTM8009A <---
+ */
+
+#if HSE_VALUE != 25000000
+#error "This driver only supports HSE at 25MHz"
+#endif
+
+using namespace miosix;
+
+GpioPin dsiTe(GPIOJ_BASE, 2);
+GpioPin dsiReset(GPIOJ_BASE, 15);
+
+uint32_t HSYNC = 1; // Horizontal start active time
+uint32_t HFP = 16; // Horizontal Front Porch time
+uint32_t HBP = 15; // Horizontal Back Porch time
+uint32_t HACT = 800; // Horizontal Active time = X size
+uint32_t VSYNC = 2; // Vertical start active time
+uint32_t VFP = 34; // Vertical Front Porch time
+uint32_t VBP = 34; // Vertical Back Porch time
+uint32_t VACT = 480; // Vertical Active time = Y size
+
+/**
+ * @brief DCS or Generic short write command
+ * @param ChannelID: Virtual channel ID.
+ * @param Mode: DSI short packet data type.
+ * This parameter can be any value of @ref
+ * DSI_SHORT_WRITE_PKT_Data_Type.
+ * @param Param1: DSC command or first generic parameter.
+ * This parameter can be any value of @ref DSI_DCS_Command or a
+ * generic command code.
+ * @param Param2: DSC parameter or second generic parameter.
+ * @retval HAL status
+ */
+void HAL_DSI_ShortWrite(uint32_t ChannelID, uint32_t Mode, uint32_t Param1,
+ uint32_t Param2)
+{
+ // Wait for Command FIFO Empty
+ while (!(DSI->GPSR & DSI_GPSR_CMDFE))
+ ;
+
+ // Configure the packet to send a short DCS command with 0 or 1 parameter
+ DSI->GHCR = (Mode | (ChannelID << 6) | (Param1 << 8) | (Param2 << 16));
+}
+
+/**
+ * @brief DCS or Generic long write command
+ * @param ChannelID: Virtual channel ID.
+ * @param Mode: DSI long packet data type.
+ * This parameter can be any value of @ref
+ * DSI_LONG_WRITE_PKT_Data_Type.
+ * @param NbParams: Number of parameters.
+ * @param Param1: DSC command or first generic parameter.
+ * This parameter can be any value of @ref DSI_DCS_Command or a
+ * generic command code
+ * @param ParametersTable: Pointer to parameter values table.
+ * @retval HAL status
+ */
+void HAL_DSI_LongWrite(uint32_t ChannelID, uint32_t Mode, uint32_t NbParams,
+ uint32_t Param1, uint8_t *ParametersTable)
+{
+ // Wait for Command FIFO Empty
+ while (!(DSI->GPSR & DSI_GPSR_CMDFE))
+ ;
+
+ // Set the DCS code hexadecimal on payload byte 1, and the other parameters
+ // on the write FIFO command
+ for (uint32_t uicounter = 0; uicounter < NbParams;)
+ {
+ if (uicounter == 0x00)
+ {
+ DSI->GPDR =
+ (Param1 | ((uint32_t)(*(ParametersTable + uicounter)) << 8) |
+ ((uint32_t)(*(ParametersTable + uicounter + 1)) << 16) |
+ ((uint32_t)(*(ParametersTable + uicounter + 2)) << 24));
+ uicounter += 3;
+ }
+ else
+ {
+ DSI->GPDR =
+ ((uint32_t)(*(ParametersTable + uicounter)) |
+ ((uint32_t)(*(ParametersTable + uicounter + 1)) << 8) |
+ ((uint32_t)(*(ParametersTable + uicounter + 2)) << 16) |
+ ((uint32_t)(*(ParametersTable + uicounter + 3)) << 24));
+ uicounter += 4;
+ }
+ }
+
+ // Configure the packet to send a long DCS command
+ DSI->GHCR = (Mode | (ChannelID << 6) | (((NbParams + 1) & 0x00FF) << 8) |
+ (((NbParams + 1) & 0xFF00) << 16));
+}
+
+/**
+ * @brief DCS or Generic short/long write command
+ * @param NbParams: 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(uint32_t NbrParams, uint8_t *pParams)
+{
+#define LCD_OTM8009A_ID ((uint32_t)0)
+
+ if (NbrParams <= 1)
+ {
+#define DSI_DCS_SHORT_PKT_WRITE_P1 \
+ ((uint32_t)0x00000015U) // DCS short write, one parameter
+ HAL_DSI_ShortWrite(LCD_OTM8009A_ID, DSI_DCS_SHORT_PKT_WRITE_P1,
+ pParams[0], pParams[1]);
+ }
+ else
+ {
+#define DSI_DCS_LONG_PKT_WRITE ((uint32_t)0x00000039U) // DCS long write
+ HAL_DSI_LongWrite(LCD_OTM8009A_ID, DSI_DCS_LONG_PKT_WRITE, NbrParams,
+ pParams[NbrParams], pParams);
+ }
+}
+
+void bspSetup()
+{
+ // All GPIOs ports already enabled by the bsp
+
+ // LCD GPIOs configuration
+ dsiTe.mode(Mode::ALTERNATE); // TODO: Is TE necessary?
+ dsiTe.alternateFunction(13);
+ dsiReset.mode(Mode::OUTPUT_PULL_UP);
+ dsiReset.speed(Speed::_100MHz);
+
+ // Toggle Hardware Reset of the DSI LCD using its XRES signal
+ dsiReset.low(); // Active low
+ delayUs(20); // 10us minimum
+ dsiReset.high();
+ delayMs(10); // 5ms minumum
+
+ // Enable the LTDC clock
+ RCC->APB2ENR |= RCC_APB2ENR_LTDCEN;
+ RCC_SYNC();
+
+ // Toggle soft reset of LTDC IP
+ RCC->APB2RSTR |= RCC_APB2RSTR_LTDCRST;
+ RCC->APB2RSTR &= ~RCC_APB2RSTR_LTDCRST;
+
+ // // Enable the DMA2D clock
+ // RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
+ // RCC_SYNC();
+
+ // // Toggle soft reset of DMA2D IP
+ // RCC->AHB1RSTR |= RCC_AHB1RSTR_DMA2DRST;
+ // RCC->AHB1RSTR &= ~RCC_AHB1RSTR_DMA2DRST;
+
+ // Enable DSI Host and wrapper clocks
+ RCC->APB2ENR |= RCC_APB2ENR_DSIEN;
+ RCC_SYNC();
+
+ // Toggle soft reset the DSI Host and wrapper
+ RCC->APB2RSTR |= RCC_APB2RSTR_DSIRST;
+ RCC->APB2RSTR &= ~RCC_APB2RSTR_DSIRST;
+
+ // // NVIC configuration for LTDC interrupt that is now enabled
+ // NVIC_SetPriority(LTDC_IRQn, 3);
+ // NVIC_EnableIRQ(LTDC_IRQn);
+
+ // // NVIC configuration for DMA2D interrupt that is now enabled
+ // NVIC_SetPriority(DMA2D_IRQn, 3);
+ // NVIC_EnableIRQ(DMA2D_IRQn);
+
+ // // NVIC configuration for DSI interrupt that is now enabled
+ // NVIC_SetPriority(DSI_IRQn, 3);
+ // NVIC_EnableIRQ(DSI_IRQn);
+}
+
+void pllsaiSetup()
+{
+ // The LCD-TFT controller peripheral uses 3 clock domains:
+ // - AHB clock domain (HCLK): For data transfer from the memories to the
+ // Layer FIFO and the frame buffer
+ // - APB2 clock domain (PCLK2): Configuration registers
+ // - Pixel clock domain (LCD_CLK): This domain contains the pixel data
+ // generation, the layer configuration register as well as the LCD-TFT
+ // interface signal generator.
+
+ // LCD_CLK = width x height x refresh rate
+ // = 800 x 480 x 60
+ // = 23.04MHz
+
+ // The LTDC clock is connected to the PLLLSAIR clock
+ //
+ // LCD_CLK = 1MHz * N / R / DIV
+ //
+ // Where:
+ // N = 375
+ // R = 6
+ // DIV = 2
+ //
+ // LCD_CLK = 1MHz * 375 / 6 / 2 = 31.25
+
+ // Disable PLLSAI Clock
+ RCC->CR &= ~RCC_CR_PLLSAION;
+
+ // Wait till PLLSAI is disabled
+ while (RCC->CR & RCC_CR_PLLSAIRDY)
+ ;
+
+ // Note that this registers are set at 0 after reset
+ RCC->PLLSAICFGR |= 375 << RCC_PLLSAICFGR_PLLSAIN_Pos;
+ RCC->PLLSAICFGR |= 6 << RCC_PLLSAICFGR_PLLSAIR_Pos;
+ RCC->DCKCFGR1 |= 0 << RCC_DCKCFGR1_PLLSAIDIVR_Pos;
+
+ // Enable PLLSAI Clock
+ RCC->CR |= RCC_CR_PLLSAION;
+
+ // Wait till PLLSAI is ready
+ while (!(RCC->CR & RCC_CR_PLLSAIRDY))
+ ;
+}
+
+void ltdcSetup()
+{
+ // Initialize the LTDC
+ {
+ // The polarity for all control signals is active low (default)
+
+ // Set Synchronization size
+ LTDC->SSCR = (HSYNC - 1) << LTDC_SSCR_HSW_Pos;
+ LTDC->SSCR |= (VSYNC - 1) << LTDC_SSCR_VSH_Pos;
+
+ // Set Accumulated Back porch
+ LTDC->BPCR = (HSYNC + HBP - 1) << LTDC_BPCR_AHBP_Pos;
+ LTDC->BPCR |= (VSYNC + VBP - 1) << LTDC_BPCR_AVBP_Pos;
+
+ // Set Accumulated Active Width
+ LTDC->AWCR = (HSYNC + HBP + HACT - 1) << LTDC_AWCR_AAW_Pos;
+ LTDC->AWCR |= (VSYNC + VBP + VACT - 1) << LTDC_AWCR_AAH_Pos;
+
+ // Set Total Width
+ LTDC->TWCR = (HSYNC + HBP + HACT + HFP - 1) << LTDC_TWCR_TOTALW_Pos;
+ LTDC->TWCR |= (VSYNC + VBP + VACT + VFP - 1) << LTDC_TWCR_TOTALH_Pos;
+
+ // Set the background color value
+ LTDC->BCCR = 0 << LTDC_BCCR_BCRED_Pos;
+ LTDC->BCCR |= 255 << LTDC_BCCR_BCGREEN_Pos;
+ LTDC->BCCR |= 0 << LTDC_BCCR_BCBLUE_Pos;
+ }
+
+ // Layer setup
+ {
+ // Configure the horizontal start and stop position
+ LTDC_Layer1->WHPCR = (HSYNC + HBP + HACT - 1)
+ << LTDC_LxWHPCR_WHSPPOS_Pos;
+ LTDC_Layer1->WHPCR |= (HSYNC + HBP) << LTDC_LxWHPCR_WHSTPOS_Pos;
+
+ // Configure the vertical start and stop position
+ LTDC_Layer1->WVPCR = (VSYNC + VBP + VACT - 1)
+ << LTDC_LxWVPCR_WVSPPOS_Pos;
+ LTDC_Layer1->WVPCR |= (VSYNC + VBP) << LTDC_LxWVPCR_WVSTPOS_Pos;
+
+ // Specify the pixel format
+ LTDC_Layer1->PFCR = 0x1; // for RGB888 (24bit)
+
+ // Configure the background color
+ LTDC_Layer1->DCCR = 0; // Black
+
+ // Specifies the constant alpha value
+ LTDC_Layer1->CACR = 255;
+
+ // Specifies the blending factors
+ // Blanded color = const alpha x current color + cont alpah x back color
+ LTDC_Layer1->BFCR |= 4 << LTDC_LxBFCR_BF1_Pos;
+ LTDC_Layer1->BFCR |= 5 << LTDC_LxBFCR_BF1_Pos;
+
+ // Configures the color frame buffer pitch
+ // The pitch is the increment in bytes to jump to the next line
+ LTDC_Layer1->CFBLR |= (HACT * 3) << LTDC_LxCFBLR_CFBP_Pos;
+ LTDC_Layer1->CFBLR |= (HACT * 3 + 3) << LTDC_LxCFBLR_CFBLL_Pos;
+
+ // Configures the frame buffer line number
+ LTDC_Layer1->CFBLNR = VACT;
+
+ // Configures the color frame buffer start address
+ // The frame buffer will be in the SDRAM and is 1152000B = 1.1MB
+ LTDC_Layer1->CFBAR = 0xC0000000;
+
+ // Enable the layer
+ LTDC_Layer1->CR |= LTDC_LxCR_LEN;
+
+ // Reload shadow registers
+ LTDC->SRCR = LTDC_SRCR_IMR;
+ }
+}
+
+void dsiSetup()
+{
+ // Turn on the regulator and enable the DSI PLL
+ {
+ // Enable the regulator
+ DSI->WRPCR |= DSI_WRPCR_REGEN;
+
+ // Wait until the regulator is ready
+ while (!(DSI->WISR & DSI_WISR_RRS))
+ ;
+ }
+
+ // Set the DSI clock parameters
+ {
+ /**
+ * DSI input clock is HSE at 25MHz
+ *
+ * F_VCO = CLK_IN / IDF * 2 * NDIV
+ * = 25MHz / 5 * 2 * 100
+ * = 1GHz (between 500MHz and 1GHz)
+ *
+ * PHI = F_vco / (2 * ODF)
+ * = 1GHz / (2 * 1)
+ * = 500MHz
+ *
+ * PHI is the lane frequency
+ *
+ * Lane_Byte_CLK = PHI / 8
+ * = 62.5MHz
+ *
+ * Lane_Byte_CLK must be between 31.25 MHz and 82.5 MHz
+ */
+
+ // Set the PLL division factors
+ DSI->WRPCR |= 100 << DSI_WRPCR_PLL_NDIV_Pos; // NDIV = 100
+ DSI->WRPCR |= 5 << DSI_WRPCR_PLL_IDF_Pos; // IDF = 5
+ DSI->WRPCR |= 0 << DSI_WRPCR_PLL_ODF_Pos; // ODF = 1
+
+ // Enable the DSI PLL
+ DSI->WRPCR |= DSI_WRPCR_PLLEN;
+
+ // Wait for the lock of the PLL
+ while (!(DSI->WISR & DSI_WISR_PLLLS))
+ ;
+
+ // Configure the D-PHY parameters
+ DSI->CCR = 4;
+
+ /**
+ * Calculate the bit period in high-speed mode in unit of 0.25 ns
+ *
+ * UIX4 = IntegerPart((1000 / F_PHY_Mhz) * 4)
+ * = IntegerPart((1000 / 500) * 4)
+ * = IntegerPart(2 * 4)
+ * = 8
+ */
+ DSI->WPCR[0] = 8;
+ }
+
+ // Set the PHY parameters
+ {
+ // Enable D-PHY clock and data lane
+ DSI->PCTLR |= DSI_PCTLR_CKE;
+ DSI->PCTLR |= DSI_PCTLR_DEN;
+
+ // Set automatic clock lane control
+ DSI->CLCR |= (DSI_CLCR_DPCC | DSI_CLCR_ACR);
+
+ // Configure the number of active data lanes
+ DSI->PCONFR |= DSI_PCONFR_NL0; // Two lanes
+
+ // Time for LP/HS and HS/LP transitions for both clock lane and data
+ // lanes
+ DSI->CLTCR |= 40 << DSI_CLTCR_HS2LP_TIME_Pos; // HS to LP
+ DSI->CLTCR |= 40 << DSI_CLTCR_LP2HS_TIME_Pos; // LP to HS
+ DSI->DLTCR |= 20 << DSI_DLTCR_HS2LP_TIME_Pos; // HS to LP
+ DSI->DLTCR |= 20 << DSI_DLTCR_LP2HS_TIME_Pos; // HS to LP
+
+ // Stop wait time (don't know how much should it be, random high number)
+ DSI->PCONFR |= 100 << DSI_PCONFR_SW_TIME_Pos;
+ }
+
+ // Configure DSI Video mode timings
+ {
+ // Select video mode by resetting CMDM and DSIM bits
+ // Default values
+
+ // Configure burst mode
+ DSI->VMCR |= DSI_VMCR_VMT1;
+
+ // Configure the video packet size
+ DSI->VPCR |= HACT; // Packet size is the horizontal size
+
+ // The number of chunks is 0
+
+ // Set the size of the null packet
+ DSI->VNPCR |= 0xFFF;
+
+ // The virtual channel id for the LTDC interface is 0
+
+ // The polarity of control signals is active low (default)
+
+ // Select 24bit color coding for the host
+ DSI->LCOLCR |= 0b0100 << DSI_LCOLCR_COLC_Pos;
+ // TODO: Check, for 24bit the value should be 0b0101
+
+ // Select the color coding for the wrapper
+ DSI->WCFGR |= 0b101 << DSI_WCFGR_COLMUX_Pos;
+ // TODO: Check, for 24bit the value should be 0b101
+
+ // Set the Horizontal Synchronization time in lane byte clock cycles
+ DSI->VHSACR |= HSYNC * 62500 / 31250;
+
+ // Set the Horizontal Back Porch in lane byte clock cycles
+ DSI->VHBPCR |= HBP * 62500 / 31250;
+
+ // Set the total line time in lane byte clock cycles
+ DSI->VLCR |= (HSYNC + HBP + HACT + HFP) * 62500 / 31250;
+
+ // Set the Vertical Synchronization time
+ DSI->VVSACR |= VSYNC;
+
+ // Set the Vertical Back Porch
+ DSI->VVBPCR |= VBP;
+
+ // Set the Vertical Front Porch
+ DSI->VVFPCR |= VFP;
+
+ // Set the Vertical Active period
+ DSI->VVACR |= VACT;
+
+ // Enable sending commands in Low Power mode
+ DSI->VMCR |= DSI_VMCR_LPCE;
+
+ // Low power largest packet size
+ // Largest packet size possible to transmit in LP mode in VSA, VBP,
+ // VFP regions. Only useful when sending LP packets is allowed while
+ // streaming is active in video mode
+ DSI->LPMCR |= 64 << DSI_LPMCR_LPSIZE_Pos;
+
+ // Low power VACT largest packet size
+ // Largest packet size possible to transmit in LP mode in HFP region
+ // during VACT period. Only useful when sending LP packets is
+ // allowed while streaming is active in video mode
+ DSI->LPMCR |= 64;
+
+ // Enable LP transition in HFP period
+ DSI->VMCR |= DSI_VMCR_LPHFPE;
+
+ // Enable LP transition in HBP period
+ DSI->VMCR |= DSI_VMCR_LPHBPE;
+
+ // Enable LP transition in VACT period
+ DSI->VMCR |= DSI_VMCR_LPVAE;
+
+ // Enable LP transition in VFP period
+ DSI->VMCR |= DSI_VMCR_LPVFPE;
+
+ // Enable LP transition in VBP period
+ DSI->VMCR |= DSI_VMCR_LPVFPE;
+
+ // Enable LP transition in vertical sync period
+ DSI->VMCR |= DSI_VMCR_LPVSAE;
+
+ // Disable the request for an acknowledge response at the end of a
+ // frame (default)
+ }
+}
+
+void otm8009aSetup()
+{
+/* List of OTM8009A used commands */
+/* Detailed in OTM8009A Data Sheet 'DATA_SHEET_OTM8009A_V0 92.pdf' */
+/* Version of 14 June 2012 */
+#define OTM8009A_CMD_NOP 0x00 /* NOP command */
+#define OTM8009A_CMD_SWRESET 0x01 /* Sw reset command */
+#define OTM8009A_CMD_RDDMADCTL \
+ 0x0B /* Read Display MADCTR command : read memory display access ctrl */
+#define OTM8009A_CMD_RDDCOLMOD 0x0C /* Read Display pixel format */
+#define OTM8009A_CMD_SLPIN 0x10 /* Sleep In command */
+#define OTM8009A_CMD_SLPOUT 0x11 /* Sleep Out command */
+#define OTM8009A_CMD_PTLON 0x12 /* Partial mode On command */
+
+#define OTM8009A_CMD_DISPOFF 0x28 /* Display Off command */
+#define OTM8009A_CMD_DISPON 0x29 /* Display On command */
+
+#define OTM8009A_CMD_CASET 0x2A /* Column address set command */
+#define OTM8009A_CMD_PASET 0x2B /* Page address set command */
+
+#define OTM8009A_CMD_RAMWR 0x2C /* Memory (GRAM) write command */
+#define OTM8009A_CMD_RAMRD 0x2E /* Memory (GRAM) read command */
+
+#define OTM8009A_CMD_PLTAR 0x30 /* Partial area command (4 parameters) */
+
+#define OTM8009A_CMD_TEOFF \
+ 0x34 /* Tearing Effect Line Off command : command with no parameter */
+
+#define OTM8009A_CMD_TEEON \
+ 0x35 /* Tearing Effect Line On command : command with 1 parameter 'TELOM' \
+ */
+
+/* Parameter TELOM : Tearing Effect Line Output Mode : possible values */
+#define OTM8009A_TEEON_TELOM_VBLANKING_INFO_ONLY 0x00
+#define OTM8009A_TEEON_TELOM_VBLANKING_AND_HBLANKING_INFO 0x01
+
+#define OTM8009A_CMD_MADCTR 0x36 /* Memory Access write control command */
+
+/* Possible used values of MADCTR */
+#define OTM8009A_MADCTR_MODE_PORTRAIT 0x00
+#define OTM8009A_MADCTR_MODE_LANDSCAPE \
+ 0x60 /* MY = 0, MX = 1, MV = 1, ML = 0, RGB = 0 */
+
+#define OTM8009A_CMD_IDMOFF 0x38 /* Idle mode Off command */
+#define OTM8009A_CMD_IDMON 0x39 /* Idle mode On command */
+
+#define OTM8009A_CMD_COLMOD 0x3A /* Interface Pixel format command */
+
+/* Possible values of COLMOD parameter corresponding to used pixel formats */
+#define OTM8009A_COLMOD_RGB565 0x55
+#define OTM8009A_COLMOD_RGB888 0x77
+
+#define OTM8009A_CMD_RAMWRC 0x3C /* Memory write continue command */
+#define OTM8009A_CMD_RAMRDC 0x3E /* Memory read continue command */
+
+#define OTM8009A_CMD_WRTESCN 0x44 /* Write Tearing Effect Scan line command */
+#define OTM8009A_CMD_RDSCNL 0x45 /* Read Tearing Effect Scan line command */
+
+/* CABC Management : ie : Content Adaptive Back light Control in IC OTM8009a */
+#define OTM8009A_CMD_WRDISBV \
+ 0x51 /* Write Display Brightness command */
+#define OTM8009A_CMD_WRCTRLD \
+ 0x53 /* Write CTRL Display command */
+#define OTM8009A_CMD_WRCABC \
+ 0x55 /* Write Content Adaptive Brightness command \
+ */
+#define OTM8009A_CMD_WRCABCMB \
+ 0x5E /* Write CABC Minimum Brightness command */
+
+ const uint8_t ShortRegData1[] = {OTM8009A_CMD_NOP, 0x00};
+ const uint8_t ShortRegData2[] = {OTM8009A_CMD_NOP, 0x80};
+ const uint8_t ShortRegData3[] = {0xC4, 0x30};
+ const uint8_t ShortRegData4[] = {OTM8009A_CMD_NOP, 0x8A};
+ const uint8_t ShortRegData5[] = {0xC4, 0x40};
+ const uint8_t ShortRegData6[] = {OTM8009A_CMD_NOP, 0xB1};
+ const uint8_t ShortRegData7[] = {0xC5, 0xA9};
+ const uint8_t ShortRegData8[] = {OTM8009A_CMD_NOP, 0x91};
+ const uint8_t ShortRegData9[] = {0xC5, 0x34};
+ const uint8_t ShortRegData10[] = {OTM8009A_CMD_NOP, 0xB4};
+ const uint8_t ShortRegData11[] = {0xC0, 0x50};
+ const uint8_t ShortRegData12[] = {0xD9, 0x4E};
+ const uint8_t ShortRegData13[] = {OTM8009A_CMD_NOP, 0x81};
+ const uint8_t ShortRegData14[] = {0xC1, 0x66};
+ const uint8_t ShortRegData15[] = {OTM8009A_CMD_NOP, 0xA1};
+ const uint8_t ShortRegData16[] = {0xC1, 0x08};
+ const uint8_t ShortRegData17[] = {OTM8009A_CMD_NOP, 0x92};
+ const uint8_t ShortRegData18[] = {0xC5, 0x01};
+ const uint8_t ShortRegData19[] = {OTM8009A_CMD_NOP, 0x95};
+ const uint8_t ShortRegData20[] = {OTM8009A_CMD_NOP, 0x94};
+ const uint8_t ShortRegData21[] = {0xC5, 0x33};
+ const uint8_t ShortRegData22[] = {OTM8009A_CMD_NOP, 0xA3};
+ const uint8_t ShortRegData23[] = {0xC0, 0x1B};
+ const uint8_t ShortRegData24[] = {OTM8009A_CMD_NOP, 0x82};
+ const uint8_t ShortRegData25[] = {0xC5, 0x83};
+ const uint8_t ShortRegData26[] = {0xC4, 0x83};
+ const uint8_t ShortRegData27[] = {0xC1, 0x0E};
+ const uint8_t ShortRegData28[] = {OTM8009A_CMD_NOP, 0xA6};
+ const uint8_t ShortRegData29[] = {OTM8009A_CMD_NOP, 0xA0};
+ const uint8_t ShortRegData30[] = {OTM8009A_CMD_NOP, 0xB0};
+ const uint8_t ShortRegData31[] = {OTM8009A_CMD_NOP, 0xC0};
+ const uint8_t ShortRegData32[] = {OTM8009A_CMD_NOP, 0xD0};
+ const uint8_t ShortRegData33[] = {OTM8009A_CMD_NOP, 0x90};
+ const uint8_t ShortRegData34[] = {OTM8009A_CMD_NOP, 0xE0};
+ const uint8_t ShortRegData35[] = {OTM8009A_CMD_NOP, 0xF0};
+ const uint8_t ShortRegData36[] = {OTM8009A_CMD_SLPOUT, 0x00};
+ const uint8_t ShortRegData37[] = {OTM8009A_CMD_COLMOD,
+ OTM8009A_COLMOD_RGB565};
+ const uint8_t ShortRegData38[] = {OTM8009A_CMD_COLMOD,
+ OTM8009A_COLMOD_RGB888};
+ const uint8_t ShortRegData39[] = {OTM8009A_CMD_MADCTR,
+ OTM8009A_MADCTR_MODE_LANDSCAPE};
+ const uint8_t ShortRegData40[] = {OTM8009A_CMD_WRDISBV, 0x7F};
+ const uint8_t ShortRegData41[] = {OTM8009A_CMD_WRCTRLD, 0x2C};
+ const uint8_t ShortRegData42[] = {OTM8009A_CMD_WRCABC, 0x02};
+ const uint8_t ShortRegData43[] = {OTM8009A_CMD_WRCABCMB, 0xFF};
+ const uint8_t ShortRegData44[] = {OTM8009A_CMD_DISPON, 0x00};
+ const uint8_t ShortRegData45[] = {OTM8009A_CMD_RAMWR, 0x00};
+ const uint8_t ShortRegData46[] = {0xCF, 0x00};
+ const uint8_t ShortRegData47[] = {0xC5, 0x66};
+ const uint8_t ShortRegData48[] = {OTM8009A_CMD_NOP, 0xB6};
+ const uint8_t ShortRegData49[] = {0xF5, 0x06};
+ const uint8_t ShortRegData50[] = {OTM8009A_CMD_NOP, 0xB1};
+ const uint8_t ShortRegData51[] = {0xC6, 0x06};
+
+ /*
+ * @brief Constant tables of register settings used to transmit DSI
+ * command packets as power up initialization sequence of the KoD LCD
+ * (OTM8009A LCD Driver)
+ */
+ const uint8_t lcdRegData1[] = {0x80, 0x09, 0x01, 0xFF};
+ const uint8_t lcdRegData2[] = {0x80, 0x09, 0xFF};
+ const uint8_t lcdRegData3[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
+ 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08,
+ 0x0F, 0x10, 0x0A, 0x01, 0xE1};
+ const uint8_t lcdRegData4[] = {0x00, 0x09, 0x0F, 0x0E, 0x07, 0x10,
+ 0x0B, 0x0A, 0x04, 0x07, 0x0B, 0x08,
+ 0x0F, 0x10, 0x0A, 0x01, 0xE2};
+ const uint8_t lcdRegData5[] = {0x79, 0x79, 0xD8};
+ const uint8_t lcdRegData6[] = {0x00, 0x01, 0xB3};
+ const uint8_t lcdRegData7[] = {0x85, 0x01, 0x00, 0x84, 0x01, 0x00, 0xCE};
+ const uint8_t lcdRegData8[] = {0x18, 0x04, 0x03, 0x39, 0x00,
+ 0x00, 0x00, 0x18, 0x03, 0x03,
+ 0x3A, 0x00, 0x00, 0x00, 0xCE};
+ const uint8_t lcdRegData9[] = {0x18, 0x02, 0x03, 0x3B, 0x00,
+ 0x00, 0x00, 0x18, 0x01, 0x03,
+ 0x3C, 0x00, 0x00, 0x00, 0xCE};
+ const uint8_t lcdRegData10[] = {0x01, 0x01, 0x20, 0x20, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00, 0xCF};
+ const uint8_t lcdRegData11[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData12[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData13[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData14[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData15[] = {0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData16[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData17[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xCB};
+ const uint8_t lcdRegData18[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xCB};
+ const uint8_t lcdRegData19[] = {0x00, 0x26, 0x09, 0x0B, 0x01, 0x25,
+ 0x00, 0x00, 0x00, 0x00, 0xCC};
+ const uint8_t lcdRegData20[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x26,
+ 0x0A, 0x0C, 0x02, 0xCC};
+ const uint8_t lcdRegData21[] = {0x25, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCC};
+ const uint8_t lcdRegData22[] = {0x00, 0x25, 0x0C, 0x0A, 0x02, 0x26,
+ 0x00, 0x00, 0x00, 0x00, 0xCC};
+ const uint8_t lcdRegData23[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x25,
+ 0x0B, 0x09, 0x01, 0xCC};
+ const uint8_t lcdRegData24[] = {0x26, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xCC};
+ const uint8_t lcdRegData25[] = {0xFF, 0xFF, 0xFF, 0xFF};
+ /*
+ * CASET value (Column Address Set) : X direction LCD GRAM boundaries
+ * depending on LCD orientation mode and PASET value (Page Address Set) : Y
+ * direction LCD GRAM boundaries depending on LCD orientation mode XS[15:0]
+ * = 0x000 = 0, XE[15:0] = 0x31F = 799 for landscape mode : apply to CASET
+ * YS[15:0] = 0x000 = 0, YE[15:0] = 0x31F = 799 for portrait mode : : apply
+ * to PASET
+ */
+ const uint8_t lcdRegData27[] = {0x00, 0x00, 0x03, 0x1F, OTM8009A_CMD_CASET};
+ /*
+ * XS[15:0] = 0x000 = 0, XE[15:0] = 0x1DF = 479 for portrait mode : apply to
+ * CASET YS[15:0] = 0x000 = 0, YE[15:0] = 0x1DF = 479 for landscape mode :
+ * apply to PASET
+ */
+ const uint8_t lcdRegData28[] = {0x00, 0x00, 0x01, 0xDF, OTM8009A_CMD_PASET};
+
+ // LCD Initialization
+ {
+ /* Enable CMD2 to access vendor specific commands */
+ /* Enter in command 2 mode and set EXTC to enable address shift function
+ * (0x00) */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(3, (uint8_t *)lcdRegData1);
+
+ /* Enter ORISE Command 2 */
+ DSI_IO_WriteCmd(0,
+ (uint8_t *)ShortRegData2); /* Shift address to 0x80 */
+ DSI_IO_WriteCmd(2, (uint8_t *)lcdRegData2);
+
+ /////////////////////////////////////////////////////////////////////
+ /* SD_PCH_CTRL - 0xC480h - 129th parameter - Default 0x00 */
+ /* Set SD_PT */
+ /* -> Source output level during porch and non-display area to GND */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData3);
+ delayMs(10);
+ /* Not documented */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData4);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData5);
+ delayMs(10);
+ /////////////////////////////////////////////////////////////////////
+
+ /* PWR_CTRL4 - 0xC4B0h - 178th parameter - Default 0xA8 */
+ /* Set gvdd_en_test */
+ /* -> enable GVDD test mode !!! */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData6);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData7);
+
+ /* PWR_CTRL2 - 0xC590h - 146th parameter - Default 0x79 */
+ /* Set pump 4 vgh voltage */
+ /* -> from 15.0v down to 13.0v */
+ /* Set pump 5 vgh voltage */
+ /* -> from -12.0v downto -9.0v */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData8);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData9);
+
+ /* P_DRV_M - 0xC0B4h - 181th parameter - Default 0x00 */
+ /* -> Column inversion */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData10);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData11);
+
+ /* VCOMDC - 0xD900h - 1st parameter - Default 0x39h */
+ /* VCOM Voltage settings */
+ /* -> from -1.0000v downto -1.2625v */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData12);
+
+ /* Oscillator adjustment for Idle/Normal mode (LPDT only) set to 65Hz
+ * (default is 60Hz) */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData14);
+
+ /* Video mode internal */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData15);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData16);
+
+ /* PWR_CTRL2 - 0xC590h - 147h parameter - Default 0x00 */
+ /* Set pump 4&5 x6 */
+ /* -> ONLY VALID when PUMP4_EN_ASDM_HV = "0" */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData17);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData18);
+
+ /* PWR_CTRL2 - 0xC590h - 150th parameter - Default 0x33h */
+ /* Change pump4 clock ratio */
+ /* -> from 1 line to 1/2 line */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData19);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData9);
+
+ /* GVDD/NGVDD settings */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(2, (uint8_t *)lcdRegData5);
+
+ /* PWR_CTRL2 - 0xC590h - 149th parameter - Default 0x33h */
+ /* Rewrite the default value ! */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData20);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData21);
+
+ /* Panel display timing Setting 3 */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData22);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData23);
+
+ /* Power control 1 */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData24);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData25);
+
+ /* Source driver precharge */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData26);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData15);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData27);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData28);
+ DSI_IO_WriteCmd(2, (uint8_t *)lcdRegData6);
+
+ /* GOAVST */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2);
+ DSI_IO_WriteCmd(6, (uint8_t *)lcdRegData7);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29);
+ DSI_IO_WriteCmd(14, (uint8_t *)lcdRegData8);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30);
+ DSI_IO_WriteCmd(14, (uint8_t *)lcdRegData9);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData10);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData46);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData11);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData33);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData12);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData13);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData14);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData15);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData16);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData34);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData17);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData35);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData18);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData2);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData19);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData33);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData20);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData29);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData21);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData30);
+ DSI_IO_WriteCmd(10, (uint8_t *)lcdRegData22);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData31);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData23);
+
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData32);
+ DSI_IO_WriteCmd(15, (uint8_t *)lcdRegData24);
+
+ /////////////////////////////////////////////////////////////////////////////
+ /* PWR_CTRL1 - 0xc580h - 130th parameter - default 0x00 */
+ /* Pump 1 min and max DM */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData13);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData47);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData48);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData49);
+ /////////////////////////////////////////////////////////////////////////////
+
+ /* CABC LEDPWM frequency adjusted to 19,5kHz */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData50);
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData51);
+
+ /* Exit CMD2 mode */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(3, (uint8_t *)lcdRegData25);
+
+ /***************************************************************************
+ */
+ /* Standard DCS Initialization TO KEEP CAN BE DONE IN HSDT */
+ /***************************************************************************
+ */
+
+ /* NOP - goes back to DCS std command ? */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+
+ /* Gamma correction 2.2+ table (HSDT possible) */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(16, (uint8_t *)lcdRegData3);
+
+ /* Gamma correction 2.2- table (HSDT possible) */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+ DSI_IO_WriteCmd(16, (uint8_t *)lcdRegData4);
+
+ /* Send Sleep Out command to display : no parameter */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData36);
+
+ /* Wait for sleep out exit */
+ delayMs(120);
+
+ /* Set Pixel color format to RGB888 */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData38);
+
+ /* Send command to configure display in landscape orientation mode. By
+ default the orientation mode is portrait */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData39);
+ DSI_IO_WriteCmd(4, (uint8_t *)lcdRegData27);
+ DSI_IO_WriteCmd(4, (uint8_t *)lcdRegData28);
+
+ /** CABC : Content Adaptive Backlight Control section start >> */
+ /* Note : defaut is 0 (lowest Brightness), 0xFF is highest Brightness,
+ * try 0x7F : intermediate value */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData40);
+
+ /* defaut is 0, try 0x2C - Brightness Control Block, Display Dimming &
+ * BackLight on */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData41);
+
+ /* defaut is 0, try 0x02 - image Content based Adaptive Brightness
+ * [Still Picture] */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData42);
+
+ /* defaut is 0 (lowest Brightness), 0xFF is highest Brightness */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData43);
+
+ /** CABC : Content Adaptive Backlight Control section end << */
+
+ /* Send Command Display On */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData44);
+
+ /* NOP command */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData1);
+
+ /* Send Command GRAM memory write (no parameters) : this initiates frame
+ * write via other DSI commands sent by */
+ /* DSI host from LTDC incoming pixels in video mode */
+ DSI_IO_WriteCmd(0, (uint8_t *)ShortRegData45);
+ }
+
+ // Enable LTDC by setting LTDCEN bit
+ LTDC->GCR |= LTDC_GCR_LTDCEN;
+
+ DSI->CR |= DSI_CR_EN;
+
+ // Start the LTDC flow through the DSI wrapper (CR.LTDCEN = 1).
+ // In video mode, the data streaming starts as soon as the LTDC is enabled.
+ // In adapted command mode, the frame buffer update is launched as soon as
+ // the CR.LTDCEN bit is set.
+ {
+ // Enable the DSI host
+ DSI->CR |= DSI_CR_EN;
+
+ // Enable the DSI wrapper
+ DSI->WCR |= DSI_WCR_DSIEN;
+ }
+
+ // Switch on the display. Exit DSI ULPM mode if was configured
+ HAL_DSI_ShortWrite(LCD_OTM8009A_ID, DSI_DCS_SHORT_PKT_WRITE_P1,
+ OTM8009A_CMD_DISPON, 0x00);
+}
+
+int main()
+{
+ bspSetup();
+
+ pllsaiSetup();
+
+ ltdcSetup();
+
+ dsiSetup();
+
+ otm8009aSetup();
+
+ printf("LCD initialization completed!\n");
+
+ while (true)
+ ;
+}
\ No newline at end of file