diff options
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.c | 261 |
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 |