unsigned portLONG ulSpeed;\r
unsigned portLONG ulCD;\r
xComPortHandle xReturn = serHANDLE;\r
-extern void ( vUART_ISR )( void );\r
+extern void ( vUART_ISR_Wrapper )( void );\r
\r
/* The queues are used in the serial ISR routine, so are created from\r
serialISR.c (which is always compiled to ARM mode. */\r
/* Setup the interrupt for USART0.\r
\r
Store interrupt handler function address in USART0 vector register... */\r
- AT91C_BASE_AIC->AIC_SVR[ portUSART0_AIC_CHANNEL ] = (unsigned long)vUART_ISR;\r
+ AT91C_BASE_AIC->AIC_SVR[ portUSART0_AIC_CHANNEL ] = (unsigned long)vUART_ISR_Wrapper;\r
\r
/* USART0 interrupt level-sensitive, priority 1... */\r
AT91C_BASE_AIC->AIC_SMR[ portUSART0_AIC_CHANNEL ] = AIC_SRCTYPE_INT_LEVEL_SENSITIVE | 1;\r
\r
/* UART0 interrupt service routine. This can cause a context switch so MUST\r
be declared "naked". */\r
-void vUART_ISR( void ) __attribute__ ((naked));\r
+void vUART_ISR_Wrapper( void ) __attribute__ ((naked));\r
+\r
+/* The ISR function that actually performs the work. This must be separate \r
+from the wrapper to ensure the correct stack frame is set up. */\r
+void vUART_ISR_Handler( void );\r
\r
/*-----------------------------------------------------------*/\r
void vSerialISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx )\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vUART_ISR( void )\r
+void vUART_ISR_Wrapper( void )\r
{\r
- /* This ISR can cause a context switch, so the first statement must be a\r
- call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any\r
- variable declarations. */\r
- portENTER_SWITCHING_ISR();\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
\r
- /* Now we can declare the local variables. These must be static. */\r
- static signed portCHAR cChar;\r
- static portBASE_TYPE xTaskWokenByTx, xTaskWokenByRx;\r
- static unsigned portLONG ulStatus;\r
+ /* Call the handler. This must be a separate function to ensure the \r
+ stack frame is correctly set up. */\r
+ vUART_ISR_Handler();\r
\r
- /* These variables are static so need initialising manually here. */\r
- xTaskWokenByTx = pdFALSE;\r
- xTaskWokenByRx = pdFALSE;\r
+ /* Restore the context of whichever task will run next. */\r
+ portRESTORE_CONTEXT();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vUART_ISR_Handler( void )\r
+{\r
+/* Now we can declare the local variables. These must be static. */\r
+signed portCHAR cChar;\r
+portBASE_TYPE xTaskWokenByTx = pdFALSE, xTaskWokenByRx = pdFALSE;\r
+unsigned portLONG ulStatus;\r
\r
/* What caused the interrupt? */\r
ulStatus = AT91C_BASE_US0->US_CSR & AT91C_BASE_US0->US_IMR;\r
/* Acknowledge the interrupt at AIC level... */\r
AT91C_BASE_AIC->AIC_EOICR = serCLEAR_AIC_INTERRUPT;\r
\r
- /* Exit the ISR. If a task was woken by either a character being received\r
- or transmitted then a context switch will occur. */\r
- portEXIT_SWITCHING_ISR( ( xTaskWokenByTx || xTaskWokenByRx ) );\r
+ /* If an event caused a task to unblock then we call "Yield from ISR" to\r
+ ensure that the unblocked task is the task that executes when the interrupt\r
+ completes if the unblocked task has a priority higher than the interrupted\r
+ task. */\r
+ if( xTaskWokenByTx || xTaskWokenByRx )\r
+ {\r
+ portYIELD_FROM_ISR();\r
+ }\r
}\r
/*-----------------------------------------------------------*/\r
\r
#define configTICK_RATE_HZ ( ( portTickType ) 1000 )\r
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )\r
#define configMINIMAL_STACK_SIZE ( ( unsigned portSHORT ) 128 )\r
-#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 23 * 1024 ) )\r
+#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 24 * 1024 ) )\r
#define configMAX_TASK_NAME_LEN ( 16 )\r
#define configUSE_TRACE_FACILITY 0\r
#define configUSE_16_BIT_TICKS 0\r
/* Priorities for the demo application tasks. */\r
#define mainLED_TASK_PRIORITY ( tskIDLE_PRIORITY + 3 )\r
#define mainCOM_TEST_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
-#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
+#define mainQUEUE_POLL_PRIORITY ( tskIDLE_PRIORITY + 0 )\r
#define mainCHECK_TASK_PRIORITY ( tskIDLE_PRIORITY + 4 )\r
-#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )\r
+#define mainSEM_TEST_PRIORITY ( tskIDLE_PRIORITY + 0 )\r
#define mainBLOCK_Q_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
\r
/* The rate at which the on board LED will toggle when there is/is not an \r
parameter. */\r
ulMemCheckTaskRunningCount = mainCOUNT_INITIAL_VALUE;\r
xCreatedTask = mainNO_TASK;\r
+\r
if( xTaskCreate( vMemCheckTask, ( signed portCHAR * ) "MEM_CHECK", configMINIMAL_STACK_SIZE, ( void * ) &ulMemCheckTaskRunningCount, tskIDLE_PRIORITY, &xCreatedTask ) != pdPASS )\r
{\r
/* Could not create the task - we have probably run out of heap. */\r
{\r
unsigned portLONG ulDivisor, ulWantedClock;\r
xComPortHandle xReturn = serHANDLE;\r
-extern void ( vUART_ISR )( void );\r
+extern void ( vUART_ISR_Wrapper )( void );\r
\r
/* The queues are used in the serial ISR routine, so are created from\r
serialISR.c (which is always compiled to ARM mode. */\r
/* Setup the VIC for the UART. */\r
VICIntSelect &= ~( serUART0_VIC_CHANNEL_BIT );\r
VICIntEnable |= serUART0_VIC_CHANNEL_BIT;\r
- VICVectAddr1 = ( portLONG ) vUART_ISR;\r
+ VICVectAddr1 = ( portLONG ) vUART_ISR_Wrapper;\r
VICVectCntl1 = serUART0_VIC_CHANNEL | serUART0_VIC_ENABLE;\r
\r
/* Enable UART0 interrupts. */\r
*/\r
void vSerialISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, xQueueHandle *pxCharsForTx, portLONG volatile **pplTHREEmptyFlag );\r
\r
-/* UART0 interrupt service routine. This can cause a context switch so MUST\r
-be declared "naked". */\r
-void vUART_ISR( void ) __attribute__ ((naked));\r
+/* UART0 interrupt service routine entry point. */\r
+void vUART_ISR_Wrapper( void ) __attribute__ ((naked));\r
+\r
+/* UART0 interrupt service routine handler. */\r
+void vUART_ISR_Handler( void );\r
\r
/*-----------------------------------------------------------*/\r
void vSerialISRCreateQueues( unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRxedChars, \r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vUART_ISR( void )\r
+void vUART_ISR_Wrapper( void )\r
{\r
- /* This ISR can cause a context switch, so the first statement must be a\r
- call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any\r
- variable declarations. */\r
- portENTER_SWITCHING_ISR();\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* Call the handler. This must be a separate function from the wrapper\r
+ to ensure the correct stack frame is set up. */\r
+ vUART_ISR_Handler();\r
\r
- /* Now we can declare the local variables. These must be static. */\r
- static signed portCHAR cChar;\r
- static portBASE_TYPE xTaskWokenByTx, xTaskWokenByRx;\r
+ /* Restore the context of whichever task is going to run next. */\r
+ portRESTORE_CONTEXT();\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
- /* As these variables are static they must be initialised manually here. */\r
- xTaskWokenByTx = pdFALSE;\r
- xTaskWokenByRx = pdFALSE;\r
+void vUART_ISR_Handler( void )\r
+{\r
+signed portCHAR cChar;\r
+portBASE_TYPE xTaskWokenByTx = pdFALSE, xTaskWokenByRx = pdFALSE;\r
\r
/* What caused the interrupt? */\r
switch( UART0_IIR & serINTERRUPT_SOURCE_MASK )\r
break;\r
}\r
\r
+ if( xTaskWokenByTx || xTaskWokenByRx )\r
+ {\r
+ portYIELD_FROM_ISR();\r
+ }\r
+\r
/* Clear the ISR in the VIC. */\r
VICVectAddr = serCLEAR_VIC_INTERRUPT;\r
-\r
- /* Exit the ISR. If a task was woken by either a character being received\r
- or transmitted then a context switch will occur. */\r
- portEXIT_SWITCHING_ISR( ( xTaskWokenByTx || xTaskWokenByRx ) );\r
}\r
-/*-----------------------------------------------------------*/\r
+\r
\r
\r
\r
#define mainLED_DELAY ( ( portTickType ) 500 / portTICK_RATE_MS )\r
#define mainCHECK_DELAY ( ( portTickType ) 5000 / portTICK_RATE_MS )\r
#define mainLIST_BUFFER_SIZE 2048\r
+#define mainNO_DELAY ( 0 )\r
+#define mainSHORT_DELAY ( 150 / portTICK_RATE_MS )\r
\r
/* Task priorities. */\r
#define mainLED_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )\r
/* Start the scheduler. */\r
vTaskStartScheduler();\r
\r
- /* The scheduler should now running, so we will only ever reach here if we\r
+ /* The scheduler should now be running, so we will only ever reach here if we\r
ran out of heap space. */\r
\r
return 0;\r
static portCHAR cListBuffer[ mainLIST_BUFFER_SIZE ];\r
const portCHAR *pcList = &( cListBuffer[ 0 ] );\r
const portCHAR * const pcHeader = "\nTask State Priority Stack #\n************************************************";\r
-extern void (vButtonISR) ( void );\r
+extern void (vButtonISRWrapper) ( void );\r
\r
/* Configure the interrupt. */\r
portENTER_CRITICAL(); \r
/* Setup the VIC for EINT 1. */\r
VICIntSelect &= ~mainEINT_1_VIC_CHANNEL_BIT;\r
VICIntEnable |= mainEINT_1_VIC_CHANNEL_BIT;\r
- VICVectAddr1 = ( portLONG ) vButtonISR;\r
+ VICVectAddr1 = ( portLONG ) vButtonISRWrapper;\r
VICVectCntl1 = mainEINT_1_ENABLE_BIT | mainEINT_1_CHANNEL;\r
}\r
portEXIT_CRITICAL();\r
\r
for( ;; )\r
{\r
+ /* For debouncing, wait a while then clear the semaphore. */\r
+ vTaskDelay( mainSHORT_DELAY );\r
+ xSemaphoreTake( xButtonSemaphore, mainNO_DELAY );\r
+\r
/* Wait for an interrupt. */\r
- while( xSemaphoreTake( xButtonSemaphore, portMAX_DELAY ) != pdPASS );\r
+ xSemaphoreTake( xButtonSemaphore, portMAX_DELAY );\r
\r
/* Send the column headers to the print task for display. */\r
xQueueSend( xPrintQueue, &pcHeader, portMAX_DELAY );\r
\r
/*\r
* Interrupt routine that simply wakes vButtonHandlerTask on each interrupt \r
- * generated by a push of the built in button.\r
+ * generated by a push of the built in button. The wrapper takes care of\r
+ * the ISR entry. This then calls the actual handler function to perform\r
+ * the work. This work should not be done in the wrapper itself unless\r
+ * you are absolutely sure that no stack space is used.\r
*/\r
-void vButtonISR( void ) __attribute__ ((naked));\r
+void vButtonISRWrapper( void ) __attribute__ ((naked));\r
+void vButtonHandler( void );\r
+\r
+void vButtonHandler( void )\r
+{\r
extern xSemaphoreHandle xButtonSemaphore;\r
\r
-void vButtonISR( void )\r
+ if( xSemaphoreGiveFromISR( xButtonSemaphore, pdFALSE ) )\r
+ {\r
+ /* We have woken a task. Calling "yield from ISR" here will ensure\r
+ the interrupt returns to the woken task if it has a priority higher\r
+ than the interrupted task. */\r
+ portYIELD_FROM_ISR();\r
+ }\r
+\r
+ EXTINT = isrCLEAR_EINT_1;\r
+ VICVectAddr = 0;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vButtonISRWrapper( void )\r
{\r
- portENTER_SWITCHING_ISR();\r
- xSemaphoreGiveFromISR( xButtonSemaphore, pdFALSE );\r
- EXTINT = isrCLEAR_EINT_1;\r
- VICVectAddr = 0;\r
- portEXIT_SWITCHING_ISR( pdTRUE );\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* Call the handler to do the work. This must be a separate function to\r
+ the wrapper to ensure the correct stack frame is set up. */\r
+ vButtonHandler();\r
+\r
+ /* Restore the context of whichever task is going to run once the interrupt\r
+ completes. */\r
+ portRESTORE_CONTEXT();\r
}\r
\r
\r
#include "Semphr.h"\r
#include "Task.h"\r
\r
-void vEMAC_ISR( void ) __attribute__((naked));\r
+/* The interrupt entry point. */\r
+void vEMAC_ISR_Wrapper( void ) __attribute__((naked));\r
\r
-extern xSemaphoreHandle xEMACSemaphore;\r
+/* The handler that does the actual work. */\r
+void vEMAC_ISR_Handler( void );\r
\r
-void vEMAC_ISR( void )\r
-{\r
- portENTER_SWITCHING_ISR();\r
+extern xSemaphoreHandle xEMACSemaphore;\r
\r
- static portBASE_TYPE xSwitchRequired;\r
\r
- xSwitchRequired = pdFALSE;\r
+void vEMAC_ISR_Handler( void )\r
+{\r
+portBASE_TYPE xSwitchRequired = pdFALSE;\r
\r
/* Clear the interrupt. */\r
MAC_INTCLEAR = 0xffff;\r
/* Ensure the uIP task is not blocked as data has arrived. */\r
if( xSemaphoreGiveFromISR( xEMACSemaphore, pdFALSE ) )\r
{\r
- xSwitchRequired = pdTRUE;\r
+ /* Giving the semaphore woke a task. */\r
+ portYIELD_FROM_ISR();\r
}\r
-\r
- /* Switch to the uIP task. */\r
- portEXIT_SWITCHING_ISR( xSwitchRequired );\r
}\r
+/*-----------------------------------------------------------*/\r
\r
+void vEMAC_ISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+ \r
+ /* Call the handler. This must be a separate function unless you can\r
+ guarantee that no stack will be used. */\r
+ vEMAC_ISR_Handler();\r
+ \r
+ /* Restore the context of whichever task is going to run next. */\r
+ portRESTORE_CONTEXT();\r
+}\r
\r
#define uipIP_ADDR0 172\r
#define uipIP_ADDR1 25\r
#define uipIP_ADDR2 218\r
-#define uipIP_ADDR3 10 \r
+#define uipIP_ADDR3 16 \r
\r
/* How long to wait before attempting to connect the MAC again. */\r
#define uipINIT_WAIT 100\r
portBASE_TYPE i;\r
uip_ipaddr_t xIPAddr;\r
struct timer periodic_timer, arp_timer;\r
-extern void ( vEMAC_ISR )( void );\r
+extern void ( vEMAC_ISR_Wrapper )( void );\r
\r
/* Create the semaphore used by the ISR to wake this task. */\r
vSemaphoreCreateBinary( xEMACSemaphore );\r
{\r
MAC_INTENABLE = INT_RX_DONE;\r
VICIntEnable |= 0x00200000;\r
- VICVectAddr21 = ( portLONG ) vEMAC_ISR;\r
+ VICVectAddr21 = ( portLONG ) vEMAC_ISR_Wrapper;\r
prvSetMACAddress();\r
}\r
portEXIT_CRITICAL();\r
#include "Semphr.h"\r
#include "Task.h"\r
\r
-void vEMAC_ISR( void ) __attribute__((naked));\r
+/* The interrupt entry point. */\r
+void vEMAC_ISR_Wrapper( void ) __attribute__((naked));\r
+\r
+/* The function that actually performs the interrupt processing. This must be \r
+separate to the wrapper to ensure the correct stack frame is set up. */\r
+void vEMAC_ISR_Handler( void );\r
\r
extern xSemaphoreHandle xEMACSemaphore;\r
\r
-void vEMAC_ISR( void )\r
+void vEMAC_ISR_Handler( void )\r
{\r
- portENTER_SWITCHING_ISR();\r
-\r
-\r
- /* Variable must be static. */\r
- static portBASE_TYPE xSwitchRequired;\r
-\r
- /* As the variable is static it must be manually initialised here. */\r
- xSwitchRequired = pdFALSE;\r
-\r
/* Clear the interrupt. */\r
IntClear = 0xffff;\r
VICVectAddr = 0;\r
/* Ensure the uIP task is not blocked as data has arrived. */\r
if( xSemaphoreGiveFromISR( xEMACSemaphore, pdFALSE ) )\r
{\r
- xSwitchRequired = pdTRUE;\r
+ /* If the uIP task was unblocked then calling "Yield from ISR" here\r
+ will ensure the interrupt returns directly to the uIP task, if it\r
+ is the highest priority read task. */\r
+ portYIELD_FROM_ISR();\r
}\r
+}\r
+/*-----------------------------------------------------------*/\r
\r
- /* Switch to the uIP task. */\r
- portEXIT_SWITCHING_ISR( xSwitchRequired );\r
+void vEMAC_ISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* Call the handler function. This must be separate from the wrapper\r
+ function to ensure the correct stack frame is set up. */\r
+ vEMAC_ISR_Handler();\r
+\r
+ /* Restore the context of whichever task is going to run next. */\r
+ portRESTORE_CONTEXT();\r
}\r
\r
\r
+\r
+\r
portBASE_TYPE i;\r
uip_ipaddr_t xIPAddr;\r
struct timer periodic_timer, arp_timer;\r
-extern void ( vEMAC_ISR )( void );\r
+extern void ( vEMAC_ISR_Wrapper )( void );\r
\r
/* Create the semaphore used by the ISR to wake this task. */\r
vSemaphoreCreateBinary( xEMACSemaphore );\r
{\r
IntEnable = INT_RX_DONE;\r
VICIntEnable |= 0x00200000;\r
- VICVectAddr21 = ( portLONG ) vEMAC_ISR;\r
+ VICVectAddr21 = ( portLONG ) vEMAC_ISR_Wrapper;\r
prvSetMACAddress();\r
}\r
portEXIT_CRITICAL();\r
/* Install the ISR into the VIC - but don't enable it yet! */\r
portENTER_CRITICAL();\r
{\r
- extern void ( vEINT0_ISR )( void );\r
+ extern void ( vEINT0_ISR_Wrapper )( void );\r
\r
VICIntSelect &= ~( tcpEINT0_VIC_CHANNEL_BIT );\r
- VICVectAddr3 = ( portLONG ) vEINT0_ISR;\r
+ VICVectAddr3 = ( portLONG ) vEINT0_ISR_Wrapper;\r
\r
VICVectCntl3 = tcpEINT0_VIC_CHANNEL | tcpEINT0_VIC_ENABLE;\r
}\r
#define tcpEINT0_VIC_CHANNEL_BIT ( ( unsigned portLONG ) 0x4000 )\r
\r
/* EINT0 interrupt handler. This processes interrupts from the WIZnet device. */\r
-void vEINT0_ISR( void ) __attribute__((naked));\r
+void vEINT0_ISR_Wrapper( void ) __attribute__((naked));\r
+\r
+/* The handler that goes with the EINT0 wrapper. */\r
+void vEINT0_ISR_Handler( void );\r
\r
/* Variable is required for its address, but does not otherwise get used. */\r
static portLONG lDummyVariable;\r
* the TCP task. This wakes the task so the interrupt can be processed. The\r
* source of the interrupt has to be ascertained by the TCP task as this \r
* requires an I2C transaction which cannot be performed from this ISR.\r
+ * Note this code predates the introduction of semaphores, a semaphore should\r
+ * be used in place of the empty queue message.\r
*/\r
-void vEINT0_ISR( void )\r
+void vEINT0_ISR_Handler( void )\r
{\r
- portENTER_SWITCHING_ISR();\r
-\r
- extern xQueueHandle xTCPISRQueue;\r
-\r
- /* Must be declared static. */\r
- static portBASE_TYPE xTaskWoken;\r
-\r
- /* As the variable is static it must be manually initialised. */\r
- xTaskWoken = pdFALSE;\r
+extern xQueueHandle xTCPISRQueue;\r
+portBASE_TYPE xTaskWoken = pdFALSE;\r
\r
/* Just wake the TCP task so it knows an ISR has occurred. */\r
- xQueueSendFromISR( xTCPISRQueue, ( void * ) &lDummyVariable, xTaskWoken ); \r
+ xTaskWoken = xQueueSendFromISR( xTCPISRQueue, ( void * ) &lDummyVariable, xTaskWoken ); \r
\r
/* We cannot carry on processing interrupts until the TCP task has \r
processed this one - so for now interrupts are disabled. The TCP task will\r
/* Clear the interrupt bit. */ \r
VICVectAddr = tcpCLEAR_VIC_INTERRUPT;\r
\r
- /* Switch to the TCP task immediately so the cause of the interrupt can\r
- be ascertained. It is the responsibility of the TCP task to clear the\r
- interrupts. */\r
- portEXIT_SWITCHING_ISR( ( xTaskWoken ) );\r
+ if( xTaskWoken )\r
+ {\r
+ portYIELD_FROM_ISR();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vEINT0_ISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* The handler must be a separate function from the wrapper to\r
+ ensure the correct stack frame is set up. */\r
+ vEINT0_ISR_Handler();\r
+\r
+ /* Restore the context of whichever task is going to run next. */\r
+ portRESTORE_CONTEXT();\r
}\r
\r
\r
\r
void i2cInit( void )\r
{\r
-extern void ( vI2C_ISR )( void );\r
+extern void ( vI2C_ISR_Wrapper )( void );\r
\r
/* Create the queue used to send messages to the ISR. */\r
vI2CISRCreateQueues( i2cQUEUE_LENGTH, &xMessagesForTx, &pulBusFree );\r
/* Setup the VIC for the i2c interrupt. */\r
VICIntSelect &= ~( i2cI2C_VIC_CHANNEL_BIT );\r
VICIntEnable |= i2cI2C_VIC_CHANNEL_BIT;\r
- VICVectAddr2 = ( portLONG ) vI2C_ISR;\r
+ VICVectAddr2 = ( portLONG ) vI2C_ISR_Wrapper;\r
\r
VICVectCntl2 = i2cI2C_VIC_CHANNEL | i2cI2C_VIC_ENABLE;\r
}\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vI2C_ISR( void ) __attribute__ (( naked ));\r
-void vI2C_ISR( void )\r
-{\r
- portENTER_SWITCHING_ISR();\r
+/* The ISR entry point. */\r
+void vI2C_ISR_Wrapper( void ) __attribute__ (( naked ));\r
\r
- /* Variables must be static. */\r
+/* The ISR function to perform the actual work. This must be a separate\r
+function from the wrapper to ensure the correct stack frame is set up. */\r
+void vI2C_ISR_Handler( void );\r
\r
- /* Holds the current transmission state. */ \r
- static I2C_STATE eCurrentState = eSentStart;\r
- static portLONG lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */\r
- static portBASE_TYPE xTaskWokenByTx;\r
- static portLONG lBytesLeft;\r
+/*-----------------------------------------------------------*/\r
\r
- xTaskWokenByTx = pdFALSE;\r
+void vI2C_ISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
\r
+ /* Call the handler to perform the actual work. This must be a\r
+ separate function to ensure the correct stack frame is set up. */\r
+ vI2C_ISR_Handler();\r
+\r
+ /* Restore the context of whichever task is going to run next. */\r
+ portRESTORE_CONTEXT();\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vI2C_ISR_Handler( void )\r
+{\r
+/* Holds the current transmission state. */ \r
+static I2C_STATE eCurrentState = eSentStart;\r
+static portLONG lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */\r
+portBASE_TYPE xTaskWokenByTx = pdFALSE;\r
+portLONG lBytesLeft;\r
\r
/* The action taken for this interrupt depends on our current state. */\r
switch( eCurrentState )\r
I2C_I2CONCLR = i2cSI_BIT;\r
VICVectAddr = i2cCLEAR_VIC_INTERRUPT;\r
\r
- portEXIT_SWITCHING_ISR( ( xTaskWokenByTx ) );\r
+ if( xTaskWokenByTx )\r
+ {\r
+ portYIELD_FROM_ISR();\r
+ }\r
}\r
/*-----------------------------------------------------------*/\r
\r
/* See the header file for descriptions of public functions. */\r
\r
/*\r
- * Prototype for the EMAC interrupt function - called by the asm wrapper.\r
+ * Prototype for the EMAC interrupt function.\r
*/\r
-void vEMACISR( void ) __attribute__ ((naked));\r
+void vEMACISR_Wrapper( void ) __attribute__ ((naked));\r
\r
/*\r
* Initialise both the Tx and Rx descriptors used by the EMAC.\r
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP | AT91C_EMAC_TCOMP;\r
\r
/* Enable the interrupts in the AIC. */\r
- AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR );\r
+ AT91F_AIC_ConfigureIt( AT91C_ID_EMAC, emacINTERRUPT_LEVEL, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vEMACISR_Wrapper );\r
AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_EMAC;\r
}\r
portEXIT_CRITICAL();\r
***************************************************************************\r
*/\r
\r
-/* \r
-Changes from V3.2.4\r
-\r
- + Also read the EMAC_RSR register in the EMAC ISR as a work around the \r
- the EMAC bug that can reset the RX bit in EMAC_ISR register before the\r
- bit has been read.\r
-\r
-Changes from V4.0.1\r
-\r
- + Only check the interrupt status register to see if an EMAC Tx interrupt\r
- has occurred. Previously the TSR register was also inspected.\r
-*/\r
\r
#include "FreeRTOS.h"\r
#include "task.h"\r
task. */\r
static xSemaphoreHandle xSemaphore = NULL;\r
\r
-void vEMACISR( void ) __attribute__((naked));\r
+/* The interrupt entry point is naked so we can control the context saving. */\r
+void vEMACISR_Wrapper( void ) __attribute__((naked));\r
+\r
+/* The interrupt handler function must be separate from the entry function\r
+to ensure the correct stack frame is set up. */\r
+void vEMACISR_Handler( void );\r
\r
/*-----------------------------------------------------------*/\r
/*\r
* The EMAC ISR. Handles both Tx and Rx complete interrupts.\r
*/\r
-void vEMACISR( void )\r
+void vEMACISR_Handler( void )\r
{\r
- /* This ISR can cause a context switch, so the first statement must be a\r
- call to the portENTER_SWITCHING_ISR() macro. This must be BEFORE any\r
- variable declarations. */\r
- portENTER_SWITCHING_ISR();\r
-\r
- /* Variable definitions can be made now. These must be static. */\r
- static volatile unsigned portLONG ulIntStatus, ulEventStatus;\r
- static portBASE_TYPE xSwitchRequired;\r
- extern void vClearEMACTxBuffer( void );\r
-\r
- /* As the variable is static it must be initialised manually here. */\r
- xSwitchRequired = pdFALSE;\r
+volatile unsigned portLONG ulIntStatus, ulEventStatus;\r
+portBASE_TYPE xSwitchRequired = pdFALSE;\r
+extern void vClearEMACTxBuffer( void );\r
\r
/* Find the cause of the interrupt. */\r
ulIntStatus = AT91C_BASE_EMAC->EMAC_ISR;\r
AT91C_BASE_AIC->AIC_EOICR = 0;\r
\r
/* If a task was woken by either a frame being received then we may need to \r
- switch to another task. */\r
- portEXIT_SWITCHING_ISR( xSwitchRequired );\r
+ switch to another task. If the unblocked task was of higher priority then\r
+ the interrupted task it will then execute immediately that the ISR\r
+ completes. */\r
+ if( xSwitchRequired )\r
+ {\r
+ portYIELD_FROM_ISR();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vEMACISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* Call the handler to do the work. This must be a separate\r
+ function to ensure the stack frame is set up correctly. */\r
+ vEMACISR_Handler();\r
+\r
+ /* Restore the context of whichever task will execute next. */\r
+ portRESTORE_CONTEXT();\r
}\r
/*-----------------------------------------------------------*/\r
\r
\r
static void vInitUSBInterface( void )\r
{\r
-extern void ( vUSB_ISR )( void );\r
+extern void ( vUSB_ISR_Wrapper )( void );\r
\r
/* Create the queue used to communicate between the USB ISR and task. */\r
xUSBInterruptQueue = xQueueCreate( usbQUEUE_LENGTH + 1, sizeof( xISRStatus * ) );\r
\r
/* Enable the USB interrupts - other interrupts get enabled as the \r
enumeration process progresses. */\r
- AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR );\r
+ AT91F_AIC_ConfigureIt( AT91C_ID_UDP, usbINTERRUPT_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vUSB_ISR_Wrapper );\r
AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_UDP;\r
\r
\r
/*-----------------------------------------------------------*/\r
\r
/* The ISR can cause a context switch so is declared naked. */\r
-void vUSB_ISR( void ) __attribute__ ((naked));\r
+void vUSB_ISR_Wrapper( void ) __attribute__ ((naked));\r
\r
+/* The function that actually performs the ISR work. This must be separate\r
+from the wrapper function to ensure the correct stack frame gets set up. */\r
+void vUSB_ISR_Handler( void );\r
/*-----------------------------------------------------------*/\r
\r
-\r
-void vUSB_ISR( void )\r
+void vUSB_ISR_Handler( void )\r
{\r
- /* This ISR can cause a context switch. Therefore a call to the \r
- portENTER_SWITCHING_ISR() macro is made. This must come BEFORE any \r
- stack variable declarations. */\r
- portENTER_SWITCHING_ISR();\r
-\r
- /* Now variables can be declared. These must be static. */\r
- static portCHAR cTaskWokenByPost; \r
- static volatile unsigned portLONG ulNextMessage = 0;\r
- static xISRStatus *pxMessage;\r
- static unsigned portLONG ulRxBytes;\r
- static unsigned portCHAR ucFifoIndex;\r
-\r
- /* As the variables are static they must be initialised manually here. */\r
- cTaskWokenByPost = pdFALSE; \r
+portCHAR cTaskWokenByPost = pdFALSE;\r
+static volatile unsigned portLONG ulNextMessage = 0;\r
+xISRStatus *pxMessage;\r
+unsigned portLONG ulRxBytes;\r
+unsigned portCHAR ucFifoIndex;\r
\r
/* Use the next message from the array. */\r
pxMessage = &( xISRMessages[ ( ulNextMessage & usbQUEUE_LENGTH ) ] );\r
AT91C_BASE_AIC->AIC_EOICR = 0;\r
\r
/* Do a task switch if needed */\r
- portEXIT_SWITCHING_ISR( cTaskWokenByPost )\r
+ if( cTaskWokenByPost )\r
+ {\r
+ /* This call will ensure that the unblocked task will be executed\r
+ immediately upon completion of the ISR if it has a priority higher\r
+ than the interrupted task. */\r
+ portYIELD_FROM_ISR();\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void vUSB_ISR_Wrapper( void )\r
+{\r
+ /* Save the context of the interrupted task. */\r
+ portSAVE_CONTEXT();\r
+\r
+ /* Call the handler to do the work. This must be a separate\r
+ function to ensure the stack frame is set up correctly. */\r
+ vUSB_ISR_Handler();\r
+\r
+ /* Restore the context of whichever task will execute next. */\r
+ portRESTORE_CONTEXT();\r
}\r
\r
+\r
\r
Changes from V4.5.0\r
\r
- + The macro portENTER_SWITCHING_ISR() no longer attempts to use the frame\r
- pointer. Variables declared within ISRs must now be declared static.\r
+ + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros\r
+ and replaced them with portYIELD_FROM_ISR() macro. Application code \r
+ should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT()\r
+ macros as per the V4.5.1 demo code.\r
*/\r
\r
#ifndef PORTMACRO_H\r
#define portSTACK_GROWTH ( -1 )\r
#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ ) \r
#define portBYTE_ALIGNMENT 4\r
-#define portYIELD() asm volatile ( "SWI" ); \r
-#define portNOP() asm volatile ( "NOP" );\r
+#define portYIELD() asm volatile ( "SWI" )\r
+#define portNOP() asm volatile ( "NOP" )\r
\r
/*\r
* These define the timer to use for generating the tick interrupt.\r
( void ) pxCurrentTCB; \\r
}\r
\r
-/*-----------------------------------------------------------\r
- * ISR entry and exit macros. These are only required if a task switch\r
- * is required from the ISR.\r
- *----------------------------------------------------------*/\r
-\r
-#define portENTER_SWITCHING_ISR() \\r
- /* Save the context of the interrupted task. */ \\r
- portSAVE_CONTEXT(); \\r
- {\r
-\r
-#define portEXIT_SWITCHING_ISR( SwitchRequired ) \\r
- /* If a switch is required then we just need to call */ \\r
- /* vTaskSwitchContext() as the context has already been */ \\r
- /* saved. */ \\r
- if( SwitchRequired ) \\r
- { \\r
- vTaskSwitchContext(); \\r
- } \\r
- } \\r
- /* Restore the context of which ever task is now the highest */ \\r
- /* priority that is ready to run. */ \\r
- portRESTORE_CONTEXT();\r
-/*-----------------------------------------------------------*/ \r
+#define portYIELD_FROM_ISR() vTaskSwitchContext()\r
\r
/* Critical section handling. */\r
\r
+ The assembler statements are now included in a single asm block rather\r
than each line having its own asm block.\r
\r
- + The macro portENTER_SWITCHING_ISR() no longer attempts to use the frame\r
- pointer. Variables declared within ISRs must now be declared static.\r
+ Changes from V4.5.0\r
+\r
+ + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros\r
+ and replaced them with portYIELD_FROM_ISR() macro. Application code \r
+ should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT()\r
+ macros as per the V4.5.1 demo code.\r
*/\r
\r
#ifndef PORTMACRO_H\r
}\r
\r
\r
-/*-----------------------------------------------------------\r
- * ISR entry and exit macros. These are only required if a task switch\r
- * is required from the ISR.\r
- *----------------------------------------------------------*/\r
-\r
-\r
-#define portENTER_SWITCHING_ISR() \\r
- /* Save the context of the interrupted task. */ \\r
- portSAVE_CONTEXT(); \\r
- {\r
-\r
-#define portEXIT_SWITCHING_ISR( SwitchRequired ) \\r
- /* If a switch is required then we just need to call */ \\r
- /* vTaskSwitchContext() as the context has already been */ \\r
- /* saved. */ \\r
- if( SwitchRequired ) \\r
- { \\r
- vTaskSwitchContext(); \\r
- } \\r
- } \\r
- /* Restore the context of which ever task is now the highest */ \\r
- /* priority that is ready to run. */ \\r
- portRESTORE_CONTEXT();\r
-\r
-#define portYIELD() asm volatile ( "SWI" ); \r
+#define portYIELD_FROM_ISR() vTaskSwitchContext()\r
+#define portYIELD() asm volatile ( "SWI" )\r
/*-----------------------------------------------------------*/\r
\r
\r
+ The assembler statements are now included in a single asm block rather\r
than each line having its own asm block.\r
\r
- + The macro portENTER_SWITCHING_ISR() no longer attempts to use the frame\r
- pointer. Variables declared within ISRs must now be declared static.\r
+ Changes from V4.5.0\r
+\r
+ + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros\r
+ and replaced them with portYIELD_FROM_ISR() macro. Application code \r
+ should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT()\r
+ macros as per the V4.5.1 demo code.\r
*/\r
\r
#ifndef PORTMACRO_H\r
}\r
\r
\r
-/*-----------------------------------------------------------\r
- * ISR entry and exit macros. These are only required if a task switch\r
- * is required from the ISR.\r
- *----------------------------------------------------------*/\r
-\r
-\r
-#define portENTER_SWITCHING_ISR() \\r
- /* Save the context of the interrupted task. */ \\r
- portSAVE_CONTEXT(); \\r
- {\r
-\r
-#define portEXIT_SWITCHING_ISR( SwitchRequired ) \\r
- /* If a switch is required then we just need to call */ \\r
- /* vTaskSwitchContext() as the context has already been */ \\r
- /* saved. */ \\r
- if( SwitchRequired ) \\r
- { \\r
- vTaskSwitchContext(); \\r
- } \\r
- } \\r
- /* Restore the context of which ever task is now the highest */ \\r
- /* priority that is ready to run. */ \\r
- portRESTORE_CONTEXT();\r
-\r
-#define portYIELD() asm volatile ( "SWI" ); \r
+#define portYIELD_FROM_ISR() vTaskSwitchContext()\r
+#define portYIELD() asm volatile ( "SWI" )\r
/*-----------------------------------------------------------*/\r
\r
\r
+ The assembler statements are now included in a single asm block rather\r
than each line having its own asm block.\r
\r
- + The macro portENTER_SWITCHING_ISR() no longer attempts to use the frame\r
- pointer. Variables declared within ISRs must now be declared static.\r
+ Changes from V4.5.0\r
+\r
+ + Removed the portENTER_SWITCHING_ISR() and portEXIT_SWITCHING_ISR() macros\r
+ and replaced them with portYIELD_FROM_ISR() macro. Application code \r
+ should now make use of the portSAVE_CONTEXT() and portRESTORE_CONTEXT()\r
+ macros as per the V4.5.1 demo code.\r
*/\r
\r
#ifndef PORTMACRO_H\r
}\r
\r
\r
-/*-----------------------------------------------------------\r
- * ISR entry and exit macros. These are only required if a task switch\r
- * is required from the ISR.\r
- *----------------------------------------------------------*/\r
-\r
-\r
-#define portENTER_SWITCHING_ISR() \\r
- /* Save the context of the interrupted task. */ \\r
- portSAVE_CONTEXT(); \\r
- {\r
-\r
-#define portEXIT_SWITCHING_ISR( SwitchRequired ) \\r
- /* If a switch is required then we just need to call */ \\r
- /* vTaskSwitchContext() as the context has already been */ \\r
- /* saved. */ \\r
- if( SwitchRequired ) \\r
- { \\r
- vTaskSwitchContext(); \\r
- } \\r
- } \\r
- /* Restore the context of which ever task is now the highest */ \\r
- /* priority that is ready to run. */ \\r
- portRESTORE_CONTEXT();\r
-\r
-#define portYIELD() asm volatile ( "SWI" ); \r
+#define portYIELD_FROM_ISR() vTaskSwitchContext()\r
+#define portYIELD() asm volatile ( "SWI" )\r
/*-----------------------------------------------------------*/\r
\r
\r