cancel
Showing results for 
Search instead for 
Did you mean: 

32F417: trying to interrupt from PE12 rising edge

PHolt.1
Senior III

Post edited by the ST moderator to be inline with ST community rules especially for the code. Please use </> button to paste your code. 

 

Hello :)

I almost have this working. In fact I had the ISR running and incrementing an integer. Then I went to the next stage and put in the xTaskResumeFromISR() but that crashes in configASSERT( xTaskToResume ).

Can anyone see any problems with this code?

Init:

__disable_irq();

GPIO_InitTypeDef GPIO_InitStruct = {0};

// Configure PE12

GPIO_InitStruct.Pin = GPIO_PIN_12;

GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // Interrupt on rising edge

GPIO_InitStruct.Pull = GPIO_PULLDOWN; // pulldown

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // This does nothing on an input pin

HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

// Configure NVIC

HAL_NVIC_SetPriority(EXTI15_10_IRQn, 10, 0);   // Maybe the priority is not suitable for xTaskResumeFromISR ?

HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

__enable_irq();

Vector table piece:

.word USART2_IRQHandler /* USART2 */

.word USART3_IRQHandler /* USART3 */

.word EXTI15_10_IRQHandler /* EXTI15_10_IRQHandler External Line[15:10] used for PE12 (TE) interrupt */

.word 0 /* RTC_Alarm_IRQHandler RTC Alarm (A and B) through EXTI Line */

.word 0 /* OTG_FS_WKUP_IRQHandler USB OTG FS Wakeup through EXTI line */

ISR:

// Handler for TE (PE12=1) interrupt.

// This restarts the xLCDHandle task which was suspended with vTaskSuspend(NULL).

void EXTI15_10_IRQHandler(void)

{

// Check if interrupt is from EXTI12 (PE12)

if (EXTI->PR & (1 << 12))

{

// Clear the interrupt pending bit

EXTI->PR = (1 << 12);

// Restart the suspended LCD task. If task not suspended, nothing happens

//xTaskResumeFromISR( xLCDHandle ); // uncommenting this breaks it

}

}

Currently I have no tasks suspended (so nothing to resume) but xTaskResumeFromISR should then just return False.

Digging around I found this

// Restart the suspended LCD task. If task not suspended, nothing happens

xYieldRequired = xTaskResumeFromISR( xLCDHandle );

if ( xYieldRequired == pdTRUE )

{

portYIELD_FROM_ISR( xYieldRequired );

}

but it doesn't help because the crash happens inside xTaskResumeFromISR.

Thank you very much for any input.

 

 

5 REPLIES 5
Chris21
Senior III

ISR priorities must not be higher than the RTOS system interrupt priority defined by configSYSTEM_INTERRUPT_PRIORITY for any interrupt service routine that calls RTOS functions.

PHolt.1
Senior III

Thank you!

I can't find that value.

I have these

/* 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) )

I have tried the ISR with various priorities all the way down to 15 which is Systick.

Also, would this be correct for the ISR?

void EXTI15_10_IRQHandler(void)
{

	BaseType_t xYieldRequired;

    // Check if interrupt is from EXTI12 (PE12)
    if (EXTI->PR & (1 << 12))
    {

        // Clear the interrupt pending bit
        EXTI->PR = (1 << 12);

        // Restart the suspended LCD task. If task not suspended, nothing happens
        xYieldRequired = xTaskResumeFromISR( xLCDHandle );
        if ( xYieldRequired == pdTRUE )
        {
        	portYIELD_FROM_ISR( xYieldRequired );
        }
    }

}
Chris21
Senior III

In your system: 

configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

so your ISR must have priority >= 5.

Example from: https://www.freertos.org/Documentation/02-Kernel/04-API-references/02-Task-control/08-xTaskResumeFromISR

void vAnExampleISR( void )
{
    BaseType_t xYieldRequired;

    // Resume the suspended task.
    xYieldRequired = xTaskResumeFromISR( xHandle );

    // We should switch context so the ISR returns to a different task.
    // NOTE:  How this is done depends on the port you are using.  Check
    // the documentation and examples for your port.

    portYIELD_FROM_ISR( xYieldRequired );
}

They recommend against this in general:

xTaskResumeFromISR()

is generally considered a dangerous function because its actions are not latched. For this reason it should definitely not be used to synchronise a task with an interrupt if there is a chance that the interrupt could arrive prior to the task being suspended, and therefore the interrupt being lost. Use of a semaphore, or preferable a direct to task notification, would avoid this eventuality. A worked example that uses a direct to task notification is provided. 

 

Pavel A.
Super User

It looks like the interrupt occurs for the 1st time before the scheduler has been activated. Thus xTaskToResume is invalid. Your IRQ priority is 10 which is lower than configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY (5), so OK.

 

PHolt.1
Senior III

The interrupt is initialised inside the RTOS task, so should not occur before RTOS is started. I have it working now, though not sure how exactly!

Task is defined with this

xTaskCreate(vLCDTask, "LCD", configMINIMAL_STACK_SIZE*2, NULL, osPriorityLow, &xLCDHandle);

Then inside the task I set up the ISR with this

	GPIO_InitTypeDef GPIO_InitStruct = {0};

	// Configure PE12
	GPIO_InitStruct.Pin = GPIO_PIN_12;
	GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;     // Interrupt on rising edge
	GPIO_InitStruct.Pull = GPIO_PULLDOWN;        	// pulldown
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;	// This does nothing on an input pin
	HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
	// Configure NVIC
	HAL_NVIC_SetPriority(EXTI15_10_IRQn, 2, 0);	// Priority must be <=configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY (5)
	HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

 The ISR is now this (I did a lot of googling and also used Claude to dig up more (Claude is >50% garbage as we know, but so are google hits to code fragments posted on forums)

// Handler for TE (PE12=1) interrupt.
// This restarts the xLCDHandle task which was suspended with vTaskSuspend(xLCDHandle).
// Exec time of this ISR is 1.5us.

void EXTI15_10_IRQHandler(void)
{
	BaseType_t xYieldRequired;
	// Check if interrupt is from EXTI12 (PE12)
	if (EXTI->PR & (1 << 12))
	{
		// Clear the interrupt pending bit
		EXTI->PR = (1 << 12);

		// Check if task handle is valid before using it
		if (xLCDHandle != NULL)
		{
            xYieldRequired = xTaskResumeFromISR(xLCDHandle);
            portYIELD_FROM_ISR(xYieldRequired);
		}

	}
}

and it is running!

I am interrupting from the TE=1 vertical blanking output of an LCD controller. If you do all display writing during TE=1 (1ms long) then you get no flicker etc. So I am using

vTaskSuspend(xLCDHandle);

right before drawing any graphics. The ISR from TE rising edge then unsuspends the graphics activity. I have to manually ensure it completes within that 1ms (though there are some tricks one can do, using the knowledge of which way the display controller will scan its video RAM, etc).

The ISR priority is a mystery because 4 or 5 works but 6+ blows it up. This is the opposite of what is documented.

Thank you all for your help.

Let me add that this is a product under development for several years. It is rock solid, running about 30 FreeRTOS tasks, MbedTLS, ADCs, DACs, counters, all kinds of weird stuff, and I have just been adding the LCD functionality, which works great but I thought I would try to implement the video writing sync with the vertical sync.

If anyone has any hints about making the code more reliable, I am all ears.

There are loads of interrupts, some complex like USB and ETH, but this ISR is the only one from an external pin (PE12). I have never done that before.