summaryrefslogtreecommitdiff
path: root/src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c')
-rw-r--r--src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c
new file mode 100644
index 00000000..21fb3001
--- /dev/null
+++ b/src/libs/lvgl/src/lv_gpu/lv_gpu_stm32_dma2d.c
@@ -0,0 +1,261 @@
+/**
+ * @file lv_gpu_stm32_dma2d.c
+ *
+ */
+
+/*********************
+ * INCLUDES
+ *********************/
+#include "lv_gpu_stm32_dma2d.h"
+#include "../lv_core/lv_disp.h"
+#include "../lv_core/lv_refr.h"
+
+#if LV_USE_GPU_STM32_DMA2D
+
+#include LV_GPU_DMA2D_CMSIS_INCLUDE
+
+/*********************
+ * DEFINES
+ *********************/
+
+#if LV_COLOR_16_SWAP
+ // TODO: F7 has red blue swap bit in control register for all layers and output
+ #error "Can't use DMA2D with LV_COLOR_16_SWAP 1"
+#endif
+
+#if LV_COLOR_DEPTH == 8
+ #error "Can't use DMA2D with LV_COLOR_DEPTH == 8"
+#endif
+
+#if LV_COLOR_DEPTH == 16
+ #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565
+#elif LV_COLOR_DEPTH == 32
+ #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888
+#else
+ /*Can't use GPU with other formats*/
+#endif
+
+/**********************
+ * TYPEDEFS
+ **********************/
+
+/**********************
+ * STATIC PROTOTYPES
+ **********************/
+static void invalidate_cache(void);
+static void wait_finish(void);
+
+/**********************
+ * STATIC VARIABLES
+ **********************/
+
+/**********************
+ * MACROS
+ **********************/
+
+/**********************
+ * GLOBAL FUNCTIONS
+ **********************/
+
+/**
+ * Turn on the peripheral and set output color mode, this only needs to be done once
+ */
+void lv_gpu_stm32_dma2d_init(void)
+{
+ /* Enable DMA2D clock */
+#if defined(STM32F4) || defined(STM32F7)
+ RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
+#elif defined(STM32H7)
+ RCC->AHB3ENR |= RCC_AHB3ENR_DMA2DEN;
+#else
+# warning "LVGL can't enable the clock of DMA2D"
+#endif
+
+ /* Wait for hardware access to complete */
+ __asm volatile("DSB\n");
+
+ /* Delay after setting peripheral clock */
+ volatile uint32_t temp = RCC->AHB1ENR;
+
+ /* set output colour mode */
+ DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT;
+}
+
+/**
+ * Fill an area in the buffer with a color
+ * @param buf a buffer which should be filled
+ * @param buf_w width of the buffer in pixels
+ * @param color fill color
+ * @param fill_w width to fill in pixels (<= buf_w)
+ * @param fill_h height to fill in pixels
+ * @note `buf_w - fill_w` is offset to the next line after fill
+ */
+void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h)
+{
+ invalidate_cache();
+
+ DMA2D->CR = 0x30000;
+ DMA2D->OMAR = (uint32_t)buf;
+ /* as input color mode is same as output we don't need to convert here do we? */
+ DMA2D->OCOLR = color.full;
+ DMA2D->OOR = buf_w - fill_w;
+ DMA2D->NLR = (fill_w << DMA2D_NLR_PL_Pos) | (fill_h << DMA2D_NLR_NL_Pos);
+
+ /* start transfer */
+ DMA2D->CR |= DMA2D_CR_START_Msk;
+
+ wait_finish();
+}
+
+/**
+ * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel
+ * @param buf a buffer which should be filled using a mask
+ * @param buf_w width of the buffer in pixels
+ * @param color fill color
+ * @param mask 0..255 values describing the opacity of the corresponding pixel. It's width is `fill_w`
+ * @param opa overall opacity. 255 in `mask` should mean this opacity.
+ * @param fill_w width to fill in pixels (<= buf_w)
+ * @param fill_h height to fill in pixels
+ * @note `buf_w - fill_w` is offset to the next line after fill
+ */
+void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask,
+ lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h)
+{
+#if 0
+ invalidate_cache();
+
+ /* Configure the DMA2D Mode, Color Mode and line output offset */
+ hdma2d.Init.Mode = DMA2D_M2M_BLEND;
+ hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT;
+ hdma2d.Init.OutputOffset = buf_w - fill_w;
+
+ /* Configure the foreground -> The character */
+ lv_color32_t c32;
+ c32.full = lv_color_to32(color);
+ c32.ch.alpha = opa;
+ hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
+ hdma2d.LayerCfg[1].InputAlpha = c32.full;
+ hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8;
+ hdma2d.LayerCfg[1].InputOffset = 0;
+
+ /* Configure the background -> Display buffer */
+ hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
+ hdma2d.LayerCfg[0].InputAlpha = 0x00;
+ hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT;
+ hdma2d.LayerCfg[0].InputOffset = buf_w - fill_w;
+
+ /* DMA2D Initialization */
+ HAL_DMA2D_Init(&hdma2d);
+ HAL_DMA2D_ConfigLayer(&hdma2d, 0);
+ HAL_DMA2D_ConfigLayer(&hdma2d, 1);
+ HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h);
+ wait_finish();
+#endif
+}
+
+/**
+ * Copy a map (typically RGB image) to a buffer
+ * @param buf a buffer where map should be copied
+ * @param buf_w width of the buffer in pixels
+ * @param map an "image" to copy
+ * @param map_w width of the map in pixels
+ * @param copy_w width of the area to copy in pixels (<= buf_w)
+ * @param copy_h height of the area to copy in pixels
+ * @note `map_w - fill_w` is offset to the next line after copy
+ */
+void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w,
+ lv_coord_t copy_w, lv_coord_t copy_h)
+{
+ invalidate_cache();
+
+ DMA2D->CR = 0;
+ /* copy output colour mode, this register controls both input and output colour format */
+ DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT;
+ DMA2D->FGMAR = (uint32_t)map;
+ DMA2D->FGOR = map_w - copy_w;
+ DMA2D->OMAR = (uint32_t)buf;
+ DMA2D->OOR = buf_w - copy_w;
+ DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
+
+ /* start transfer */
+ DMA2D->CR |= DMA2D_CR_START_Msk;
+ wait_finish();
+}
+
+/**
+ * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer
+ * @param buf a buffer where `map` should be copied
+ * @param buf_w width of the buffer in pixels
+ * @param map an "image" to copy
+ * @param opa opacity of `map`
+ * @param map_w width of the map in pixels
+ * @param copy_w width of the area to copy in pixels (<= buf_w)
+ * @param copy_h height of the area to copy in pixels
+ * @note `map_w - fill_w` is offset to the next line after copy
+ */
+void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa,
+ lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h)
+{
+ invalidate_cache();
+ DMA2D->CR = 0x20000;
+
+ DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT;
+ DMA2D->BGMAR = (uint32_t)buf;
+ DMA2D->BGOR = buf_w - copy_w;
+
+ DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT
+ /* alpha mode 2, replace with foreground * alpha value */
+ | (2 << DMA2D_FGPFCCR_AM_Pos)
+ /* alpha value */
+ | (opa << DMA2D_FGPFCCR_ALPHA_Pos);
+ DMA2D->FGMAR = (uint32_t)map;
+ DMA2D->FGOR = map_w - copy_w;
+
+ DMA2D->OMAR = (uint32_t)buf;
+ DMA2D->OOR = buf_w - copy_w;
+ DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
+
+ /* start transfer */
+ DMA2D->CR |= DMA2D_CR_START_Msk;
+ wait_finish();
+}
+
+void lv_gpu_stm32_dma2d_wait_cb(lv_disp_drv_t * drv)
+{
+ if(drv && drv->wait_cb) {
+ while(DMA2D->CR & DMA2D_CR_START_Msk) {
+ drv->wait_cb(drv);
+ }
+ }
+ else {
+ while(DMA2D->CR & DMA2D_CR_START_Msk);
+ }
+}
+
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
+
+static void invalidate_cache(void)
+{
+ lv_disp_t * disp = _lv_refr_get_disp_refreshing();
+ if(disp->driver.clean_dcache_cb) disp->driver.clean_dcache_cb(&disp->driver);
+ else {
+#if __CORTEX_M >= 0x07
+ if((SCB->CCR) & (uint32_t)SCB_CCR_DC_Msk)
+ SCB_CleanInvalidateDCache();
+#endif
+ }
+}
+
+static void wait_finish(void)
+{
+ lv_disp_t * disp = _lv_refr_get_disp_refreshing();
+ if(disp->driver.gpu_wait_cb) return;
+
+ while(DMA2D->CR & DMA2D_CR_START_Msk) {
+ if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver);
+ }
+}
+
+#endif