Problem with Task Using Queue

Hi

I have a lower priority task whose job is to write to external flash memory on both a regular and ad-hoc basis. Viz:

#define NORFLASH_TASK_STACK_SIZE 512
#define HAL_TIME_OUT 10

TaskHandle_t 		USE_DTCM norFlashTskHandle;
StaticTask_t		USE_DTCM norFlashTskBuffer;
StackType_t 		USE_DTCM norFlashTskStack[NORFLASH_TASK_STACK_SIZE];
SemaphoreHandle_t	USE_DTCM flashMemRdySemHandle = {NULL};

#define QUEUE_LENGTH   5
#define ITEM_SIZE   OSPI_BLOCK_SIZE  /* (4096) */
StaticQueue_t 		USE_DTCM xStaticQueue;
QueueHandle_t 		USE_DTCM xQueueFlashMem;
uint8_t 			ucQueueStorageArea[QUEUE_LENGTH * ITEM_SIZE];



/*****************************************************************************/
static void createNorFlashTask(void)
{
	/* Create a queue capable of containing 5 flash memory blocks. */
	xQueueFlashMem = xQueueCreateStatic( QUEUE_LENGTH,
								 	 	 ITEM_SIZE,
										 ucQueueStorageArea,
										 &xStaticQueue );

	configASSERT(xQueueFlashMem);

	vQueueAddToRegistry(xQueueFlashMem, "xQueueFlashMem");


	norFlashTskHandle = xTaskCreateStatic(norFlashTask,
										 "norFlashTask",
										 NORFLASH_TASK_STACK_SIZE,
										 NULL,
										 PRIO_NOR_FLASH_TASK,
										 norFlashTskStack,
										 &norFlashTskBuffer);

	configASSERT(norFlashTskHandle);

	rtosTaskStates.norFlashTsk = eRunning;

#if(DEBUG_FLASH_DRVR == 1)
		 printfdma("Create NOR Flash Task\r\n\r\n");
#endif
}



/*****************************************************************************/
USE_ITCM flashError_t writeFlashData(const uint8_t* parData, const uint32_t writeDataLen)
{
	flashInit.writeDataLen 						= writeDataLen;
	flashInit.disableMemoryMappedMode = false;
	flashInit.norFlashBusy = true;

	if(xQueueSend(xQueueFlashMem, parData, 10) != pdPASS)
	{
		flashInit.writeDataLen = writeDataLen; /* Debug only */
	}

#if(DEBUG_FLASH_DRVR == 1)
		 printfdma("writeFlashData Fcn\r\n");
#endif

	return FLASH_MEM_OK;
}


/*****************************************************************************/
USE_ITCM void norFlashTask(void *argument)
{
	while(1)
	{
		if(xQueueReceive(xQueueFlashMem, &flashInit.parData,  portMAX_DELAY) != pdPASS)
		{
			flashInit.norFlashBusy = false; /* TODO */
		}
		else
		{
			flashInit.flashError = writeDataToNorFlash();
			flashInit.norFlashBusy = false; /* TODO */
		}

		HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_11);
//		vTaskDelay(100);
	}
}

I start the norFlashTskHandle task in the default startup task i call the monitor:

#if(FLASH_MEM_ON == 1)
	/* Initialise nor flash task */
	initialiseNorFlash(TOUCHGFX_ENABLE,
					   OCTISPI_IRQP,
					   OCTISPI_IRQP); /* TODO */

	/* Make time for the flash task to run through its initialisation */
	vTaskDelay(10);
#endif

You can see I put a small delay in to make time for the lower priority flash task to startup.

After this I call a function setSystemSpecificConstants(); that calls the writeFlashData() function that puts data to be stored in the queue.

The problem I have is that if I include the xQueueReceive code in the flash task the system hangs. If I comment it out and put in a delay the task runs normally. I seems like the nor flash task is not being unblocked when the items are sent to the queue. The monitor task runs every 250 ms and the system idle time is 65%. If I put a breakpoint after the queueReceive it never gets hit.

The task priorities for all the tasks are:

/*********************************************************************
 * 						  TASK PRIORITIES                         *
 *********************************************************************
 */

#define PRIO_PROX_TASK 		osPriorityRealtime7
#define PRIO_CLOCK_CONTROL 	osPriorityRealtime6
#define PRIO_TMR_SRVC		osPriorityNormal3   /* Set manually in FreeRTOSConfig.h */
#define PRIO_MONITOR_TASK	osPriorityNormal2
#define PRIO_GUI_TASK		osPriorityNormal
#define PRIO_NOR_FLASH_TASK osPriorityBelowNormal7
#define PRIO_WI_FI_TASK		osPriorityBelowNormal6
#define PRIO_DIG_TEMP_TASK  osPriorityLow5
#define PRIO_PRINTF_DMA		osPriorityLow4
#define PRIO_FLASH_BACKUP   osPriorityLow3

My FreeRTOS Config File is:

/* USER CODE BEGIN Header */
/*
 * FreeRTOS Kernel V10.2.1

/* USER CODE END Header */

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H


/* USER CODE BEGIN Includes */
#include "cmsis_os2.h"
#include "RTOSParameters.h"
/* USER CODE END Includes */

/* Ensure definitions are only used by the compiler, and not by the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  #include <stdint.h>
  extern uint32_t SystemCoreClock;
  extern void configureTimerForRunTimeStats(void);
  extern unsigned long getRunTimeCounterValue(void);
#endif
#ifndef CMSIS_device_header
#define CMSIS_device_header "stm32h7xx.h"
#endif /* CMSIS_device_header */

#define configENABLE_FPU                         0
#define configENABLE_MPU                         0

#define configUSE_PREEMPTION                     1
#define configSUPPORT_STATIC_ALLOCATION          1
#define configSUPPORT_DYNAMIC_ALLOCATION         1
#define configUSE_IDLE_HOOK                      0
#define configUSE_TICK_HOOK                      1
#define configCPU_CLOCK_HZ                       ( SystemCoreClock )
#define configTICK_RATE_HZ                       ((TickType_t)1000)
#define configMAX_PRIORITIES                     ( 56 )
#define configMINIMAL_STACK_SIZE                 ((uint16_t)128)
#define configTOTAL_HEAP_SIZE                    ((size_t)32768)
#define configMAX_TASK_NAME_LEN                  ( 16 )
#define configUSE_TRACE_FACILITY                 1
#define configGENERATE_RUN_TIME_STATS 			 1
#define configUSE_STATS_FORMATTING_FUNCTIONS     1
#define configRECORD_STACK_HIGH_ADDRESS          1
#define configUSE_16_BIT_TICKS                   0
#define configUSE_MUTEXES                        1
#define configQUEUE_REGISTRY_SIZE                16
#define configUSE_RECURSIVE_MUTEXES              1
#define configUSE_COUNTING_SEMAPHORES            1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION  0
#define configCHECK_FOR_STACK_OVERFLOW 			 0
#define configUSE_TASK_NOTIFICATIONS			 1
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1


/* USER CODE BEGIN MESSAGE_BUFFER_LENGTH_TYPE */
/* Defaults to size_t for backward compatibility, but can be changed
   if lengths will always be less than the number of bytes in a size_t. */
#define configMESSAGE_BUFFER_LENGTH_TYPE         size_t
/* USER CODE END MESSAGE_BUFFER_LENGTH_TYPE */

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES                0
#define configMAX_CO_ROUTINE_PRIORITIES      ( 2 )

/* Software timer definitions. */
#define configUSE_TIMERS                     1
#define configTIMER_TASK_PRIORITY            PRIO_TMR_SRVC
#define configTIMER_QUEUE_LENGTH             30
#define configTIMER_TASK_STACK_DEPTH         512

/* CMSIS-RTOS V2 flags */
#define configUSE_OS2_THREAD_SUSPEND_RESUME  1
#define configUSE_OS2_THREAD_ENUMERATE       1
#define configUSE_OS2_EVENTFLAGS_FROM_ISR    1
#define configUSE_OS2_THREAD_FLAGS           1
#define configUSE_OS2_TIMER                  1
#define configUSE_OS2_MUTEX                  1

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet             1
#define INCLUDE_uxTaskPriorityGet            1
#define INCLUDE_vTaskDelete                  1
#define INCLUDE_vTaskCleanUpResources        0
#define INCLUDE_vTaskSuspend                 1
#define INCLUDE_vTaskDelayUntil              1
#define INCLUDE_vTaskDelay                   1
#define INCLUDE_xTaskGetSchedulerState       1
#define INCLUDE_xTimerPendFunctionCall       1
#define INCLUDE_xQueueGetMutexHolder         1
#define INCLUDE_uxTaskGetStackHighWaterMark  1
#define INCLUDE_xTaskGetCurrentTaskHandle    1
#define INCLUDE_eTaskGetState                1
#define INCLUDE_xTaskGetIdleTaskHandle       1


/*
 * The CMSIS-RTOS V2 FreeRTOS wrapper is dependent on the heap implementation used
 * by the application thus the correct define need to be enabled below
 */
#define USE_FreeRTOS_HEAP_4

/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
 /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
 #define configPRIO_BITS         __NVIC_PRIO_BITS
#else
 #define configPRIO_BITS         4
#endif

/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15

/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

/* Interrupt priorities used by the kernel port layer itself.  These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
/* USER CODE BEGIN 1 */
#define configASSERT( x ) if ((x) == 0) {taskDISABLE_INTERRUPTS(); for( ;; );}
/* USER CODE END 1 */

/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler    SVC_Handler
#define xPortPendSVHandler PendSV_Handler

/* IMPORTANT: After 10.3.1 update, Systick_Handler comes from NVIC (if SYS timebase = systick), otherwise from cmsis_os2.c */

#define USE_CUSTOM_SYSTICK_HANDLER_IMPLEMENTATION 0

/* USER CODE BEGIN Defines */
  /* Definitions needed when configGENERATE_RUN_TIME_STATS is on */
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats
#define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue

  /* IMPORTANT: This define is commented when used with STM32Cube firmware, when the timebase source is SysTick,
                to prevent overwriting SysTick_Handler defined within STM32Cube HAL */
//  #define xPortSysTickHandler SysTick_Handler

/* Integrates the Tracealyzer recorder with FreeRTOS */
#if ( configUSE_TRACE_FACILITY == 1 )
//#include "trcRecorder.h"
#endif
/* USER CODE END Defines */

#endif /* FREERTOS_CONFIG_H */

When I run the program in debug when I halt it with the pause button the progam invariably stops in portmacr.h at:

portFORCE_INLINE static void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI;  /* <== Stops here */

	__asm volatile
	(
		"	mov %0, %1												\n"	\
		"	msr basepri, %0											\n" \
		"	isb														\n" \
		"	dsb														\n" \
		:"=r" (ulNewBASEPRI) : "i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
	);
}

When I run the profiler I get:

I have checked all my interrupt to ensure they are above the minimum set by FreeRTOS Config.

I have checked that the data is being copied to the queue buffer correctly in the xQueueSend function and it is.

Has anyone any idea what I might be doing wrong? Am I using the queue correctly?

Best regards
Rob

Can you break the code in debugger when it appears hang and see what it is doing?

Using delay for synchronizing among tasks is not a good idea. You should use synchronization primitives - task notification, semaphore etc.

Hi AG
Thanks for you prompt reply.

I hadn’t completed the post before you replied: sorry about that.

I have included the info you asked for in the first post.

It is getting stuck in the function vTasakNotifyGiveFromISR in the function:
portFORCE_INLINE static void vPortRaiseBASEPRI( void )

If I put a break point at: HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_11),
in the norFlashTask it never gets there.

There is a hint at the possible problem in the profiler output:

HAL__TIM_IRQHandler() running at 0.07%

The code for this is:

/**
  * @brief This function handles TIM2 global interrupt.
  */
USE_ITCM void TIM2_IRQHandler(void)
{
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  HAL_TIM_IRQHandler(&htim2);

  vTaskNotifyGiveFromISR(xHandleProx, &xHigherPriorityTaskWoken);
  xSemaphoreGiveFromISR(clockControllerSemHandle, 0);

  portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

I think the problem may be with the way I am running the tasks driven by the Timer 2 interrupt.

My RTC is 1 kHz and Timer 2 interrupt is also is running at 1 KHz, the prox task has a higher priority than the clockContoller task.

So every millisecond I kick off the prox task which does I2C transactions using DMA and interrupts with the optical sensor. Viz:

/* Main i2c Handler Task  */
USE_ITCM static void i2c_1_HandlerTsk(void * pvParameters)
{
	/* Initialise the  VCNL40x0 Prox Device*/
	initProxProbe();


  /* Start the sample clock */
	HAL_TIM_Base_Start_IT(&htim2);

	/* Main sample loop driven by Timer 2 Interrupt */
	while(1)
	{
		if(ulTaskNotifyTake(pdTRUE,  (uint32_t)6U) == 0)
		{
				/* TODO */
			proxSampleCount = 1; /* debug statement only TODO */
		}

		/* Get the proximiter 16 bit value from the device */
		ReadProxiOnDemand(&proxValue);
	}
}


__inline VCNL40x0Error_e ReadProxiOnDemand (unsigned int *ProxiValue) {

    unsigned char Command=0;

    // enable prox value on demand
    SetCommandRegister (COMMAND_PROX_ENABLE | COMMAND_PROX_ON_DEMAND);

    // wait on prox data ready bit
    do {
        ReadCommandRegister (&Command);                     // read command register
    } while (!(Command & COMMAND_MASK_PROX_DATA_READY));

    ReadProxiValue (ProxiValue);                            // read prox value

    SetCommandRegister (COMMAND_ALL_DISABLE);               // stop prox value on demand

    return VCNL40x0_ERROR_OK;
}

When the prox task returns to the blocked state the clockController Task runs. This task does a lot of calculations - floating point and integer then blocks waiting for the semaphore from timer 2 interrupt.

	/* Main sample loop driven by Timer 2 Interrupt */
	while(1)
	{
		if (xSemaphoreTake(clockControllerSemHandle, (uint32_t)3U) == osErrorTimeout)
		{
			appErrHandlerVcom(18U, osErrorTimeout, __FILE__, __LINE__);
		}

		/* Get the proximiter 16 bit value from the device and buffer it */
		/* Limit proxValue range to linear curve fit input range
		 * Buffer it first in case the Prox driver updates during the limit code */

#if(SIMULATE_PROX_PEND_DATA == 1)
		simDataFcn();
		proxValueWord = (uint32_t)proxValue;
#endif
		proxValueBuff = proxValue;

		if(MAX_PROX_COUNT < proxValueBuff)  PositionCurveFit_U.Input = (double)MAX_PROX_COUNT;
		else 			PositionCurveFit_U.Input = (double)proxValueBuff;

		if(MIN_PROX_COUNT > proxValueBuff)  PositionCurveFit_U.Input = (double)MIN_PROX_COUNT;
		else 			PositionCurveFit_U.Input = (double)proxValueBuff;

		PositionCurveFit_step();
		PositionFilter_U.positionRaw = (float)PositionCurveFit_Y.Output;

		/* Low pass filter the data */
		PositionFilter_step();

		impulseDBG = PositionFilter_Y.zeroThetaTrigger;
		pendPosDBG 		= (uint32_t)(PositionFilter_Y.FilterOP * 1000.0F + 16000);
		pendPosRawFitDBG = (uint32_t)(PositionCurveFit_Y.Output  + 16000);


		/********************** TEST FOR ZERO CROSSING ********************************/
		if(/* 0 == 1 && */ PositionFilter_Y.zeroThetaTrigger == 1 && startUpCount == 0U)
		{
			/* Disable the Timer Interrupts to prevent timer  timCountUpper roll-over whilst
			 * reading the count and timerCountUpperValues
			 */
			HAL_NVIC_DisableIRQ(TIM5_IRQn);
				/* Get the reference clock time-stamp values */
				clkVars.tim5Count = htim5.Instance->CNT;
				clkVars.tim5CountUpperAtTrig = clkVars.timCountUpper;
			HAL_NVIC_EnableIRQ(TIM5_IRQn);

			clkVars.tickImplsCount--;

			/* Grab the last cycle */
			if(clkVars.tickImplsCount == 1)
			{
				lastCycleFlag = true;
				cycleSampleCountPre = 0;
			}

			if(clkVars.tickImplsCount == 0)
			{
#if(CURVE_FIT_IMPULSE_TIME == 1)
				clkVars.tickImplsCount = TICK_IMPULSE_COUNT;
				impulseCurveFit_U.Input = clkVars.impulseMagIC;
				impulseCurveFit_step();
				impulseGen(0.0F, (float)impulseCurveFit_Y.Out1);
#else
				impulseGen(0.0F, IMPULSE_MAGNITUDE);
#endif
				/* Grab the first cycle */
				firstCycleFlag = true;
				cycleSampleCountPost  = 0;
			}
			else
			{
				triggerLED_Start(75, IMP_LED_GREEN, false);
			}

			/* refresh the Independent Watchdog timer - IWDG */
			#if(USE_IWDG == 1)
				if(iwdgEnabled == false)
				{
					iwdgEnabled = true;
					MX_IWDG1_Init();
				}
				else
				{
					/* Reset the window watchdog timer */
					HAL_IWDG_Refresh(&hiwdg1);
				}
			#endif

			SeikoClockTick(SEIKO_MODE_RUN);
		} /* End Of Zero Crossing Processing */

		/* Get the 1000 sample position values */
		if((firstCycleFlag == true) && (cycleSampleCountPost < STATS_BUFFER_LENGTH))
		{
			statsBuffPostImpls[cycleSampleCountPost] = PositionFilter_Y.FilterOP;
			cycleSampleCountPost++;
			if(cycleSampleCountPost == STATS_BUFFER_LENGTH)
			{
				firstCycleFlag = 	false;
				cycleSampleCountPost = 0u;
				/* Flag the position statistics process to run */
				clkVars.runPosStatsTask = true;
			}
		}

		if(lastCycleFlag == true && cycleSampleCountPre < STATS_BUFFER_LENGTH) /* TODO - Logic Error */
		{
			statsBuffPreImpls[cycleSampleCountPre] = PositionFilter_Y.FilterOP;
			cycleSampleCountPre++;
			if(cycleSampleCountPre == STATS_BUFFER_LENGTH)
			{
				lastCycleFlag = false;
				cycleSampleCountPre = 0u;
			}
		}

		if(PositionFilter_Y.minSwingDetect == 1  && startUpCount == 0U)
		{
			triggerFailureTmr_Stop();
		}
	}

I have a suspicion that running these high priority tasks at the same frequency as the RTC could be causing FreeRTOS to have a meltdown when using a queue even in unrelated low priority tasks.

I guess my question is whether my setup, sending and receiving from the queue code is correct?

And whether my problem could be caused by my high priority tasks.

I am thinking I will make the clock controller task a function of the prox task or even put the whole thing in the timer 2 interrupt routine. This would not be that difficult.

I didn’t want to put these tasks as functions within the timer 2 interrupt routine because the controller uses floating point instructions, but I’m thinking that this might be the simpler approach and allow a slower RTC say 10 ms (100 Hz) to run the other slower tasks such as the WiFi driver and flash memory driver. The additional interrupt overhead of saving the floating point reg’s would still be less than the execution of the code used by freeRTOS to handle the notifications/semaphores.

Your thoughts on this would be appreciated.

Best regards
Rob

Why do you have wait for 6 and 3 ticks in the following 2 calls -

if(ulTaskNotifyTake(pdTRUE,  (uint32_t)6U) == 0)
if (xSemaphoreTake(clockControllerSemHandle, (uint32_t)3U) == osErrorTimeout)

If these are unblocked by timer interrupt, you should use some high value to detect error cases such as timer interrupt does not fire for too long.

Share the callstack at that point.

Hi AG

The Timer 2 interrupt occurs every 1 ms or one RTOS timer tick, so I figured that the longest the semaphore/notification would have to wait is one or two RTOS ticks so I made it 6 and 3. These values have been working fine with no errors. It is only when I add the flash memory queue I have problems, but I don’t think these problems are related to the timeouts. Timer 2 has a high interrupt priority and all others higher than it are very short so the blocking of the semaphore/notification should at most take only two RTOS ticks.

I am not sure how to get the call stack, could you advise.

Best regards
Rob

Just for confirming, increase them while debugging this issue.

That depends on the IDE you are using. One window in IDE usually shows callstack.

Also, this can be a memory corruption issue. Please make sure to have configASSERT defined, stack and heap overflow detection enabled. As a quick check, you can try increasing the stack sizes of the tasks dealing with Flash functions.

Hi AG,

I have found the problem.

I hadn’t initialised the output message variable flashInit.parData . So you were correct, the problem was memory corruption of the worst possible kind.

So this can be closed now.

Thanks for your help.

Best regards
Rob

Thanks for taking the time to report back.