Tasks are Not running after the callback function works

void vTaskDisplay(void *pvParameters) 
{
  while(1) {
	 SWO_PRINTF("Task display entry");
         lv_task_handler();
         SWO_PRINTF("Task display exit");
         vTaskDelay(5/ portTICK_PERIOD_MS);
  }
}

void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	 SWO_PRINTF("Task analog entry");
	HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);  // Here i start the ADC DMA.
	ulNotifiedValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // here i am taking notification.
	if(ulNotifiedValue > 0) {
		SWO_PRINTF("ADC1_ch2 = %d\n ADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
	}
   }
}

I am using these two tasks. Analog and Display Tasks.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1) {
		xTaskNotifyGive(vTaskAnalogHandle);   // here i am giving task notification
	}
}

Task Creation: Tasks are created successfully.

xTaskCreate(vTaskAnalog, "vTaskAnalog", 128, 0, tskIDLE_PRIORITY+1, &vTaskAnalogHandle);
xTaskCreate(vTaskDisplay, "vTaskDisplay", 4096, 0, tskIDLE_PRIORITY+2, &vTaskDisplayHandle);

FreeRTOSConfig.h:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY   15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

ADC1:

HAL_NVIC_SetPriority(ADC_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);

DMA2 Stream4:

/* DMA2_Stream4_IRQn interrupt configuration */
	  HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 5, 0);
	  HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);

Can anyone give me solution. Because i am beginner of RTOS. I don’t know where i am doing mistake.

Thanks
Manikandan D

Welcome @Manikandan !
What’s the problem exactly ? No notification as expected ? Crash / Hard_Fault ?

Just a few things:

If SWO_PRINTF is calling a printf family function internally the stack size of vTaskAnalogis probably way too small. If it’s a debug macro you could also define different stack sizes for debug/release accordingly.

Since (I think) HAL_ADC_ConvCpltCallback is the completion callback from the DMA ISR you’ve to use xTaskNotifyGiveFromISR.
See e.g. the vTransmitEndISR example of the API documentation for the exact usage.
Note the FromISR suffix of all FreeRTOS API functions allowed/possible to be called in ISRs.

It might be helpful to add the FreeRTOS version you’re using and better also the MCU/port (e.g. ARM_CM3) used.

I strongly recommend to define configASSERT and also enable stack overflow checking for development/debugging. It helps a lot !

Hint: When posting code blocks please enclose them in 3 tildas ‘~~~’ or backticks ‘```’ for better readability. There is also a button </> for inline quoting. Thanks !

1 Like

Hi @hs2 First of all thank you for your reply.

What’s the problem exactly ?
After loading this hex file to my board, nothing will print. Display is working but touch is not working.

As per your suggestion i will change my vTaskAnalog Stack value. I will use xTaskNotifyGiveFromISR instead of xTaskNotifyGive.

I am using FreeRTOS Kernel V10.4.3 and I am using STM32F746G discovery board.

After implementing all Your suggestion , i will be back.

Thanks
Manikandan D

Now my logic was working fine. I increased stack size of Analog Task and now i am using vTaskNotifyGiveFromISR instead of xTaskNotify.

Analog and Display tasks are running perfectly. Thank you @hs2

Now i want to read three ADC. ADC1, ADC2 and ADC3.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if( hadc->Instance == ADC1) {
		vTaskNotifyGiveFromISR(vTaskAnalogHandle,500);
	}
	else if(hadc->Instance == ADC2) {
		vTaskNotifyGiveFromISR(vTaskAnalogHandle,500);
	}
	else if(hadc->Instance == ADC3) {
		vTaskNotifyGiveFromISR(vTaskAnalogHandle,500);
	}
}

This is my callback function. Previously i am using single ADC.
My previous Analog Task function,

void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	SWO_PRINTF("Task analog entry");
	HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
	ulNotifiedValue = ulTaskNotifyTake(pdTRUE, 500);
	if(ulNotifiedValue > 0) {
		SWO_PRINTF("ADC1_ch2 = %d\n ADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
	}
}

My new analog task function,

void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	SWO_PRINTF("Task analog entry");
	HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
	HAL_ADC_Start_DMA(&hadc2, value_buff2, 1024);
	HAL_ADC_Start_DMA(&hadc3, value_buff3, 1024);
	ulNotifiedValue = ulTaskNotifyTake(pdTRUE, 500);
	if(ulNotifiedValue > 0) {
		SWO_PRINTF("ADC1_ch2 = %d\n ADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
                SWO_PRINTF("ADC2_ch4 = %d\n ADC2_ch5 = %d\n", value_buff2[0], value_buff2[1]);
                SWO_PRINTF("ADC3_ch6 = %d\n ADC3_ch7 = %d\n", value_buff3[0], value_buff3[1]);
	}
}

I don’t know this way of printing is correct or not for my three ADC.
Please suggest some solution. I am using ulTaskNotifyTake for taking notification of three ADC. It is correct or not ?

Thanks
Manikandan D

The function vTaskNotifyGiveFromISR() needs these 2 parameters:

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle, BaseType_t *pxHigherPriorityTaskWoken )

So the code should look like :

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if( hadc->Instance == ADC1) {
        vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
    }
    else if(hadc->Instance == ADC2) {
        vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
    }
    else if(hadc->Instance == ADC3) {
        vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
    }
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

Or shorter if you like:

    if( ( hadc->Instance == ADC1 ) ||
        ( hadc->Instance == ADC2 ) ||
        ( hadc->Instance == ADC3 ) )
        vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }

And if you have not initialised any other ADC/DMA channel, the test looks unnecessary, so it may become:

{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
1 Like

Thanks @htibosch

From Your suggestion now my Callback function, logic confusion was solved. Still i have a doubt in my Analog Task. How get my Three ADC notification. How to i know Which ADC notification is coming.

Thanks
Manikandan D

Besides the fix from @htibosch it depends on what you need. If you’re interested in the result of all 3 ADCs as bundle and you know that e.g. ADC3 is completed last, you could notify the task on completion of ADC3.
Or use a (static) ADC completion counter/flag to accumulate the ADC conversion completions in the ISR and notify the post-processing task if all conversions are done.
In your current code you get notified e.g. on completion of ADC1 but accessing (printing) the results of ADC2 and 3 which might be invalid because the conversion is still in progress.
Alternatively you could use xTaskNotifyFromISR and use the notification value as bitmap with a bit per ADC if you’re interested in the result of each ADC and want to get notified by each ADC separately. See the example code of xTaskNotifyFromISR which makes use of this approach.

1 Like

You could have the interrupt handler set a volatile variable, e.g.

volatile uint32_t ulDMAReadMask = 0U;

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    if( hadc->Instance == ADC1 )
    {
        ulDMAReadMask  |= 0x01U;
    }
    if( hadc->Instance == ADC2 )
    {
        ulDMAReadMask  |= 0x02U;
    }
    if( hadc->Instance == ADC3 )
    {
        ulDMAReadMask  |= 0x04U;
    }
    vTaskNotifyGiveFromISR(vTaskAnalogHandle, &( xHigherPriorityTaskWoken ) );
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

In the task you can test and clear the bits. Mind you that you should disable the DMA interrupt when read/clear the mask.

    taskENTER_CRITICAL();
    uint32_t ulMask = ulDMAReadMask;
    ulDMAReadMask = 0U;
    taskEXIT_CRITICAL();
    /* Now you can test ulMask */
1 Like

Although this works I’d propose to use the built-in FreeRTOS mechanism using xTaskNotifyFromISR with eSetBits action to use the notifications as event group pattern as described here FreeRTOS task notifications, fast Real Time Operating System (RTOS) event mechanism

1 Like

Thank you for your answer @htibosch . i will check with this method.

Hi @hs2
Now i am using vTaskNotifyGiveFromISR from your suggestion for giving notification.
Now you told xTaskNotifyFromISR use this function instead of vTaskNotifyGiveFromISR. It is correct?

Hartmut wrote:

the built-in FreeRTOS mechanism using xTaskNotifyFromISR with eSetBits

Yes you are right, it is a cleaner solution. They are clearly described on the mentioned page.

From the ISR:

   /* Notify the task that the reception is complete by setting the RX_BIT
   in the task's notification value. */
   xTaskNotifyFromISR( xHandlingTask,
                       ulBitMask,
                       eSetBits,
                       &xHigherPriorityTaskWoken );

From the task:

xResult = xTaskNotifyWait( pdTRUE,          /* Don't clear bits on entry. */
                           ULONG_MAX,        /* Clear all bits on exit. */
                           &ulNotifiedValue, /* Stores the notified value. */
                           xMaxBlockTime );
1 Like

Hai @hs2 @htibosch

Now I am using xTaskNotifyFromISR instead of vTaskNotifyGiveFromISR.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<0), eSetBits, 500);	
	}
	else if(hadc->Instance == ADC2) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<1), eSetBits, 500);
	}
	else if(hadc->Instance == ADC3) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<2), eSetBits, 500);
	}
}

void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	SWO_PRINTF("Task analog entry\n");
	HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
	HAL_ADC_Start_DMA(&hadc2, value_buff2, 1024);
	HAL_ADC_Start_DMA(&hadc3, value_buff3, 1024);
	ulNotifiedValue = xTaskNotifyWait(0xFFFFFFFF, 0, &ulNotifiedValue, 500);
	SWO_PRINTF("Notification Value = %d\n", ulNotifiedValue);
	if(ulNotifiedValue == 1) {
		SWO_PRINTF("ADC1_ch2 = %d\nADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
	}
	if(ulNotifiedValue == 2) {
		SWO_PRINTF("ADC2_ch4 = %d\nADC2_ch5 = %d\n", value_buff2[0], value_buff2[1]);
	}
	if(ulNotifiedValue == 4) {
		SWO_PRINTF("ADC3_ch6 = %d\nADC3_ch7 = %d\n", value_buff3[0], value_buff3[1]);
	}
}

But this is always print ADC1 value only. ulNotifiedValue is always 1.

@Manikandan You really should use the API as documented including the provided FreeRTOS constants.
Better do NOT use arbitrary literal values instead.
You made a slight mistake with xTaskNotifyWait(0xFFFFFFFF, 0, ...
This is correct:

This is also still wrong:

[quote=“Manikandan, post:13, topic:13024”]

if(hadc->Instance == ADC1) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<0), eSetBits, 500);	

Please re-read @htibosch 's post and the API documentation regarding the 3rd argument xHigherPriorityTaskWoken.

Also if using notifications as event group (bits) you have to check the notification value for BITS as explained in the code example.

xTaskNotifyFromISR(vTaskAnalogHandle, (1<<0), eSetBits, &xHigherPriorityTaskWoken);	
...
xTaskNotifyFromISR(vTaskAnalogHandle, (1<<1), eSetBits, &xHigherPriorityTaskWoken);	
...
xTaskNotifyFromISR(vTaskAnalogHandle, (1<<2), eSetBits, &xHigherPriorityTaskWoken);	
...

must be paired with:

1 Like
void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	SWO_PRINTF("Task analog entry\n");
	HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
	HAL_ADC_Start_DMA(&hadc2, value_buff2, 1024);
	HAL_ADC_Start_DMA(&hadc3, value_buff3, 1024);
	ulNotifiedValue = xTaskNotifyWait(pdTRUE, 0, &ulNotifiedValue, 500);
	SWO_PRINTF("Notification Value = %d\n", ulNotifiedValue);
	if(ulNotifiedValue & (1<<0)) {
		SWO_PRINTF("ADC1_ch2 = %d\nADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
	}
	if(ulNotifiedValue & (1<<1)) {
		SWO_PRINTF("ADC2_ch4 = %d\nADC2_ch5 = %d\n", value_buff2[0], value_buff2[1]);
	}
	if(ulNotifiedValue & (1<<2)) {
		SWO_PRINTF("ADC3_ch6 = %d\nADC3_ch7 = %d\n", value_buff3[0], value_buff3[1]);
	}
}

I tried with this method also but still it’s giving ulNotifiedvalue is always 1.

Hai @hs2 @htibosch

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if(hadc->Instance == ADC1) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<0), eSetBits, &( xHigherPriorityTaskWoken ));	
	}
	else if(hadc->Instance == ADC2) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<1), eSetBits, &( xHigherPriorityTaskWoken ));
	}
	else if(hadc->Instance == ADC3) {
		xTaskNotifyFromISR(vTaskAnalogHandle, (1<<2), eSetBits, &( xHigherPriorityTaskWoken ));
	}
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}

void vTaskAnalog(void *pvParameters)
{
  int ulNotifiedValue;
  while(1) {
	SWO_PRINTF("Task analog entry\n");
	//HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
	HAL_ADC_Start_DMA(&hadc2, value_buff2, 1024);
	HAL_ADC_Start_DMA(&hadc3, value_buff3, 1024);
	ulNotifiedValue = xTaskNotifyWait(pdTRUE, 0, &ulNotifiedValue, 500);
	SWO_PRINTF("Notification Value = %d\n", ulNotifiedValue);
	if(ulNotifiedValue & (1<<0)) {
		SWO_PRINTF("ADC1_ch2 = %d\nADC1_ch3 = %d\n", value_buff1[0], value_buff1[1]);
	}
	if(ulNotifiedValue & (1<<1)) {
		SWO_PRINTF("ADC2_ch4 = %d\nADC2_ch5 = %d\n", value_buff2[0], value_buff2[1]);
	}
	if(ulNotifiedValue & (1<<2)) {
		SWO_PRINTF("ADC3_ch6 = %d\nADC3_ch7 = %d\n", value_buff3[0], value_buff3[1]);
	}
}

In this functions, i commented the HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024);
Only this function start the ADC1. After commenting this HAL_ADC_Start_DMA(&hadc1, value_buff1, 1024); still the ulNotifiedValue =1;

Thanks
Manikandan D

Sorry, your code is still buggy and still not following the documentation nor the example…

ulNotifiedValue = xTaskNotifyWait(pdTRUE, 0, &ulNotifiedValue, 500);

overwrites ulNotifiedValue with the return code of xTaskNotifyWait
which is either pdTRUE (==1) or pdFALSE (== 0).
It must similar to this:


if ( xTaskNotifyWait(pdTRUE, ULONG_MAX, &ulNotifiedValue, 500) == pdTRUE )
{
    // ... check the bits set in ulNotifiedValue
}

BTW Do you really need the timeout ? Why not just using portMAX_DELAY ?

Thank you @hs2
I am doing mistake in this line
ulNotifiedValue = xTaskNotifyWait(pdTRUE, 0, &ulNotifiedValue, 500);

Now i changed that one,
if ( xTaskNotifyWait(pdTRUE, 0, &ulNotifiedValue, 500) == pdTRUE )
{
} like that.

But now i am facing new issue. I configure three ADC but It will print ADC1 and ADC3 only. It is not printing ADC2.
For testing i configure ADC2 only, in this case ADC2 working.
What’s happening i don’t know.

Thanks
Manikandan D

I afraid you’ve to double check/review your code and debug it yourself.
Likely a tiny bug / typo somewhere in your code. Good luck !

Edit: I missed to fix all issues of your original wrong xTaskNotifyWait usage.
I’ve edited the post above and you need to set ulBitsToClearOnExit parameter to e.g.
ULONG_MAX although 0x7 (bit 2…0) would be sufficient in your case.

Remember that you have to check for each bit independently. The ISR might be called e.g. twice (in case ADC1 and ADC2 are completed almost at the same time) before the task is able to run.
Hence the seperate ifs per bit check and not else if.

1 Like

Thanks @hs2
I will check, I think i am doing small mistake somewhere in my code.