Arm-2D  
2D Image Processing Library for Cortex-M Processors
arm_2d_helper_pfb.h
1/*
2 * Copyright (C) 2022 Arm Limited or its affiliates. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/* ----------------------------------------------------------------------
20 * Project: Arm-2D Library
21 * Title: #include "arm_2d_helper_pfb.h"
22 * Description: Public header file for the PFB helper service
23 *
24 * $Date: 29. Aug 2022
25 * $Revision: V.1.2.0
26 *
27 * Target Processor: Cortex-M cores
28 * -------------------------------------------------------------------- */
29
30#ifndef __ARM_2D_HELPER_PFB_H__
31#define __ARM_2D_HELPER_PFB_H__
32
33/*============================ INCLUDES ======================================*/
34#include "arm_2d.h"
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40
41#if defined(__clang__)
42# pragma clang diagnostic push
43# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
44# pragma clang diagnostic ignored "-Wpadded"
45#endif
46
47
48/*!
49 * \addtogroup gHelper 7 Helper Services
50 * @{
51 */
52
53/*============================ MACROS ========================================*/
54/*============================ MACROFIED FUNCTIONS ===========================*/
55
56/*!
57 * \brief a macro wrapper in uppercase to help initialising PFB service
58 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
59 * \param[in] __SCREEN_WIDTH the width of the screen
60 * \param[in] __SCREEN_HEIGHT the hight of the screen
61 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
62 * uint32_t
63 * \param[in] __WIDTH the width of the PFB block
64 * \param[in] __HEIGHT the height of the PFB block
65 * \note For the same number of pixels in a PFB block, please priority the width
66 * over height, for example, 240 * 1 is better than 30 * 8
67 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
68 * \param[in] ... a code block to add additional initializer, see example below:
69 * \return arm_2d_err_t the result of the initialisation process
70 *
71 * \code {.c}
72
73 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
74 ...
75 // initialise FPB helper
76 if (ARM_2D_HELPER_PFB_INIT(
77 &s_tExamplePFB, // FPB Helper object
78 __GLCD_CFG_SCEEN_WIDTH__, // screen width
79 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
80 uint16_t, // colour date type
81 240, // PFB block width
82 1, // PFB block height
83 1, // number of PFB in the PFB pool
84 {
85 .evtOnLowLevelRendering = {
86 // callback for low level rendering
87 .fnHandler = &__pfb_render_handler,
88 },
89 .evtOnDrawing = {
90 // callback for drawing GUI
91 .fnHandler = &__pfb_draw_background_handler,
92 },
93 },
94 //.FrameBuffer.bSwapRGB16 = true,
95 ) < 0) {
96 //! error detected
97 assert(false);
98 }
99 * \endcode
100 *
101 */
102#define ARM_2D_HELPER_PFB_INIT( __CB_ADDR, /* PFB Helper object address */ \
103 __SCREEN_WIDTH, /* Screen width */ \
104 __SCREEN_HEIGHT,/* Screen height */ \
105 __PIXEL_TYPE, /* The type of the pixels */ \
106 __WIDTH, /* The width of the PFB block */\
107 __HEIGHT, /* The height of the PFB block*/\
108 __PFB_NUM, /* Block count in the PFB pool*/\
109 ... /* Event Handler */ \
110 ) \
111 ({ \
112 __attribute__((section(".bss.noinit.arm_2d_pfb_pool"))) \
113 static struct { \
114 arm_2d_pfb_t tFPB; \
115 __ALIGNED(4) \
116 __PIXEL_TYPE tBuffer[(__WIDTH) * (__HEIGHT)]; \
117 } s_tPFBs[__PFB_NUM]; \
118 \
119 arm_2d_helper_pfb_cfg_t tCFG = { \
120 .tDisplayArea.tSize = { \
121 .iWidth = (__SCREEN_WIDTH), \
122 .iHeight = (__SCREEN_HEIGHT), \
123 }, \
124 \
125 .FrameBuffer.ptPFBs = (arm_2d_pfb_t *)s_tPFBs, \
126 .FrameBuffer.tFrameSize = { \
127 .iWidth = (__WIDTH), \
128 .iHeight = (__HEIGHT), \
129 }, \
130 .FrameBuffer.wBufferSize = sizeof(s_tPFBs[0].tBuffer), \
131 .FrameBuffer.hwPFBNum = dimof(s_tPFBs), \
132 .Dependency = \
133 __VA_ARGS__ \
134 }; \
135 \
136 arm_2d_helper_pfb_init((__CB_ADDR), &tCFG); \
137 })
138
139/*!
140 * \brief a macro wrapper to update the evtOnDrawring event handler
141 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
142 * \param[in] __HANDLER the new handler
143 * \param[in] ... [Optional] an address (of user defined structure) passed to the
144 * event handler.
145 * \return arm_2d_err_t the process result
146 */
147#define ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
148 __CB_ADDR, /* PFB Helper object address */ \
149 __HANDLER, /* new on-draw-handler function*/\
150 ...) /* An optional target address */ \
151 arm_2d_helper_pfb_update_dependency((__CB_ADDR), \
152 ARM_2D_PFB_DEPEND_ON_DRAWING, \
153 (arm_2d_helper_pfb_dependency_t []) {{ \
154 .evtOnDrawing = { \
155 .fnHandler = (__HANDLER), \
156 .pTarget = (NULL,##__VA_ARGS__),\
157 }, \
158 }})
159
160
161#define __IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
162 enum { \
163 __NAME##_offset = __COUNTER__, \
164 }; \
165 __VA_ARGS__ \
166 arm_2d_region_list_item_t __NAME[] = {
167
168
169#define IMPL_ARM_2D_REGION_LIST(__NAME, ...) \
170 __IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
171
172
173#define END_IMPL_ARM_2D_REGION_LIST(...) \
174 };
175
176#define __ADD_REGION_TO_LIST(__NAME, ...) \
177 { \
178 .ptNext = (arm_2d_region_list_item_t *) \
179 &(__NAME[__COUNTER__ - __NAME##_offset]), \
180 .tRegion = { \
181 __VA_ARGS__ \
182 }, \
183 }
184
185#define ADD_REGION_TO_LIST(__NAME, ...) \
186 __ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
187
188
189#define __ADD_LAST_REGION_TO_LIST(__NAME, ...) \
190 { \
191 .ptNext = NULL, \
192 .tRegion = { \
193 __VA_ARGS__ \
194 }, \
195 }
196
197#define ADD_LAST_REGION_TO_LIST(__NAME, ...) \
198 __ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
199
200#define IMPL_PFB_ON_DRAW(__NAME) \
201 arm_fsm_rt_t __NAME(void *pTarget, \
202 const arm_2d_tile_t *ptTile, \
203 bool bIsNewFrame)
204
205#define IMPL_PFB_ON_LOW_LV_RENDERING(__NAME) \
206 void __NAME(void *pTarget, \
207 const arm_2d_pfb_t *ptPFB, \
208 bool bIsNewFrame)
209
210
211#define IMPL_PFB_ON_FRAME_SYNC_UP(__NAME) \
212 bool __NAME(void *pTarget)
213
214
215/*!
216 * \brief a macro wrapper in lowercase to help initialising PFB service
217 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
218 * \param[in] __SCREEN_WIDTH the width of the screen
219 * \param[in] __SCREEN_HEIGHT the hight of the screen
220 * \param[in] __PIXEL_TYPE the integer type of the pixel, i.e. uint8_t, uint16_t,
221 * uint32_t
222 * \param[in] __WIDTH the width of the PFB block
223 * \param[in] __HEIGHT the height of the PFB block
224 * \note For the same number of pixels in a PFB block, please priority the width
225 * over height, for example, 240 * 1 is better than 30 * 8
226 * \param[in] __PFB_NUM the number of PFB blocks in the built-in PFB pool.
227 * \param[in] ... a code block to add additional initializer, see example below:
228 * \return arm_2d_err_t the result of the initialisation process
229 *
230 * \code {.c}
231
232 static ARM_NOINIT arm_2d_helper_pfb_t s_tExamplePFB;
233 ...
234 // initialise FPB helper
235 if (init_arm_2d_helper_pfb(
236 &s_tExamplePFB, // FPB Helper object
237 __GLCD_CFG_SCEEN_WIDTH__, // screen width
238 __GLCD_CFG_SCEEN_HEIGHT__, // screen height
239 uint16_t, // colour date type
240 240, // PFB block width
241 1, // PFB block height
242 1, // number of PFB in the PFB pool
243 {
244 .evtOnLowLevelRendering = {
245 // callback for low level rendering
246 .fnHandler = &__pfb_render_handler,
247 },
248 .evtOnDrawing = {
249 // callback for drawing GUI
250 .fnHandler = &__pfb_draw_background_handler,
251 },
252 },
253 //.FrameBuffer.bSwapRGB16 = true,
254 ) < 0) {
255 //! error detected
256 assert(false);
257 }
258 * \endcode
259 *
260 */
261#define init_arm_2d_helper_pfb( __CB_ADDR, \
262 __SCREEN_WIDTH, \
263 __SCREEN_HEIGHT, \
264 __PIXEL_TYPE, \
265 __WIDTH, \
266 __HEIGHT, \
267 __PFB_NUM, \
268 ... \
269 ) \
270 ARM_2D_HELPER_PFB_INIT( \
271 __CB_ADDR, \
272 __SCREEN_WIDTH, \
273 __SCREEN_HEIGHT, \
274 __PIXEL_TYPE, \
275 __WIDTH, \
276 __HEIGHT, \
277 __PFB_NUM, \
278 ##__VA_ARGS__ \
279 )
280
281/*!
282 * \brief a macro wrapper to update the evtOnDrawring event handler
283 * \param[in] __CB_ADDR the address of the arm_2d_helper_pfb_t object
284 * \param[in] __HANDLER the new handler
285 * \param[in] ... [Optional] an address (of user defined structure) passed to the
286 * event handler.
287 * \return arm_2d_err_t the process result
288 */
289#define update_arm_2d_helper_pfb_on_draw_handler( \
290 __CB_ADDR, /* PFB Helper object address */ \
291 __HANDLER, /* new on-draw-handler function*/\
292 ...) /* An optional target address */ \
293 ARM_2D_HELPER_PFB_UPDATE_ON_DRAW_HANDLER( \
294 (__CB_ADDR), \
295 (__HANDLER),##__VA_ARGRS__)
296
297#define impl_arm_2d_region_list(__NAME, ...) \
298 IMPL_ARM_2D_REGION_LIST(__NAME,##__VA_ARGS__)
299#define add_region_to_list(__NAME, ...) \
300 ADD_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
301#define add_last_region_to_list(__NAME, ...) \
302 ADD_LAST_REGION_TO_LIST(__NAME, ##__VA_ARGS__)
303#define end_impl_arm_2d_region_list(...) \
304 END_IMPL_ARM_2D_REGION_LIST(__VA_ARGS__)
305
306#define impl_pfb_on_draw(__NAME) IMPL_PFB_ON_DRAW(__NAME)
307#define impl_pfb_on_low_lv_rendering(__NAME) \
308 IMPL_PFB_ON_LOW_LV_RENDERING(__NAME)
309
310/*============================ TYPES =========================================*/
311
313/*!
314 * \brief the header of a PFB block
315 */
316typedef struct arm_2d_pfb_t {
317 struct arm_2d_pfb_t *ptNext; //!< next pfb block
318 arm_2d_helper_pfb_t *ptPFBHelper; //!< the pfb helper service current PFB block comes from
319 arm_2d_tile_t tTile; //!< descriptor
320 uint32_t u24Size : 24;
321 uint32_t : 7;
322 uint32_t bIsNewFrame : 1; //!< a flag to indicate the starting of a frame
324
325/*!
326 * \brief the node of a region list
327 *
328 */
330 struct arm_2d_region_list_item_t *ptNext; //!< the next node
331 arm_2d_region_t tRegion; //!< the region
333
334/*!
335 * \brief the On-Drawing event handler for application layer
336 *
337 * \param[in] pTarget a user attached target address
338 * \param[in] ptTile a tile for the virtual screen
339 * \param[in] bIsNewFrame a flag indicate the starting of a new frame
340 * \return arm_fsm_rt_t the status of the FSM.
341 */
343 void *pTarget,
344 const arm_2d_tile_t *ptTile,
345 bool bIsNewFrame);
346
347/*!
348 * \brief the On Low Level Rendering event handler for the low level (LCD Driver)
349 *
350 * \param[in] pTarget a user attached target address
351 * \param[in] ptPFB the PFB block
352 * \param[in] bIsNewFrame a flag indicate the starting of a new frame
353 */
355 void *pTarget,
356 const arm_2d_pfb_t *ptPFB,
357 bool bIsNewFrame);
358
359/*!
360 * \brief on low level render event
361 */
363 arm_2d_helper_render_handler_t *fnHandler; //!< event handler function
364 void *pTarget; //!< user attached target
366
367/*!
368 * \brief on drawing event
369 */
371 arm_2d_helper_draw_handler_t *fnHandler; //!< event handler function
372 void *pTarget; //!< user attached target
374
375/*!
376 * \brief the enumeration for events
377 *
378 */
379enum {
380 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_RENDERING = _BV(0), //!< On Low Level Rendering Event
381 ARM_2D_PFB_DEPEND_ON_DRAWING = _BV(1), //!< On Drawing Event
382 ARM_2D_PFB_DEPEND_ON_LOW_LEVEL_SYNC_UP = _BV(2), //!< On Low Level Sync-up Event
383 ARM_2D_PFB_DEPEND_ON_FRAME_SYNC_UP = _BV(3), //!< On Frame Sync-up Event
384};
385
386/*!
387 * \brief The PFB Helper Service Dependency
388 *
389 */
391 //! event handler for low level rendering
393
394 //! event handler for drawing GUI
396
397 //! low level rendering handler wants to sync-up (return arm_fsm_rt_wait_for_obj)
399
401
402/*!
403 * \brief PFB Helper configuration
404 *
405 */
407
408 arm_2d_region_t tDisplayArea; //!< screen description
409
410 struct {
411 arm_2d_pfb_t *ptPFBs; //!< current PFB block
412 arm_2d_size_t tFrameSize; //!< the size of the frame
413 uint32_t wBufferSize; //!< the buffer size
414 uint16_t hwPFBNum; //!< the number of PFB
415 uint16_t bDoNOTUpdateDefaultFrameBuffer : 1; //!< A flag to disable automatically default-framebuffer-registration
416 uint16_t bDisableDynamicFPBSize : 1; //!< A flag to disable resize of the PFB block
417 uint16_t bSwapRGB16 : 1; //!< A flag to enable swapping high and low bytes of an RGB16 pixel
418 uint16_t : 9;
419 uint16_t u4PoolReserve : 4; //!< reserve specific number of PFB for other helper services
420
421 } FrameBuffer; //!< frame buffer context
422
423 arm_2d_helper_pfb_dependency_t Dependency; //!< user registered dependency
424
426
427/*!
428 * \brief the PFB helper control block
429 *
430 */
432
433ARM_PRIVATE(
434 arm_2d_helper_pfb_cfg_t tCFG; //!< user configuration
435
436 struct {
437 arm_2d_region_t tDrawRegion;
438 arm_2d_region_t tTargetRegion;
439 arm_2d_region_list_item_t *ptDirtyRegion;
440 arm_2d_tile_t tPFBTile;
441 arm_2d_size_t tFrameSize;
442 bool bFirstIteration;
443 bool bIsRegionChanged;
444 uint8_t chPT;
445 struct {
446 uint8_t bIsNewFrame : 1;
447 uint8_t bIsFlushRequested :1;
448 };
449 uint16_t hwFreePFBCount;
450 arm_2d_pfb_t *ptCurrent;
451 arm_2d_pfb_t *ptFreeList;
452
453 struct {
454 arm_2d_pfb_t *ptHead;
455 arm_2d_pfb_t *ptTail;
456 }FlushFIFO;
457 arm_2d_tile_t *ptFrameBuffer;
458 } Adapter;
460
461 struct {
462 int64_t lTimestamp; //!< PLEASE DO NOT USE
463 int32_t nTotalCycle; //!< cycles used by drawing
464 int32_t nRenderingCycle; //!< cycles used in LCD flushing
465 } Statistics; //!< performance statistics
466
467};
468
469/*============================ GLOBAL VARIABLES ==============================*/
470/*============================ LOCAL VARIABLES ===============================*/
471/*============================ PROTOTYPES ====================================*/
472
473/*!
474 * \brief initialize pfb helper service
475 * \param[in] ptThis the pfb helper control block
476 * \param[in] ptCFG the configuration
477 * \return arm_2d_err_t the process result
478 */
479extern
480ARM_NONNULL(1,2)
483
484/*!
485 * \brief get the display (screen) region
486 * \param[in] ptThis the pfb helper control block
487 * \return arm_2d_region_t the screen region
488 */
489extern
490ARM_NONNULL(1)
492
493/*!
494 * \brief the task function for pfb helper
495 * \param[in] ptThis an initialised PFB control block
496 * \param[in] ptDirtyRegions a region list pending for refresh, NULL means
497 * refreshing the whole screen
498 * \retval arm_fsm_rt_cpl complete refreshing one frame
499 * \retval arm_fsm_rt_on_going the refreshing work is on-going
500 * \retval arm_fsm_rt_wait_for_obj user's OnDrawing event handler wants to wait
501 * for some objects, e.g. semaphore etc.
502 * \retval <0 An error is detected
503 */
504extern
505ARM_NONNULL(1)
507 arm_2d_region_list_item_t *ptDirtyRegions);
508
509/*!
510 * \brief flush the FPB FIFO
511 * \note This function is THREAD-SAFE
512 * \note For normal usage, please DO NOT use this function unless you know what
513 * you are doing.
514 * \param[in] ptThis an initialised PFB control block
515 */
516extern
517ARM_NONNULL(1)
519
520/*!
521 * \brief update PFB dependency (event handlers)
522 * \param[in] ptThis the PFB control block
523 * \param[in] chMask the bit mask for event handlers
524 * \param[in] ptDependency the new dependency description
525 * \return arm_2d_err_t the process result
526 */
527extern
528ARM_NONNULL(1,3)
530 arm_2d_helper_pfb_t *ptThis,
531 uint_fast8_t chMask,
532 const arm_2d_helper_pfb_dependency_t *ptDependency);
533
534/*!
535 * \brief tell PFB helper that a low level LCD flushing work is complete
536 * \note This function is THREAD-SAFE, You can call this function asynchronously,
537 * e.g.
538 * - A ISR to indicate DMA-transfer complete event or
539 * - A different Thread
540 * \param[in] ptThis the PFB control block
541 * \param[in] ptPFB the used PFB block
542 */
543extern
544ARM_NONNULL(1,2)
546 arm_2d_pfb_t *ptPFB);
547
548/*!
549 * \brief swap the high and low bytes for each rgb16 pixel
550 *
551 * \params[in] phwBuffer the pixel buffer
552 * \note the phwBuffer MUST aligned to half-word addresses
553 *
554 * \params[in] wSize the number of pixels
555 */
556extern
557void arm_2d_helper_swap_rgb16(uint16_t *phwBuffer, uint32_t wCount);
558
559/*!
560 * \brief convert ticks of a reference timer to millisecond
561 *
562 * \param[in] lTick the tick count
563 * \return int64_t the millisecond
564 */
565extern
567
568/*!
569 * \brief convert millisecond into ticks of the reference timer
570 *
571 * \param[in] wMS the target time in millisecond
572 * \return int64_t the ticks
573 */
574extern
576
577/*!
578 * \brief get the reference clock frequency
579 * \return uint32_t the frequency
580 */
581extern
583
584/*!
585 * \brief get the current system stamp from the reference clock
586 *
587 * \return int64_t the timestamp in ticks (no overflow issue)
588 * \note you have to call arm_2d_helper_convert_ticks_to_ms() to convert the
589 * the timestamp into milliseconds when required.
590 */
591extern
593
594/*!
595 * \brief try to get a PFB block from the pool
596 * \param[in] ptThis the PFB control block
597 * \retval NULL the pool is empty
598 * \retval !NULL a valid pfb block
599 */
600extern
601ARM_NONNULL(1)
603
604/*!
605 * \brief free a PFB block to the pool
606 * \param[in] ptThis the PFB control block
607 * \param[in] ptPFB the target PFB block
608 */
609extern
610ARM_NONNULL(1)
612
613/*! @} */
614
615#if defined(__clang__)
616# pragma clang diagnostic pop
617#endif
618
619#ifdef __cplusplus
620}
621#endif
622
623
624
625#endif