Trouble on ATmega128L
Hello.
I have ported to the ATMega128 by only changing the mcu definition in the makefile.
I then created an app with one ISR triggered off the 8-bit Timer0 and two tasks, (Task1) a low priority task (0 priority) and (Task2) a high priority task (1 priority). ISR uses cQueueSendFromISR() to send a portCHAR to Task2. Task1 uses vTaskDelay(10) then writes a portCHAR to a static array. Task2 uses cQueueReceive() to wait for a message containing a portCHAR from ISR. Task2 is set to block for 20 ticks. When Task2 gets the message it writes the received portCHAR to the same static array as Task1 uses.
It all works fine with a single task only running, i.e. I see the portCHAR appearing in the static array. But when both tasks are running then the system hangs in the Idle task. I am using Atmel Studio4 debugger to step through the code.
For the ISR I have tried both SIGNAL() and INTERRUPT() constructs.
Does anybody have any pointers ?
Thanks
Khusro
Trouble on ATmega128L
Hi again,
I’ve actually put the code here in case somebody can help me. I’ve added an extra task Task0 wich is equivalent to Task1.
The main code:
**************************************************************
*
* main.c
*
* File containing the main() function.
*
* Task1 is a low priority task. Task2 is a high priority task.
* ISR is tied to Timer2 which ticks over at fc/(256*256).
* FreeRTOS system tick is based on Timer0 which ticks over at
* fc/(256*8). The value of fc is 8MHz generally. The mcu is
* the ATmega128.
*
* The ISR sends a message consisting of a single incrementing
* portCHAR value to Task2 using vQueueSendFromISR(). Task2
* blocks on receiving a message from ISR using cQueueReceive().
* Task1 blocks for 10 ticks using vTaskDelay().
*
* Both tasks, when running, write a character value to the
* global static array, pcCharArray[]. Task1 writes the character
* ‘-‘ whereas Task2 writes whatever the ISR sent it via the
* message queue; the value is ‘A’,’B’,…,’Z’ and repeating.
*
*
*
* Revision (do not edit):
*
* $Id$
*
**************************************************************/
/*-INCLUDES—————————————————*/
#include <stdlib.h>
#include "projdefs.h"
#include "portable.h"
#include "task.h"
#include "queue.h"
#include "ISR.h"
/*-DEFINES—————————————————-*/
#define TASK0_PRIORITY ( tskIDLE_PRIORITY )
#define TASK1_PRIORITY ( tskIDLE_PRIORITY )
#define TASK2_PRIORITY ( tskIDLE_PRIORITY + ( unsigned portCHAR ) 1 )
#define TASK_STACK_SIZE portMINIMAL_STACK_SIZE
#define BLOCK_TIME ( ( portTickType ) 250 )
#define CHARARRAY_LENGTH 200
/*-TYPEDEFS—————————————————*/
/* Parameters for Task2. */
typedef struct
{
xQueueHandle xQueue;
portTickType xBlockTime;
} xTask2Parameters;
/*-GLOBALS—————————————————-*/
static portCHAR pcCharArray[ CHARARRAY_LENGTH ];
static portSHORT cArrayIndex = 0;
/*-PROTOTYPES————————————————-*/
/* Create a specific queue. */
xQueueHandle pxCreateTask2Queue( void );
/* Task0 code. */
void vTask0Code( void * pvParameters );
/* Task1 code. */
void vTask1Code( void * pvParameters );
/* Task2 code. */
void vTask2Code( void * pvParameters );
/* Function to log a character in an array. */
void vLogCharacter( portCHAR cCharacter );
/*-IMPLEMENTATIONS——————————————–*/
portSHORT main( void )
{
xTask2Parameters *pxParameters2;
/* A handle to the queue shared by Task2 and ISR. */
xQueueHandle xTask2Queue;
/* Get the queues for the tasks. */
xTask2Queue = pxCreateTask2Queue();
/* Initialize parameters for Task1 – NO PARAMETERS. */
/* Initialize parameters for Task2. */
pxParameters2 = ( xTask2Parameters * ) pvPortMalloc( sizeof( xTask2Parameters ) );
pxParameters2->xQueue = xTask2Queue;
pxParameters2->xBlockTime = BLOCK_TIME;
/* Create Task0 – LOW PRIORITY. */
sTaskCreate( vTask0Code, "TASK0", TASK_STACK_SIZE, NULL, TASK0_PRIORITY, NULL );
/* Create Task1 – LOW PRIORITY. */
sTaskCreate( vTask1Code, "TASK1", TASK_STACK_SIZE, NULL, TASK1_PRIORITY, NULL );
/* Create Task2 – HIGH PRIORITY. */
//sTaskCreate( vTask2Code, "TASK2", TASK_STACK_SIZE, pxParameters2, TASK2_PRIORITY, NULL );
/* Set up ISRs, give it the handle to the queue. */
vInitializeISR( xTask2Queue );
/* Start the scheduler. */
vTaskStartScheduler( portUSE_PREEMPTION );
return 0;
}
void vTask0Code( void * pvParameters )
{
for (;;)
{
/* Block for some ticks then log a ‘|’ character. */
vTaskDelay( ( portTickType ) 10 );
vLogCharacter( ‘|’ );
}
}
void vTask1Code( void * pvParameters )
{
for (;;)
{
/* Block for some ticks then log a ‘-‘ character. */
vTaskDelay( ( portTickType ) 5 );
vLogCharacter( ‘-‘ );
}
}
void vTask2Code( void * pvParameters )
{
unsigned portCHAR ucMessage;
xTask2Parameters * pxParameters = ( xTask2Parameters * ) pvParameters;
for (;;)
{
/* Block on message available from ISR, and log the received character. */
if( cQueueReceive( pxParameters->xQueue, &ucMessage, pxParameters->xBlockTime ) == pdPASS )
{
vLogCharacter( ucMessage );
}
}
}
xQueueHandle pxCreateTask2Queue( void )
{
xQueueHandle xQueue;
const unsigned portCHAR ucQueueSize = 1;
/* Create the queue. */
xQueue = xQueueCreate( ucQueueSize, ( unsigned portCHAR ) sizeof ( portCHAR ) );
/* Check that the queue was create. */
if ( xQueue == 0 )
{
/* Queue not created. Should call error handler. */
}
return xQueue;
}
void vLogCharacter( portCHAR cCharacter )
{
pcCharArray[ cArrayIndex ] = cCharacter;
++cArrayIndex;
/* The array is a circular buffer. */
if ( cArrayIndex > CHARARRAY_LENGTH )
{
cArrayIndex = 0;
}
}
The ISR code:
*************************************
**************************************************************
*
* ISR.c
*
* A brief description
*
*
* Revision (do not edit):
*
* $Id$
*
**************************************************************/
#include "ISR.h"
#include <avr/signal.h>
static xQueueHandle pxQueueHandle;
static portCHAR ucMessage;
void vInitializeISR( xQueueHandle xQueue )
{
pxQueueHandle = xQueue;
ucMessage = ‘A’;
}
/* This ISR kicks off when the 8-bit Timer2 overflows. */
SIGNAL( SIG_OVERFLOW2 )
{
portCHAR cTaskWokenByPost = pdFALSE;
/* The message is a portCHAR and it cycles from ‘A’ to ‘Z’. */
if ( ucMessage > ‘Z’ )
{
ucMessage = ‘A’;
}
/* Send the current message to Task2. */
cTaskWokenByPost = cQueueSendFromISR( pxQueueHandle, &ucMessage, cTaskWokenByPost );
/* Go to the next letter in the alphabet. */
++ucMessage;
/* If a higher priority task is woken by this message then yield the current task. */
if ( cTaskWokenByPost )
{
taskYIELD();
}
}
Trouble on ATmega128L
I will take a look at the code. In the mean time can you verify that the scheduler tick is running.
The timer used for the scheduler tick is configured by the function prvSetupTimerInterrupt() in the file source/portable/gcc/ATMega323/port.c. I think some of the AVR family have a slightly different register configuration and the code needs modifiying accordingly.
To check the timer is running in AVRStudio:
+ Open the file port.c (path as above).
+ Search for the function vPortYieldFromTick() (around line 346).
+ In this function place a break point on the line vTaskIncrementTick();
+ Run the program and check the break point is hit over and over again.
If the break point is continuously hit then the timer is fine and we need to look elsewhere.
This assumes you are using the preemptive scheduler? (portUSE_PREEMPTION is set to 1 in portmacro.h [same path as above] – this is the default as downloaded).
Trouble on ATmega128L
The code does not seem to include the timer configuration. vInitializeISR() does not perform any hardware/register configuration to start the timer off(?).
Are you able to send me your entire project? If so zip up all the files including your FreeRTOS/source directory and makefiles etc. and send them to the email address from the FreeRTOS WEB site contact page. Can you also include brief build instructions (go to x directory and type "make", or go to y directory and run batch file, that sort of thing).
If I have the project I should be able to try it in the studio simulator.
At the moment the code just switches between idle task and vTask1Code(). vTask2Code() never executes because the timer is not running so no messages get posted into the queue.
Trouble on ATmega128L
Thanks for you replies. Barry, I have emailed you the zip file containing all my files.
I should make a few points:
1. I have made Timer0, an 8-bit timer, the System Tick timer, so I have changed ‘prvSetupTimerInterrup()’ in ‘port.c’. The system timer event is an overflow on timer 0. I did this because I really want the 16-bit timer for something else.
2. Timer 2 is used to trigger the interrupt. I have put the code to configure timer 2 in the ‘vInitializeISR()’ function in ‘ISR.c’. The code looks like :
void vInitializeISR( xQueueHandle xQueue )
{
pxQueueHandle = xQueue;
ucMessage = ‘A’;
/* Using 8bit timer 2 to generate another tick. */
TCCR2 = (1<<CS22); /* Timer clock = system clock/256. */
TIFR = 1<<TOV2; /* Clear TOV2 clear pending interrupts. */
TIMSK = 1<<TOIE2; /* Enable Timer2 Overflow Interrupt. */
}
3. I have three tasks now, Task0, Task1 and Task2. Task0 and Task1
are identical, just a different ‘vTaskDelay()’ call. Task2 is the higher priority
task awaiting a message from the ISR.
4. Everything works fine as long as the interrupt from Timer2 never happens.
So for example, if I comment out the Task2 ‘vTaskCreate()’ call and if in the
ISR I don’t call ‘cQueueSendFromISR()’, the other two tasks still don’t work.
But, however, I do enter the ISR routine at the right time intervals. So it seems
that I might not be setting up the ISR routing correctly.
Thank you again for all your replies.
Khusro
Trouble on ATmega128L
I think this is what is happening –
The tick interrupt is not running. In prvSetupTimerInterrupt() timer 0 is first configured to generate an interrupt for the tick, timer 2 is then configured for your application interrupt. However the line that enables the second interrupt disables the first:
TIMSK = 1<<TOIE2;
This means your application interrupt fires but not the kernel tick.
Change the line to :
TIMSK |= ( 1<<TOIE2 );
and everything seems to be ok.
Let me know if otherwise.
Regards.
Trouble on ATmega128L
Other little thing for function logcharacter access var used by two task so need protection as below. Ensures no corruption of cArrayIndex and pcCharArray.
void vLogCharacter( portCHAR cCharacter )
{
portENTER_CRITICAL();
{
pcCharArray[ cArrayIndex ] = cCharacter;
++cArrayIndex;
/* The array is a circular buffer. */
if ( cArrayIndex > CHARARRAY_LENGTH )
{
cArrayIndex = 0;
}
}
portEXIT_CRITICAL();
}
Trouble on ATmega128L
IT WORKS NOW. Barry, you hit it right on the nail. The only hitch was that I had to do the same OR operation with Timer0.
Well, this teaches me, yet again, read those darn datasheets!
Thank you all for your help and advice, it is very much appreciated. I will have to register with this forum to stop appearing as Anon. Hopefully I can be of the same assistance to others discovering the benefits of FreeRTOS !
Khusro