1 /**
2 * @file lv_gpu_stm32_dma2d.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_gpu_stm32_dma2d.h"
10 #include "../lv_core/lv_disp.h"
11 #include "../lv_core/lv_refr.h"
12
13 #if LV_USE_GPU_STM32_DMA2D
14
15 #include LV_GPU_DMA2D_CMSIS_INCLUDE
16
17 /*********************
18 * DEFINES
19 *********************/
20
21 #if LV_COLOR_16_SWAP
22 // TODO: F7 has red blue swap bit in control register for all layers and output
23 #error "Can't use DMA2D with LV_COLOR_16_SWAP 1"
24 #endif
25
26 #if LV_COLOR_DEPTH == 8
27 #error "Can't use DMA2D with LV_COLOR_DEPTH == 8"
28 #endif
29
30 #if LV_COLOR_DEPTH == 16
31 #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_RGB565
32 #elif LV_COLOR_DEPTH == 32
33 #define LV_DMA2D_COLOR_FORMAT LV_DMA2D_ARGB8888
34 #else
35 /*Can't use GPU with other formats*/
36 #endif
37
38 /**********************
39 * TYPEDEFS
40 **********************/
41
42 /**********************
43 * STATIC PROTOTYPES
44 **********************/
45 static void invalidate_cache(void);
46 static void dma2d_wait(void);
47
48 /**********************
49 * STATIC VARIABLES
50 **********************/
51
52 /**********************
53 * MACROS
54 **********************/
55
56 /**********************
57 * GLOBAL FUNCTIONS
58 **********************/
59
60 /**
61 * Turn on the peripheral and set output color mode, this only needs to be done once
62 */
lv_gpu_stm32_dma2d_init(void)63 void lv_gpu_stm32_dma2d_init(void)
64 {
65 /* Enable DMA2D clock */
66 RCC->AHB1ENR |= RCC_AHB1ENR_DMA2DEN;
67
68 /* Delay after setting peripheral clock */
69 volatile uint32_t temp = RCC->AHB1ENR;
70
71 /* set output colour mode */
72 DMA2D->OPFCCR = LV_DMA2D_COLOR_FORMAT;
73 }
74
75 /**
76 * Fill an area in the buffer with a color
77 * @param buf a buffer which should be filled
78 * @param buf_w width of the buffer in pixels
79 * @param color fill color
80 * @param fill_w width to fill in pixels (<= buf_w)
81 * @param fill_h height to fill in pixels
82 * @note `buf_w - fill_w` is offset to the next line after fill
83 */
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)84 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)
85 {
86 invalidate_cache();
87
88 DMA2D->CR = 0x30000;
89 DMA2D->OMAR = (uint32_t)buf;
90 /* as input color mode is same as output we don't need to convert here do we? */
91 DMA2D->OCOLR = color.full;
92 DMA2D->OOR = buf_w - fill_w;
93 DMA2D->NLR = (fill_w << DMA2D_NLR_PL_Pos) | (fill_h << DMA2D_NLR_NL_Pos);
94
95 /* start transfer */
96 DMA2D->CR |= DMA2D_CR_START_Msk;
97
98 dma2d_wait();
99 }
100
101 /**
102 * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel
103 * @param buf a buffer which should be filled using a mask
104 * @param buf_w width of the buffer in pixels
105 * @param color fill color
106 * @param mask 0..255 values describing the opacity of the corresponding pixel. It's width is `fill_w`
107 * @param opa overall opacity. 255 in `mask` should mean this opacity.
108 * @param fill_w width to fill in pixels (<= buf_w)
109 * @param fill_h height to fill in pixels
110 * @note `buf_w - fill_w` is offset to the next line after fill
111 */
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)112 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,
113 lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h)
114 {
115 #if 0
116 invalidate_cache();
117
118 /* Configure the DMA2D Mode, Color Mode and line output offset */
119 hdma2d.Init.Mode = DMA2D_M2M_BLEND;
120 hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT;
121 hdma2d.Init.OutputOffset = buf_w - fill_w;
122
123 /* Configure the foreground -> The character */
124 lv_color32_t c32;
125 c32.full = lv_color_to32(color);
126 c32.ch.alpha = opa;
127 hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA;
128 hdma2d.LayerCfg[1].InputAlpha = c32.full;
129 hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8;
130 hdma2d.LayerCfg[1].InputOffset = 0;
131
132 /* Configure the background -> Display buffer */
133 hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA;
134 hdma2d.LayerCfg[0].InputAlpha = 0x00;
135 hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT;
136 hdma2d.LayerCfg[0].InputOffset = buf_w - fill_w;
137
138 /* DMA2D Initialization */
139 HAL_DMA2D_Init(&hdma2d);
140 HAL_DMA2D_ConfigLayer(&hdma2d, 0);
141 HAL_DMA2D_ConfigLayer(&hdma2d, 1);
142 HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h);
143 dma2d_wait();
144 #endif
145 }
146
147 /**
148 * Copy a map (typically RGB image) to a buffer
149 * @param buf a buffer where map should be copied
150 * @param buf_w width of the buffer in pixels
151 * @param map an "image" to copy
152 * @param map_w width of the map in pixels
153 * @param copy_w width of the area to copy in pixels (<= buf_w)
154 * @param copy_h height of the area to copy in pixels
155 * @note `map_w - fill_w` is offset to the next line after copy
156 */
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)157 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,
158 lv_coord_t copy_w, lv_coord_t copy_h)
159 {
160 invalidate_cache();
161
162 DMA2D->CR = 0;
163 /* copy output colour mode, this register controls both input and output colour format */
164 DMA2D->FGPFCCR = LV_DMA2D_COLOR_FORMAT;
165 DMA2D->FGMAR = (uint32_t)map;
166 DMA2D->FGOR = map_w - copy_w;
167 DMA2D->OMAR = (uint32_t)buf;
168 DMA2D->OOR = buf_w - copy_w;
169 DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
170
171 /* start transfer */
172 DMA2D->CR |= DMA2D_CR_START_Msk;
173 dma2d_wait();
174 }
175
176 /**
177 * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer
178 * @param buf a buffer where `map` should be copied
179 * @param buf_w width of the buffer in pixels
180 * @param map an "image" to copy
181 * @param opa opacity of `map`
182 * @param map_w width of the map in pixels
183 * @param copy_w width of the area to copy in pixels (<= buf_w)
184 * @param copy_h height of the area to copy in pixels
185 * @note `map_w - fill_w` is offset to the next line after copy
186 */
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)187 void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa,
188 lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h)
189 {
190 invalidate_cache();
191 DMA2D->CR = 0x20000;
192
193 DMA2D->BGPFCCR = LV_DMA2D_COLOR_FORMAT;
194 DMA2D->BGMAR = (uint32_t)buf;
195 DMA2D->BGOR = buf_w - copy_w;
196
197 DMA2D->FGPFCCR = (uint32_t)LV_DMA2D_COLOR_FORMAT
198 /* alpha mode 2, replace with foreground * alpha value */
199 | (2 << DMA2D_FGPFCCR_AM_Pos)
200 /* alpha value */
201 | (opa << DMA2D_FGPFCCR_ALPHA_Pos);
202 DMA2D->FGMAR = (uint32_t)map;
203 DMA2D->FGOR = map_w - copy_w;
204
205 DMA2D->OMAR = (uint32_t)buf;
206 DMA2D->OOR = buf_w - copy_w;
207 DMA2D->NLR = (copy_w << DMA2D_NLR_PL_Pos) | (copy_h << DMA2D_NLR_NL_Pos);
208
209 /* start transfer */
210 DMA2D->CR |= DMA2D_CR_START_Msk;
211 dma2d_wait();
212 }
213
214 /**********************
215 * STATIC FUNCTIONS
216 **********************/
217
invalidate_cache(void)218 static void invalidate_cache(void)
219 {
220 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
221 if(disp->driver.clean_dcache_cb) disp->driver.clean_dcache_cb(&disp->driver);
222 else {
223 #if __CORTEX_M >= 0x07
224 SCB_CleanInvalidateDCache();
225 #endif
226 }
227 }
228
dma2d_wait(void)229 static void dma2d_wait(void)
230 {
231 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
232 while(DMA2D->CR & DMA2D_CR_START_Msk) {
233 if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver);
234 }
235 }
236
237 #endif
238