libyggdrasil  v1.0.0
display.hpp
Go to the documentation of this file.
1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * _____.___. .___ .__.__ *
3  * \__ | | ____ ____ __| _/___________ _____|__| | *
4  * / | |/ ___\ / ___\ / __ |\_ __ \__ \ / ___/ | | *
5  * \____ / /_/ > /_/ > /_/ | | | \// __ \_\___ \| | |__ *
6  * / ______\___ /\___ /\____ | |__| (____ /____ >__|____/ *
7  * \/ /_____//_____/ \/ \/ \/ *
8  * - Midgard - *
9  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10  * This software can be used by students and other personal of the *
11  * Bern University of Applied Sciences under the terms of the MIT *
12  * license. *
13  * For other persons this software is under the terms of the GNU *
14  * General Public License version 2. *
15  * *
16  * Copyright © 2021, Bern University of Applied Sciences. *
17  * All rights reserved. *
18  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26 #pragma once
27 
31 
32 #include <cpp/midgard/st/otm8009a.h>
33 
34 #include <cmath>
35 
36 namespace bsp::drv {
37 
38  enum class Color : u8 {
39  Black = 0b000'000'00,
40  Navy = 0b000'000'10,
41  Blue = 0b000'000'11,
42  Green = 0b000'011'00,
43  Teal = 0b000'010'01,
44  Lime = 0b000'111'00,
45  Aqua = 0b000'111'11,
46  Maroon = 0b011'000'00,
47  Purple = 0b011'000'11,
48  Olive = 0b011'011'00,
49  Gray = 0b010'010'01,
50  Red = 0b111'000'00,
51  Fuchsia = 0b111'000'11,
52  Yellow = 0b111'111'00,
53  Orange = 0b111'100'00,
54  White = 0b111'111'11,
55  };
56 
57 }
58 
59 namespace bsp::mid::drv {
60 
67  template<auto Context>
68  struct Display {
69  Display(const Display&) = delete;
70 
71  enum class Orientation {
72  Portrait = 0x00,
73  };
74 
75 
76  /*
77  * @brief Display initialization
78  *
79  * @param orientation Display orientation
80  * @return Success
81  */
82  static bool init(Orientation orientation = Orientation::Portrait) noexcept {
83  auto [hltdc, hdsi, hdma2d] = Context;
84 
85  DSI_PLLInitTypeDef dsiPllInit;
86  static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
87  uint32_t LcdClock = 27429;
89  u32 laneByteClk_kHz = 0;
90  u32 VSA, VBP, VFP, VACT, HSA, HBP, HFP, HACT;
91 
93 
94  HAL_NVIC_DisableIRQ(LTDC_IRQn);
95  HAL_NVIC_DisableIRQ(DMA2D_IRQn);
96  HAL_NVIC_DisableIRQ(DSI_IRQn);
97 
98  __HAL_RCC_LTDC_FORCE_RESET();
99  __HAL_RCC_DMA2D_FORCE_RESET();
100  __HAL_RCC_DSI_FORCE_RESET();
101 
102  __HAL_RCC_LTDC_CLK_DISABLE();
103  __HAL_RCC_DMA2D_CLK_DISABLE();
104  __HAL_RCC_DSI_CLK_DISABLE();
105 
106  __HAL_RCC_LTDC_CLK_ENABLE();
107  __HAL_RCC_LTDC_FORCE_RESET();
108  __HAL_RCC_LTDC_RELEASE_RESET();
109 
110  __HAL_RCC_DMA2D_CLK_ENABLE();
111  __HAL_RCC_DMA2D_FORCE_RESET();
112  __HAL_RCC_DMA2D_RELEASE_RESET();
113 
114  __HAL_RCC_DSI_CLK_ENABLE();
115  __HAL_RCC_DSI_FORCE_RESET();
116  __HAL_RCC_DSI_RELEASE_RESET();
117 
118  HAL_NVIC_SetPriority(LTDC_IRQn, 0x0F, 0);
119  HAL_NVIC_EnableIRQ(LTDC_IRQn);
120  HAL_NVIC_SetPriority(DMA2D_IRQn, 0x0F, 0);
121  HAL_NVIC_EnableIRQ(DMA2D_IRQn);
122  HAL_NVIC_SetPriority(DSI_IRQn, 0x0F, 0);
123  HAL_NVIC_EnableIRQ(DSI_IRQn);
124 
125  hdsi->Instance = DSI;
126 
127  HAL_DSI_DeInit(hdsi);
128 
129  dsiPllInit.PLLNDIV = 100;
130  dsiPllInit.PLLIDF = DSI_PLL_IN_DIV5;
131  dsiPllInit.PLLODF = DSI_PLL_OUT_DIV1;
132  laneByteClk_kHz = 62500;
133 
134  hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES;
135 
136  hdsi->Init.TXEscapeCkdiv = laneByteClk_kHz/15620;
137 
138  HAL_DSI_Init(hdsi, &dsiPllInit);
139 
140  if(orientation == Orientation::Portrait) {
141  Display::s_xSize = OTM8009A_480X800_WIDTH;
142  Display::s_ySize = OTM8009A_480X800_HEIGHT;
143  }
144  else {
145  Display::s_xSize = OTM8009A_800X480_WIDTH;
146  Display::s_ySize = OTM8009A_800X480_HEIGHT;
147  }
148 
149  HACT = Display::s_xSize;
150  VACT = Display::s_ySize;
151 
152  VSA = OTM8009A_480X800_VSYNC;
153  VBP = OTM8009A_480X800_VBP;
154  VFP = OTM8009A_480X800_VFP;
155  HSA = OTM8009A_480X800_HSYNC;
156  HBP = OTM8009A_480X800_HBP;
157  HFP = OTM8009A_480X800_HFP;
158 
159  Display::s_hdsiVideo.VirtualChannelID = 0;
160  Display::s_hdsiVideo.ColorCoding = DSI_RGB888;
161  Display::s_hdsiVideo.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
162  Display::s_hdsiVideo.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
163  Display::s_hdsiVideo.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
164  Display::s_hdsiVideo.Mode = DSI_VID_MODE_BURST;
165  Display::s_hdsiVideo.NullPacketSize = 0xFFF;
166  Display::s_hdsiVideo.NumberOfChunks = 0;
167  Display::s_hdsiVideo.PacketSize = HACT;
168  Display::s_hdsiVideo.HorizontalSyncActive = (HSA * laneByteClk_kHz)/LcdClock;
169  Display::s_hdsiVideo.HorizontalBackPorch = (HBP * laneByteClk_kHz)/LcdClock;
170  Display::s_hdsiVideo.HorizontalLine = ((HACT + HSA + HBP + HFP) * laneByteClk_kHz)/LcdClock;
171  Display::s_hdsiVideo.VerticalSyncActive = VSA;
172  Display::s_hdsiVideo.VerticalBackPorch = VBP;
173  Display::s_hdsiVideo.VerticalFrontPorch = VFP;
174  Display::s_hdsiVideo.VerticalActive = VACT;
175 
176  Display::s_hdsiVideo.LPCommandEnable = DSI_LP_COMMAND_ENABLE;
177 
178  Display::s_hdsiVideo.LPLargestPacketSize = 16;
179 
180  Display::s_hdsiVideo.LPVACTLargestPacketSize = 0;
181 
182  Display::s_hdsiVideo.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
183  Display::s_hdsiVideo.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
184  Display::s_hdsiVideo.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
185  Display::s_hdsiVideo.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
186  Display::s_hdsiVideo.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
187  Display::s_hdsiVideo.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
188 
189  HAL_DSI_ConfigVideoMode(hdsi, &Display::s_hdsiVideo);
190 
191  hltdc->Init.HorizontalSync = (HSA - 1);
192  hltdc->Init.AccumulatedHBP = (HSA + HBP - 1);
193  hltdc->Init.AccumulatedActiveW = (Display::s_xSize + HSA + HBP - 1);
194  hltdc->Init.TotalWidth = (Display::s_ySize + HSA + HBP + HFP - 1);
195 
196  hltdc->LayerCfg->ImageWidth = Display::s_xSize;
197  hltdc->LayerCfg->ImageHeight = Display::s_ySize;
198 
199  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
200  PeriphClkInitStruct.PLLSAI.PLLSAIN = 384;
201  PeriphClkInitStruct.PLLSAI.PLLSAIR = 7;
202  PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
203  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
204 
205  hltdc->Init.Backcolor.Blue = 0;
206  hltdc->Init.Backcolor.Green = 0;
207  hltdc->Init.Backcolor.Red = 0;
208  hltdc->Init.PCPolarity = LTDC_PCPOLARITY_IPC;
209  hltdc->Instance = LTDC;
210 
211  HAL_LTDC_StructInitFromVideoConfig(hltdc, &Display::s_hdsiVideo);
212  HAL_LTDC_Init(hltdc);
213 
214  HAL_DSI_Start(hdsi);
215 
216  OTM8009A_Init(OTM8009A_FORMAT_RGB888, enumValue(orientation));
217 
218  LTDC_LayerCfgTypeDef layerCfg;
219 
220  layerCfg.WindowX0 = 0;
221  layerCfg.WindowX1 = Display::getWidth();
222  layerCfg.WindowY0 = 0;
223  layerCfg.WindowY1 = Display::getHeight();
224  layerCfg.PixelFormat = LTDC_PIXEL_FORMAT_L8;
225  layerCfg.FBStartAdress = Display::FramebufferAddress;
226  layerCfg.Alpha = 255;
227  layerCfg.Alpha0 = 0;
228  layerCfg.Backcolor.Blue = 0;
229  layerCfg.Backcolor.Green = 0;
230  layerCfg.Backcolor.Red = 0;
231  layerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
232  layerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
233  layerCfg.ImageWidth = Display::getWidth();
234  layerCfg.ImageHeight = Display::getHeight();
235 
236  HAL_LTDC_ConfigLayer(hltdc, &layerCfg, 0);
237  HAL_LTDC_EnableCLUT(hltdc, 0);
238 
240  Display::clear(static_cast<u8>(bsp::drv::Color::Black));
241  Display::turnOn();
242 
243  return true;
244  }
245 
251  static bool deinit() {
252  return true;
253  }
254 
255  /*
256  * @brief Display reset
257  */
258  static void reset() noexcept {
260  constexpr auto& DisplayReset = GPIOPortD::Pin<11, bsp::drv::Active::Low>;
261 
262  DisplayReset = true;
263  core::delay(20);
264  DisplayReset = false;
265  core::delay(10);
266  }
267 
268  /*
269  * @brief Enable the display
270  */
271  static void turnOn() noexcept {
272  const auto [hltdc, hdsi, hdma2d] = Context;
273 
274  HAL_DSI_ShortWrite(hdsi, Display::s_hdsiVideo.VirtualChannelID, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_DISPON, 0x00);
275  }
276 
277  /*
278  * @brief Disable the display
279  */
280  static void turnOff() noexcept {
281  const auto [hltdc, hdsi, hdma2d] = Context;
282 
283  HAL_DSI_ShortWrite(hdsi, Display::s_hdsiVideo.VirtualChannelID, DSI_DCS_SHORT_PKT_WRITE_P1, OTM8009A_CMD_DISPOFF, 0x00);
284  }
285 
286  /*
287  * @brief Get the display width
288  *
289  * @return display width
290  */
291  static inline u16 getWidth() {
292  return Display::s_xSize;
293  }
294 
295  /*
296  * @brief Get the display height
297  *
298  * @return display height
299  */
300  static inline u16 getHeight() {
301  return Display::s_ySize;
302  }
303 
304  /*
305  * @brief Set the color palette
306  *
307  * @param palettet Color palette
308  */
309  static inline void setPalette(const std::array<u32, 256> &palette) {
310  const auto [hltdc, hdsi, hdma2d] = Context;
311 
312  HAL_LTDC_ConfigCLUT(hltdc, const_cast<u32*>(palette.data()), palette.size(), 0);
313  }
314 
315  /*
316  * @brief Get the default color palette
317  *
318  * @return Default color palette
319  */
320  static std::array<u32, 256> getDefaultPalette() {
321  return std::array<u32, 256> {
322  0xFF000000, 0xFF00004E, 0xFF00009C, 0xFF0000EA, 0xFF002400, 0xFF00244E, 0xFF00249C, 0xFF0024EA, 0xFF004800, 0xFF00484E, 0xFF00489C, 0xFF0048EA, 0xFF006C00, 0xFF006C4E, 0xFF006C9C, 0xFF006CEA, 0xFF009000, 0xFF00904E, 0xFF00909C, 0xFF0090EA, 0xFF00B400, 0xFF00B44E, 0xFF00B49C, 0xFF00B4EA, 0xFF00D800, 0xFF00D84E, 0xFF00D89C, 0xFF00D8EA, 0xFF00FC00, 0xFF00FC4E, 0xFF00FC9C, 0xFF00FCEA, 0xFF240000, 0xFF24004E, 0xFF24009C, 0xFF2400EA, 0xFF242400, 0xFF24244E, 0xFF24249C, 0xFF2424EA, 0xFF244800, 0xFF24484E, 0xFF24489C, 0xFF2448EA, 0xFF246C00, 0xFF246C4E, 0xFF246C9C, 0xFF246CEA, 0xFF249000, 0xFF24904E, 0xFF24909C, 0xFF2490EA, 0xFF24B400, 0xFF24B44E, 0xFF24B49C, 0xFF24B4EA, 0xFF24D800, 0xFF24D84E, 0xFF24D89C, 0xFF24D8EA, 0xFF24FC00, 0xFF24FC4E, 0xFF24FC9C, 0xFF24FCEA, 0xFF480000, 0xFF48004E, 0xFF48009C, 0xFF4800EA, 0xFF482400, 0xFF48244E, 0xFF48249C, 0xFF4824EA, 0xFF484800, 0xFF48484E, 0xFF48489C, 0xFF4848EA, 0xFF486C00, 0xFF486C4E, 0xFF486C9C, 0xFF486CEA, 0xFF489000, 0xFF48904E, 0xFF48909C, 0xFF4890EA, 0xFF48B400, 0xFF48B44E, 0xFF48B49C, 0xFF48B4EA, 0xFF48D800, 0xFF48D84E, 0xFF48D89C, 0xFF48D8EA, 0xFF48FC00, 0xFF48FC4E, 0xFF48FC9C, 0xFF48FCEA, 0xFF6C0000, 0xFF6C004E, 0xFF6C009C, 0xFF6C00EA, 0xFF6C2400, 0xFF6C244E, 0xFF6C249C, 0xFF6C24EA, 0xFF6C4800, 0xFF6C484E, 0xFF6C489C, 0xFF6C48EA, 0xFF6C6C00, 0xFF6C6C4E, 0xFF6C6C9C, 0xFF6C6CEA, 0xFF6C9000, 0xFF6C904E, 0xFF6C909C, 0xFF6C90EA, 0xFF6CB400, 0xFF6CB44E, 0xFF6CB49C, 0xFF6CB4EA, 0xFF6CD800, 0xFF6CD84E, 0xFF6CD89C, 0xFF6CD8EA, 0xFF6CFC00, 0xFF6CFC4E, 0xFF6CFC9C, 0xFF6CFCEA, 0xFF900000, 0xFF90004E, 0xFF90009C, 0xFF9000EA, 0xFF902400, 0xFF90244E, 0xFF90249C, 0xFF9024EA, 0xFF904800, 0xFF90484E, 0xFF90489C, 0xFF9048EA, 0xFF906C00, 0xFF906C4E, 0xFF906C9C, 0xFF906CEA, 0xFF909000, 0xFF90904E, 0xFF90909C, 0xFF9090EA, 0xFF90B400, 0xFF90B44E, 0xFF90B49C, 0xFF90B4EA, 0xFF90D800, 0xFF90D84E, 0xFF90D89C, 0xFF90D8EA, 0xFF90FC00, 0xFF90FC4E, 0xFF90FC9C, 0xFF90FCEA, 0xFFB40000, 0xFFB4004E, 0xFFB4009C, 0xFFB400EA, 0xFFB42400, 0xFFB4244E, 0xFFB4249C, 0xFFB424EA, 0xFFB44800, 0xFFB4484E, 0xFFB4489C, 0xFFB448EA, 0xFFB46C00, 0xFFB46C4E, 0xFFB46C9C, 0xFFB46CEA, 0xFFB49000, 0xFFB4904E, 0xFFB4909C, 0xFFB490EA, 0xFFB4B400, 0xFFB4B44E, 0xFFB4B49C, 0xFFB4B4EA, 0xFFB4D800, 0xFFB4D84E, 0xFFB4D89C, 0xFFB4D8EA, 0xFFB4FC00, 0xFFB4FC4E, 0xFFB4FC9C, 0xFFB4FCEA, 0xFFD80000, 0xFFD8004E, 0xFFD8009C, 0xFFD800EA, 0xFFD82400, 0xFFD8244E, 0xFFD8249C, 0xFFD824EA, 0xFFD84800, 0xFFD8484E, 0xFFD8489C, 0xFFD848EA, 0xFFD86C00, 0xFFD86C4E, 0xFFD86C9C, 0xFFD86CEA, 0xFFD89000, 0xFFD8904E, 0xFFD8909C, 0xFFD890EA, 0xFFD8B400, 0xFFD8B44E, 0xFFD8B49C, 0xFFD8B4EA, 0xFFD8D800, 0xFFD8D84E, 0xFFD8D89C, 0xFFD8D8EA, 0xFFD8FC00, 0xFFD8FC4E, 0xFFD8FC9C, 0xFFD8FCEA, 0xFFFC0000, 0xFFFC004E, 0xFFFC009C, 0xFFFC00EA, 0xFFFC2400, 0xFFFC244E, 0xFFFC249C, 0xFFFC24EA, 0xFFFC4800, 0xFFFC484E, 0xFFFC489C, 0xFFFC48EA, 0xFFFC6C00, 0xFFFC6C4E, 0xFFFC6C9C, 0xFFFC6CEA, 0xFFFC9000, 0xFFFC904E, 0xFFFC909C, 0xFFFC90EA, 0xFFFCB400, 0xFFFCB44E, 0xFFFCB49C, 0xFFFCB4EA, 0xFFFCD800, 0xFFFCD84E, 0xFFFCD89C, 0xFFFCD8EA, 0xFFFCFC00, 0xFFFCFC4E, 0xFFFCFC9C, 0xFFFCFCEA,
323  };
324  }
325 
326  /*
327  * @brief Get the framebuffer address
328  *
329  * @return framebuffer address
330  */
332  return reinterpret_cast<void*>(FramebufferAddress);
333  }
334 
335  /*
336  * @brief Set a Pixel
337  *
338  * @param x X coordinate
339  * @param y Y coordinate
340  * @param color Index for the color
341  */
342  ALWAYS_INLINE static void setPixel(u16 x, u16 y, u8 color) {
343  reinterpret_cast<u8*>(FramebufferAddress)[y * Display::s_xSize + x] = paletteIndex;
344  }
345 
351  ALWAYS_INLINE static void clear(u8 color) {
352  const auto [hltdc, hdsi, hdma2d] = Context;
353 
354  hdma2d->Init.Mode = DMA2D_R2M;
355  hdma2d->Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
356  hdma2d->Init.OutputOffset = 0;
357  hdma2d->Instance = DMA2D;
358 
359  if(HAL_DMA2D_Init(hdma2d) == HAL_OK) {
360  if(HAL_DMA2D_ConfigLayer(hdma2d, 0) == HAL_OK) {
361  if (HAL_DMA2D_Start(hdma2d, paletteIndex << 24 | paletteIndex << 16 | paletteIndex << 8 | paletteIndex, FramebufferAddress, Display::s_xSize / 4, Display::s_ySize) == HAL_OK) {
362 
363  HAL_DMA2D_PollForTransfer(hdma2d, 10);
364  }
365  }
366  }
367  }
368 
369  private:
370  Display() = default;
371 
372  constexpr static u32 FramebufferAddress = 0x2002'0000;
373 
374  static inline u16 s_xSize, s_ySize;
375  static inline DSI_VidCfgTypeDef s_hdsiVideo;
376 
380  template<auto, template<auto> typename>
381  friend struct bsp::drv::Display;
382  };
383 
384 }
u16
uint16_t u16
Definition: types.h:37
u8
uint8_t u8
Unsigned integer definitions.
Definition: types.h:36
bsp::mid::drv::Display::setPalette
static void setPalette(const std::array< u32, 256 > &palette)
Definition: display.hpp:309
cortex.hpp
Core control functions for Midgard.
bsp::drv::Color::Black
@ Black
display.hpp
Frontend for the Display abstraction.
gpio.hpp
GPIO Pin abstraction implementation for Midgard.
bsp::mid::drv::Display::Orientation::Portrait
@ Portrait
bsp::mid::drv::Display::getWidth
static u16 getWidth()
Definition: display.hpp:291
bsp::mid::drv::Display::init
static bool init(Orientation orientation=Orientation::Portrait) noexcept
Definition: display.hpp:82
ALWAYS_INLINE
#define ALWAYS_INLINE
Definition: attributes.h:34
bsp::drv::Color
Color
Definition: display.hpp:39
u32
uint32_t u32
Definition: types.h:38
bsp::enumValue
auto enumValue(T value)
Casts a scoped enum type into its underlying value.
Definition: utils.hpp:151
hdsi
DSI_HandleTypeDef hdsi
bsp::mid::drv::Display::deinit
static bool deinit()
Deinit function.
Definition: display.hpp:251
bsp::drv::GPIOPort
Base class for GPIO port abstraction.
Definition: gpio.hpp:48
bsp::mid::drv::Display::turnOn
static void turnOn() noexcept
Definition: display.hpp:271
bsp::mid::drv::Display
Display implementation for Midgard.
Definition: display.hpp:68
bsp::mid::drv::Display::Display
Display(const Display &)=delete
bsp::mid::drv::Display::setPixel
static ALWAYS_INLINE void setPixel(u16 x, u16 y, u8 color)
Definition: display.hpp:342
bsp::mid::drv::Display::turnOff
static void turnOff() noexcept
Definition: display.hpp:280
bsp::mid::drv::Display::reset
static void reset() noexcept
Definition: display.hpp:258
Orientation
Absolute board orientation.
Definition: six_axis_sensor.h:40
bsp::mid::drv::Display::clear
static ALWAYS_INLINE void clear(u8 color)
Clear the display to a color.
Definition: display.hpp:351
bsp::drv
Definition: display.hpp:37
bsp::mid::drv::Display::getDefaultPalette
static std::array< u32, 256 > getDefaultPalette()
Definition: display.hpp:320
bsp::mid::drv::Display::getHeight
static u16 getHeight()
Definition: display.hpp:300
bsp::core::delay
ALWAYS_INLINE void delay(u32 ms)
Delays execution by a certain number of milliseconds.
Definition: cortex.hpp:39
bsp::mid::drv::Display::getFramebufferAddress
static ALWAYS_INLINE void * getFramebufferAddress()
Definition: display.hpp:331
bsp::mid::drv
Definition: adc.hpp:32