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