Probs w/ xSemaphoreGiveFromISR & on ...

rgibbs wrote on Friday, March 05, 2010:

I have an ISR that communicates with a task via a semaphore.  If I use xSemaphoreGive in the ISR (against the documentation), everything works fine.  However, if I use xSemaphoreGiveFromISR and (conditionally) call vPortYieldFromISR as I should, the scheduler becomes confused after the first interrupt and never finds a task to schedule after the waiting task blocks, even though there’s another task that’s always ready to run. 

The scenario is as follows:

There are two tasks - a low-priority task that does something to cause an interrupt, and a higher priority task that’s waiting on a semaphore.  The ISR simply posts to the semaphore.  In the case were I use the correct “FromISR” functions from the ISR, the waiting task wakes up, performs it’s function (nothing) , and goes back to waiting for the semaphore.  The low-priority task never gets scheduled again.  However, if I use the INCORRECT function in the ISR, everything works smoothly, and the low-priority task gets scheduled after the waiting task re-waits.

I’m using the GCC/ARM_CM3 port on a ARM Cortex-M3 target.  I’m actually pre-silicon and am running on RTL/VCS simulations.

Any help would be greatly appreciated.

rgibbs wrote on Friday, March 05, 2010:

I found the previous post where you using binary semaphores fixed the problem.  I tried a binary semaphore with no success.  Further, I need counting semaphores in this instance.

davedoors wrote on Saturday, March 06, 2010:

Which CM3 will you use when it is ready.

Are you sure your simulator is working correctly? Many don’t when simulating an RTOS.

davedoors wrote on Saturday, March 06, 2010:

Also, can you post the code of the two tasks, which sound like they are only a few lines of code. Use the

tags to keep the formatting.

rgibbs wrote on Monday, March 08, 2010:

Per your question about the simulator, I have never had a problem with the simulator before. The simulator is VCS and it’s simulating the M3 processor from the RTL, so it should be cycle-accurate.  And I’ve been simulating other things under freeRTOS and other RTOS’s with this simulator with no problems.

Per your question about which CM3 I’ll be using,  I’m writing code for a new chip incorporating a Cortex-M3.

The task and the ISR are shown below, somewhat simplified.

Thanks for your help with this.

Richard

/**
 * GPIOHelpersTask is the task that performs most of the functionality for
 * all GPIO interrupts.  It spends most of its time waiting on a signal
 * from the ISR that an interrupt has occurred.  When it receives a signal
 * (actually a "put" on its semaphore), it processes all GPIO interrupts
 * that have occurred since the last signal.
 *
 * void GPIOHelpersTask(void)
 *
 *
 **/
void GPIOHelpersTask(void)
{
	uint32_t retCode;
	uint32_t i;
	uint8_t  lclIntPending[HW_MAX_GPIO];
	/* init  the gpio and the ISR-to-this-task counting semaphore*/
	gpioHelpers_sysInit();
	/* this is the main task loop;  it runs off of a counting semaphore so it doesn't miss any semaphore posts */
	while (pdTRUE)
	{
	/* wait on semaphore */
        retCode = xSemaphoreTake(((posixSemaphore *)gpioHelpersSema)->handle,0xffffffff);
  
		if (retCode < 0)
		{
			/***TODO***log an error***/
			while (1) {};
		}
		/* process "pending" interrupts */
	    /* first pick up all pending interrupts and save them locally */
		/* to avoid multiple interrupt enable/disables				  */
		taskENTER_CRITICAL();
		for (i = 0 ; i < HW_MAX_GPIO ; i++)
		{
			lclIntPending[i] = gpioHelper.gpioPendInt[i];
			gpioHelper.gpioPendInt[i] = 0;
		}
		taskEXIT_CRITICAL();
		/* process each entry in table (comparing to pending mask for that gpio) ***/
		/* note:  races shouldn't be an issue here, as count is never decrementing */
		/*        and all other change, we'll either get before or after, but not  */
		/*        inconsistent state.											   */
		for (i = 0 ; i < gpioHelper.gpioHandleCount ; i++)
		{
			/* check each entry against the corresponding pending interrupt bits */
			if ((lclIntPending[gpioHelper.configTable[i].gpioNum] &
											gpioHelper.configTable[i].mask) &&
					gpioHelper.configTable[i].IOType > GPIO_INT_TYPES)
			{
				/* found one, now process it (call call-back) */
				((gpio_callback_t)gpioHelper.configTable[i].notifier)
							(
								GPIO_DATA_R(gpioHelper.configTable[i].gpioNum,
									gpioHelper.configTable[i].basePin,
									BIT_MASK(gpioHelper.configTable[i].numPins))
							);
				}
			} /* if (lclIntPending[gpioHelper.configTable[i].gpioNum] & ... */
		}
	} /* while (pdTRUE) */
    /*** should never get here ***/
}
/**
 * GPIOISR is the interrupt service routine for the GPIO blocks.  It fields
 * all GPIO interrupts and signals the background function to determine what
 * to do with the interrupt.
 *
 * void GPIOISR(void)
 *
 *
 **/
void GPIOISR(void)
{
	uint32_t retCode;
	uint8_t IRQNum;
	uint8_t gpioNum;
	uint8_t intsPending;
	portBASE_TYPE preEmptionRequired = pdFALSE;
	/* determine which GPIO is firing */
	IRQNum = get_irq_in_process();
	/* convert IRQ to gpio # and check validity  */
	gpioNum = HW_IRQ2GPIO(IRQNum);
	if (gpioNum > HW_MAX_GPIO)
	{
		/*****BAD ERROR -- should never get here.  IGNORE THIS *****/
		/*****             or, during debug, hang                ***/
		while (pdTRUE){};
		return;
	}
	/* pick up its pending interrupts and "or" it into the saved */
	/* pending interrupts then clear the interrupts in GPIO.     */
	/* NOTE:  "pend" in NVIC is automatically cleared when an    */
	/* the isr is entered, so it doesn't need to be cleared, and */
	/* in fact, shouldn't be cleared, as it means another intrupt*/
	/* has arrived after the current one was active.  Also, the  */
	/* "active" bit is read-only and automagically set & cleared */
	/* by the NVIC.						     */
	intsPending = GPIO_MIS_R(gpioNum);
	gpioHelper.gpioPendInt[gpioNum] |= intsPending;
	GPIO_INTCLR_W(gpioNum,intsPending);
	/* now notify the gpio helper task that it's got work to do  */
	given = xSemaphoreGiveFromISR(sem->handle,&preEmptionRequired);
        /****handle pre-emption****/
        if (preEmptionRequired != pdFALSE) 
	{
					vPortYieldFromISR();
	}
}

rgibbs wrote on Wednesday, March 10, 2010:

Is anyone successfully using xSemaphoreGiveFromISR/vPortYieldFromISR on a counting semaphore on a CORTEX_M3?

rgibbs wrote on Tuesday, March 16, 2010:

Problem solved.  This was my problem and NOT a freeRTOS problem.

I had configSYSCALL_INTERRUPT_PRIORITY set at lower priority (higher priority # on ARM CORTEX M3) than my GPIO interrupt was running at.  When I fixed this, the problem went away.

Richard