# HG changeset patch
# User Ideenmodellierer
# Date 1612731883 -3600
# Node ID ba83a8ef9badfbc87e8a70f7d8aeab8fe520fd02
# Parent  8f78faf88fc56a167a8e5a7bbe4f705ed4d4f2f0
Improvment frame Handling:
In previous version, especially during fast menu operations, from time to time a flicker (in case of cyclic updated views) or corrupted menus appeared. Possible root cause is a interferance in the chain: refresh display (~100ms) => release frame (in parallel to) provide frame (~45ms) => clear frame (~45ms). to improve the behaviour the clear frame loop is not iterated until all bufferes are cleared (before one buffer every~45ms). getFrame() does now iterate through all frame buffers instead reusing the first possible (to avoid ghoust views and to provide more time to housekeeping function for cleanup)

diff -r 8f78faf88fc5 -r ba83a8ef9bad Discovery/Src/base.c
--- a/Discovery/Src/base.c	Wed Feb 03 21:45:48 2021 +0100
+++ b/Discovery/Src/base.c	Sun Feb 07 22:04:43 2021 +0100
@@ -292,6 +292,7 @@
 uint32_t base_tempLightLevel = 0;
 static uint8_t	wasFirmwareUpdateCheckBattery = 0;
 static uint8_t DoDisplayRefresh = 0;	/* trigger to refresh display data */
+static uint8_t DoHousekeeping = 0;		/* trigger to cleanup the frame buffers */
 
 /* Private function prototypes -----------------------------------------------*/
 static void SystemClock_Config(void);
@@ -497,6 +498,10 @@
 
         deco_loop();
         TriggerButtonAction();
+        if(DoHousekeeping)
+        {
+           	DoHousekeeping = housekeepingFrame();
+        }
         if(DoDisplayRefresh)							/* set every 100ms by timer interrupt */
         {
 	        DoDisplayRefresh = 0;
@@ -509,7 +514,8 @@
             updateMiniLiveLogbook(1);
 
         	RefreshDisplay();
-        	TimeoutControl();								/* exit menus if needed */
+        	DoHousekeeping = 0;							/* make sure frames are not cleared before they are transferred */
+        	TimeoutControl();							/* exit menus if needed */
 
 #ifdef ENABLE_MOTION_CONTROL
         	if((stateUsed->mode == MODE_DIVE) && (settingsGetPointer()->MotionDetection != MOTION_DETECT_OFF))		/* handle motion events in divemode only */
@@ -648,7 +654,7 @@
 	if (GPIO_Pin == VSYNC_IRQ_PIN) // rechts, unten
 	{
 		GFX_change_LTDC();
-		housekeepingFrame();
+		DoHousekeeping = 1;
 		/*
 		 #ifdef DEMOMODE
 		 static uint8_t countCall = 0;
diff -r 8f78faf88fc5 -r ba83a8ef9bad Discovery/Src/gfx_engine.c
--- a/Discovery/Src/gfx_engine.c	Wed Feb 03 21:45:48 2021 +0100
+++ b/Discovery/Src/gfx_engine.c	Sun Feb 07 22:04:43 2021 +0100
@@ -3375,27 +3375,45 @@
 
 uint32_t getFrame(uint8_t callerId)
 {
+	static uint8_t lastFrameProvided = 0;
 	uint8_t i;
 
-	i = 0;
-	while((i < MAXFRAMES) && (frame[i].status != CLEAR))
+/* first iteration: look for a clear frame */
+	i = lastFrameProvided;
+	do
+	{
 		i++;
+		if(i == MAXFRAMES)
+		{
+			i = 0;
+		}
+	} while((i != lastFrameProvided) && (frame[i].status != CLEAR));
 
 	if((i < MAXFRAMES) && (frame[i].status == CLEAR))
 	{
 		frame[i].status = BLOCKED;
 		frame[i].caller = callerId;
+		lastFrameProvided = i;
 		return frame[i].StartAddress;
 	}
 
-	i = 0;
-	while((i < MAXFRAMES) && (frame[i].status != RELEASED))
+/* second iteration: look for a frame which may be reused after clearing */
+	i = lastFrameProvided;
+	do
+	{
 		i++;
+		if(i == MAXFRAMES)
+		{
+			i = 0;
+		}
+	}while((i < MAXFRAMES) && (frame[i].status != RELEASED));
+
 
 	if((i < MAXFRAMES) && (frame[i].status == RELEASED))
 	{
 		GFX_clear_frame_immediately(frame[i].StartAddress);
 		frame[i].status = BLOCKED;
+		lastFrameProvided = i;
 		return frame[i].StartAddress;
 	}
 	return 0;
@@ -3458,47 +3476,52 @@
 }
 
 
-void housekeepingFrame(void)
+uint8_t housekeepingFrame(void)
 {
 	static uint8_t countLogClear = 0;
+	uint8_t i;
+	uint8_t retVal = 1;
 	
-	if(DMA2D_at_work != 255)
-		return;
-
-	/* new for debug hw 151202 */
-	for(int i=1;i<MAXFRAMECOUNTER;i++)
+	if(DMA2D_at_work == 255)
 	{
-		frameCounter[i] = 0;
-	}
-	for(int i=1;i<MAXFRAMES;i++)
-	{
-		if(frame[i].status == BLOCKED)
+		/* new for debug hw 151202 */
+		for(i=1;i<MAXFRAMECOUNTER;i++)
+		{
+			frameCounter[i] = 0;
+		}
+		for(int i=1;i<MAXFRAMES;i++)
 		{
-			if(frame[i].caller < (MAXFRAMECOUNTER - 2))
-				frameCounter[frame[i].caller]++;
+			if(frame[i].status == BLOCKED)
+			{
+				if(frame[i].caller < (MAXFRAMECOUNTER - 2))
+					frameCounter[frame[i].caller]++;
+				else
+					frameCounter[MAXFRAMECOUNTER-3]++;
+			}
+			else
+			if(frame[i].status == RELEASED)
+				frameCounter[MAXFRAMECOUNTER-2]++;
 			else
-				frameCounter[MAXFRAMECOUNTER-3]++;
+				frameCounter[MAXFRAMECOUNTER-1]++;
+		}
+
+		i = 0;
+		/* skip frame cleaning for actual frames which have not yet been replaced by new top/bottom frames */
+		while((i < MAXFRAMES) && ((frame[i].status != RELEASED) || (frame[i].StartAddress == GFX_get_pActualFrameTop()) || (frame[i].StartAddress == GFX_get_pActualFrameBottom())))
+			i++;
+	
+		if((i < MAXFRAMES) && (frame[i].status == RELEASED))
+		{
+			if(frame[i].caller == 15)
+				countLogClear++;
+			GFX_clear_frame_dma2d(i);
 		}
 		else
-		if(frame[i].status == RELEASED)
-			frameCounter[MAXFRAMECOUNTER-2]++;
-		else
-			frameCounter[MAXFRAMECOUNTER-1]++;
+		{
+			retVal = 0;		/* no more frame to be cleaned found */
+		}
 	}
-	
-	
-	uint8_t i;
-
-	i = 0;
-	while((i < MAXFRAMES) && ((frame[i].status != RELEASED) || (frame[i].StartAddress == GFX_get_pActualFrameTop()) || (frame[i].StartAddress == GFX_get_pActualFrameBottom())))
-		i++;
-
-	if((i < MAXFRAMES) && (frame[i].status == RELEASED))
-	{
-		if(frame[i].caller == 15)
-			countLogClear++;
-		GFX_clear_frame_dma2d(i);
-	}
+	return retVal;
 }