nobody wrote on Thursday, February 24, 2005:
Hi,
I am using an ATmega128L with an 8MHz clock. FreeRTOS is configured to for a tick rate of 4KHz.
I have three tasks. Task0 and Task1 are IDLE priority tasks that use vTaskDelayUntil(…) to wake up every 2000 and 1000 ticks, respectively. Everytime these two tasks run, they simply toggle a LED each.
There is an ISR that uses timer/counter0 to trigger an overflow interrupt every 1ms (1KHz rate). Each time, the ISR sends a message to Task2 containing a pointer to a CHAR buffer using cQueueSendFromISR(…). The ISR sets a LED when it enters and clears the LED when it exits.
Task2 is a higher priority ISR (idle+1) that blocks for 8000 ticks on a message from ISR. When it receives a message it performs a simple loop through the message. Task2 also sets a LED when it has successfully received a message and clears the LED when it has finished its work.
I would have expected the following behavior from the LEDS on the ISR and Task2:
T2: xxxxOOOxxxxOOOxxxxOOOxxxxOOO…
ISR:xxOOxxxxxxOOxxxxxOOxxxxxOO…
But instead I see,
T2: xxxxOOxxxxxxxOOxxxxxxOOxxxxxxOO…
ISR:xxxOOOOxxxxOOOOxxxOOOOxxxOOOO…
How can T2 execute before ISR has finished executing? Is it possible that there is a context switch occuring inside the ISR before it has even finished executing (because after all the FreeRTOS tick rate is 4KHz where as the ISR rate is only 1KHz).
I would appreciate any help on the subject. I have included my code in case it helps. If you need the makefile, I have that too, I can email the whole thing.
******* CODE *******
/**************************************************************************************
**
**
** Tasks:
** 1. Task0: Low priority task that toggles a led every few ticks.
** 2. Task1: Another low priority task that toggle another led every few ticks.
** 3. Task2: The high priority task that’s waiting for a message containing a CHAR
** buffer from ISR.
**
** ISR: Sends a CHAR buffer to Task2 every 1ms (1KHz)
**
** Diagnostics:
** Task0 and Task1 toggle LEDS everytime they execute.
** ISR sets a led when it is entered, and clears the led when it exits.
** Task2 sets a led when cQueueReceive is successfull and clears a led when it’s done.
**
** Problems:
**
**
***************************************************************************************/
#include <stdlib.h>
#include "projdefs.h"
#include "portable.h"
#include "task.h"
#include "queue.h"
/* This is just because the program used to consists of many files but now combined into one. */
#define _SINGLE_FILE_
#if defined (_SINGLE_FILE_)
#include <avr/signal.h>
#include <avr/interrupt.h>
#else
#include "types.h"
#include "task0.h"
#include "task1.h"
#include "task2.h"
#include "ISR.h"
#endif
#define TASK0_PRIORITY ( tskIDLE_PRIORITY )
#define TASK1_PRIORITY ( tskIDLE_PRIORITY )
#define TASK2_PRIORITY ( tskIDLE_PRIORITY + ( unsigned portCHAR ) 1 )
#if defined (_SINGLE_FILE_)
#define SET_STATUS_LED()
PORTB |= 0x80;
#define CLEAR_STATUS_LED()
PORTB &= 0x7F;
#define TOGGLE_STATUS_LED()
PORTB ^= 0x80;
#define TOGGLE_TEST1_LED()
PORTE ^= 0x08;
#define SET_TEST1_LED()
PORTE |= 0x08;
#define CLEAR_TEST1_LED()
PORTE &= 0xF7;
#define TOGGLE_TEST2_LED()
PORTB ^= 0x10;
#define TOGGLE_TEST3_LED()
PORTE ^= 0x10;
#define SET_TEST3_LED()
PORTE |= 0x10;
#define CLEAR_TEST3_LED()
PORTE &= 0xEF;
#define MAX_MESSAGE_SIZE ( ( unsigned portCHAR ) 5 )
#define BLOCK_TIME ( ( portTickType ) 8000 )
typedef struct
{
xQueueHandle xInputQueue;
portTickType xBlockTime;
} xTASK2_PARAMS;
typedef struct
{
unsigned portCHAR ucPacket[MAX_MESSAGE_SIZE];
} xRX_BUFFER;
xRX_BUFFER * pxRxBuffer;
#endif
static xQueueHandle pxQueueHandle;
/**************************************************************************************
**
** PROTOTYPES
**
***************************************************************************************/
#if defined (_SINGLE_FILE_)
void vTask0Init( unsigned portCHAR ucPriority );
void vTask0Code( void * pvParameters );
void vTask1Init( unsigned portCHAR ucPriority );
void vTask1Code( void * pvParameters );
void vTask2Init( unsigned portCHAR ucPriority );
void vTask2Code( void * pvParameters );
void vInitializeISR( void );
#endif
/**************************************************************************************
**
** MAIN
**
***************************************************************************************/
portSHORT main( void )
{
/*
** Set ports D abd E as outputs so we can flash LEDS.
*/
DDRB = 0xFF;
PORTB = 0x00;
DDRE = 0xFF;
PORTE = 0x00;
/*
** Allocate memory all queues.
*/
const unsigned portCHAR ucQueueSize = 1;
pxQueueHandle = xQueueCreate( ucQueueSize, ( unsigned portCHAR ) (sizeof ( xRX_BUFFER * )) );
/*
** Initialize the RX BUFFER storage area.
*/
pxRxBuffer = ( xRX_BUFFER * ) pvPortMalloc( sizeof( xRX_BUFFER ) );
/* Create Task0 - LOW PRIORITY. */
vTask0Init( TASK0_PRIORITY );
/* Create Task1 - LOW PRIORITY. */
vTask1Init( TASK1_PRIORITY );
#if defined (_SINGLE_FILE_)
/* Create Task2 - HIGH PRIORITY. */
vTask2Init( TASK2_PRIORITY );
/* Set up ISR. */
vInitializeISR();
#else
/* Create Task2 - HIGH PRIORITY. */
vTask2Init( TASK2_PRIORITY, pxQueueHandle );
/* Set up ISR. */
vInitializeISR(pxQueueHandle);
#endif
/* Start the scheduler. */
vTaskStartScheduler( portUSE_PREEMPTION );
while(1);
return 0;
}
#if defined (_SINGLE_FILE_)
/**************************************************************************************
**
** TASK 0: Low priority task that toggles TEST2 LED every few ticks.
**
***************************************************************************************/
/* Task initialization. */
void vTask0Init( unsigned portCHAR ucPriority )
{
/* Create task. */
sTaskCreate( vTask0Code, "TASK0", portMINIMAL_STACK_SIZE, NULL, ucPriority, NULL );
}
/* Task code. */
void vTask0Code( void * pvParameters )
{
/* This task will execute at 4K/2K Hz when portTICK_RATE_HZ = 4K. */
const portTickType xFrequency = 2000;
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for (;
{
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//vTaskDelay(2000);
TOGGLE_TEST2_LED();
}
}
/**************************************************************************************
**
** TASK 1: Low priority task that toggles STATUS LED every few ticks.
**
***************************************************************************************/
/* Task initialization. */
void vTask1Init( unsigned portCHAR ucPriority )
{
/* Create task. */
sTaskCreate( vTask1Code, "TASK1", portMINIMAL_STACK_SIZE, NULL, ucPriority, NULL );
}
/* Task code. */
void vTask1Code( void * pvParameters )
{
/* This task will execute at 4K/1K Hz when portTICK_RATE_HZ = 4K. */
const portTickType xFrequency = 1000;
portTickType xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
for (;
{
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//vTaskDelay(1000);
TOGGLE_STATUS_LED();
}
}
/**************************************************************************************
**
** TASK 2: Highest priority task that blocks until it receives a CHAR buffer from the
** ISR.
**
***************************************************************************************/
/*
** Initialize Task2 parameter structure, including block time and queue handle.
*/
void vTask2Init( unsigned portCHAR ucPriority )
{
/* The pointer to parameters for this task. */
xTASK2_PARAMS *pxTask2Params;
pxTask2Params = ( xTASK2_PARAMS * ) pvPortMalloc( sizeof( xTASK2_PARAMS ) );
pxTask2Params->xInputQueue = pxQueueHandle;
pxTask2Params->xBlockTime = BLOCK_TIME;
/* Create task. */
sTaskCreate( vTask2Code, "TASK2", portMINIMAL_STACK_SIZE, pxTask2Params, ucPriority, NULL );
}
/*
** The actual Task2 code.
*/
void vTask2Code( void * pvParameters )
{
/* Declare message handles used in this task. */
xRX_BUFFER * ucReceivedBuffer;
/* Cast the task parameters. */
xTASK2_PARAMS * pxParameters = ( xTASK2_PARAMS * ) pvParameters;
/* The actual work. */
for (;
{
/* Block on message available from ISR, and log the received packet. */
if( cQueueReceive( pxParameters->xInputQueue, &(ucReceivedBuffer), pxParameters->xBlockTime ) == pdPASS )
{
/* Set TEST3 LED to indicate we have received a CHAR buffer from ISR. */
SET_TEST3_LED();
}
/* Do something with CHAR buffer. */
for ( unsigned portCHAR ucCount=0; ucCount < MAX_MESSAGE_SIZE; ucCount++ )
{
ucReceivedBuffer->ucPacket[ucCount] = 0xA1;
}
/* Clear TEST3 LED to indicate we are done and waiting for the next CHAR buffer. */
CLEAR_TEST3_LED();
}
}
/**************************************************************************************
**
** ISR: This ISR uses timer/counter0 to generate a (~)1KHz overflow interrupt.
**
***************************************************************************************/
/*
** Set up timer/counter0 to generate the interrupt. Initialize the CHAR buffer that
** will be sent to Task2.
*/
void vInitializeISR( void )
{
/*
** Generate a 1KHz interrupt using overflow on timer/counter0.
*/
/* TimerSetT0Prescaler to 32 */
TCCR0 &= 0xF8;
TCCR0 |= ( ( unsigned portCHAR ) 3 );
/* TimerClearT0PendingInterrupts */
TIFR |= _BV (TOV0);
TIFR |= _BV (OCF0);
/* TimerEnableT0OverflowEvent */
TCCR0 &= 0xB7; /* clear */
TCCR0 |= 0x00; /* set */
/* TimerEnableT0OverflowInterrupt */
TIMSK |= _BV (TOIE0);
/* Initialize the contents of the buffer. */
for ( unsigned portCHAR ucCount=0; ucCount < MAX_MESSAGE_SIZE; ucCount++ )
{
pxRxBuffer->ucPacket[ucCount] = 0xA5;
}
}
/*
** The ISR sends a pointer to the CHAR buffer to Task2.
*/
SIGNAL( SIG_OVERFLOW0 )
{
portCHAR cTaskWokenByPost = pdFALSE;
/* Set TEST1 LED to indicate we are in this ISR. */
SET_TEST1_LED();
/* Send the current message to Task2. Note we send the address of the pointer to the RX buffer. */
cTaskWokenByPost = cQueueSendFromISR( pxQueueHandle, &pxRxBuffer, cTaskWokenByPost );
/* If a higher priority task is woken by this message then yield the current task. */
if ( cTaskWokenByPost )
{
taskYIELD();
}
/* Clear TEST1 LED to indicate we are leaving this ISR. */
CLEAR_TEST1_LED();
}
#endif