Task switching using notifications

I need feedback if this RTOS structure can work. If not, what is the problem?

Two tasks same priority. Currently configUSE_TIME_SLICING is set to 1
Whenever an interrupt occurs, a flag is set.

Task 1 loops checking for interrupt flags. If flag is set, the appropriate function is called. A total of 9 interrupt flags are checked in this task.
If the flag specific to task 2 is set, task 1 calls xTaskNotifyGive(&Task2Handle);

Task 2 activates on a specific interrupt flag and stays blocked at other times.
for( ;; )
{
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
do some processing
xTaskNotifyGive(&Task1Handle);
}

Priya

That would work but has a few inefficiencies - notably having a task polling for interrupt flags. Is that all the task is doing? If so then why not have the notification sent directly from the interrupt to the task that needs to be unblocked? Secondly, depending on the prioritisation and real time requirements of your system, if you can combine processing multiple interrupts into a single task then that will prevent you from having to create a task stack for each interrupt type. That would mean the [deferred] interrupt processing that occurs in the ‘do some processing’ part of your code would only be able to do the processing for one interrupt type at a time, then when that was done, it could do the next, effectively serialising processing. Like I said - it might be that is not appropriate for you needs but thought I would mention all the same.

I am now trying vTaskNotifyGiveFromISR from the interrupt that will wake up task 2. Task 2 stays indefinitely blocked ulTaskNotifyTake( pdTRUE, portMAX_DELAY );

However this is not waking task 2. If I step into vTaskNotifyGiveFromISR it skips traceTASK_NOTIFY_GIVE_FROM_ISR(); the eOriginalNotifyState is not eWaitingNotification and it exits the API. What does this mean?

Thanks,
Priya

That part is fine - the macro won’t be defined unless you defined it.

Please show the code you use to create the task, the task itself, and the code in the interrupt that calls vTaskNotifyGiveFromISR().

xTaskCreate( ArcTask, "ARC", mainARC_TASK_STACK_SIZE, NULL, ( unsigned portBASE_TYPE ) mainARC_TASK_PRIORITY, &ARCTaskHandle);

`\
void ArcTask(void * pvParameters)
{
//	unsigned portBASE_TYPE uxHighWaterMark;
//	uxHighWaterMark = uxTaskGetStackHighWaterMark(NULL);
    UINT8   RcvPage;
	for( ;; )
	{
	    ulTaskNotifyTake( pdTRUE, portMAX_DELAY );

	    if (arcnetIsrFlag){
	         arcnetIsrFlag = 0;
	         x_Int_IRQ7();
	    }
#ifdef _TEST_CODE_TFA
		if (m_ucCurrentState)
			{
			ROM_GPIOPinWrite(FBFEED_PMOTF_GPIO_PORT_BASE, FBFEED_PMOTF_GPIO_PIN, FBFEED_PMOTF_GPIO_PIN); //PMOTF toggled by ARC Task
				m_ucCurrentState = FALSE;
			}
			else
			{
				ROM_GPIOPinWrite(FBFEED_PMOTF_GPIO_PORT_BASE, FBFEED_PMOTF_GPIO_PIN, 0); //PMOTF toggled by ARC Task
				m_ucCurrentState = TRUE;
			}
#endif


		/** My RECON occured check **/
		if( (2 == ARC_Condit) && (1 == NET_obs_flg) ){
			ARC_F7();
			NET_obs_flg = 0;
		}

		if( 1 == x_MailRecv( X_TSKID_ARC, (UINT32 *)&ARC_RcvMail) ){	/* mail exist (Y) */

			switch( ARC_RcvMail.Kind ){		/* branch by Mail-ID */
			case	X_MID_START:			/* task start */

				ARC_F1();
				break;

			case	X_MID_STOP:				/* task stop */
				ARC_F2();
				break;

			case	X_MID_ARCSND1:			/* arcnet command send request */
			case	X_MID_ARCSND2:
			case	X_MID_ARCSND3:
				ARC_F3();
				break;

			case	X_MID_ARCRCV1_FREE:		/* arcnet received buffer release */
			case	X_MID_ARCRCV2_FREE:
			case	X_MID_ARCRCV3_FREE:
				ARC_F4();
				break;
			}	/* switch end */
		}	/* end of mail received process */

		/** chip event (send/receive) event check **/

		if( 2 == ARC_Condit ){				/* I will check only IDLE phase */

			/** packet received complete event check **/
			RcvPage = ARC_RcvQueRead();		/* received information get */
			if( 0xff != RcvPage ){			/* received packet exist (Y) */
				ARC_F5( RcvPage );			/* arcnet receive event process */
				continue;					/* send will be next time */
			}
		}

		if( (2 == ARC_Condit) || (3 == ARC_Condit) ){	/* send complete check phase (Y) */

			/** packet send complete event check **/
			if( (1 == ARC_f_Sending.flag) &&	/* now send requesting, and */
				(0 == Arc_Txd_Mode) ){			/* send complete */

				ARC_F6();				/* arcnet send complete event process */
			}
		}


	}
}

void ARCNET_Interupt_ISR(void)
{
    Bool bMasked = false;
    uint32_t intStatus = 0;
    int pxHigherPriorityTaskWoken = pdFALSE;

	//Check if this is a GPIO Interrupt
	intStatus = ROM_GPIOPinIntStatus(ARCNET_INTR_PORT_BASE, bMasked);
	if((intStatus & ARCNET_INTR_PIN) == ARCNET_INTR_PIN)
	{
		//CLEAR THE INTERUPT
		ROM_GPIOPinIntClear(ARCNET_INTR_PORT_BASE, ARCNET_INTR_PIN);
		
		//CALL THE RELEVENT ROUTINE
		arcnetIsrFlag = 1;
		vTaskNotifyGiveFromISR(&ARCTaskHandle, &pxHigherPriorityTaskWoken);
		portYIELD_FROM_ISR( pxHigherPriorityTaskWoken );
	}
}

This line:

vTaskNotifyGiveFromISR(&ARCTaskHandle, &pxHigherPriorityTaskWoken);

is passing the address of the task handle, whereas it should be passing the task handle itself. Try removing the ‘&’ as per:

vTaskNotifyGiveFromISR(ARCTaskHandle, &pxHigherPriorityTaskWoken);

pxHigherPriorityTaskWoken is not becoming TRUE. Currently task 1 and task 2 are both tskIDLE_PRIORITY + 2. Is this a problem?

The priority of the interrupt whose ISR calls this API is set to 1 (MCU priority number). How should this relate to configKERNEL_INTERRUPT_PRIORITY

Thanks,
Priya

Sorry - I took the ‘&’ off the wrong parameter and just edited to correct it. It should have been:

vTaskNotifyGiveFromISR(ARCTaskHandle, &pxHigherPriorityTaskWoken);

First - note the correction to my post above!

If both tasks are the same priority, then a higher priority task won’t be unblocked, and it would be expected that *pxHigherPriorityTaskWoken remains pdFALSE.

Interrupts that call API functions must be at or below the priority set by configMAX_SYSCALL_INTERRUPT_PRIORITY (some ports call this configMAX_API_CALL_INTERRUPT_PRIORITY) - how to configure that depends on the port you are using. configKERNEL_INTERRUPT_PRIORITY should always be the lowest interrupt priority there is. There are several pages that document this, including https://www.freertos.org/RTOS-Cortex-M3-M4.html

Thank you for your reply. For equal priority tasks, is it possible to block a task until the notification is given from an ISR? Or is the scheduler responsible for the task switch?

If a task switch can only happen to a higher priority task, how does the task switch happen out of the higher priority task to the lower priority task?

ISR:
vTaskNotifyGiveFromISR(ISRTaskHandle, &pxHigherPriorityTaskWoken);
portYIELD_FROM_ISR( pxHigherPriorityTaskWoken );

Task 2
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

I’m not sure I understand the question because I thought that was what were doing. If you block on the notification, and the ISR gives the notification, then it will unblock the task because the event the task was waiting on will have happened.

The higher priority task must enter either the Blocked or Suspended state (the Blocked state in 99.999% of use cases). This is fundamental knowledge you need in order to write an efficient functioning application so I highly recommend you take some time to read through the first few chapters of the pdf book - it won’t take long at all.