diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
index 1d9dcfbc6..4431c9a66 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/.project
@@ -49,6 +49,11 @@
1FREERTOS_ROOT/FreeRTOS-Plus/Demo/Common/FreeRTOS_Plus_CLI_Demos/UARTCommandConsole.c
+
+ src/Standard_Demo_Tasks/IntQueue.c
+ 1
+ FREERTOS_ROOT/FreeRTOS/Demo/Common/Minimal/IntQueue.c
+
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
index e2d387664..9130dc805 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOSConfig.h
@@ -132,14 +132,14 @@
#define configUSE_QUEUE_SETS 1
/* Co-routine definitions. */
-#define configUSE_CO_ROUTINES 0
-#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
-#define configUSE_TIMERS 1
-#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
-#define configTIMER_QUEUE_LENGTH 5
-#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
+#define configTIMER_QUEUE_LENGTH 5
+#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
@@ -165,13 +165,14 @@ Zynq MPU. */
#define configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET ( -0xf00 )
#define configUNIQUE_INTERRUPT_PRIORITIES 32
-/* Run time stats gathering definitions. */
-unsigned long ulGetRunTimeCounterValue( void );
-void vInitialiseRunTimeStats( void );
-
+/* portCONFIGURE_TIMER_FOR_RUN_TIME_STATS is not required because the time base
+comes from the ulHighFrequencyTimerCounts variable which is incremented in a
+high frequency timer that is already being started as part of the interrupt
+nesting test. */
#define configGENERATE_RUN_TIME_STATS 1
-#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vInitialiseRunTimeStats()
-#define portGET_RUN_TIME_COUNTER_VALUE() ulGetRunTimeCounterValue()
+extern volatile uint32_t ulHighFrequencyTimerCounts;
+#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
+#define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerCounts
/* The size of the global output buffer that is available for use when there
are multiple command interpreters running at once (for example, one on a UART
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOS_tick_config.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOS_tick_config.c
index 601311059..0134d31d7 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOS_tick_config.c
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/FreeRTOS_tick_config.c
@@ -88,6 +88,7 @@ BaseType_t xStatus;
extern void FreeRTOS_Tick_Handler( void );
XScuTimer_Config *pxTimerConfig;
XScuGic_Config *pxGICConfig;
+const uint8_t ucRisingEdge = 3;
/* This function is called with the IRQ interrupt disabled, and the IRQ
interrupt should be left disabled. It is enabled automatically when the
@@ -99,8 +100,11 @@ XScuGic_Config *pxGICConfig;
xStatus = XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress );
configASSERT( xStatus == XST_SUCCESS );
+ /* The priority must be the lowest possible. */
+ XScuGic_SetPriorityTriggerType( &xInterruptController, XPAR_SCUTIMER_INTR, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, ucRisingEdge );
+
/* Install the FreeRTOS tick handler. */
- xStatus = XScuGic_Connect(&xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, (void *)&xTimer);
+ xStatus = XScuGic_Connect( &xInterruptController, XPAR_SCUTIMER_INTR, (Xil_ExceptionHandler) FreeRTOS_Tick_Handler, ( void * ) &xTimer );
configASSERT( xStatus == XST_SUCCESS );
/* Initialise the timer. */
@@ -127,21 +131,6 @@ XScuGic_Config *pxGICConfig;
}
/*-----------------------------------------------------------*/
-/*
- * Crude implementation of a run time counter used to measure how much time
- * each task spends in the Running state.
- */
-unsigned long ulGetRunTimeCounterValue( void )
-{
- return 0;
-}
-/*-----------------------------------------------------------*/
-
-void vInitialiseRunTimeStats( void )
-{
-}
-/*-----------------------------------------------------------*/
-
void vClearTickInterrupt( void )
{
XScuTimer_ClearInterruptStatus( &xTimer );
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/IntQueueTimer.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/IntQueueTimer.c
index c0bd4c077..1a24a4cba 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/IntQueueTimer.c
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/IntQueueTimer.c
@@ -63,6 +63,24 @@
1 tab == 4 spaces!
*/
+/*
+ * This file initialises three timers as follows:
+ *
+ * Timer 0 and Timer 1 provide the interrupts that are used with the IntQ
+ * standard demo tasks, which test interrupt nesting and using queues from
+ * interrupts. Both these interrupts operate below the maximum syscall
+ * interrupt priority.
+ *
+ * Timer 2 is a much higher frequency timer that tests the nesting of interrupts
+ * that execute above the maximum syscall interrupt priority.
+ *
+ * All the timers can nest with the tick interrupt - creating a maximum
+ * interrupt nesting depth of 4.
+ *
+ * For convenience, the high frequency timer is also used to provide the time
+ * base for the run time stats.
+ */
+
/* Scheduler includes. */
#include "FreeRTOS.h"
@@ -71,214 +89,173 @@
#include "IntQueue.h"
/* Xilinx includes. */
-#include "xstatus.h"
-#include "xil_io.h"
-#include "xil_exception.h"
#include "xttcps.h"
#include "xscugic.h"
+/* The frequencies at which the first two timers expire are slightly offset to
+ensure they don't remain synchronised. The frequency of the interrupt that
+operates above the max syscall interrupt priority is 10 times faster so really
+hammers the interrupt entry and exit code. */
+#define tmrTIMERS_USED 3
#define tmrTIMER_0_FREQUENCY ( 2000UL )
#define tmrTIMER_1_FREQUENCY ( 2001UL )
+#define tmrTIMER_2_FREQUENCY ( 20000UL )
-#define TTC_TICK_DEVICE_ID XPAR_XTTCPS_0_DEVICE_ID
-#define TTC_TICK_INTR_ID XPAR_XTTCPS_0_INTR
-#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
+/*-----------------------------------------------------------*/
/*
- * Constants to set the basic operating parameters.
- * PWM_DELTA_DUTY is critical to the running time of the test. Smaller values
- * make the test run longer.
+ * The single interrupt service routines that is used to service all three
+ * timers.
*/
-#define TICK_TIMER_FREQ_HZ 100 /* Tick timer counter's output frequency */
+static void prvTimerHandler( void *CallBackRef );
-#define TICKS_PER_CHANGE_PERIOD TICK_TIMER_FREQ_HZ /* Tick signals per update */
+/*-----------------------------------------------------------*/
-#define TIMERS_USED 2
+/* Hardware constants. */
+static const BaseType_t xDeviceIDs[ tmrTIMERS_USED ] = { XPAR_XTTCPS_0_DEVICE_ID, XPAR_XTTCPS_1_DEVICE_ID, XPAR_XTTCPS_2_DEVICE_ID };
+static const BaseType_t xInterruptIDs[ tmrTIMERS_USED ] = { XPAR_XTTCPS_0_INTR, XPAR_XTTCPS_1_INTR, XPAR_XTTCPS_2_INTR };
-static void TickHandler(void *CallBackRef);
+/* Timer configuration settings. */
+typedef struct
+{
+ uint32_t OutputHz; /* Output frequency. */
+ uint16_t Interval; /* Interval value. */
+ uint8_t Prescaler; /* Prescaler value. */
+ uint16_t Options; /* Option settings. */
+} TmrCntrSetup;
-static volatile uint8_t UpdateFlag; /* Flag to update the seconds counter */
-static uint32_t TickCount; /* Ticker interrupts between seconds change */
-static XTtcPs TtcPsInst[ TIMERS_USED ]; /* Timer counter instance */
+static TmrCntrSetup xTimerSettings[ tmrTIMERS_USED ] =
+{
+ { tmrTIMER_0_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE },
+ { tmrTIMER_1_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE },
+ { tmrTIMER_2_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE }
+};
+
+/* Lower priority number means higher logical priority, so
+configMAX_API_CALL_INTERRUPT_PRIORITY - 1 is above the maximum system call
+interrupt priority. */
+static const UBaseType_t uxInterruptPriorities[ tmrTIMERS_USED ] =
+{
+ configMAX_API_CALL_INTERRUPT_PRIORITY + 1,
+ configMAX_API_CALL_INTERRUPT_PRIORITY,
+ configMAX_API_CALL_INTERRUPT_PRIORITY - 1
+}
+static XTtcPs xTimerInstances[ tmrTIMERS_USED ];
-typedef struct {
- u32 OutputHz; /* Output frequency */
- u16 Interval; /* Interval value */
- u8 Prescaler; /* Prescaler value */
- u16 Options; /* Option settings */
-} TmrCntrSetup;
+/* Used to provide a means of ensuring the intended interrupt nesting depth is
+actually being reached. */
+extern uint32_t ulPortInterruptNesting;
+static uint32_t ulMaxRecordedNesting = 0;
-static const TmrCntrSetup SettingsTable[ TIMERS_USED ] = { { tmrTIMER_0_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE },
- { tmrTIMER_1_FREQUENCY, 0, 0, XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE } };
+/* For convenience the high frequency timer increments a variable that is then
+used as the time base for the run time stats. */
+volatile uint32_t ulHighFrequencyTimerCounts = 0;
-BaseType_t DeviceIDs[ TIMERS_USED ] = { XPAR_XTTCPS_0_DEVICE_ID, XPAR_XTTCPS_1_DEVICE_ID };
-BaseType_t InterruptIDs[ TIMERS_USED ] = { XPAR_XTTCPS_0_INTR, XPAR_XTTCPS_1_INTR };
+/*-----------------------------------------------------------*/
void vInitialiseTimerForIntQueueTest( void )
{
-int Status;
-TmrCntrSetup *TimerSetup;
-XTtcPs *TtcPsTick;
+BaseType_t xStatus;
+TmrCntrSetup *pxTimerSettings;
extern XScuGic xInterruptController;
BaseType_t xTimer;
-XTtcPs *Timer;
-XTtcPs_Config *Config;
+XTtcPs *pxTimerInstance;
+XTtcPs_Config *pxTimerConfiguration;
+const uint8_t ucRisingEdge = 3;
- for( xTimer = 0; xTimer < TIMERS_USED; xTimer++ )
+ for( xTimer = 0; xTimer < tmrTIMERS_USED; xTimer++ )
{
+ /* Look up the timer's configuration. */
+ pxTimerInstance = &( xTimerInstances[ xTimer ] );
+ pxTimerConfiguration = XTtcPs_LookupConfig( xDeviceIDs[ xTimer ] );
+ configASSERT( pxTimerConfiguration );
+
+ pxTimerSettings = &( xTimerSettings[ xTimer ] );
+
+ /* Initialise the device. */
+ xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
+ if( xStatus != XST_SUCCESS )
+ {
+ /* Not sure how to do this before XTtcPs_CfgInitialize is called
+ as pxTimerInstance is set within XTtcPs_CfgInitialize(). */
+ XTtcPs_Stop( pxTimerInstance );
+ xStatus = XTtcPs_CfgInitialize( pxTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
+ configASSERT( xStatus == XST_SUCCESS );
+ }
+
+ /* Set the options. */
+ XTtcPs_SetOptions( pxTimerInstance, pxTimerSettings->Options );
+
+ /* The timer frequency is preset in the pxTimerSettings structure.
+ Derive the values for the other structure members. */
+ XTtcPs_CalcIntervalFromFreq( pxTimerInstance, pxTimerSettings->OutputHz, &( pxTimerSettings->Interval ), &( pxTimerSettings->Prescaler ) );
+
+ /* Set the interval and prescale. */
+ XTtcPs_SetInterval( pxTimerInstance, pxTimerSettings->Interval );
+ XTtcPs_SetPrescaler( pxTimerInstance, pxTimerSettings->Prescaler );
+
+ /* The priority must be the lowest possible. */
+ XScuGic_SetPriorityTriggerType( &xInterruptController, xInterruptIDs[ xTimer ], uxInterruptPriorities[ xTimer ] << portPRIORITY_SHIFT, ucRisingEdge );
- TimerSetup = &( SettingsTable[ xTimer ] );
- Timer = &TtcPsInst[ xTimer ];
-
- /*
- * Look up the configuration based on the device identifier
- */
- Config = XTtcPs_LookupConfig(DeviceIDs[ xTimer ]);
- configASSERT( Config );
-
- /*
- * Initialize the device
- */
- Status = XTtcPs_CfgInitialize(Timer, Config, Config->BaseAddress);
- configASSERT(Status == XST_SUCCESS);
-
- /*
- * Stop the timer first
- */
- XTtcPs_Stop( Timer );
-
- /*
- * Set the options
- */
- XTtcPs_SetOptions(Timer, TimerSetup->Options);
-
- /*
- * Timer frequency is preset in the TimerSetup structure,
- * however, the value is not reflected in its other fields, such as
- * IntervalValue and PrescalerValue. The following call will map the
- * frequency to the interval and prescaler values.
- */
- XTtcPs_CalcIntervalFromFreq(Timer, TimerSetup->OutputHz,
- &(TimerSetup->Interval), &(TimerSetup->Prescaler));
-
- /*
- * Set the interval and prescale
- */
- XTtcPs_SetInterval(Timer, TimerSetup->Interval);
- XTtcPs_SetPrescaler(Timer, TimerSetup->Prescaler);
-
-
- /*
- * Connect to the interrupt controller
- */
- Status = XScuGic_Connect(&xInterruptController, InterruptIDs[ xTimer ], (Xil_InterruptHandler)TickHandler, (void *)Timer);
- configASSERT( Status == XST_SUCCESS);
-
- /*
- * Enable the interrupt for the Timer counter
- */
- XScuGic_Enable(&xInterruptController, InterruptIDs[ xTimer ]);
-
- /*
- * Enable the interrupts for the tick timer/counter
- * We only care about the interval timeout.
- */
- XTtcPs_EnableInterrupts(Timer, XTTCPS_IXR_INTERVAL_MASK);
-
- /*
- * Start the tick timer/counter
- */
- XTtcPs_Start(Timer);
+ /* Connect to the interrupt controller. */
+ xStatus = XScuGic_Connect( &xInterruptController, xInterruptIDs[ xTimer ], ( Xil_InterruptHandler ) prvTimerHandler, ( void * ) pxTimerInstance );
+ configASSERT( xStatus == XST_SUCCESS);
+
+ /* Enable the interrupt in the GIC. */
+ XScuGic_Enable( &xInterruptController, xInterruptIDs[ xTimer ] );
+
+ /* Enable the interrupts in the timer. */
+ XTtcPs_EnableInterrupts( pxTimerInstance, XTTCPS_IXR_INTERVAL_MASK );
+
+ /* Start the timer. */
+ XTtcPs_Start( pxTimerInstance );
}
}
/*-----------------------------------------------------------*/
-void vT2InterruptHandler( void )
+static void prvTimerHandler( void *pvCallBackRef )
{
- portEND_SWITCHING_ISR( xFirstTimerHandler() );
-}
-/*-----------------------------------------------------------*/
+uint32_t ulInterruptStatus;
+XTtcPs *pxTimer = ( XTtcPs * ) pvCallBackRef;
+BaseType_t xYieldRequired;
-void vT3InterruptHandler( void )
-{
- portEND_SWITCHING_ISR( xSecondTimerHandler() );
-}
-/*-----------------------------------------------------------*/
+ /* Read the interrupt status, then write it back to clear the interrupt. */
+ ulInterruptStatus = XTtcPs_GetInterruptStatus( pxTimer );
+ XTtcPs_ClearInterruptStatus( pxTimer, ulInterruptStatus );
-volatile uint32_t ulTimer1Count = 0, ulTimer2Count = 0;
+ /* Only one interrupt event type is expected. */
+ configASSERT( ( XTTCPS_IXR_INTERVAL_MASK & ulInterruptStatus ) != 0 );
-static void TickHandler(void *CallBackRef)
-{
-uint32_t StatusEvent;
-XTtcPs *pxTtcPs = (XTtcPs *)CallBackRef;
- /*
- * Read the interrupt status, then write it back to clear the interrupt.
- */
- StatusEvent = XTtcPs_GetInterruptStatus(pxTtcPs);
- XTtcPs_ClearInterruptStatus(pxTtcPs, StatusEvent);
-
- if (0 != (XTTCPS_IXR_INTERVAL_MASK & StatusEvent)) {
- if( pxTtcPs->Config.DeviceId == DeviceIDs[ 0 ] )
- {
- ulTimer1Count++;
- }
- else
+ /* Check the device ID to know which IntQueue demo to call. */
+ if( pxTimer->Config.DeviceId == xDeviceIDs[ 0 ] )
+ {
+ xYieldRequired = xFirstTimerHandler();
+ }
+ else if( pxTimer->Config.DeviceId == xDeviceIDs[ 1 ] )
+ {
+ xYieldRequired = xSecondTimerHandler();
+ }
+ else
+ {
+ /* The high frequency timer is also used to generate the time base for
+ the run time state. */
+ ulHighFrequencyTimerCounts++;
+
+ /* Latch the highest interrupt nesting count detected. */
+ if( ulPortInterruptNesting > ulMaxRecordedNesting )
{
- ulTimer2Count++;
+ ulMaxRecordedNesting = ulPortInterruptNesting;
}
- TickCount++;
+
+ xYieldRequired = pdFALSE;
}
-}
-#if 0
-int SetupTimer(int DeviceID)
-{
- int Status;
- XTtcPs_Config *Config;
- XTtcPs *Timer;
- TmrCntrSetup *TimerSetup;
-
- TimerSetup = &SettingsTable;
-
- Timer = &TtcPsInst;
- /*
- * Stop the timer first
- */
- XTtcPs_Stop( &TtcPsInst );
-
- /*
- * Look up the configuration based on the device identifier
- */
- Config = XTtcPs_LookupConfig(DeviceIDs[ DeviceID ]);
- configASSERT( Config );
-
- /*
- * Initialize the device
- */
- Status = XTtcPs_CfgInitialize(Timer, Config, Config->BaseAddress);
- configASSERT(Status == XST_SUCCESS);
-
- /*
- * Set the options
- */
- XTtcPs_SetOptions(Timer, TimerSetup->Options);
-
- /*
- * Timer frequency is preset in the TimerSetup structure,
- * however, the value is not reflected in its other fields, such as
- * IntervalValue and PrescalerValue. The following call will map the
- * frequency to the interval and prescaler values.
- */
- XTtcPs_CalcIntervalFromFreq(Timer, TimerSetup->OutputHz,
- &(TimerSetup->Interval), &(TimerSetup->Prescaler));
-
- /*
- * Set the interval and prescale
- */
- XTtcPs_SetInterval(Timer, TimerSetup->Interval);
- XTtcPs_SetPrescaler(Timer, TimerSetup->Prescaler);
-
- return XST_SUCCESS;
+ /* If xYieldRequired is not pdFALSE then calling either xFirstTimerHandler()
+ or xSecondTimerHandler() resulted in a task leaving the blocked state and
+ the task that left the blocked state had a priority higher than the currently
+ running task (the task this interrupt interrupted) - so a context switch
+ should be performed so the interrupt returns directly to the higher priority
+ task. xYieldRequired is tested inside the following macro. */
+ portYIELD_FROM_ISR( xYieldRequired );
}
-#endif
diff --git a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
index 3019fc0c8..f6f632573 100644
--- a/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
+++ b/FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo/src/main_full.c
@@ -324,6 +324,11 @@ unsigned long ulErrorFound = pdFALSE;
/* Check all the demo tasks (other than the flash tasks) to ensure
that they are all still running, and that none have detected an error. */
+ if( xAreIntQueueTasksStillRunning() != pdTRUE )
+ {
+ ulErrorFound = pdTRUE;
+ }
+
if( xAreMathsTaskStillRunning() != pdTRUE )
{
ulErrorFound = pdTRUE;