From 4738239d53a01be1b90fb6afd427df57fde22b95 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Tue, 20 Dec 2016 14:07:50 +0100 Subject: ucoo/hal/frame_buffer: add DSI video mode support --- ucoo/hal/frame_buffer/dsi.stm32f4.cc | 142 ++++++++++++++++++++++------------ ucoo/hal/frame_buffer/dsi.stm32f4.hh | 11 ++- ucoo/hal/frame_buffer/ltdc.stm32f4.cc | 2 +- ucoo/hal/frame_buffer/ltdc.stm32f4.hh | 2 +- 4 files changed, 103 insertions(+), 54 deletions(-) diff --git a/ucoo/hal/frame_buffer/dsi.stm32f4.cc b/ucoo/hal/frame_buffer/dsi.stm32f4.cc index e344c81..5dae469 100644 --- a/ucoo/hal/frame_buffer/dsi.stm32f4.cc +++ b/ucoo/hal/frame_buffer/dsi.stm32f4.cc @@ -64,25 +64,29 @@ enum DcsCommand bool Dsi::refreshing_; -Dsi::Dsi (int width, int heigth, int lanes) - : Ltdc (width, heigth, 2, 1, 1, 2, 1, 1), lanes_ (lanes) +Dsi::Dsi (int width, int heigth, int lanes, bool video_mode, + int hsync, int hbp, int hfp, + int vsync, int vbp, int vfp) + : Ltdc (width, heigth, hsync, hbp, hfp, vsync, vbp, vfp), lanes_ (lanes), + video_mode_ (video_mode) { } void -Dsi::enable (const Function &config) +Dsi::enable (const Function &config, int phy_hz, int pclk_hz) { - // TODO: make this more configurable. // Enable clocks. rcc_peripheral_clock_enable (Rcc::DSI); // Enable DSI regulator. reg::DSI->WRPCR = DSI_WRPCR_REGEN; while (!(reg::DSI->WISR & DSI_WISR_RRS)) ; - // Enable PLL, 500 MHz output frequency (HSE @ 8 MHz). - const int phy_hz = 500000000; + // Enable PLL. + int ndiv = phy_hz * 2 / rcc_hse_freq_hz; + assert (ndiv >= 10 && ndiv <= 125 + && rcc_hse_freq_hz / 2 * ndiv == phy_hz); reg::DSI->WRPCR = DSI_WRPCR_REGEN - | (125 << DSI_WRPCR_PLL_NDIV_Pos) + | (ndiv << DSI_WRPCR_PLL_NDIV_Pos) | (2 << DSI_WRPCR_PLL_IDF_Pos) | DSI_WRPCR_PLL_ODF_Div1; reg::DSI->WRPCR |= DSI_WRPCR_PLLEN; @@ -95,19 +99,25 @@ Dsi::enable (const Function &config) reg::DSI->PCONFR = lanes_ - 1; // Clock control. reg::DSI->CLCR = DSI_CLCR_DPCC; - // TODO: Time for LP/HS and HS/LP transition in CLTCR/DLTCR. - // TODO: Stop wait time in PCONFR. + // Time for LP/HS and HS/LP transition (using workaround for clock) & + // maximum read time. + reg::DSI->CLTCR = 35 * DSI_CLTCR_HS2LP_TIME0 | 35 * DSI_CLTCR_LP2HS_TIME0; + reg::DSI->DLTCR = 35 * DSI_DLTCR_HS2LP_TIME0 | 35 * DSI_DLTCR_LP2HS_TIME0 + | 256 * DSI_DLTCR_MRD_TIME0; + // Stop wait time. + reg::DSI->PCONFR |= 10 * DSI_PCONFR_SW_TIME0; //// Timings. // TX escape clock division factor. - reg::DSI->CCR = 4; // 500 MHz / 8 (bit) / 4 < 20 MHz + int txeckdiv = (phy_hz + (8 * 20000000 - 1)) / (8 * 20000000); + assert (txeckdiv >= 2 && txeckdiv <= 255); + reg::DSI->CCR = txeckdiv; // TX timeouts. - reg::DSI->CCR |= 4 << 8; - reg::DSI->TCCR[0] = 0x01000000; - reg::DSI->TCCR[1] = 0x00000100; - reg::DSI->TCCR[2] = 0x00000100; - reg::DSI->TCCR[3] = 0x00000100; - reg::DSI->TCCR[4] = 0x00000100; - reg::DSI->TCCR[5] = 0x00000100; + reg::DSI->TCCR[0] = 0; // No HS or LP TX timeout. + reg::DSI->TCCR[1] = 256; // HS read. + reg::DSI->TCCR[2] = 256; // LP read. + reg::DSI->TCCR[3] = 256; // HS write. + reg::DSI->TCCR[4] = 256; // LP write. + reg::DSI->TCCR[5] = 256; // BTA. //// Flow control & DBI interface. reg::DSI->CMCR = DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX | DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX | DSI_CMCR_GLWTX @@ -124,26 +134,48 @@ Dsi::enable (const Function &config) // Polarity of control signals. reg::DSI->LPCR = 0; // HSP, VSP, DEP reg::DSI->WCFGR |= 0; // VSPOL - //// Configure adapted command mode. - // Command mode. - reg::DSI->MCR |= DSI_MCR_CMDM; - reg::DSI->WCFGR |= DSI_WCFGR_DSIM; - // Maximum memory write. - reg::DSI->LCCR = width_; - // Tearing effect source and polarity, no automatic refresh. - reg::DSI->WCFGR &= ~(DSI_WCFGR_TESRC | DSI_WCFGR_AR); - // Tearing effect acknowledge. - reg::DSI->CMCR |= DSI_CMCR_TEARE; + if (!video_mode_) + { + //// Configure adapted command mode. + // Command mode. + reg::DSI->MCR |= DSI_MCR_CMDM; + reg::DSI->WCFGR |= DSI_WCFGR_DSIM; + // Maximum memory write. + reg::DSI->LCCR = width_; + // Tearing effect source and polarity, no automatic refresh. + reg::DSI->WCFGR &= ~(DSI_WCFGR_TESRC | DSI_WCFGR_AR); + // Tearing effect acknowledge. + reg::DSI->CMCR |= DSI_CMCR_TEARE; + reg::DSI->PCR |= DSI_PCR_BTAE; + } + else + { + //// Configure video mode. + reg::DSI->VMCR = DSI_VMCR_VMT_Burst | DSI_VMCR_LPVSAE + | DSI_VMCR_LPVBPE | DSI_VMCR_LPVFPE | DSI_VMCR_LPVAE + | DSI_VMCR_LPHBPE | DSI_VMCR_LPHFPE | DSI_VMCR_LPCE; + reg::DSI->MCR &= ~DSI_MCR_CMDM; + reg::DSI->WCFGR &= ~DSI_WCFGR_DSIM; + // Packet size. + reg::DSI->VPCR = width_; + reg::DSI->VCCR = 0; + // Timings. + reg::DSI->VHSACR = static_cast (hsync_) + * (phy_hz / 8) / pclk_hz; + reg::DSI->VHBPCR = static_cast (hbp_) + * (phy_hz / 8) / pclk_hz; + reg::DSI->VLCR = static_cast (hsync_ + hbp_ + width_ + hfp_) + * (phy_hz / 8) / pclk_hz; + reg::DSI->VVSACR = vsync_; + reg::DSI->VVBPCR = vbp_; + reg::DSI->VVFPCR = vfp_; + reg::DSI->VVACR = heigth_; + reg::DSI->LPMCR = 64 * DSI_LPMCR_LPSIZE0 | 0 * DSI_LPMCR_VLPSIZE0; + } //// Enable D-PHY and D-PHY clock lane settings. reg::DSI->PCTLR = DSI_PCTLR_DEN; reg::DSI->PCTLR = DSI_PCTLR_CKE | DSI_PCTLR_DEN; //// Configure LTDC. - rcc_sai_pll_setup (8000000, - 4, // pllm => 8 MHz / 4 = 2 MHz - 208, // plln => 2 MHz * 208 = 416 MHz - 8, // pllp => 416 MHz / 8 = 52 MHz - 15, 32, // pllq, pllq_div => 416 MHz / 15 / 32 ~= 0.86 MHz - 5, 2); // pllr, pllr_div => 416 MHz / 5 / 2 ~= 41.6 MHz Ltdc::enable (); //// Enable DSI Host and DSI wrapper. reg::DSI->WIER = DSI_WIER_ERIE | DSI_WIER_TEIE; @@ -152,12 +184,14 @@ Dsi::enable (const Function &config) reg::DSI->WCR = DSI_WCR_DSIEN; //// Configure display. config (); - //// Flow control & DBI interface. - reg::DSI->CMCR &= ~(DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX - | DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX - | DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX - | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); - reg::DSI->PCR = DSI_PCR_BTAE; + if (!video_mode_) + { + // Need HS to transmit pixels. + reg::DSI->CMCR &= ~(DSI_CMCR_GSW0TX | DSI_CMCR_GSW1TX | DSI_CMCR_GSW2TX + | DSI_CMCR_GSR0TX | DSI_CMCR_GSR1TX | DSI_CMCR_GSR2TX + | DSI_CMCR_GLWTX | DSI_CMCR_DSW0TX | DSI_CMCR_DSW1TX + | DSI_CMCR_DSR0TX | DSI_CMCR_DLWTX | DSI_CMCR_MRDPS); + } } void @@ -174,21 +208,29 @@ Dsi::disable () void Dsi::layer_setup (int layer, const Surface &surface, int x, int y) { - reg::DSI->WCR &= ~DSI_WCR_DSIEN; - Ltdc::layer_setup (layer, surface, x, y); - reg::DSI->WCR |= DSI_WCR_DSIEN; + if (!video_mode_) + { + reg::DSI->WCR &= ~DSI_WCR_DSIEN; + Ltdc::layer_setup (layer, surface, x, y); + reg::DSI->WCR |= DSI_WCR_DSIEN; + } + else + Ltdc::layer_setup (layer, surface, x, y); } void Dsi::refresh (bool wait_hsync) { - refreshing_ = true; - if (wait_hsync) - ucoo::Dsi::write_command ({ DCS_SET_TEAR_ON, 0x00 }); - else - ucoo::reg::DSI->WCR |= DSI_WCR_LTDCEN; - while (refreshing_) - ucoo::barrier (); + if (!video_mode_) + { + refreshing_ = true; + if (wait_hsync) + ucoo::Dsi::write_command ({ DCS_SET_TEAR_ON, 0x00 }); + else + ucoo::reg::DSI->WCR |= DSI_WCR_LTDCEN; + while (refreshing_) + ucoo::barrier (); + } } void @@ -196,6 +238,8 @@ Dsi::write_command (std::initializer_list data) { while (!(reg::DSI->GPSR & DSI_GPSR_CMDFE)) ; + while (!(reg::DSI->GPSR & DSI_GPSR_PWRFE)) + ; uint32_t w = 0; int wb = 0; for (auto d : data) diff --git a/ucoo/hal/frame_buffer/dsi.stm32f4.hh b/ucoo/hal/frame_buffer/dsi.stm32f4.hh index 6842f19..307d4be 100644 --- a/ucoo/hal/frame_buffer/dsi.stm32f4.hh +++ b/ucoo/hal/frame_buffer/dsi.stm32f4.hh @@ -36,20 +36,25 @@ class Dsi : public Ltdc { public: /// Constructor. - Dsi (int width, int heigth, int lanes); + Dsi (int width, int heigth, int lanes, bool video_mode = false, + int hsync = 2, int hbp = 1, int hfp = 1, + int vsync = 2, int vbp = 1, int vfp = 1); /// Enable controller. - void enable (const Function &config); + void enable (const Function &config, int phy_hz = 500000000, + int pclk_hz = 40000000); /// Disable controller. void disable (); /// Setup a layer. void layer_setup (int layer, const Surface &surface, int x, int y); /// Refresh screen. - static void refresh (bool wait_hsync); + void refresh (bool wait_hsync); /// Write a command to display. static void write_command (std::initializer_list data); private: /// Number of data lanes. int lanes_; + /// Using video mode or adapted command mode? + bool video_mode_; /// Refresh is being done. static bool refreshing_; private: diff --git a/ucoo/hal/frame_buffer/ltdc.stm32f4.cc b/ucoo/hal/frame_buffer/ltdc.stm32f4.cc index 4255ff7..a1e4f47 100644 --- a/ucoo/hal/frame_buffer/ltdc.stm32f4.cc +++ b/ucoo/hal/frame_buffer/ltdc.stm32f4.cc @@ -80,7 +80,7 @@ Ltdc::layer_setup (int layer, const Surface &surface, int x, int y) reg->CFBLNR = surface.h; reg->CR = LTDC_LxCR_LEN; // Load parameters. - reg::LTDC->SRCR = LTDC_SRCR_IMR; + reg::LTDC->SRCR = LTDC_SRCR_VBR; } } // namespace ucoo diff --git a/ucoo/hal/frame_buffer/ltdc.stm32f4.hh b/ucoo/hal/frame_buffer/ltdc.stm32f4.hh index edf95b0..72ceda1 100644 --- a/ucoo/hal/frame_buffer/ltdc.stm32f4.hh +++ b/ucoo/hal/frame_buffer/ltdc.stm32f4.hh @@ -43,7 +43,7 @@ class Ltdc void layer_setup (int layer, const Surface &surface, int x, int y); protected: int width_, heigth_; - private: + protected: int hsync_, hbp_, hfp_; int vsync_, vbp_, vfp_; }; -- cgit v1.2.3