Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Real time embedded FreeRTOS mailing list 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem TCP & FAT Training




Loading

Task priority, interrupt, semaphore problem

Posted by Erik Agerup on August 8, 2012
Dear support forum,
I have a problem regarding tha task priority, interrupt priority and the use of semaphores.

At initialization, a startupThread is created and the scheduler is started.
If the task priority of the startupThread is lower than 9, the code is working. If it is higher than 9, the code only works if I put a breakpoint in the xPortPendSVHandler and steps through the code.

The problem occurs when the startupThread is waiting for a semaphore that is released in an I2C interrupt. When the semaphore is released, the StartupThread does not continue to run. Neither because of a semaphore timeout or because of the release. I can see that the semaphore is released and that portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken ) is called with xHigherPriorityTaskWoken == 1. However the startupThread is never continued. Since the semaphore also have a timeout I find this very strange.

I suspect that there might be an issue regarding the setup of the interrupt priorities or task priorities. Any ideas? Can the increased size of the taskList cause more delay and trigger a problem with a race-condition?
Is there a limit for the task priority other than configMAX_PRIORITIES?

Info:
FreeRTOS V7.0.1
MCU: Freescale Kinetis K10.
Compiler: IAR 6.21

#define configMAX_PRIORITIES( ( unsigned portBASE_TYPE ) 12 )
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY0xf
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY5


Best regards,
Erik Agerup

RE: Task priority, interrupt, semaphore problem

Posted by Richard on August 8, 2012
Have you followed all the instructions on this page?
http://www.freertos.org/RTOS-Cortex-M3-M4.html

Regards.

RE: Task priority, interrupt, semaphore problem

Posted by Erik Agerup on August 9, 2012
Yes, I have followed the instructions, and I can see that the BASEPRI register is set to 0x50 during the first xTaskCreate().
However, after calling vTaskStartScheduler() and starting the first task, the BASEPRI register is reset to 0. This is also the case in the FreeRTOS blinky demo. Is this correct?

Regards


RE: Task priority, interrupt, semaphore problem

Posted by Erik Agerup on August 9, 2012
Forget my previous post, I now understand the BASEPRI register, and I also found the error:)

In xPortPendSVHandler the interupts are disabled, vTaskSwitchContext is run and the interrupts are enabled again.

stmdb sp!, {r3, r14}
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0
bl vTaskSwitchContext
mov r0, #0
msr basepri, r0
ldmia sp!, {r3, r14}

But in vTaskSwitchContext, the function portGET_RUN_TIME_COUNTER_VALUE is run when configGENERATE_RUN_TIME_STATS is enabled, and that function calls xTaskGetTickCountFromISR();

xTaskGetTickCountFromISR() disables interrupts, and enables them again.
The remaining code of vTaskSwitchContext is now run with interrupts enabled.

portTickType xTaskGetTickCountFromISR( void )
{
portTickType xReturn;
unsigned portBASE_TYPE uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
xReturn = xTickCount;
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
return xReturn;
}
I am sure the intension is to store the previous state of the interrupt in uxSavedInterruptStatus, but that does not work, it is always 0.

I think these defines need to be changed in portmacro.h:
#define portSET_INTERRUPT_MASK_FROM_ISR()0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)vPortClearInterruptMask();(void)x

If 0 always is returned from portSET_INTERRUPT_MASK_FROM_ISR(), interrupts will be enabled when they are not supposed to.

How can I update these macros such that the BASEPRI register is read instead of 0?

Regards

RE: Task priority, interrupt, semaphore problem

Posted by Richard on August 9, 2012
“In xPortPendSVHandler the interupts are disabled, vTaskSwitchContext is run and the interrupts are enabled again.”


No they are not. The intelligent Cortex-M NVIC (nested interrupt controller) will not accept an interrupt at a priority above the currently running interrupt. As BASE_PRI is set to 0 the code effectively sets the interrupt mask to the priority of the existing interrupt.


“I think these defines need to be changed in portmacro.h:
#define portSET_INTERRUPT_MASK_FROM_ISR()0;vPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)vPortClearInterruptMask();(void)x


It is set to zero because saving the old interrupt state and then restoring the old interrupt state would cause the compiler to generate more assembly code with no difference being made to the effective state of the compiler or the execution of your code. As it is, turning the optimiser on in the compiler settings will just remove the code all together as it does nothing.

Regards.

RE: Task priority, interrupt, semaphore problem

Posted by Erik Agerup on August 9, 2012
Ok, I understand, and thank you for your reply.
That was strange, because changing the code solved my problem.

The strange thing is that if I either disable configGENERATE_RUN_TIME_STATS or uncomment as shown below, the code is working.
If I don't do this, it depends on the value of the highest task priority if it works or not. I suspect that a higher task priority value will make it take a longer time to go through the task list in vTaskSwitchContext and therefore it is more likely that the I2C interrupt is occurring here. I can see that the I2C interrupt is run while vTaskSwitchContext is running.

//uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
xReturn = xTickCount;
//portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

So, it is OK that the BASEPRI is changed from 0x50 to 0x00 during vTaskSwitchContext if and only if configGENERATE_RUN_TIME_STATS is enabled?

Can you think of something else causing my problem, when changing this makes my problem disappear.

Regards.

RE: Task priority, interrupt, semaphore problem

Posted by MEdwards on August 10, 2012
When configGENERATE_RUN_TIME_STATS is set to 1, the kernel will try an call user defined functions to first initialize the run time stats gathering, and then obtain the run time stats pointers. How are your run time stats functions implemented?

RE: Task priority, interrupt, semaphore problem

Posted by Richard on August 16, 2012
Update -

This is probably the cause of the issue. The run time stats function is called from within a critical section, and exiting the critical section from the run time stats implementation would be a problem on a Cortex-M. I have just looked at the run time stats implementation in the FreeRTOS/Demo projects, and see that it specifically accounts for this potential issue be re-entering the critical section in the code. See the call to portSET_INTERRUPT_MASK_FROM_ISR() in the snipped below, which is taken from the official Kinetis K60 demo.

/* The SysTick is a down counter.  How many clocks have passed since it was
last reloaded? */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;

/* How many times has it overflowed? */
ulTickCount = xTaskGetTickCountFromISR();

/* This is called from the context switch, so will be called from a
critical section. xTaskGetTickCountFromISR() contains its own critical
section, and the ISR safe critical sections are not designed to nest,
so reset the critical section. */
portSET_INTERRUPT_MASK_FROM_ISR();

/* Is there a SysTick interrupt pending? */
if( ( *pulInterruptCTRLState & ulSysTickPendingBit ) != 0UL )
{
/* There is a SysTick interrupt pending, so the SysTick has overflowed
but the tick count not yet incremented. */
ulTickCount++;

/* Read the SysTick again, as the overflow might have occurred since
it was read last. */
ulSysTickCounts = ulSysTickReloadValue - *pulCurrentSysTickCount;
}

/* Convert the tick count into tenths of a millisecond. THIS ASSUMES
configTICK_RATE_HZ is 1000! */
ulReturn = ( ulTickCount * 10UL ) ;

/* Add on the number of tenths of a millisecond that have passed since the
tick count last got updated. */
ulReturn += ( ulSysTickCounts / ulClocksPer10thOfAMilliSecond );

return ulReturn;


I might put something into the core code to guard against this, as I can see it is an area that could cause users an issue.

Regards.


[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]




Copyright (C) 2004-2010 Richard Barry. Copyright (C) 2010-2016 Real Time Engineers Ltd.
Any and all data, files, source code, html content and documentation included in the FreeRTOSTM distribution or available on this site are the exclusive property of Real Time Engineers Ltd.. See the files license.txt (included in the distribution) and this copyright notice for more information. FreeRTOSTM and FreeRTOS.orgTM are trade marks of Real Time Engineers Ltd.

Latest News:

FreeRTOS V9.0.0 is now available for download.


Free TCP/IP and file system demos for the RTOS


Sponsored Links

⇓ Now With No Code Size Limit! ⇓
⇑ Free Download Without Registering ⇑


FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

Renesas Electronics Gold Alliance RTOS Partner.jpg

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

Atmel RTOS partner supporting ARM Cortex-M3 and AVR32 microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Xilinx Microblaze and Zynq partner

Silicon Labs low power RTOS partner

Altera RTOS partner for Nios II and Cortex-A9 SoC

Freescale Alliance RTOS Member supporting ARM and ColdFire microcontrollers

Infineon ARM Cortex-M microcontrollers

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

Cypress RTOS partner supporting ARM Cortex-M3

Fujitsu RTOS partner supporting ARM Cortex-M3 and FM3

Microsemi (previously Actel) RTOS partner supporting ARM Cortex-M3

Atollic Partner

IAR Partner

Keil ARM Partner

Embedded Artists