mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-11-06 19:52:24 -05:00
Before changing headers to V6 and changing portLONG, portSHORt and portCHAR to their standard C types.
This commit is contained in:
parent
3dfbb349ca
commit
5c64e1fad9
4417 changed files with 1261274 additions and 0 deletions
328
20091005/Demo/Common/Full/BlockQ.c
Normal file
328
20091005/Demo/Common/Full/BlockQ.c
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
* \page BlockQC blockQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.00:
|
||||
|
||||
+ Reversed the priority and block times of the second two demo tasks so
|
||||
they operate as per the description above.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
|
||||
Changes from V4.0.2
|
||||
|
||||
+ The second set of tasks were created the wrong way around. This has been
|
||||
corrected.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
#include "print.h"
|
||||
|
||||
#define blckqSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE )
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
xQueueHandle xQueue; /*< The queue to be used by the task. */
|
||||
portTickType xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile portSHORT *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static void vBlockingQueueProducer( void *pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
it is the expected number. */
|
||||
static void vBlockingQueueConsumer( void *pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
found to be the expected value.
|
||||
These are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( portSHORT ) 0, ( portSHORT ) 0, ( portSHORT ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( portSHORT ) 0, ( portSHORT ) 0, ( portSHORT ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
|
||||
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
|
||||
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
|
||||
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
|
||||
const portTickType xDontBlock = ( portTickType ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueProducer( void *pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
const portCHAR * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
|
||||
const portCHAR * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vBlockingQueueConsumer( void *pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
const portCHAR * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
|
||||
const portCHAR * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( portSHORT ) 0, ( portSHORT ) 0, ( portSHORT ) 0 };
|
||||
static portSHORT sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( portSHORT ) 0, ( portSHORT ) 0, ( portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not.
|
||||
|
||||
Loop through each check variable and return pdFALSE if any are found not
|
||||
to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
240
20091005/Demo/Common/Full/PollQ.c
Normal file
240
20091005/Demo/Common/Full/PollQ.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* This is a very simple queue test. See the BlockQ. c documentation for a more
|
||||
* comprehensive version.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*
|
||||
* \page PollQC pollQ.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static void vPolledQueueProducer( void *pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static void vPolledQueueConsumer( void *pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no errors. */
|
||||
static volatile portSHORT sPollingConsumerCount = 0, sPollingProducerCount = 0;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
static xQueueHandle xPolledQueue;
|
||||
const unsigned portBASE_TYPE uxQueueSize = 10;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueProducer( void *pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = 0, usLoop;
|
||||
xQueueHandle *pxQueue;
|
||||
const portTickType xDelay = ( portTickType ) 200 / portTICK_RATE_MS;
|
||||
const unsigned portSHORT usNumToProduce = 3;
|
||||
const portCHAR * const pcTaskStartMsg = "Polled queue producer started.\r\n";
|
||||
const portCHAR * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( xQueueHandle * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( portTickType ) 0 ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full - this is an error. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
check variable. */
|
||||
++sPollingProducerCount;
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
empties the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPolledQueueConsumer( void *pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = 0;
|
||||
xQueueHandle *pxQueue;
|
||||
const portTickType xDelay = ( portTickType ) 200 / portTICK_RATE_MS;
|
||||
const portCHAR * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
|
||||
const portCHAR * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The queue being used is passed in as the parameter. */
|
||||
pxQueue = ( xQueueHandle * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *pxQueue ) )
|
||||
{
|
||||
if( xQueueReceive( *pxQueue, &usData, ( portTickType ) 0 ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
occurred. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sError = pdTRUE;
|
||||
/* Catch-up to the value we received so our next expected value
|
||||
should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
occurred. */
|
||||
++sPollingConsumerCount;
|
||||
}
|
||||
}
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
items in the queue. */
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
portBASE_TYPE xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
|
||||
( sLastPollingProducerCount == sPollingProducerCount )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastPollingConsumerCount = sPollingConsumerCount;
|
||||
sLastPollingProducerCount = sPollingProducerCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
366
20091005/Demo/Common/Full/comtest.c
Normal file
366
20091005/Demo/Common/Full/comtest.c
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A loopback
|
||||
* connector should be used so that everything that is transmitted is also received.
|
||||
* The serial port does not use any flow control. On a standard 9way 'D' connector
|
||||
* pins two and three should be connected together.
|
||||
*
|
||||
* The first task repeatedly sends a string to a queue, character at a time. The
|
||||
* serial port interrupt will empty the queue and transmit the characters. The
|
||||
* task blocks for a pseudo random period before resending the string.
|
||||
*
|
||||
* The second task blocks on a queue waiting for a character to be received.
|
||||
* Characters received by the serial port interrupt routine are posted onto the
|
||||
* queue - unblocking the task making it ready to execute. If this is then the
|
||||
* highest priority task ready to run it will run immediately - with a context
|
||||
* switch occurring at the end of the interrupt service routine. The task
|
||||
* receiving characters is spawned with a higher priority than the task
|
||||
* transmitting the characters.
|
||||
*
|
||||
* With the loop back connector in place, one task will transmit a string and the
|
||||
* other will immediately receive it. The receiving task knows the string it
|
||||
* expects to receive so can detect an error.
|
||||
*
|
||||
* This also creates a third task. This is used to test semaphore usage from an
|
||||
* ISR and does nothing interesting.
|
||||
*
|
||||
* \page ComTestC comtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.00:
|
||||
|
||||
+ The priority of the Rx task has been lowered. Received characters are
|
||||
now processed (read from the queue) at the idle priority, allowing low
|
||||
priority tasks to run evenly at times of a high communications overhead.
|
||||
|
||||
Changes from V1.01:
|
||||
|
||||
+ The Tx task now waits a pseudo random time between transissions.
|
||||
Previously a fixed period was used but this was not such a good test as
|
||||
interrupts fired at regular intervals.
|
||||
|
||||
Changes From V1.2.0:
|
||||
|
||||
+ Use vSerialPutString() instead of single character puts.
|
||||
+ Only stop the check variable incrementing after two consecutive errors.
|
||||
|
||||
Changed from V1.2.5
|
||||
|
||||
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was
|
||||
only 1. This is done to tie in better with the other demo application
|
||||
tasks.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
+ Slight modification to task priorities.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( portTickType ) 0x15e )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0xc8 )
|
||||
|
||||
#define comMAX_CONSECUTIVE_ERRORS ( 2 )
|
||||
|
||||
#define comSTACK_SIZE ( ( unsigned portSHORT ) 256 )
|
||||
|
||||
#define comRX_RELATIVE_PRIORITY ( 1 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort;
|
||||
|
||||
/* The transmit function as described at the top of the file. */
|
||||
static void vComTxTask( void *pvParameters );
|
||||
|
||||
/* The receive function as described at the top of the file. */
|
||||
static void vComRxTask( void *pvParameters );
|
||||
|
||||
/* The semaphore test function as described at the top of the file. */
|
||||
static void vSemTestTask( void * pvParameters );
|
||||
|
||||
/* The string that is repeatedly transmitted. */
|
||||
const portCHAR * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
|
||||
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
|
||||
|
||||
/* Variables that are incremented on each cycle of each task. These are used to
|
||||
check that both tasks are still executing. */
|
||||
volatile portSHORT sTxCount = 0, sRxCount = 0, sSemCount = 0;
|
||||
|
||||
/* The handle to the semaphore test task. */
|
||||
static xTaskHandle xSemTestTaskHandle = NULL;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority, eCOMPort ePort, eBaud eBaudRate )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxBufferLength = 255;
|
||||
|
||||
/* Initialise the com port then spawn both tasks. */
|
||||
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
|
||||
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
|
||||
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
|
||||
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComTxTask( void *pvParameters )
|
||||
{
|
||||
const portCHAR * const pcTaskStartMsg = "COM Tx task started.\r\n";
|
||||
portTickType xTimeToWait;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Send the string to the serial port. */
|
||||
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
|
||||
|
||||
/* We have posted all the characters in the string - increment the variable
|
||||
used to check that this task is still running, then wait before re-sending
|
||||
the string. */
|
||||
sTxCount++;
|
||||
|
||||
xTimeToWait = xTaskGetTickCount();
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vComRxTask( void *pvParameters )
|
||||
{
|
||||
const portCHAR * const pcTaskStartMsg = "COM Rx task started.\r\n";
|
||||
const portCHAR * const pcTaskErrorMsg = "COM read error\r\n";
|
||||
const portCHAR * const pcTaskRestartMsg = "COM resynced\r\n";
|
||||
const portCHAR * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
|
||||
const portTickType xBlockTime = ( portTickType ) 0xffff / portTICK_RATE_MS;
|
||||
const portCHAR *pcExpectedChar;
|
||||
portBASE_TYPE xGotChar;
|
||||
portCHAR cRxedChar;
|
||||
portSHORT sResyncRequired, sConsecutiveErrors, sLatchedError;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The first expected character is the first character in the string. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
sConsecutiveErrors = 0;
|
||||
sLatchedError = pdFALSE;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Receive a message from the com port interrupt routine. If a message is
|
||||
not yet available the call will block the task. */
|
||||
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
|
||||
if( xGotChar == pdTRUE )
|
||||
{
|
||||
if( sResyncRequired == pdTRUE )
|
||||
{
|
||||
/* We got out of sequence and are waiting for the start of the next
|
||||
transmission of the string. */
|
||||
if( cRxedChar == '\n' )
|
||||
{
|
||||
/* This is the end of the message so we can start again - with
|
||||
the first character in the string being the next thing we expect
|
||||
to receive. */
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
sResyncRequired = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say that we are going to try
|
||||
again. */
|
||||
vPrintDisplayMessage( &pcTaskRestartMsg );
|
||||
|
||||
/* Stop incrementing the check variable, if consecutive errors occur. */
|
||||
sConsecutiveErrors++;
|
||||
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
|
||||
{
|
||||
sLatchedError = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have received a character, but is it the expected character? */
|
||||
if( cRxedChar != *pcExpectedChar )
|
||||
{
|
||||
/* This was not the expected character so post a message for
|
||||
printing to say that an error has occurred. We will then wait
|
||||
to resynchronise. */
|
||||
vPrintDisplayMessage( &pcTaskErrorMsg );
|
||||
sResyncRequired = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This was the expected character so next time we will expect
|
||||
the next character in the string. Wrap back to the beginning
|
||||
of the string when the null terminator has been reached. */
|
||||
pcExpectedChar++;
|
||||
if( *pcExpectedChar == '\0' )
|
||||
{
|
||||
pcExpectedChar = pcMessageToExchange;
|
||||
|
||||
/* We have got through the entire string without error. */
|
||||
sConsecutiveErrors = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Increment the count that is used to check that this task is still
|
||||
running. This is only done if an error has never occurred. */
|
||||
if( sLatchedError == pdFALSE )
|
||||
{
|
||||
sRxCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskTimeoutMsg );
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSemTestTask( void * pvParameters )
|
||||
{
|
||||
const portCHAR * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
|
||||
portBASE_TYPE xError = pdFALSE;
|
||||
|
||||
/* Stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xSerialWaitForSemaphore( xPort ) )
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
sSemCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xError = pdTRUE;
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not. */
|
||||
|
||||
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
sLastTxCount = sTxCount;
|
||||
sLastRxCount = sRxCount;
|
||||
sLastSemCount = sSemCount;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vComTestUnsuspendTask( void )
|
||||
{
|
||||
/* The task that is suspended on the semaphore will be referenced from the
|
||||
Suspended list as it is blocking indefinitely. This call just checks that
|
||||
the kernel correctly detects this and does not attempt to unsuspend the
|
||||
task. */
|
||||
xTaskResumeFromISR( xSemTestTaskHandle );
|
||||
}
|
||||
223
20091005/Demo/Common/Full/death.c
Normal file
223
20091005/Demo/Common/Full/death.c
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* four tasks. The original task is called the creator task, the four tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* Two of the created suicidal tasks kill one other suicidal task before killing
|
||||
* themselves - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
#include "print.h"
|
||||
|
||||
#define deathSTACK_SIZE ( ( unsigned portSHORT ) 512 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
creating another four tasks. */
|
||||
static void vCreateTasks( void *pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static void vSuicidalTask( void *pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
is used to check that the task is still running. */
|
||||
static volatile portSHORT sCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
task can tell if any of the suicidal tasks have failed to die. */
|
||||
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
|
||||
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
|
||||
|
||||
/* Used to store a handle to the tasks that should be killed by a suicidal task,
|
||||
before it kills itself. */
|
||||
xTaskHandle xCreatedTask1, xCreatedTask2;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE *puxPriority;
|
||||
|
||||
/* Create the Creator tasks - passing in as a parameter the priority at which
|
||||
the suicidal tasks should be created. */
|
||||
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
|
||||
*puxPriority = uxPriority;
|
||||
|
||||
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
|
||||
|
||||
/* Record the number of tasks that are running now so we know if any of the
|
||||
suicidal tasks have failed to be killed. */
|
||||
uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSuicidalTask( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2;
|
||||
xTaskHandle xTaskToKill;
|
||||
const portTickType xDelay = ( portTickType ) 500 / portTICK_RATE_MS;
|
||||
|
||||
if( pvParameters != NULL )
|
||||
{
|
||||
/* This task is periodically created four times. Tow created tasks are
|
||||
passed a handle to the other task so it can kill it before killing itself.
|
||||
The other task is passed in null. */
|
||||
xTaskToKill = *( xTaskHandle* )pvParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskToKill = NULL;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Do something random just to use some stack and registers. */
|
||||
d1 = 2.4;
|
||||
d2 = 89.2;
|
||||
d2 *= d1;
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
if( xTaskToKill != NULL )
|
||||
{
|
||||
/* Make sure the other task has a go before we delete it. */
|
||||
vTaskDelay( ( portTickType ) 0 );
|
||||
/* Kill the other task that was created by vCreateTasks(). */
|
||||
vTaskDelete( xTaskToKill );
|
||||
/* Kill ourselves. */
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
}
|
||||
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCreateTasks( void *pvParameters )
|
||||
{
|
||||
const portTickType xDelay = ( portTickType ) 1000 / portTICK_RATE_MS;
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
const portCHAR * const pcTaskStartMsg = "Create task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
|
||||
vPortFree( pvParameters );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just loop round, delaying then creating the four suicidal tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 );
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL );
|
||||
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 );
|
||||
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL );
|
||||
|
||||
++sCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
are not any more than four extra tasks. */
|
||||
portBASE_TYPE xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastCreationCount = 0;
|
||||
portSHORT sReturn = pdTRUE;
|
||||
unsigned portBASE_TYPE uxTasksRunningNow;
|
||||
|
||||
if( sLastCreationCount == sCreationCount )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
|
||||
uxTasksRunningNow = uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
sReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return sReturn;
|
||||
}
|
||||
|
||||
|
||||
598
20091005/Demo/Common/Full/dynamic.c
Normal file
598
20091005/Demo/Common/Full/dynamic.c
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises it's priority above that of the controller task before each
|
||||
* increment, lowering it again to it's original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of it's loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume ().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from it's suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*
|
||||
* The final set of two tasks implements a third test. This simply raises the
|
||||
* priority of a task while the scheduler is suspended. Again this test was
|
||||
* added to exercise parts of the code not covered by the first test.
|
||||
*
|
||||
* \page Priorities dynamic.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
+ Added a second, simple test that uses the functions
|
||||
vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
|
||||
|
||||
Changes from V3.1.1
|
||||
|
||||
+ Added a third simple test that uses the vTaskPrioritySet() function
|
||||
while the scheduler is suspended.
|
||||
+ Modified the controller task slightly to test the calling of
|
||||
vTaskResumeAll() while the scheduler is suspended.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static void vLimitedIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static void vContinuousIncrementTask( void * pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static void vCounterControlTask( void * pvParameters );
|
||||
|
||||
/* The simple test functions that check sending and receiving while the
|
||||
scheduler is suspended. */
|
||||
static void vQueueReceiveWhenSuspendedTask( void *pvParameters );
|
||||
static void vQueueSendWhenSuspendedTask( void *pvParameters );
|
||||
|
||||
/* The simple test functions that check raising and lowering of task priorities
|
||||
while the scheduler is suspended. */
|
||||
static void prvChangePriorityWhenSuspendedTask( void *pvParameters );
|
||||
static void prvChangePriorityHelperTask( void *pvParameters );
|
||||
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#define priSTACK_SIZE ( ( unsigned portSHORT ) configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME ( ( portTickType ) 50 )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( unsigned portLONG ) 0xff )
|
||||
#define priNO_BLOCK ( ( portTickType ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
to the controller task to prevent them having to be file scope. */
|
||||
static xTaskHandle xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
counter variables for demonstration purposes. */
|
||||
static unsigned portLONG ulCounter;
|
||||
|
||||
/* Variable used in a similar way by the test that checks the raising and
|
||||
lowering of task priorities while the scheduler is suspended. */
|
||||
static unsigned portLONG ulPrioritySetCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
Each complete iteration of the controller task increments this variable
|
||||
provided no errors have been found. The variable maintaining the same value
|
||||
is therefore indication of an error. */
|
||||
static unsigned portSHORT usCheckVariable = ( unsigned portSHORT ) 0;
|
||||
static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
|
||||
static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
|
||||
static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
xQueueHandle xSuspendedTestQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*
|
||||
* Start the seven tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
||||
xTaskCreate( vContinuousIncrementTask, "CONT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, "SUSP_SEND", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, "SUSP_RECV", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvChangePriorityWhenSuspendedTask, "1st_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL );
|
||||
xTaskCreate( prvChangePriorityHelperTask, "2nd_P_CHANGE", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xChangePriorityWhenSuspendedHandle );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static void vLimitedIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned portLONG *pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned portLONG * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static void vContinuousIncrementTask( void * pvParameters )
|
||||
{
|
||||
unsigned portLONG *pulCounter;
|
||||
unsigned portBASE_TYPE uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned portLONG * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Raise our priority above the controller task to ensure a context
|
||||
switch does not occur while we are accessing this variable. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
( *pulCounter )++;
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static void vCounterControlTask( void * pvParameters )
|
||||
{
|
||||
unsigned portLONG ulLastCounter;
|
||||
portSHORT sLoops;
|
||||
portSHORT sError = pdFALSE;
|
||||
const portCHAR * const pcTaskStartMsg = "Priority manipulation tasks started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( unsigned portLONG ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
shared variable without risk of corruption. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
ulLastCounter = ulCounter;
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
exclusion the whole scheduler will be locked. This is just for
|
||||
demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared variable. */
|
||||
vTaskSuspend( xContinuousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( unsigned portLONG ) 0;
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
We should therefore not return from this call until the limited count
|
||||
task has suspended itself with a known value in the counter variable.
|
||||
The scheduler suspension is not necessary but is included for test
|
||||
purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinuousIncrementHandle );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueSendWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
static unsigned portLONG ulValueToSend = ( unsigned portLONG ) 0;
|
||||
const portCHAR * const pcTaskStartMsg = "Queue send while suspended task started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Queue send while suspended failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
if( xSuspendedQueueSendError == pdFALSE )
|
||||
{
|
||||
xTaskResumeAll();
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
vTaskSuspendAll();
|
||||
}
|
||||
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vQueueReceiveWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
static unsigned portLONG ulExpectedValue = ( unsigned portLONG ) 0, ulReceivedValue;
|
||||
const portCHAR * const pcTaskStartMsg = "Queue receive while suspended task started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Queue receive while suspended failed.\r\n";
|
||||
portBASE_TYPE xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
undesirable for a normal application. It is done here purely
|
||||
to test the scheduler. The inner xTaskResumeAll() should
|
||||
never return pdTRUE as the scheduler is still locked by the
|
||||
outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
if( xTaskResumeAll() )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
if( xSuspendedQueueReceiveError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityWhenSuspendedTask( void *pvParameters )
|
||||
{
|
||||
const portCHAR * const pcTaskStartMsg = "Priority change when suspended task started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Priority change when suspended task failed.\r\n";
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at 0 so we know what the counter should be
|
||||
when we check it next. */
|
||||
ulPrioritySetCounter = ( unsigned portLONG ) 0;
|
||||
|
||||
/* Resume the helper task. At this time it has a priority lower than
|
||||
ours so no context switch should occur. */
|
||||
vTaskResume( xChangePriorityWhenSuspendedHandle );
|
||||
|
||||
/* Check to ensure the task just resumed has not executed. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned portLONG ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Now try raising the priority while the scheduler is suspended. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
|
||||
|
||||
/* Again, even though the helper task has a priority greater than
|
||||
ours, it should not have executed yet because the scheduler is
|
||||
suspended. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned portLONG ) 0 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* Now the scheduler has been resumed the helper task should
|
||||
immediately preempt us and execute. When it executes it will increment
|
||||
the ulPrioritySetCounter exactly once before suspending itself.
|
||||
|
||||
We should now always find the counter set to 1. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
if( ulPrioritySetCounter != ( unsigned portLONG ) 1 )
|
||||
{
|
||||
xPriorityRaiseWhenSuspendedError = pdTRUE;
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Delay until we try this again. */
|
||||
vTaskDelay( priSLEEP_TIME * 2 );
|
||||
|
||||
/* Set the priority of the helper task back ready for the next
|
||||
execution of this task. */
|
||||
vTaskSuspendAll();
|
||||
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvChangePriorityHelperTask( void *pvParameters )
|
||||
{
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* This is the helper task for prvChangePriorityWhenSuspendedTask().
|
||||
It has it's priority raised and lowered. When it runs it simply
|
||||
increments the counter then suspends itself again. This allows
|
||||
prvChangePriorityWhenSuspendedTask() to know how many times it has
|
||||
executed. */
|
||||
ulPrioritySetCounter++;
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
since the last call. */
|
||||
static unsigned portSHORT usLastTaskCheck = ( unsigned portSHORT ) 0;
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xPriorityRaiseWhenSuspendedError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
388
20091005/Demo/Common/Full/events.c
Normal file
388
20091005/Demo/Common/Full/events.c
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This file exercises the event mechanism whereby more than one task is
|
||||
* blocked waiting for the same event.
|
||||
*
|
||||
* The demo creates five tasks - four 'event' tasks, and a controlling task.
|
||||
* The event tasks have various different priorities and all block on reading
|
||||
* the same queue. The controlling task writes data to the queue, then checks
|
||||
* to see which of the event tasks read the data from the queue. The
|
||||
* controlling task has the lowest priority of all the tasks so is guaranteed
|
||||
* to always get preempted immediately upon writing to the queue.
|
||||
*
|
||||
* By selectively suspending and resuming the event tasks the controlling task
|
||||
* can check that the highest priority task that is blocked on the queue is the
|
||||
* task that reads the posted data from the queue.
|
||||
*
|
||||
* Two of the event tasks share the same priority. When neither of these tasks
|
||||
* are suspended they should alternate - one reading one message from the queue,
|
||||
* the other the next message, etc.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "mevents.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo specific constants. */
|
||||
#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
|
||||
#define evtNUM_TASKS ( 4 )
|
||||
#define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
|
||||
#define evtNO_DELAY 0
|
||||
|
||||
/* Just indexes used to uniquely identify the tasks. Note that two tasks are
|
||||
'highest' priority. */
|
||||
#define evtHIGHEST_PRIORITY_INDEX_2 3
|
||||
#define evtHIGHEST_PRIORITY_INDEX_1 2
|
||||
#define evtMEDIUM_PRIORITY_INDEX 1
|
||||
#define evtLOWEST_PRIORITY_INDEX 0
|
||||
|
||||
/* Each event task increments one of these counters each time it reads data
|
||||
from the queue. */
|
||||
static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Each time the controlling task posts onto the queue it increments the
|
||||
expected count of the task that it expected to read the data from the queue
|
||||
(i.e. the task with the highest priority that should be blocked on the queue).
|
||||
|
||||
xExpectedTaskCounters are incremented from the controlling task, and
|
||||
xTaskCounters are incremented from the individual event tasks - therefore
|
||||
comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
|
||||
correct task was unblocked by the post. */
|
||||
static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
|
||||
|
||||
/* Handles to the four event tasks. These are required to suspend and resume
|
||||
the tasks. */
|
||||
static xTaskHandle xCreatedTasks[ evtNUM_TASKS ];
|
||||
|
||||
/* The single queue onto which the controlling task posts, and the four event
|
||||
tasks block. */
|
||||
static xQueueHandle xQueue;
|
||||
|
||||
/* Flag used to indicate whether or not an error has occurred at any time.
|
||||
An error is either the queue being full when not expected, or an unexpected
|
||||
task reading data from the queue. */
|
||||
static portBASE_TYPE xHealthStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Function that implements the event task. This is created four times. */
|
||||
static void prvMultiEventTask( void *pvParameters );
|
||||
|
||||
/* Function that implements the controlling task. */
|
||||
static void prvEventControllerTask( void *pvParameters );
|
||||
|
||||
/* This is a utility function that posts data to the queue, then compares
|
||||
xExpectedTaskCounters with xTaskCounters to ensure everything worked as
|
||||
expected.
|
||||
|
||||
The event tasks all have higher priorities the controlling task. Therefore
|
||||
the controlling task will always get preempted between writhing to the queue
|
||||
and checking the task counters.
|
||||
|
||||
@param xExpectedTask The index to the task that the controlling task thinks
|
||||
should be the highest priority task waiting for data, and
|
||||
therefore the task that will unblock.
|
||||
|
||||
@param xIncrement The number of items that should be written to the queue.
|
||||
*/
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
|
||||
|
||||
/* This is just incremented each cycle of the controlling tasks function so
|
||||
the main application can ensure the test is still running. */
|
||||
static portBASE_TYPE xCheckVariable = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMultiEventTasks( void )
|
||||
{
|
||||
/* Create the queue to be used for all the communications. */
|
||||
xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
/* Start the controlling task. This has the idle priority to ensure it is
|
||||
always preempted by the event tasks. */
|
||||
xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
/* Start the four event tasks. Note that two have priority 3, one
|
||||
priority 2 and the other priority 1. */
|
||||
xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
|
||||
xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMultiEventTask( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE *pxCounter;
|
||||
unsigned portBASE_TYPE uxDummy;
|
||||
const portCHAR * const pcTaskStartMsg = "Multi event task started.\r\n";
|
||||
|
||||
/* The variable this task will increment is passed in as a parameter. */
|
||||
pxCounter = ( portBASE_TYPE * ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block on the queue. */
|
||||
if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
|
||||
{
|
||||
/* We unblocked by reading the queue - so simply increment
|
||||
the counter specific to this task instance. */
|
||||
( *pxCounter )++;
|
||||
}
|
||||
else
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvEventControllerTask( void *pvParameters )
|
||||
{
|
||||
const portCHAR * const pcTaskStartMsg = "Multi event controller task started.\r\n";
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Just to stop warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* All tasks are blocked on the queue. When a message is posted one of
|
||||
the two tasks that share the highest priority should unblock to read
|
||||
the queue. The next message written should unblock the other task with
|
||||
the same high priority, and so on in order. No other task should
|
||||
unblock to read data as they have lower priorities. */
|
||||
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* For the rest of these tests we don't need the second 'highest'
|
||||
priority task - so it is suspended. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
|
||||
|
||||
/* Now suspend the other highest priority task. The medium priority
|
||||
task will then be the task with the highest priority that remains
|
||||
blocked on the queue. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
/* This time, when we post onto the queue we will expect the medium
|
||||
priority task to unblock and preempt us. */
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Now try resuming the highest priority task while the scheduler is
|
||||
suspended. The task should start executing as soon as the scheduler
|
||||
is resumed - therefore when we post to the queue again, the highest
|
||||
priority task should again preempt us. */
|
||||
vTaskSuspendAll();
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now we are going to suspend the high and medium priority tasks. The
|
||||
low priority task should then preempt us. Again the task suspension is
|
||||
done with the whole scheduler suspended just for test purposes. */
|
||||
vTaskSuspendAll();
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
/* Do the same basic test another few times - selectively suspending
|
||||
and resuming tasks and each time calling prvCheckTaskCounters() passing
|
||||
to the function the number of the task we expected to be unblocked by
|
||||
the post. */
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for test. */
|
||||
vTaskSuspendAll(); /* Just for even more test. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
xTaskResumeAll();
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
|
||||
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
|
||||
|
||||
/* Now a slight change, first suspend all tasks. */
|
||||
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* Now when we resume the low priority task and write to the queue 3
|
||||
times. We expect the low priority task to service the queue three
|
||||
times. */
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
|
||||
|
||||
/* Again suspend all tasks (only the low priority task is not suspended
|
||||
already). */
|
||||
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
|
||||
/* This time we are going to suspend the scheduler, resume the low
|
||||
priority task, then resume the high priority task. In this state we
|
||||
will write to the queue three times. When the scheduler is resumed
|
||||
we expect the high priority task to service all three messages. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
|
||||
|
||||
for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should not have been serviced yet!. The scheduler
|
||||
is still suspended. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
/* We should have been preempted by resuming the scheduler - so by the
|
||||
time we are running again we expect the high priority task to have
|
||||
removed three items from the queue. */
|
||||
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
/* The medium priority and second high priority tasks are still
|
||||
suspended. Make sure to resume them before starting again. */
|
||||
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
|
||||
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
|
||||
|
||||
/* Just keep incrementing to show the task is still executing. */
|
||||
xCheckVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
|
||||
{
|
||||
portBASE_TYPE xDummy = 0;
|
||||
|
||||
/* Write to the queue the requested number of times. The data written is
|
||||
not important. */
|
||||
for( xDummy = 0; xDummy < xIncrement; xDummy++ )
|
||||
{
|
||||
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
|
||||
{
|
||||
/* Did not expect to ever find the queue full. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* All the tasks blocked on the queue have a priority higher than the
|
||||
controlling task. Writing to the queue will therefore have caused this
|
||||
task to be preempted. By the time this line executes the event task will
|
||||
have executed and incremented its counter. Increment the expected counter
|
||||
to the same value. */
|
||||
( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
|
||||
|
||||
/* Check the actual counts and expected counts really are the same. */
|
||||
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
|
||||
{
|
||||
/* The counters were not the same. This means a task we did not expect
|
||||
to unblock actually did unblock. */
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreMultiEventTasksStillRunning( void )
|
||||
{
|
||||
static portBASE_TYPE xPreviousCheckVariable = 0;
|
||||
|
||||
/* Called externally to periodically check that this test is still
|
||||
operational. */
|
||||
|
||||
if( xPreviousCheckVariable == xCheckVariable )
|
||||
{
|
||||
xHealthStatus = pdFAIL;
|
||||
}
|
||||
|
||||
xPreviousCheckVariable = xCheckVariable;
|
||||
|
||||
return xHealthStatus;
|
||||
}
|
||||
|
||||
|
||||
148
20091005/Demo/Common/Full/flash.c
Normal file
148
20091005/Demo/Common/Full/flash.c
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port
|
||||
* uses IO port F.
|
||||
*
|
||||
* \page flashC flash.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
|
||||
Changes from V2.1.1
|
||||
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
#include "print.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* Structure used to pass parameters to the LED tasks. */
|
||||
typedef struct LED_PARAMETERS
|
||||
{
|
||||
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
|
||||
portTickType xFlashRate; /*< The rate at which the LED should flash. */
|
||||
} xLEDParameters;
|
||||
|
||||
/* The task that is created eight times - each time with a different xLEDParaemtes
|
||||
structure passed in as the parameter. */
|
||||
static void vLEDFlashTask( void *pvParameters );
|
||||
|
||||
/* String to print if USE_STDIO is defined. */
|
||||
const portCHAR * const pcTaskStartMsg = "LED flash task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE uxLEDTask;
|
||||
xLEDParameters *pxLEDParameters;
|
||||
const unsigned portBASE_TYPE uxNumOfLEDs = 8;
|
||||
const portTickType xFlashRate = 125;
|
||||
|
||||
/* Create the eight tasks. */
|
||||
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
|
||||
{
|
||||
/* Create and complete the structure used to pass parameters to the next
|
||||
created task. */
|
||||
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
|
||||
pxLEDParameters->uxLED = uxLEDTask;
|
||||
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( portTickType ) uxLEDTask ) );
|
||||
pxLEDParameters->xFlashRate /= portTICK_RATE_MS;
|
||||
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vLEDFlashTask( void *pvParameters )
|
||||
{
|
||||
xLEDParameters *pxParameters;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
pxParameters = ( xLEDParameters * ) pvParameters;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( portTickType ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelay( pxParameters->xFlashRate / ( portTickType ) 2 );
|
||||
vParTestToggleLED( pxParameters->uxLED );
|
||||
}
|
||||
}
|
||||
|
||||
351
20091005/Demo/Common/Full/flop.c
Normal file
351
20091005/Demo/Common/Full/flop.c
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.3
|
||||
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates eight tasks, each of which loops continuously performing an (emulated)
|
||||
* floating point calculation.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle priority
|
||||
* means that these tasks will get pre-empted any time another task is ready to run
|
||||
* or a time slice occurs. More often than not the pre-emption will occur mid
|
||||
* calculation, creating a good test of the schedulers context switch mechanism - a
|
||||
* calculation producing an unexpected result could be a symptom of a corruption in
|
||||
* the context of a task.
|
||||
*
|
||||
* \page FlopC flop.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#define mathSTACK_SIZE ( ( unsigned portSHORT ) 512 )
|
||||
#define mathNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
Each of the four is created twice. */
|
||||
static void vCompetingMathTask1( void *pvParameters );
|
||||
static void vCompetingMathTask2( void *pvParameters );
|
||||
static void vCompetingMathTask3( void *pvParameters );
|
||||
static void vCompetingMathTask4( void *pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
task gets a calculation wrong it will
|
||||
stop incrementing its check variable. */
|
||||
static volatile unsigned portSHORT usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask1( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
|
||||
const portCHAR * const pcTaskStartMsg = "Math task 1 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Math task 1 failed.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for(;;)
|
||||
{
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
d4 = ( d1 + d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask2( void *pvParameters )
|
||||
{
|
||||
portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
|
||||
const portCHAR * const pcTaskStartMsg = "Math task 2 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Math task 2 failed.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
d4 = ( d1 / d2 ) * d3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know
|
||||
this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask3( void *pvParameters )
|
||||
{
|
||||
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const unsigned portSHORT usArraySize = 250;
|
||||
unsigned portSHORT usPosition;
|
||||
const portCHAR * const pcTaskStartMsg = "Math task 3 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Math task 3 failed.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
|
||||
dTotal1 += ( portDOUBLE ) usPosition + 5.5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompetingMathTask4( void *pvParameters )
|
||||
{
|
||||
portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const unsigned portSHORT usArraySize = 250;
|
||||
unsigned portSHORT usPosition;
|
||||
const portCHAR * const pcTaskStartMsg = "Math task 4 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Math task 4 failed.\r\n";
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
|
||||
dTotal1 += ( portDOUBLE ) usPosition * 12.123;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ usPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
since the last call. */
|
||||
static unsigned portSHORT usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still incrementing. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
347
20091005/Demo/Common/Full/integer.c
Normal file
347
20091005/Demo/Common/Full/integer.c
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.3
|
||||
|
||||
+ The created tasks now include calls to tskYIELD(), allowing them to be used
|
||||
with the cooperative scheduler.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This does the same as flop. c, but uses variables of type long instead of
|
||||
* type double.
|
||||
*
|
||||
* As with flop. c, the tasks created in this file are a good test of the
|
||||
* scheduler context switch mechanism. The processor has to access 32bit
|
||||
* variables in two or four chunks (depending on the processor). The low
|
||||
* priority of these tasks means there is a high probability that a context
|
||||
* switch will occur mid calculation. See the flop. c documentation for
|
||||
* more information.
|
||||
*
|
||||
* \page IntegerC integer.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.1
|
||||
|
||||
+ The constants used in the calculations are larger to ensure the
|
||||
optimiser does not truncate them to 16 bits.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "print.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "integer.h"
|
||||
|
||||
#define intgSTACK_SIZE ( ( unsigned portSHORT ) 256 )
|
||||
#define intgNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different calculation on four byte
|
||||
variables. Each of the four is created twice. */
|
||||
static void vCompeteingIntMathTask1( void *pvParameters );
|
||||
static void vCompeteingIntMathTask2( void *pvParameters );
|
||||
static void vCompeteingIntMathTask3( void *pvParameters );
|
||||
static void vCompeteingIntMathTask4( void *pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
task gets a calculation wrong it will stop incrementing its check variable. */
|
||||
static volatile unsigned portSHORT usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask1( void *pvParameters )
|
||||
{
|
||||
portLONG l1, l2, l3, l4;
|
||||
portSHORT sError = pdFALSE;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const portLONG lAnswer = ( ( portLONG ) 74565L + ( portLONG ) 1234567L ) * ( portLONG ) -918L;
|
||||
const portCHAR * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for(;;)
|
||||
{
|
||||
l1 = ( portLONG ) 74565L;
|
||||
l2 = ( portLONG ) 1234567L;
|
||||
l3 = ( portLONG ) -918L;
|
||||
|
||||
l4 = ( l1 + l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask2( void *pvParameters )
|
||||
{
|
||||
portLONG l1, l2, l3, l4;
|
||||
portSHORT sError = pdFALSE;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const portLONG lAnswer = ( ( portLONG ) -389000L / ( portLONG ) 329999L ) * ( portLONG ) -89L;
|
||||
const portCHAR * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
l1 = -389000L;
|
||||
l2 = 329999L;
|
||||
l3 = -89L;
|
||||
|
||||
l4 = ( l1 / l2 ) * l3;
|
||||
|
||||
taskYIELD();
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( l4 != lAnswer )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask3( void *pvParameters )
|
||||
{
|
||||
portLONG *plArray, lTotal1, lTotal2;
|
||||
portSHORT sError = pdFALSE;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const unsigned portSHORT usArraySize = ( unsigned portSHORT ) 250;
|
||||
unsigned portSHORT usPosition;
|
||||
const portCHAR * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( portLONG * ) pvPortMalloc( ( size_t ) 250 * sizeof( portLONG ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
lTotal1 = ( portLONG ) 0;
|
||||
lTotal2 = ( portLONG ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( portLONG ) usPosition + ( portLONG ) 5;
|
||||
lTotal1 += ( portLONG ) usPosition + ( portLONG ) 5;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vCompeteingIntMathTask4( void *pvParameters )
|
||||
{
|
||||
portLONG *plArray, lTotal1, lTotal2;
|
||||
portSHORT sError = pdFALSE;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const unsigned portSHORT usArraySize = 250;
|
||||
unsigned portSHORT usPosition;
|
||||
const portCHAR * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
|
||||
const portCHAR * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Create the array we are going to use for our check calculation. */
|
||||
plArray = ( portLONG * ) pvPortMalloc( ( size_t ) 250 * sizeof( portLONG ) );
|
||||
|
||||
/* Keep filling the array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
lTotal1 = ( portLONG ) 0;
|
||||
lTotal2 = ( portLONG ) 0;
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
plArray[ usPosition ] = ( portLONG ) usPosition * ( portLONG ) 12;
|
||||
lTotal1 += ( portLONG ) usPosition * ( portLONG ) 12;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
|
||||
{
|
||||
lTotal2 += plArray[ usPosition ];
|
||||
}
|
||||
|
||||
|
||||
if( lTotal1 != lTotal2 )
|
||||
{
|
||||
vPrintDisplayMessage( &pcTaskFailMsg );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
taskYIELD();
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
since the last call. */
|
||||
static unsigned portSHORT usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still incrementing. */
|
||||
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
126
20091005/Demo/Common/Full/print.c
Normal file
126
20091005/Demo/Common/Full/print.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Manages a queue of strings that are waiting to be displayed. This is used to
|
||||
* ensure mutual exclusion of console output.
|
||||
*
|
||||
* A task wishing to display a message will call vPrintDisplayMessage (), with a
|
||||
* pointer to the string as the parameter. The pointer is posted onto the
|
||||
* xPrintQueue queue.
|
||||
*
|
||||
* The task spawned in main. c blocks on xPrintQueue. When a message becomes
|
||||
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next
|
||||
* string, then uses the functions defined in the portable layer FileIO. c to
|
||||
* display the message.
|
||||
*
|
||||
* <b>NOTE:</b>
|
||||
* Using console IO can disrupt real time performance - depending on the port.
|
||||
* Standard C IO routines are not designed for real time applications. While
|
||||
* standard IO is useful for demonstration and debugging an alternative method
|
||||
* should be used if you actually require console IO as part of your application.
|
||||
*
|
||||
* \page PrintC print.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "print.h"
|
||||
|
||||
static xQueueHandle xPrintQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintInitialise( void )
|
||||
{
|
||||
const unsigned portBASE_TYPE uxQueueSize = 20;
|
||||
|
||||
/* Create the queue on which errors will be reported. */
|
||||
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( portCHAR * ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend )
|
||||
{
|
||||
#ifdef USE_STDIO
|
||||
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( portTickType ) 0 );
|
||||
#else
|
||||
/* Stop warnings. */
|
||||
( void ) ppcMessageToSend;
|
||||
#endif
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
const portCHAR *pcPrintGetNextMessage( portTickType xPrintRate )
|
||||
{
|
||||
portCHAR *pcMessage;
|
||||
|
||||
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
|
||||
{
|
||||
return pcMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
305
20091005/Demo/Common/Full/semtest.c
Normal file
305
20091005/Demo/Common/Full/semtest.c
Normal file
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates two sets of two tasks. The tasks within a set share a variable, access
|
||||
* to which is guarded by a semaphore.
|
||||
*
|
||||
* Each task starts by attempting to obtain the semaphore. On obtaining a
|
||||
* semaphore a task checks to ensure that the guarded variable has an expected
|
||||
* value. It then clears the variable to zero before counting it back up to the
|
||||
* expected value in increments of 1. After each increment the variable is checked
|
||||
* to ensure it contains the value to which it was just set. When the starting
|
||||
* value is again reached the task releases the semaphore giving the other task in
|
||||
* the set a chance to do exactly the same thing. The starting value is high
|
||||
* enough to ensure that a tick is likely to occur during the incrementing loop.
|
||||
*
|
||||
* An error is flagged if at any time during the process a shared variable is
|
||||
* found to have a value other than that expected. Such an occurrence would
|
||||
* suggest an error in the mutual exclusion mechanism by which access to the
|
||||
* variable is restricted.
|
||||
*
|
||||
* The first set of two tasks poll their semaphore. The second set use blocking
|
||||
* calls.
|
||||
*
|
||||
* \page SemTestC semtest.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.0:
|
||||
|
||||
+ The tasks that operate at the idle priority now use a lower expected
|
||||
count than those running at a higher priority. This prevents the low
|
||||
priority tasks from signaling an error because they have not been
|
||||
scheduled enough time for each of them to count the shared variable to
|
||||
the high value.
|
||||
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
|
||||
Changes from V2.1.1
|
||||
|
||||
+ The stack size now uses configMINIMAL_STACK_SIZE.
|
||||
+ String constants made file scope to decrease stack depth on 8051 port.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "semtest.h"
|
||||
#include "print.h"
|
||||
|
||||
/* The value to which the shared variables are counted. */
|
||||
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned portLONG ) 0xfff )
|
||||
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned portLONG ) 0xff )
|
||||
|
||||
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
#define semtstNUM_TASKS ( 4 )
|
||||
|
||||
#define semtstDELAY_FACTOR ( ( portTickType ) 10 )
|
||||
|
||||
/* The task function as described at the top of the file. */
|
||||
static void prvSemaphoreTest( void *pvParameters );
|
||||
|
||||
/* Structure used to pass parameters to each task. */
|
||||
typedef struct SEMAPHORE_PARAMETERS
|
||||
{
|
||||
xSemaphoreHandle xSemaphore;
|
||||
volatile unsigned portLONG *pulSharedVariable;
|
||||
portTickType xBlockTime;
|
||||
} xSemaphoreParameters;
|
||||
|
||||
/* Variables used to check that all the tasks are still running without errors. */
|
||||
static volatile portSHORT sCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
static volatile portSHORT sNextCheckVariable = 0;
|
||||
|
||||
/* Strings to print if USE_STDIO is defined. */
|
||||
const portCHAR * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
|
||||
const portCHAR * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;
|
||||
const portTickType xBlockTime = ( portTickType ) 100;
|
||||
|
||||
/* Create the structure used to pass parameters to the first two tasks. */
|
||||
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxFirstSemaphoreParameters != NULL )
|
||||
{
|
||||
/* Create the semaphore used by the first two tasks. */
|
||||
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
/* Create the variable which is to be shared by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
|
||||
|
||||
/* Initialise the share variable to the value the tasks expect. */
|
||||
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
|
||||
/* The first two tasks do not block on semaphore calls. */
|
||||
pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;
|
||||
|
||||
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do exactly the same to create the second set of tasks, only this time
|
||||
provide a block time for the semaphore calls. */
|
||||
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
if( pxSecondSemaphoreParameters != NULL )
|
||||
{
|
||||
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
|
||||
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
|
||||
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;
|
||||
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSemaphoreTest( void *pvParameters )
|
||||
{
|
||||
xSemaphoreParameters *pxParameters;
|
||||
volatile unsigned portLONG *pulSharedVariable, ulExpectedValue;
|
||||
unsigned portLONG ulCounter;
|
||||
portSHORT sError = pdFALSE, sCheckVariableToUse;
|
||||
|
||||
/* See which check variable to use. sNextCheckVariable is not semaphore
|
||||
protected! */
|
||||
portENTER_CRITICAL();
|
||||
sCheckVariableToUse = sNextCheckVariable;
|
||||
sNextCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcSemaphoreTaskStart );
|
||||
|
||||
/* A structure is passed in as the parameter. This contains the shared
|
||||
variable being guarded. */
|
||||
pxParameters = ( xSemaphoreParameters * ) pvParameters;
|
||||
pulSharedVariable = pxParameters->pulSharedVariable;
|
||||
|
||||
/* If we are blocking we use a much higher count to ensure loads of context
|
||||
switches occur during the count. */
|
||||
if( pxParameters->xBlockTime > ( portTickType ) 0 )
|
||||
{
|
||||
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try to obtain the semaphore. */
|
||||
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
/* We have the semaphore and so expect any other tasks using the
|
||||
shared variable to have left it in the state we expect to find
|
||||
it. */
|
||||
if( *pulSharedVariable != ulExpectedValue )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
/* Clear the variable, then count it back up to the expected value
|
||||
before releasing the semaphore. Would expect a context switch or
|
||||
two during this time. */
|
||||
for( ulCounter = ( unsigned portLONG ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
|
||||
{
|
||||
*pulSharedVariable = ulCounter;
|
||||
if( *pulSharedVariable != ulCounter )
|
||||
{
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
}
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the semaphore, and if no errors have occurred increment the check
|
||||
variable. */
|
||||
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
|
||||
{
|
||||
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
if( sCheckVariableToUse < semtstNUM_TASKS )
|
||||
{
|
||||
( sCheckVariables[ sCheckVariableToUse ] )++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a block time then we are running at a priority higher
|
||||
than the idle priority. This task takes a long time to complete
|
||||
a cycle (deliberately so to test the guarding) so will be starving
|
||||
out lower priority tasks. Block for some time to allow give lower
|
||||
priority tasks some processor time. */
|
||||
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pxParameters->xBlockTime == ( portTickType ) 0 )
|
||||
{
|
||||
/* We have not got the semaphore yet, so no point using the
|
||||
processor. We are not blocking when attempting to obtain the
|
||||
semaphore. */
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
portBASE_TYPE xTask, xReturn = pdTRUE;
|
||||
|
||||
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
|
||||
{
|
||||
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
314
20091005/Demo/Common/Minimal/AltBlckQ.c
Normal file
314
20091005/Demo/Common/Minimal/AltBlckQ.c
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a version of BlockQ.c that uses the alternative (Alt) API.
|
||||
*
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "AltBlckQ.h"
|
||||
|
||||
#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
xQueueHandle xQueue; /*< The queue to be used by the task. */
|
||||
portTickType xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile portSHORT *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
it is the expected number. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
found to be the expected value.
|
||||
These are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartAltBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
|
||||
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
|
||||
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
|
||||
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
|
||||
const portTickType xDontBlock = ( portTickType ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt blocking queue producer task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueAltSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt blocking queue consumer task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueAltReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreAltBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
static portSHORT sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not.
|
||||
|
||||
Loop through each check variable to and return pdFALSE if any are found not
|
||||
to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
531
20091005/Demo/Common/Minimal/AltBlock.c
Normal file
531
20091005/Demo/Common/Minimal/AltBlock.c
Normal file
|
|
@ -0,0 +1,531 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a version of BlockTim.c that uses the light weight API.
|
||||
*
|
||||
* This file contains some test scenarios that ensure tasks do not exit queue
|
||||
* send or receive functions prematurely. A description of the tests is
|
||||
* included within the code.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "AltBlock.h"
|
||||
|
||||
/* Task priorities. */
|
||||
#define bktPRIMARY_PRIORITY ( 3 )
|
||||
#define bktSECONDARY_PRIORITY ( 2 )
|
||||
|
||||
/* Task behaviour. */
|
||||
#define bktQUEUE_LENGTH ( 5 )
|
||||
#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
|
||||
#define bktPRIMARY_BLOCK_TIME ( 10 )
|
||||
#define bktALLOWABLE_MARGIN ( 12 )
|
||||
#define bktTIME_TO_BLOCK ( 175 )
|
||||
#define bktDONT_BLOCK ( ( portTickType ) 0 )
|
||||
#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
|
||||
|
||||
/* The queue on which the tasks block. */
|
||||
static xQueueHandle xTestQueue;
|
||||
|
||||
/* Handle to the secondary task is required by the primary task for calls
|
||||
to vTaskSuspend/Resume(). */
|
||||
static xTaskHandle xSecondary;
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
|
||||
static portBASE_TYPE xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Provides a simple mechanism for the primary task to know when the
|
||||
secondary task has executed. */
|
||||
static volatile unsigned portBASE_TYPE xRunIndicator;
|
||||
|
||||
/* The two test tasks. Their behaviour is commented within the files. */
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters );
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateAltBlockTimeTasks( void )
|
||||
{
|
||||
/* Create the queue on which the two tasks block. */
|
||||
xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
|
||||
|
||||
|
||||
/* Create the two test tasks. */
|
||||
xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
|
||||
xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE xItem, xData;
|
||||
portTickType xTimeWhenBlocking;
|
||||
portTickType xTimeToBlock, xBlockedTime;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 1
|
||||
|
||||
Simple block time wakeup test on queue receives. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is empty. Attempt to read from the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
|
||||
|
||||
/* A critical section is used to minimise the jitter in the time
|
||||
measurements. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Test 2
|
||||
|
||||
Simple block time wakeup test on queue sends.
|
||||
|
||||
First fill the queue. It should be empty so all sends should pass. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is full. Attempt to write to the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
Wake the other task, it will block attempting to post to the queue.
|
||||
When we read from the queue the other task will wake, but before it
|
||||
can run we will post to the queue again. When the other task runs it
|
||||
will find the queue still full, even though it was woken. It should
|
||||
recognise that its block time has not expired and return to block for
|
||||
the remains of its block time.
|
||||
|
||||
Wake the other task so it blocks attempting to post to the already
|
||||
full queue. */
|
||||
xRunIndicator = 0;
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task has not yet executed. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
/* Make sure the other task is blocked on the queue. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we make space on the queue the other task should wake
|
||||
but not execute as this task has higher priority. */
|
||||
if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now fill the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
full ourselves, and the other task have set xRunIndicator. */
|
||||
if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the priority back down. */
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test 3 - but with the send and receive the other way around.
|
||||
The other task blocks attempting to read from the queue.
|
||||
|
||||
Empty the queue. We should find that it is full. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake the other task so it blocks attempting to read from the
|
||||
already empty queue. */
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we place an item on the queue the other task should
|
||||
wake but not execute as this task has higher priority. */
|
||||
if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now empty the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
empty ourselves, and the other task would be suspended. */
|
||||
if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
portTickType xTimeWhenBlocking, xBlockedTime;
|
||||
portBASE_TYPE xData;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 1 and 2
|
||||
|
||||
This task does does not participate in these tests. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
The first thing we do is attempt to read from the queue. It should be
|
||||
full so we block. Note the time before we block so we can check the
|
||||
wake time is as per that expected. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not received
|
||||
anything on the queue. */
|
||||
xData = 0;
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we inside the send function? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as
|
||||
soon as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Suspend ready for test 3. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test three, but with the send and receive reversed. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not received
|
||||
anything on the queue. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as soon
|
||||
as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
xSecondaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
|
||||
{
|
||||
static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
|
||||
portBASE_TYPE xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
last called? */
|
||||
if( xPrimaryCycles == xLastPrimaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xSecondaryCycles == xLastSecondaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred == pdTRUE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastSecondaryCycleCount = xSecondaryCycles;
|
||||
xLastPrimaryCycleCount = xPrimaryCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
257
20091005/Demo/Common/Minimal/AltPollQ.c
Normal file
257
20091005/Demo/Common/Minimal/AltPollQ.c
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a version of PollQ.c that uses the alternative (Alt) API.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "AltPollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define pollqQUEUE_SIZE ( 10 )
|
||||
#define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS )
|
||||
#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) )
|
||||
#define pollqNO_DELAY ( ( portTickType ) 0 )
|
||||
#define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 )
|
||||
#define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no
|
||||
errors. */
|
||||
static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartAltPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
static xQueueHandle xPolledQueue;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xPolledQueue, ( signed portCHAR * ) "AltPollQueue" );
|
||||
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, ( signed portCHAR * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( vPolledQueueProducer, ( signed portCHAR * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = ( unsigned portSHORT ) 0;
|
||||
signed portBASE_TYPE xError = pdFALSE, xLoop;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt polling queue producer task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueAltSendToBack( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full so if we get here there
|
||||
has been an error. */
|
||||
xError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
check variable. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingProducerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
usValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
empties the queue. */
|
||||
vTaskDelay( pollqPRODUCER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = ( unsigned portSHORT ) 0;
|
||||
signed portBASE_TYPE xError = pdFALSE;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt blocking queue consumer task started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) )
|
||||
{
|
||||
if( xQueueAltReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
occurred. */
|
||||
xError = pdTRUE;
|
||||
|
||||
/* Catch-up to the value we received so our next expected
|
||||
value should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
occurred. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingConsumerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
/* Next time round we would expect the number to be one higher. */
|
||||
usExpectedValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
items in the queue. */
|
||||
vTaskDelay( pollqCONSUMER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
portBASE_TYPE xAreAltPollingQueuesStillRunning( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Check both the consumer and producer poll count to check they have both
|
||||
been changed since out last trip round. We do not need a critical section
|
||||
around the check variables as this is called from a higher priority than
|
||||
the other tasks that access the same variables. */
|
||||
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
|
||||
( xPollingProducerCount == pollqINITIAL_VALUE )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the check variables back down so we know if they have been
|
||||
incremented the next time around. */
|
||||
xPollingConsumerCount = pollqINITIAL_VALUE;
|
||||
xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
569
20091005/Demo/Common/Minimal/AltQTest.c
Normal file
569
20091005/Demo/Common/Minimal/AltQTest.c
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This file implements the same demo and test as GenQTest.c, but uses the
|
||||
* light weight API in place of the fully featured API.
|
||||
*
|
||||
* See the comments at the top of GenQTest.c for a description.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "AltQTest.h"
|
||||
|
||||
#define genqQUEUE_LENGTH ( 5 )
|
||||
#define genqNO_BLOCK ( 0 )
|
||||
|
||||
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Tests the behaviour of the xQueueAltSendToFront() and xQueueAltSendToBack()
|
||||
* macros by using both to fill a queue, then reading from the queue to
|
||||
* check the resultant queue order is as expected. Queue data is also
|
||||
* peeked.
|
||||
*/
|
||||
static void prvSendFrontAndBackTest( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the mutex behaviour.
|
||||
* Each task is given a different priority to demonstrate the priority
|
||||
* inheritance mechanism.
|
||||
*
|
||||
* The low priority task obtains a mutex. After this a high priority task
|
||||
* attempts to obtain the same mutex, causing its priority to be inherited
|
||||
* by the low priority task. The task with the inherited high priority then
|
||||
* resumes a medium priority task to ensure it is not blocked by the medium
|
||||
* priority task while it holds the inherited high priority. Once the mutex
|
||||
* is returned the task with the inherited priority returns to its original
|
||||
* low priority, and is therefore immediately preempted by first the high
|
||||
* priority task and then the medium prioroity task before it can continue.
|
||||
*/
|
||||
static void prvLowPriorityMutexTask( void *pvParameters );
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters );
|
||||
static void prvHighPriorityMutexTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static portBASE_TYPE xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counters that are incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile unsigned portLONG ulLoopCounter = 0;
|
||||
static volatile unsigned portLONG ulLoopCounter2 = 0;
|
||||
|
||||
/* The variable that is guarded by the mutex in the mutex demo tasks. */
|
||||
static volatile unsigned portLONG ulGuardedVariable = 0;
|
||||
|
||||
/* Handles used in the mutext test to suspend and resume the high and medium
|
||||
priority mutex test tasks. */
|
||||
static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartAltGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xQueueHandle xQueue;
|
||||
xSemaphoreHandle xMutex;
|
||||
|
||||
/* Create the queue that we are going to use for the
|
||||
prvSendFrontAndBackTest demo. */
|
||||
xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Alt_Gen_Test_Queue" );
|
||||
|
||||
/* Create the demo task and pass it the queue just created. We are
|
||||
passing the queue handle by value so it does not matter that it is
|
||||
declared on the stack here. */
|
||||
xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * ) "FGenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
|
||||
|
||||
/* Create the mutex used by the prvMutexTest task. */
|
||||
xMutex = xSemaphoreCreateMutex();
|
||||
|
||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate mutex and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Alt_Q_Mutex" );
|
||||
|
||||
/* Create the mutex demo tasks and pass it the mutex just created. We are
|
||||
passing the mutex handle by value so it does not matter that it is declared
|
||||
on the stack here. */
|
||||
xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * ) "FMuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * ) "FMuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
||||
xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * ) "FMuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSendFrontAndBackTest( void *pvParameters )
|
||||
{
|
||||
unsigned portLONG ulData, ulData2;
|
||||
xQueueHandle xQueue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Alt queue SendToFront/SendToBack/Peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
xQueue = ( xQueueHandle ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The queue is empty, so sending an item to the back of the queue
|
||||
should have the same efect as sending it to the front of the queue.
|
||||
|
||||
First send to the front and check everything is as expected. */
|
||||
xQueueAltSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Then do the same, sending the data to the back, checking everything
|
||||
is as expected. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
xQueueAltSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
|
||||
for( ulData = 2; ulData < 5; ulData++ )
|
||||
{
|
||||
xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
}
|
||||
|
||||
/* Now the order in the queue should be 2, 3, 4, with 2 being the first
|
||||
thing to be read out. Now add 1 then 0 to the front of the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 3 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 1;
|
||||
xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
ulData = 0;
|
||||
xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
|
||||
/* Now the queue should be full, and when we read the data out we
|
||||
should receive 0, 1, 2, 3, 4. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
|
||||
{
|
||||
/* Try peeking the data first. */
|
||||
if( xQueueAltPeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Now try receiving the data for real. The value should be the
|
||||
same. Clobber the value first so we know we really received it. */
|
||||
ulData2 = ~ulData2;
|
||||
if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should now be empty again. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
/* Our queue is empty once more, add 10, 11 to the back. */
|
||||
ulData = 10;
|
||||
if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 11;
|
||||
if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
|
||||
front. */
|
||||
for( ulData = 9; ulData >= 7; ulData-- )
|
||||
{
|
||||
if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now check that the queue is full, and that receiving data provides
|
||||
the expected sequence of 7, 8, 9, 10, 11. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
|
||||
{
|
||||
if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLoopCounter++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Fast mutex with priority inheritance test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Take the mutex. It should be available now. */
|
||||
if( xSemaphoreAltTake( xMutex, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set our guarded variable to a known start value. */
|
||||
ulGuardedVariable = 0;
|
||||
|
||||
/* Our priority should be as per that assigned when the task was
|
||||
created. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the high priority task. This will attempt to take the
|
||||
mutex, and block when it finds it cannot obtain it. */
|
||||
vTaskResume( xHighPriorityMutexTask );
|
||||
|
||||
/* We should now have inherited the prioritoy of the high priority task,
|
||||
as by now it will have attempted to get the mutex. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We can attempt to set our priority to the test priority - between the
|
||||
idle priority and the medium/high test priorities, but our actual
|
||||
prioroity should remain at the high priority. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the medium priority task. This should not run as our
|
||||
inherited priority is above that of the medium priority task. */
|
||||
vTaskResume( xMediumPriorityMutexTask );
|
||||
|
||||
/* If the did run then it will have incremented our guarded variable. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we give back the semaphore our priority should be disinherited
|
||||
back to the priority to which we attempted to set ourselves. This means
|
||||
that when the high priority task next blocks, the medium priority task
|
||||
should execute and increment the guarded variable. When we next run
|
||||
both the high and medium priority tasks will have been suspended again. */
|
||||
if( xSemaphoreAltGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Check that the guarded variable did indeed increment... */
|
||||
if( ulGuardedVariable != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* ... and that our priority has been disinherited to
|
||||
genqMUTEX_TEST_PRIORITY. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set our priority back to our original priority ready for the next
|
||||
loop around this test. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
|
||||
|
||||
/* Just to show we are still running. */
|
||||
ulLoopCounter2++;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The medium priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is increment the guarded
|
||||
variable, this is so the low priority task knows that it has
|
||||
executed. */
|
||||
ulGuardedVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The high priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is attempt to obtain
|
||||
the mutex. It should find the mutex is not available so a
|
||||
block time is specified. */
|
||||
if( xSemaphoreAltTake( xMutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we eventually obtain the mutex we just give it back then
|
||||
return to suspend ready for the next test. */
|
||||
if( xSemaphoreAltGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreAltGenericQueueTasksStillRunning( void )
|
||||
{
|
||||
static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loopcounters to
|
||||
have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulLastLoopCounter2 == ulLoopCounter2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
ulLastLoopCounter2 = ulLoopCounter2;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return !xErrorDetected;
|
||||
}
|
||||
|
||||
|
||||
302
20091005/Demo/Common/Minimal/BlockQ.c
Normal file
302
20091005/Demo/Common/Minimal/BlockQ.c
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates six tasks that operate on three queues as follows:
|
||||
*
|
||||
* The first two tasks send and receive an incrementing number to/from a queue.
|
||||
* One task acts as a producer and the other as the consumer. The consumer is a
|
||||
* higher priority than the producer and is set to block on queue reads. The queue
|
||||
* only has space for one item - as soon as the producer posts a message on the
|
||||
* queue the consumer will unblock, pre-empt the producer, and remove the item.
|
||||
*
|
||||
* The second two tasks work the other way around. Again the queue used only has
|
||||
* enough space for one item. This time the consumer has a lower priority than the
|
||||
* producer. The producer will try to post on the queue blocking when the queue is
|
||||
* full. When the consumer wakes it will remove the item from the queue, causing
|
||||
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
|
||||
* queue.
|
||||
*
|
||||
* The last two tasks use the same queue producer and consumer functions. This time the queue has
|
||||
* enough space for lots of items and the tasks operate at the same priority. The
|
||||
* producer will execute, placing items into the queue. The consumer will start
|
||||
* executing when either the queue becomes full (causing the producer to block) or
|
||||
* a context switch occurs (tasks of the same priority will time slice).
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Changes from V4.1.1
|
||||
|
||||
+ The second set of tasks were created the wrong way around. This has been
|
||||
corrected.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "BlockQ.h"
|
||||
|
||||
#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define blckqNUM_TASK_SETS ( 3 )
|
||||
|
||||
/* Structure used to pass parameters to the blocking queue tasks. */
|
||||
typedef struct BLOCKING_QUEUE_PARAMETERS
|
||||
{
|
||||
xQueueHandle xQueue; /*< The queue to be used by the task. */
|
||||
portTickType xBlockTime; /*< The block time to use on queue reads/writes. */
|
||||
volatile portSHORT *psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
|
||||
} xBlockingQueueParameters;
|
||||
|
||||
/* Task function that creates an incrementing number and posts it on a queue. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
|
||||
|
||||
/* Task function that removes the incrementing number from a queue and checks that
|
||||
it is the expected number. */
|
||||
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables which are incremented each time an item is removed from a queue, and
|
||||
found to be the expected value.
|
||||
These are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
|
||||
/* Variable which are incremented each time an item is posted on a queue. These
|
||||
are used to check that the tasks are still running. */
|
||||
static volatile portSHORT sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
|
||||
xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
|
||||
xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
|
||||
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
|
||||
const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
|
||||
const portTickType xDontBlock = ( portTickType ) 0;
|
||||
|
||||
/* Create the first two tasks as described at the top of the file. */
|
||||
|
||||
/* First create the structure used to pass parameters to the consumer tasks. */
|
||||
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Create the queue used by the first two tasks to pass the incrementing number.
|
||||
Pass a pointer to the queue in the parameter structure. */
|
||||
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* The consumer is created first so gets a block time as described above. */
|
||||
pxQueueParameters1->xBlockTime = xBlockTime;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check it
|
||||
is still running. */
|
||||
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
|
||||
|
||||
/* Create the structure used to pass parameters to the producer task. */
|
||||
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
|
||||
/* Pass the queue to this task also, using the parameter structure. */
|
||||
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
|
||||
|
||||
/* The producer is not going to block - as soon as it posts the consumer will
|
||||
wake and remove the item so the producer should always have room to post. */
|
||||
pxQueueParameters2->xBlockTime = xDontBlock;
|
||||
|
||||
/* Pass in the variable that this task is going to increment so we can check
|
||||
it is still running. */
|
||||
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
|
||||
|
||||
|
||||
/* Note the producer has a lower priority than the consumer when the tasks are
|
||||
spawned. */
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the second two tasks as described at the top of the file. This uses
|
||||
the same mechanism but reverses the task priorities. */
|
||||
|
||||
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters3->xBlockTime = xDontBlock;
|
||||
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
|
||||
|
||||
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
|
||||
pxQueueParameters4->xBlockTime = xBlockTime;
|
||||
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
|
||||
|
||||
|
||||
|
||||
/* Create the last two tasks as described above. The mechanism is again just
|
||||
the same. This time both parameter structures are given a block time. */
|
||||
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
pxQueueParameters5->xBlockTime = xBlockTime;
|
||||
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
|
||||
|
||||
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
|
||||
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
|
||||
pxQueueParameters6->xBlockTime = xBlockTime;
|
||||
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
|
||||
|
||||
xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
|
||||
{
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully posted a message, so increment the variable
|
||||
used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the variable we are going to post next time round. The
|
||||
consumer will expect the numbers to follow in numerical order. */
|
||||
++usValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = 0;
|
||||
xBlockingQueueParameters *pxQueueParameters;
|
||||
portSHORT sErrorEverOccurred = pdFALSE;
|
||||
|
||||
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* Catch-up. */
|
||||
usExpectedValue = usData;
|
||||
|
||||
sErrorEverOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We have successfully received a message, so increment the
|
||||
variable used to check we are still running. */
|
||||
if( sErrorEverOccurred == pdFALSE )
|
||||
{
|
||||
( *pxQueueParameters->psCheckVariable )++;
|
||||
}
|
||||
|
||||
/* Increment the value we expect to remove from the queue next time
|
||||
round. */
|
||||
++usExpectedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
static portSHORT sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdPASS, xTasks;
|
||||
|
||||
/* Not too worried about mutual exclusion on these variables as they are 16
|
||||
bits and we are only reading them. We also only care to see if they have
|
||||
changed or not.
|
||||
|
||||
Loop through each check variable to and return pdFALSE if any are found not
|
||||
to have changed since the last call. */
|
||||
|
||||
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
|
||||
{
|
||||
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
|
||||
|
||||
|
||||
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
566
20091005/Demo/Common/Minimal/GenQTest.c
Normal file
566
20091005/Demo/Common/Minimal/GenQTest.c
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
|
||||
* including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
|
||||
* mutex behaviour.
|
||||
*
|
||||
* See the comments above the prvSendFrontAndBackTest() and
|
||||
* prvLowPriorityMutexTask() prototypes below for more information.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "GenQTest.h"
|
||||
|
||||
#define genqQUEUE_LENGTH ( 5 )
|
||||
#define genqNO_BLOCK ( 0 )
|
||||
|
||||
#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
|
||||
#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
|
||||
* macros by using both to fill a queue, then reading from the queue to
|
||||
* check the resultant queue order is as expected. Queue data is also
|
||||
* peeked.
|
||||
*/
|
||||
static void prvSendFrontAndBackTest( void *pvParameters );
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the mutex behaviour.
|
||||
* Each task is given a different priority to demonstrate the priority
|
||||
* inheritance mechanism.
|
||||
*
|
||||
* The low priority task obtains a mutex. After this a high priority task
|
||||
* attempts to obtain the same mutex, causing its priority to be inherited
|
||||
* by the low priority task. The task with the inherited high priority then
|
||||
* resumes a medium priority task to ensure it is not blocked by the medium
|
||||
* priority task while it holds the inherited high priority. Once the mutex
|
||||
* is returned the task with the inherited priority returns to its original
|
||||
* low priority, and is therefore immediately preempted by first the high
|
||||
* priority task and then the medium prioroity task before it can continue.
|
||||
*/
|
||||
static void prvLowPriorityMutexTask( void *pvParameters );
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters );
|
||||
static void prvHighPriorityMutexTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static portBASE_TYPE xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counters that are incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile unsigned portLONG ulLoopCounter = 0;
|
||||
static volatile unsigned portLONG ulLoopCounter2 = 0;
|
||||
|
||||
/* The variable that is guarded by the mutex in the mutex demo tasks. */
|
||||
static volatile unsigned portLONG ulGuardedVariable = 0;
|
||||
|
||||
/* Handles used in the mutext test to suspend and resume the high and medium
|
||||
priority mutex test tasks. */
|
||||
static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xQueueHandle xQueue;
|
||||
xSemaphoreHandle xMutex;
|
||||
|
||||
/* Create the queue that we are going to use for the
|
||||
prvSendFrontAndBackTest demo. */
|
||||
xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );
|
||||
|
||||
/* Create the demo task and pass it the queue just created. We are
|
||||
passing the queue handle by value so it does not matter that it is
|
||||
declared on the stack here. */
|
||||
xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
|
||||
|
||||
/* Create the mutex used by the prvMutexTest task. */
|
||||
xMutex = xSemaphoreCreateMutex();
|
||||
|
||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate mutexes and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );
|
||||
|
||||
/* Create the mutex demo tasks and pass it the mutex just created. We are
|
||||
passing the mutex handle by value so it does not matter that it is declared
|
||||
on the stack here. */
|
||||
xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
|
||||
xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSendFrontAndBackTest( void *pvParameters )
|
||||
{
|
||||
unsigned portLONG ulData, ulData2;
|
||||
xQueueHandle xQueue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
xQueue = ( xQueueHandle ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The queue is empty, so sending an item to the back of the queue
|
||||
should have the same efect as sending it to the front of the queue.
|
||||
|
||||
First send to the front and check everything is as expected. */
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Then do the same, sending the data to the back, checking everything
|
||||
is as expected. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* The data we sent to the queue should equal the data we just received
|
||||
from the queue. */
|
||||
if( ulLoopCounter != ulData )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
|
||||
for( ulData = 2; ulData < 5; ulData++ )
|
||||
{
|
||||
xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
}
|
||||
|
||||
/* Now the order in the queue should be 2, 3, 4, with 2 being the first
|
||||
thing to be read out. Now add 1 then 0 to the front of the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 3 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 1;
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
ulData = 0;
|
||||
xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
|
||||
|
||||
/* Now the queue should be full, and when we read the data out we
|
||||
should receive 0, 1, 2, 3, 4. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
|
||||
{
|
||||
/* Try peeking the data first. */
|
||||
if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
|
||||
/* Now try receiving the data for real. The value should be the
|
||||
same. Clobber the value first so we know we really received it. */
|
||||
ulData2 = ~ulData2;
|
||||
if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* The queue should now be empty again. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
|
||||
/* Our queue is empty once more, add 10, 11 to the back. */
|
||||
ulData = 10;
|
||||
if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
ulData = 11;
|
||||
if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
|
||||
front. */
|
||||
for( ulData = 9; ulData >= 7; ulData-- )
|
||||
{
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now check that the queue is full, and that receiving data provides
|
||||
the expected sequence of 7, 8, 9, 10, 11. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 5 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* Check the data we read out is in the expected order. */
|
||||
for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
|
||||
{
|
||||
if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulData != ulData2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLoopCounter++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Take the mutex. It should be available now. */
|
||||
if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set our guarded variable to a known start value. */
|
||||
ulGuardedVariable = 0;
|
||||
|
||||
/* Our priority should be as per that assigned when the task was
|
||||
created. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the high priority task. This will attempt to take the
|
||||
mutex, and block when it finds it cannot obtain it. */
|
||||
vTaskResume( xHighPriorityMutexTask );
|
||||
|
||||
/* We should now have inherited the prioritoy of the high priority task,
|
||||
as by now it will have attempted to get the mutex. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We can attempt to set our priority to the test priority - between the
|
||||
idle priority and the medium/high test priorities, but our actual
|
||||
prioroity should remain at the high priority. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now unsuspend the medium priority task. This should not run as our
|
||||
inherited priority is above that of the medium priority task. */
|
||||
vTaskResume( xMediumPriorityMutexTask );
|
||||
|
||||
/* If the did run then it will have incremented our guarded variable. */
|
||||
if( ulGuardedVariable != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we give back the semaphore our priority should be disinherited
|
||||
back to the priority to which we attempted to set ourselves. This means
|
||||
that when the high priority task next blocks, the medium priority task
|
||||
should execute and increment the guarded variable. When we next run
|
||||
both the high and medium priority tasks will have been suspended again. */
|
||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Check that the guarded variable did indeed increment... */
|
||||
if( ulGuardedVariable != 1 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* ... and that our priority has been disinherited to
|
||||
genqMUTEX_TEST_PRIORITY. */
|
||||
if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set our priority back to our original priority ready for the next
|
||||
loop around this test. */
|
||||
vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
|
||||
|
||||
/* Just to show we are still running. */
|
||||
ulLoopCounter2++;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The medium priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is increment the guarded
|
||||
variable, this is so the low priority task knows that it has
|
||||
executed. */
|
||||
ulGuardedVariable++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityMutexTask( void *pvParameters )
|
||||
{
|
||||
xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* The high priority task starts by suspending itself. The low
|
||||
priority task will unsuspend this task when required. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/* When this task unsuspends all it does is attempt to obtain
|
||||
the mutex. It should find the mutex is not available so a
|
||||
block time is specified. */
|
||||
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we eventually obtain the mutex we just give it back then
|
||||
return to suspend ready for the next test. */
|
||||
if( xSemaphoreGive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
|
||||
{
|
||||
static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loopcounters to
|
||||
have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulLastLoopCounter2 == ulLoopCounter2 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
ulLastLoopCounter2 = ulLoopCounter2;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return !xErrorDetected;
|
||||
}
|
||||
|
||||
|
||||
716
20091005/Demo/Common/Minimal/IntQueue.c
Normal file
716
20091005/Demo/Common/Minimal/IntQueue.c
Normal file
|
|
@ -0,0 +1,716 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines one of the more complex set of demo/test tasks. They are
|
||||
* designed to stress test the queue implementation though pseudo simultaneous
|
||||
* multiple reads and multiple writes from both tasks of varying priority and
|
||||
* interrupts. The interrupts are prioritised such to ensure that nesting
|
||||
* occurs (for those ports that support it).
|
||||
*
|
||||
* The test ensures that, while being accessed from three tasks and two
|
||||
* interrupts, all the data sent to the queues is also received from
|
||||
* the same queue, and that no duplicate items are either sent or received.
|
||||
* The tests also ensure that a low priority task is never able to successfully
|
||||
* read from or write to a queue when a task of higher priority is attempting
|
||||
* the same operation.
|
||||
*/
|
||||
|
||||
/* Standard includes. */
|
||||
#include <string.h>
|
||||
|
||||
/* SafeRTOS includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "queue.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo app includes. */
|
||||
#include "IntQueue.h"
|
||||
#include "IntQueueTimer.h"
|
||||
|
||||
/* Priorities used by test tasks. */
|
||||
#define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
|
||||
#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
|
||||
|
||||
/* The number of values to send/receive before checking that all values were
|
||||
processed as expected. */
|
||||
#define intqNUM_VALUES_TO_LOG ( 200 )
|
||||
#define intqSHORT_DELAY ( 75 )
|
||||
|
||||
/* The value by which the value being sent to or received from a queue should
|
||||
increment past intqNUM_VALUES_TO_LOG before we check that all values have been
|
||||
sent/received correctly. This is done to ensure that all tasks and interrupts
|
||||
accessing the queue have completed their accesses with the
|
||||
intqNUM_VALUES_TO_LOG range. */
|
||||
#define intqVALUE_OVERRUN ( 50 )
|
||||
|
||||
/* The delay used by the polling task. A short delay is used for code
|
||||
coverage. */
|
||||
#define intqONE_TICK_DELAY ( 1 )
|
||||
|
||||
/* Each task and interrupt is given a unique identifier. This value is used to
|
||||
identify which task sent or received each value. The identifier is also used
|
||||
to distinguish between two tasks that are running the same task function. */
|
||||
#define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )
|
||||
#define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )
|
||||
#define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )
|
||||
#define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )
|
||||
#define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )
|
||||
#define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )
|
||||
|
||||
/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
|
||||
from each queue by each task, otherwise an error is detected. */
|
||||
#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
|
||||
|
||||
/* Send the next value to the queue that is normally empty. This is called
|
||||
from within the interrupts. */
|
||||
#define timerNORMALLY_EMPTY_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
unsigned portBASE_TYPE uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyEmptyQueue++; \
|
||||
xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \
|
||||
} \
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
/* Send the next value to the queue that is normally full. This is called
|
||||
from within the interrupts. */
|
||||
#define timerNORMALLY_FULL_TX() \
|
||||
if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
|
||||
{ \
|
||||
unsigned portBASE_TYPE uxSavedInterruptStatus; \
|
||||
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
|
||||
{ \
|
||||
uxValueForNormallyFullQueue++; \
|
||||
xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \
|
||||
} \
|
||||
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
|
||||
} \
|
||||
|
||||
/* Receive a value from the normally empty queue. This is called from within
|
||||
an interrupt. */
|
||||
#define timerNORMALLY_EMPTY_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
|
||||
{ \
|
||||
prvQueueAccessLogError( __LINE__ ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
}
|
||||
|
||||
/* Receive a value from the normally full queue. This is called from within
|
||||
an interrupt. */
|
||||
#define timerNORMALLY_FULL_RX() \
|
||||
if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
|
||||
{ \
|
||||
prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
|
||||
} \
|
||||
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The two queues used by the test. */
|
||||
static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;
|
||||
|
||||
/* Variables used to detect a stall in one of the tasks. */
|
||||
static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
|
||||
|
||||
/* Any unexpected behaviour sets xErrorStatus to fail and log the line that
|
||||
caused the error in xErrorLine. */
|
||||
static portBASE_TYPE xErrorStatus = pdPASS;
|
||||
static unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;
|
||||
|
||||
/* Used for sequencing between tasks. */
|
||||
static portBASE_TYPE xWasSuspended = pdFALSE;
|
||||
|
||||
/* The values that are sent to the queues. An incremented value is sent each
|
||||
time to each queue. */
|
||||
volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
|
||||
|
||||
/* A handle to some of the tasks is required so they can be suspended/resumed. */
|
||||
xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
|
||||
|
||||
/* When a value is received in a queue the value is ticked off in the array
|
||||
the array position of the value is set to a the identifier of the task or
|
||||
interrupt that accessed the queue. This way missing or duplicate values can be
|
||||
detected. */
|
||||
static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
|
||||
|
||||
/* The test tasks themselves. */
|
||||
static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
|
||||
static void prvLowerPriorityNormallyFullTask( void *pvParameters );
|
||||
static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
|
||||
static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
|
||||
|
||||
/* Used to mark the positions within the ucNormallyEmptyReceivedValues and
|
||||
ucNormallyFullReceivedValues arrays, while checking for duplicates. */
|
||||
static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
|
||||
static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
|
||||
|
||||
/* Logs the line on which an error occurred. */
|
||||
static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartInterruptQueueTasks( void )
|
||||
{
|
||||
/* Start the test tasks. */
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
|
||||
xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "LQRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
|
||||
xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
|
||||
xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "LQRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
|
||||
|
||||
/* Create the queues that are accessed by multiple tasks and multiple
|
||||
interrupts. */
|
||||
xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
|
||||
xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );
|
||||
vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
has already been marked as received an error has occurred. */
|
||||
if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyFullReceivedValues[ uxValue ] = uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
|
||||
{
|
||||
if( uxValue < intqNUM_VALUES_TO_LOG )
|
||||
{
|
||||
/* We don't expect to receive the same value twice, so if the value
|
||||
has already been marked as received an error has occurred. */
|
||||
if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Log that this value has been received. */
|
||||
ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )
|
||||
{
|
||||
/* Latch the line number that caused the error. */
|
||||
xErrorLine = uxLine;
|
||||
xErrorStatus = pdFAIL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxErrorCount1 = 0, uxErrorCount2 = 0;
|
||||
|
||||
/* The timer should not be started until after the scheduler has started.
|
||||
More than one task is running this code so we check the parameter value
|
||||
to determine which task should start the timer. */
|
||||
if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
vInitialiseTimerForIntQueueTest();
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block waiting to receive a value from the normally empty queue.
|
||||
Interrupts will write to the queue so we should receive a value. */
|
||||
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Note which value was received so we can check all expected
|
||||
values are received and no values are duplicated. */
|
||||
prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );
|
||||
}
|
||||
|
||||
/* Ensure the other task running this code gets a chance to execute. */
|
||||
taskYIELD();
|
||||
|
||||
if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Have we received all the expected values? */
|
||||
if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
|
||||
|
||||
uxTask1 = 0;
|
||||
uxTask2 = 0;
|
||||
|
||||
/* Loop through the array, checking that both tasks have
|
||||
placed values into the array, and that no values are missing.
|
||||
Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value is missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
|
||||
{
|
||||
/* Value was placed into the array by task 1. */
|
||||
uxTask1++;
|
||||
}
|
||||
else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
|
||||
{
|
||||
/* Value was placed into the array by task 2. */
|
||||
uxTask2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 2 seemed to log any values. */
|
||||
uxErrorCount1++;
|
||||
if( uxErrorCount1 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount1 = 0;
|
||||
}
|
||||
|
||||
if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
|
||||
{
|
||||
/* Only task 1 seemed to log any values. */
|
||||
uxErrorCount2++;
|
||||
if( uxErrorCount2 > 2 )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uxErrorCount2 = 0;
|
||||
}
|
||||
|
||||
/* Clear the array again, ready to start a new cycle. */
|
||||
memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops1++;
|
||||
uxValueForNormallyEmptyQueue = 0;
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
actually receive something from the queue. Until now it
|
||||
will have been prevented from doing so by the higher
|
||||
priority tasks. The lower priority task will resume us
|
||||
if it receives something. We will then resume the other
|
||||
higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE uxValue, uxRxed;
|
||||
portBASE_TYPE xQueueStatus;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( ( xQueueStatus = xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* We should only obtain a value when the high priority task is
|
||||
suspended. */
|
||||
if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
|
||||
|
||||
/* Wake the higher priority task again. */
|
||||
vTaskResume( xHighPriorityNormallyEmptyTask1 );
|
||||
uxLowPriorityLoops1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we send so we can preempt the higher
|
||||
priority task, and ensure we get the Tx value into the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyEmptyQueue++;
|
||||
uxValue = uxValueForNormallyEmptyQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE uxValueToTx, ux;
|
||||
portBASE_TYPE xQueueStatus;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( ( xQueueStatus = xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) ) != pdPASS )
|
||||
{
|
||||
/* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
|
||||
expect it to ever time out. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Allow the other task running this code to run. */
|
||||
taskYIELD();
|
||||
|
||||
/* Have all the expected values been sent to the queue? */
|
||||
if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
|
||||
{
|
||||
/* Make sure the other high priority task completes its send of
|
||||
any values below intqNUM_VALUE_TO_LOG. */
|
||||
vTaskDelay( intqSHORT_DELAY );
|
||||
|
||||
vTaskSuspend( xHighPriorityNormallyFullTask2 );
|
||||
|
||||
if( xWasSuspended == pdTRUE )
|
||||
{
|
||||
/* We would have expected the other high priority task to have
|
||||
set this back to false by now. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
/* Set the suspended flag so an error is not logged if the other
|
||||
task recognises a time out when it is unsuspended. */
|
||||
xWasSuspended = pdTRUE;
|
||||
|
||||
/* Start at 1 as we expect position 0 to be unused. */
|
||||
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
|
||||
{
|
||||
if( ucNormallyFullReceivedValues[ ux ] == 0 )
|
||||
{
|
||||
/* A value was missing. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset the array ready for the next cycle. */
|
||||
memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
|
||||
|
||||
uxHighPriorityLoops2++;
|
||||
uxValueForNormallyFullQueue = 0;
|
||||
|
||||
/* Suspend ourselves, allowing the lower priority task to
|
||||
actually receive something from the queue. Until now it
|
||||
will have been prevented from doing so by the higher
|
||||
priority tasks. The lower priority task will resume us
|
||||
if it receives something. We will then resume the other
|
||||
higher priority task. */
|
||||
vTaskSuspend( NULL );
|
||||
vTaskResume( xHighPriorityNormallyFullTask2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE uxValueToTx, ux;
|
||||
portBASE_TYPE xQueueStatus;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Make sure the queue starts full or near full. >> 1 as there are two
|
||||
high priority tasks. */
|
||||
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
uxValueForNormallyFullQueue++;
|
||||
uxValueToTx = uxValueForNormallyFullQueue;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
if( ( xQueueStatus = xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) ) != pdPASS )
|
||||
{
|
||||
if( xWasSuspended != pdTRUE )
|
||||
{
|
||||
/* It is ok to time out if the task has been suspended. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
}
|
||||
|
||||
xWasSuspended = pdFALSE;
|
||||
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowerPriorityNormallyFullTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE uxValue, uxTxed = 9999;
|
||||
portBASE_TYPE xQueueStatus;
|
||||
|
||||
/* The parameters are not being used so avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
if( ( xQueueStatus = xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) ) != errQUEUE_FULL )
|
||||
{
|
||||
/* We would only expect to succeed when the higher priority task
|
||||
is suspended. */
|
||||
if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
vTaskResume( xHighPriorityNormallyFullTask1 );
|
||||
uxLowPriorityLoops2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Raise our priority while we receive so we can preempt the higher
|
||||
priority task, and ensure we get the value from the queue. */
|
||||
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
|
||||
|
||||
if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
|
||||
}
|
||||
|
||||
vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xFirstTimerHandler( void )
|
||||
{
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;
|
||||
static unsigned portBASE_TYPE uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_RX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xSecondTimerHandler( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxRxedValue;
|
||||
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
|
||||
static unsigned portBASE_TYPE uxNextOperation = 0;
|
||||
|
||||
/* Called from a timer interrupt. Perform various read and write
|
||||
accesses on the queues. */
|
||||
|
||||
uxNextOperation++;
|
||||
|
||||
if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
|
||||
{
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
timerNORMALLY_EMPTY_TX();
|
||||
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
timerNORMALLY_EMPTY_RX();
|
||||
}
|
||||
else
|
||||
{
|
||||
timerNORMALLY_FULL_RX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
timerNORMALLY_FULL_TX();
|
||||
}
|
||||
|
||||
return xHigherPriorityTaskWoken;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
|
||||
portBASE_TYPE xAreIntQueueTasksStillRunning( void )
|
||||
{
|
||||
static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
|
||||
|
||||
/* xErrorStatus can be set outside of this function. This function just
|
||||
checks that all the tasks are still cycling. */
|
||||
|
||||
if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
|
||||
{
|
||||
/* The high priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
|
||||
|
||||
if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
|
||||
{
|
||||
/* The high priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
|
||||
|
||||
if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
|
||||
{
|
||||
/* The low priority 1 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
|
||||
|
||||
if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
|
||||
{
|
||||
/* The low priority 2 task has stalled. */
|
||||
prvQueueAccessLogError( __LINE__ );
|
||||
}
|
||||
|
||||
uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
|
||||
|
||||
return xErrorStatus;
|
||||
}
|
||||
|
||||
240
20091005/Demo/Common/Minimal/PollQ.c
Normal file
240
20091005/Demo/Common/Minimal/PollQ.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version of PollQ. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that communicate over a single queue. One task acts as a
|
||||
* producer, the other a consumer.
|
||||
*
|
||||
* The producer loops for three iteration, posting an incrementing number onto the
|
||||
* queue each cycle. It then delays for a fixed period before doing exactly the
|
||||
* same again.
|
||||
*
|
||||
* The consumer loops emptying the queue. Each item removed from the queue is
|
||||
* checked to ensure it contains the expected value. When the queue is empty it
|
||||
* blocks for a fixed period, then does the same again.
|
||||
*
|
||||
* All queue access is performed without blocking. The consumer completely empties
|
||||
* the queue each time it runs so the producer should never find the queue full.
|
||||
*
|
||||
* An error is flagged if the consumer obtains an unexpected value or the producer
|
||||
* find the queue is full.
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V2.0.0
|
||||
|
||||
+ Delay periods are now specified using variables and constants of
|
||||
portTickType rather than unsigned portLONG.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "PollQ.h"
|
||||
|
||||
#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define pollqQUEUE_SIZE ( 10 )
|
||||
#define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS )
|
||||
#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) )
|
||||
#define pollqNO_DELAY ( ( portTickType ) 0 )
|
||||
#define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 )
|
||||
#define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 )
|
||||
|
||||
/* The task that posts the incrementing number onto the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
|
||||
|
||||
/* The task that empties the queue. */
|
||||
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
|
||||
|
||||
/* Variables that are used to check that the tasks are still running with no
|
||||
errors. */
|
||||
static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
static xQueueHandle xPolledQueue;
|
||||
|
||||
/* Create the queue used by the producer and consumer. */
|
||||
xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xPolledQueue, ( signed portCHAR * ) "Poll_Test_Queue" );
|
||||
|
||||
/* Spawn the producer and consumer. */
|
||||
xTaskCreate( vPolledQueueConsumer, ( signed portCHAR * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( vPolledQueueProducer, ( signed portCHAR * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usValue = ( unsigned portSHORT ) 0;
|
||||
signed portBASE_TYPE xError = pdFALSE, xLoop;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
|
||||
{
|
||||
/* Send an incrementing number on the queue without blocking. */
|
||||
if( xQueueSend( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We should never find the queue full so if we get here there
|
||||
has been an error. */
|
||||
xError = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* If an error has ever been recorded we stop incrementing the
|
||||
check variable. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingProducerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Update the value we are going to post next time around. */
|
||||
usValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait before we start posting again to ensure the consumer runs and
|
||||
empties the queue. */
|
||||
vTaskDelay( pollqPRODUCER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
|
||||
{
|
||||
unsigned portSHORT usData, usExpectedValue = ( unsigned portSHORT ) 0;
|
||||
signed portBASE_TYPE xError = pdFALSE;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Loop until the queue is empty. */
|
||||
while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) )
|
||||
{
|
||||
if( xQueueReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
|
||||
{
|
||||
if( usData != usExpectedValue )
|
||||
{
|
||||
/* This is not what we expected to receive so an error has
|
||||
occurred. */
|
||||
xError = pdTRUE;
|
||||
|
||||
/* Catch-up to the value we received so our next expected
|
||||
value should again be correct. */
|
||||
usExpectedValue = usData;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xError == pdFALSE )
|
||||
{
|
||||
/* Only increment the check variable if no errors have
|
||||
occurred. */
|
||||
portENTER_CRITICAL();
|
||||
xPollingConsumerCount++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
}
|
||||
|
||||
/* Next time round we would expect the number to be one higher. */
|
||||
usExpectedValue++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the queue is empty we block, allowing the producer to place more
|
||||
items in the queue. */
|
||||
vTaskDelay( pollqCONSUMER_DELAY );
|
||||
}
|
||||
} /*lint !e818 Function prototype must conform to API. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running with no errors. */
|
||||
portBASE_TYPE xArePollingQueuesStillRunning( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* Check both the consumer and producer poll count to check they have both
|
||||
been changed since out last trip round. We do not need a critical section
|
||||
around the check variables as this is called from a higher priority than
|
||||
the other tasks that access the same variables. */
|
||||
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
|
||||
( xPollingProducerCount == pollqINITIAL_VALUE )
|
||||
)
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the check variables back down so we know if they have been
|
||||
incremented the next time around. */
|
||||
xPollingConsumerCount = pollqINITIAL_VALUE;
|
||||
xPollingProducerCount = pollqINITIAL_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
440
20091005/Demo/Common/Minimal/QPeek.c
Normal file
440
20091005/Demo/Common/Minimal/QPeek.c
Normal file
|
|
@ -0,0 +1,440 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Tests the behaviour when data is peeked from a queue when there are
|
||||
* multiple tasks blocked on the queue.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "QPeek.h"
|
||||
|
||||
#define qpeekQUEUE_LENGTH ( 5 )
|
||||
#define qpeekNO_BLOCK ( 0 )
|
||||
#define qpeekSHORT_DELAY ( 10 )
|
||||
|
||||
#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
|
||||
#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The following three tasks are used to demonstrate the peeking behaviour.
|
||||
* Each task is given a different priority to demonstrate the order in which
|
||||
* tasks are woken as data is peeked from a queue.
|
||||
*/
|
||||
static void prvLowPriorityPeekTask( void *pvParameters );
|
||||
static void prvMediumPriorityPeekTask( void *pvParameters );
|
||||
static void prvHighPriorityPeekTask( void *pvParameters );
|
||||
static void prvHighestPriorityPeekTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile portBASE_TYPE xErrorDetected = pdFALSE;
|
||||
|
||||
/* Counter that is incremented on each cycle of a test. This is used to
|
||||
detect a stalled task - a test that is no longer running. */
|
||||
static volatile unsigned portLONG ulLoopCounter = 0;
|
||||
|
||||
/* Handles to the test tasks. */
|
||||
xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartQueuePeekTasks( void )
|
||||
{
|
||||
xQueueHandle xQueue;
|
||||
|
||||
/* Create the queue that we are going to use for the test/demo. */
|
||||
xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "QPeek_Test_Queue" );
|
||||
|
||||
/* Create the demo tasks and pass it the queue just created. We are
|
||||
passing the queue handle by value so it does not matter that it is declared
|
||||
on the stack here. */
|
||||
xTaskCreate( prvLowPriorityPeekTask, ( signed portCHAR * )"PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
|
||||
xTaskCreate( prvMediumPriorityPeekTask, ( signed portCHAR * )"PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
|
||||
xTaskCreate( prvHighPriorityPeekTask, ( signed portCHAR * )"PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
|
||||
xTaskCreate( prvHighestPriorityPeekTask, ( signed portCHAR * )"PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighestPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
|
||||
unsigned portLONG ulValue;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
{
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the high priority task to execute. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we reach here the high and medium priority tasks should still
|
||||
be blocked on the queue. We unblocked because the low priority task
|
||||
wrote a value to the queue, which we should have peeked. Peeking the
|
||||
data (rather than receiving it) will leave the data on the queue, so
|
||||
the high priority task should then have also been unblocked, but not
|
||||
yet executed. */
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we are going to actually receive the data, so when the high
|
||||
priority task runs it will find the queue empty and return to the
|
||||
blocked state. */
|
||||
ulValue = 0;
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x11223344 )
|
||||
{
|
||||
/* We did not receive the expected value - which should have been
|
||||
the same value as was peeked. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now we will block again as the queue is once more empty. The low
|
||||
priority task can then execute again. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the low priority task should have again written to the
|
||||
queue. */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
the high priority task to also peek the data. The high priority task
|
||||
will have been unblocked when we peeked the data as we left the data
|
||||
in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
|
||||
|
||||
/* This time we are going to do the same as the above test, but the
|
||||
high priority task is going to receive the data, rather than peek it.
|
||||
This means that the medium priority task should never peek the value. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHighPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
|
||||
unsigned portLONG ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the medium priority task to execute. Both the high
|
||||
and highest priority tasks will then be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the highest priority task should have peeked the data
|
||||
(unblocking this task) then suspended (allowing this task to also peek
|
||||
the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We only peeked the data, so suspending ourselves now should enable
|
||||
the medium priority task to also peek the data. The medium priority task
|
||||
will have been unblocked when we peeked the data as we left the data
|
||||
in the queue. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
|
||||
/* This time we are going actually receive the value, so the medium
|
||||
priority task will never peek the data - we removed it from the queue. */
|
||||
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0xaabbaabb )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvMediumPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
|
||||
unsigned portLONG ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try peeking from the queue. The queue should be empty so we will
|
||||
block, allowing the low priority task to execute. The highest, high
|
||||
and medium priority tasks will then all be blocked on the queue. */
|
||||
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
|
||||
{
|
||||
/* We expected to have received something by the time we unblock. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* When we get here the high priority task should have peeked the data
|
||||
(unblocking this task) then suspended (allowing this task to also peek
|
||||
the data). */
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 1 )
|
||||
{
|
||||
/* The message should have been left on the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Just so we know the test is still running. */
|
||||
ulLoopCounter++;
|
||||
|
||||
/* Now we can suspend ourselves so the low priority task can execute
|
||||
again. */
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvLowPriorityPeekTask( void *pvParameters )
|
||||
{
|
||||
xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
|
||||
unsigned portLONG ulValue;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Write some data to the queue. This should unblock the highest
|
||||
priority task that is waiting to peek data from the queue. */
|
||||
ulValue = 0x11223344;
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* By the time we get here the data should have been removed from
|
||||
the queue. */
|
||||
if( uxQueueMessagesWaiting( xQueue ) != 0 )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Write another value to the queue, again waking the highest priority
|
||||
task that is blocked on the queue. */
|
||||
ulValue = 0x01234567;
|
||||
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* All the other tasks should now have successfully peeked the data.
|
||||
The data is still in the queue so we should be able to receive it. */
|
||||
ulValue = 0;
|
||||
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
if( ulValue != 0x01234567 )
|
||||
{
|
||||
/* We did not receive the expected value. */
|
||||
}
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
|
||||
/* Unsuspend the other tasks so we can repeat the test - this time
|
||||
however not all the other tasks will peek the data as the high
|
||||
priority task is actually going to remove it from the queue. Send
|
||||
to front is used just to be different. As the queue is empty it
|
||||
makes no difference to the result. */
|
||||
vTaskResume( xMediumPriorityTask );
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
ulValue = 0xaabbaabb;
|
||||
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We were expecting the queue to be empty so we should not of
|
||||
had a problem writing to the queue. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* This time we should find that the queue is empty. The high priority
|
||||
task actually removed the data rather than just peeking it. */
|
||||
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
/* We expected to receive the data. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Unsuspend the highest and high priority tasks so we can go back
|
||||
and repeat the whole thing. The medium priority task should not be
|
||||
suspended as it was not able to peek the data in this last case. */
|
||||
vTaskResume( xHighPriorityTask );
|
||||
vTaskResume( xHighestPriorityTask );
|
||||
|
||||
/* Lets just delay a while as this is an intensive test as we don't
|
||||
want to starve other tests of processing time. */
|
||||
vTaskDelay( qpeekSHORT_DELAY );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreQueuePeekTasksStillRunning( void )
|
||||
{
|
||||
static unsigned portLONG ulLastLoopCounter = 0;
|
||||
|
||||
/* If the demo task is still running then we expect the loopcounter to
|
||||
have incremented since this function was last called. */
|
||||
if( ulLastLoopCounter == ulLoopCounter )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
ulLastLoopCounter = ulLoopCounter;
|
||||
|
||||
/* Errors detected in the task itself will have latched xErrorDetected
|
||||
to true. */
|
||||
|
||||
return !xErrorDetected;
|
||||
}
|
||||
|
||||
487
20091005/Demo/Common/Minimal/blocktim.c
Normal file
487
20091005/Demo/Common/Minimal/blocktim.c
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file contains some test scenarios that ensure tasks do not exit queue
|
||||
* send or receive functions prematurely. A description of the tests is
|
||||
* included within the code.
|
||||
*/
|
||||
|
||||
/* Kernel includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo includes. */
|
||||
#include "blocktim.h"
|
||||
|
||||
/* Task priorities. Allow these to be overridden. */
|
||||
#ifndef bktPRIMARY_PRIORITY
|
||||
#define bktPRIMARY_PRIORITY ( 3 )
|
||||
#endif
|
||||
|
||||
#ifndef bktSECONDARY_PRIORITY
|
||||
#define bktSECONDARY_PRIORITY ( 2 )
|
||||
#endif
|
||||
|
||||
/* Task behaviour. */
|
||||
#define bktQUEUE_LENGTH ( 5 )
|
||||
#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
|
||||
#define bktPRIMARY_BLOCK_TIME ( 10 )
|
||||
#define bktALLOWABLE_MARGIN ( 15 )
|
||||
#define bktTIME_TO_BLOCK ( 175 )
|
||||
#define bktDONT_BLOCK ( ( portTickType ) 0 )
|
||||
#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
|
||||
|
||||
/* The queue on which the tasks block. */
|
||||
static xQueueHandle xTestQueue;
|
||||
|
||||
/* Handle to the secondary task is required by the primary task for calls
|
||||
to vTaskSuspend/Resume(). */
|
||||
static xTaskHandle xSecondary;
|
||||
|
||||
/* Used to ensure that tasks are still executing without error. */
|
||||
static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
|
||||
static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Provides a simple mechanism for the primary task to know when the
|
||||
secondary task has executed. */
|
||||
static volatile unsigned portBASE_TYPE xRunIndicator;
|
||||
|
||||
/* The two test tasks. Their behaviour is commented within the files. */
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters );
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateBlockTimeTasks( void )
|
||||
{
|
||||
/* Create the queue on which the two tasks block. */
|
||||
xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "Block_Time_Queue" );
|
||||
|
||||
/* Create the two test tasks. */
|
||||
xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
|
||||
xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vPrimaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
portBASE_TYPE xItem, xData;
|
||||
portTickType xTimeWhenBlocking;
|
||||
portTickType xTimeToBlock, xBlockedTime;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 1
|
||||
|
||||
Simple block time wakeup test on queue receives. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is empty. Attempt to read from the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Test 2
|
||||
|
||||
Simple block time wakeup test on queue sends.
|
||||
|
||||
First fill the queue. It should be empty so all sends should pass. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* The queue is full. Attempt to write to the queue using a block
|
||||
time. When we wake, ensure the delta in time is as expected. */
|
||||
xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
|
||||
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after xTimeToBlock having not received
|
||||
anything on the queue. */
|
||||
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we blocked for? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
if( xBlockedTime < xTimeToBlock )
|
||||
{
|
||||
/* Should not have blocked for less than we requested. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
/* Should not have blocked for longer than we requested,
|
||||
although we would not necessarily run as soon as we were
|
||||
unblocked so a margin is allowed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
Wake the other task, it will block attempting to post to the queue.
|
||||
When we read from the queue the other task will wake, but before it
|
||||
can run we will post to the queue again. When the other task runs it
|
||||
will find the queue still full, even though it was woken. It should
|
||||
recognise that its block time has not expired and return to block for
|
||||
the remains of its block time.
|
||||
|
||||
Wake the other task so it blocks attempting to post to the already
|
||||
full queue. */
|
||||
xRunIndicator = 0;
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task has not yet executed. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
/* Make sure the other task is blocked on the queue. */
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we make space on the queue the other task should wake
|
||||
but not execute as this task has higher priority. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now fill the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
full ourselves, and the other task have set xRunIndicator. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Set the priority back down. */
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test 3 - but with the send and receive the other way around.
|
||||
The other task blocks attempting to read from the queue.
|
||||
|
||||
Empty the queue. We should find that it is full. */
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wake the other task so it blocks attempting to read from the
|
||||
already empty queue. */
|
||||
vTaskResume( xSecondary );
|
||||
|
||||
/* We need to wait a little to ensure the other task executes. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
xRunIndicator = 0;
|
||||
|
||||
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
|
||||
{
|
||||
/* Now when we place an item on the queue the other task should
|
||||
wake but not execute as this task has higher priority. */
|
||||
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Now empty the queue again before the other task gets a chance to
|
||||
execute. If the other task had executed we would find the queue
|
||||
empty ourselves, and the other task would be suspended. */
|
||||
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Raise the priority of the other task so it executes and blocks
|
||||
on the queue again. */
|
||||
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
|
||||
|
||||
/* The other task should now have re-blocked without exiting the
|
||||
queue function. */
|
||||
if( xRunIndicator == bktRUN_INDICATOR )
|
||||
{
|
||||
/* The other task should not have executed outside of the
|
||||
queue function. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
|
||||
}
|
||||
|
||||
/* Let the other task timeout. When it unblockes it will check that it
|
||||
unblocked at the correct time, then suspend itself. */
|
||||
while( xRunIndicator != bktRUN_INDICATOR )
|
||||
{
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
}
|
||||
vTaskDelay( bktSHORT_WAIT );
|
||||
|
||||
xPrimaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void vSecondaryBlockTimeTestTask( void *pvParameters )
|
||||
{
|
||||
portTickType xTimeWhenBlocking, xBlockedTime;
|
||||
portBASE_TYPE xData;
|
||||
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/*********************************************************************
|
||||
Test 1 and 2
|
||||
|
||||
This task does does not participate in these tests. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 3
|
||||
|
||||
The first thing we do is attempt to read from the queue. It should be
|
||||
full so we block. Note the time before we block so we can check the
|
||||
wake time is as per that expected. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not sent
|
||||
anything to the queue. */
|
||||
xData = 0;
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* How long were we inside the send function? */
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as
|
||||
soon as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Suspend ready for test 3. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
/*********************************************************************
|
||||
Test 4
|
||||
|
||||
As per test three, but with the send and receive reversed. */
|
||||
xTimeWhenBlocking = xTaskGetTickCount();
|
||||
|
||||
/* We should unblock after bktTIME_TO_BLOCK having not received
|
||||
anything on the queue. */
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
|
||||
|
||||
/* We should not have blocked for less time than bktTIME_TO_BLOCK. */
|
||||
if( xBlockedTime < bktTIME_TO_BLOCK )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN
|
||||
either. A margin is permitted as we would not necessarily run as soon
|
||||
as we unblocked. */
|
||||
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xRunIndicator = bktRUN_INDICATOR;
|
||||
|
||||
xSecondaryCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
|
||||
{
|
||||
static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
|
||||
portBASE_TYPE xReturn = pdPASS;
|
||||
|
||||
/* Have both tasks performed at least one cycle since this function was
|
||||
last called? */
|
||||
if( xPrimaryCycles == xLastPrimaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xSecondaryCycles == xLastSecondaryCycleCount )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
if( xErrorOccurred == pdTRUE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
xLastSecondaryCycleCount = xSecondaryCycles;
|
||||
xLastPrimaryCycleCount = xPrimaryCycles;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
285
20091005/Demo/Common/Minimal/comtest.c
Normal file
285
20091005/Demo/Common/Minimal/comtest.c
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This version of comtest. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* Creates two tasks that operate on an interrupt driven serial port. A
|
||||
* loopback connector should be used so that everything that is transmitted is
|
||||
* also received. The serial port does not use any flow control. On a
|
||||
* standard 9way 'D' connector pins two and three should be connected together.
|
||||
*
|
||||
* The first task posts a sequence of characters to the Tx queue, toggling an
|
||||
* LED on each successful post. At the end of the sequence it sleeps for a
|
||||
* pseudo-random period before resending the same sequence.
|
||||
*
|
||||
* The UART Tx end interrupt is enabled whenever data is available in the Tx
|
||||
* queue. The Tx end ISR removes a single character from the Tx queue and
|
||||
* passes it to the UART for transmission.
|
||||
*
|
||||
* The second task blocks on the Rx queue waiting for a character to become
|
||||
* available. When the UART Rx end interrupt receives a character it places
|
||||
* it in the Rx queue, waking the second task. The second task checks that the
|
||||
* characters removed from the Rx queue form the same sequence as those posted
|
||||
* to the Tx queue, and toggles an LED for each correct character.
|
||||
*
|
||||
* The receiving task is spawned with a higher priority than the transmitting
|
||||
* task. The receiver will therefore wake every time a character is
|
||||
* transmitted so neither the Tx or Rx queue should ever hold more than a few
|
||||
* characters.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include <stdlib.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "serial.h"
|
||||
#include "comtest.h"
|
||||
#include "partest.h"
|
||||
|
||||
#define comSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define comTX_LED_OFFSET ( 0 )
|
||||
#define comRX_LED_OFFSET ( 1 )
|
||||
#define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
|
||||
|
||||
/* The Tx task will transmit the sequence of characters at a pseudo random
|
||||
interval. This is the maximum and minimum block time between sends. */
|
||||
#define comTX_MAX_BLOCK_TIME ( ( portTickType ) 0x96 )
|
||||
#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0x32 )
|
||||
#define comOFFSET_TIME ( ( portTickType ) 3 )
|
||||
|
||||
/* We should find that each character can be queued for Tx immediately and we
|
||||
don't have to block to send. */
|
||||
#define comNO_BLOCK ( ( portTickType ) 0 )
|
||||
|
||||
/* The Rx task will block on the Rx queue for a long period. */
|
||||
#define comRX_BLOCK_TIME ( ( portTickType ) 0xffff )
|
||||
|
||||
/* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */
|
||||
#define comFIRST_BYTE ( 'A' )
|
||||
#define comLAST_BYTE ( 'X' )
|
||||
|
||||
#define comBUFFER_LEN ( ( unsigned portBASE_TYPE ) ( comLAST_BYTE - comFIRST_BYTE ) + ( unsigned portBASE_TYPE ) 1 )
|
||||
#define comINITIAL_RX_COUNT_VALUE ( 0 )
|
||||
|
||||
/* Handle to the com port used by both tasks. */
|
||||
static xComPortHandle xPort = NULL;
|
||||
|
||||
/* The transmit task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
|
||||
|
||||
/* The receive task as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
|
||||
|
||||
/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
|
||||
toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
|
||||
( uxBaseLED + comTX_LED_OFFSET ). */
|
||||
static unsigned portBASE_TYPE uxBaseLED = 0;
|
||||
|
||||
/* Check variable used to ensure no error have occurred. The Rx task will
|
||||
increment this variable after every successfully received sequence. If at any
|
||||
time the sequence is incorrect the the variable will stop being incremented. */
|
||||
static volatile unsigned portBASE_TYPE uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vAltStartComTestTasks( unsigned portBASE_TYPE uxPriority, unsigned portLONG ulBaudRate, unsigned portBASE_TYPE uxLED )
|
||||
{
|
||||
/* Initialise the com port then spawn the Rx and Tx tasks. */
|
||||
uxBaseLED = uxLED;
|
||||
xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );
|
||||
|
||||
/* The Tx task is spawned with a lower priority than the Rx task. */
|
||||
xTaskCreate( vComTxTask, ( signed portCHAR * ) "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( vComRxTask, ( signed portCHAR * ) "COMRx", comSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComTxTask, pvParameters )
|
||||
{
|
||||
signed portCHAR cByteToSend;
|
||||
portTickType xTimeToWait;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Simply transmit a sequence of characters from comFIRST_BYTE to
|
||||
comLAST_BYTE. */
|
||||
for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
|
||||
{
|
||||
if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* We have posted all the characters in the string - wait before
|
||||
re-sending. Wait a pseudo-random time as this will provide a better
|
||||
test. */
|
||||
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
|
||||
|
||||
/* Make sure we don't wait too long... */
|
||||
xTimeToWait %= comTX_MAX_BLOCK_TIME;
|
||||
|
||||
/* ...but we do want to wait. */
|
||||
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
|
||||
{
|
||||
xTimeToWait = comTX_MIN_BLOCK_TIME;
|
||||
}
|
||||
|
||||
vTaskDelay( xTimeToWait );
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vComRxTask, pvParameters )
|
||||
{
|
||||
signed portCHAR cExpectedByte, cByteRxed;
|
||||
portBASE_TYPE xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
|
||||
|
||||
/* Just to stop compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* We expect to receive the characters from comFIRST_BYTE to
|
||||
comLAST_BYTE in an incrementing order. Loop to receive each byte. */
|
||||
for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
|
||||
{
|
||||
/* Block on the queue that contains received bytes until a byte is
|
||||
available. */
|
||||
if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
|
||||
{
|
||||
/* Was this the byte we were expecting? If so, toggle the LED,
|
||||
otherwise we are out on sync and should break out of the loop
|
||||
until the expected character sequence is about to restart. */
|
||||
if( cByteRxed == cExpectedByte )
|
||||
{
|
||||
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
|
||||
}
|
||||
else
|
||||
{
|
||||
xResyncRequired = pdTRUE;
|
||||
break; /*lint !e960 Non-switch break allowed. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn the LED off while we are not doing anything. */
|
||||
vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
|
||||
|
||||
/* Did we break out of the loop because the characters were received in
|
||||
an unexpected order? If so wait here until the character sequence is
|
||||
about to restart. */
|
||||
if( xResyncRequired == pdTRUE )
|
||||
{
|
||||
while( cByteRxed != comLAST_BYTE )
|
||||
{
|
||||
/* Block until the next char is available. */
|
||||
xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
|
||||
}
|
||||
|
||||
/* Note that an error occurred which caused us to have to resync.
|
||||
We use this to stop incrementing the loop counter so
|
||||
sAreComTestTasksStillRunning() will return false - indicating an
|
||||
error. */
|
||||
xErrorOccurred++;
|
||||
|
||||
/* We have now resynced with the Tx task and can continue. */
|
||||
xResyncRequired = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
|
||||
{
|
||||
/* Increment the count of successful loops. As error
|
||||
occurring (i.e. an unexpected character being received) will
|
||||
prevent this counter being incremented for the rest of the
|
||||
execution. Don't worry about mutual exclusion on this
|
||||
variable - it doesn't really matter as we just want it
|
||||
to change. */
|
||||
uxRxLoops++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreComTestTasksStillRunning( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
|
||||
/* If the count of successful reception loops has not changed than at
|
||||
some time an error occurred (i.e. a character was received out of sequence)
|
||||
and we will return false. */
|
||||
if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
/* Reset the count of successful Rx loops. When this function is called
|
||||
again we expect this to have been incremented. */
|
||||
uxRxLoops = comINITIAL_RX_COUNT_VALUE;
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
304
20091005/Demo/Common/Minimal/countsem.c
Normal file
304
20091005/Demo/Common/Minimal/countsem.c
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Simple demonstration of the usage of counting semaphore.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "countsem.h"
|
||||
|
||||
/* The maximum count value that the semaphore used for the demo can hold. */
|
||||
#define countMAX_COUNT_VALUE ( 200 )
|
||||
|
||||
/* Constants used to indicate whether or not the semaphore should have been
|
||||
created with its maximum count value, or its minimum count value. These
|
||||
numbers are used to ensure that the pointers passed in as the task parameters
|
||||
are valid. */
|
||||
#define countSTART_AT_MAX_COUNT ( 0xaa )
|
||||
#define countSTART_AT_ZERO ( 0x55 )
|
||||
|
||||
/* Two tasks are created for the test. One uses a semaphore created with its
|
||||
count value set to the maximum, and one with the count value set to zero. */
|
||||
#define countNUM_TEST_TASKS ( 2 )
|
||||
#define countDONT_BLOCK ( 0 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Flag that will be latched to pdTRUE should any unexpected behaviour be
|
||||
detected in any of the tasks. */
|
||||
static volatile portBASE_TYPE xErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The demo task. This simply counts the semaphore up to its maximum value,
|
||||
* the counts it back down again. The result of each semaphore 'give' and
|
||||
* 'take' is inspected, with an error being flagged if it is found not to be
|
||||
* the expected result.
|
||||
*/
|
||||
static void prvCountingSemaphoreTask( void *pvParameters );
|
||||
|
||||
/*
|
||||
* Utility function to increment the semaphore count value up from zero to
|
||||
* countMAX_COUNT_VALUE.
|
||||
*/
|
||||
static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter );
|
||||
|
||||
/*
|
||||
* Utility function to decrement the semaphore count value up from
|
||||
* countMAX_COUNT_VALUE to zero.
|
||||
*/
|
||||
static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The structure that is passed into the task as the task parameter. */
|
||||
typedef struct COUNT_SEM_STRUCT
|
||||
{
|
||||
/* The semaphore to be used for the demo. */
|
||||
xSemaphoreHandle xSemaphore;
|
||||
|
||||
/* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
|
||||
its count value set to its max count value, or countSTART_AT_ZERO if it
|
||||
should have been created with its count value set to 0. */
|
||||
unsigned portBASE_TYPE uxExpectedStartCount;
|
||||
|
||||
/* Incremented on each cycle of the demo task. Used to detect a stalled
|
||||
task. */
|
||||
unsigned portBASE_TYPE uxLoopCounter;
|
||||
} xCountSemStruct;
|
||||
|
||||
/* Two structures are defined, one is passed to each test task. */
|
||||
static volatile xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartCountingSemaphoreTasks( void )
|
||||
{
|
||||
/* Create the semaphores that we are going to use for the test/demo. The
|
||||
first should be created such that it starts at its maximum count value,
|
||||
the second should be created such that it starts with a count value of zero. */
|
||||
xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
|
||||
xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
|
||||
xParameters[ 0 ].uxLoopCounter = 0;
|
||||
|
||||
xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 );
|
||||
xParameters[ 1 ].uxExpectedStartCount = 0;
|
||||
xParameters[ 1 ].uxLoopCounter = 0;
|
||||
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate semaphores and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 0 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_1" );
|
||||
vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 1 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_2" );
|
||||
|
||||
|
||||
/* Were the semaphores created? */
|
||||
if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
|
||||
{
|
||||
/* Create the demo tasks, passing in the semaphore to use as the parameter. */
|
||||
xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter )
|
||||
{
|
||||
unsigned portBASE_TYPE ux;
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
the semaphore. */
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter )
|
||||
{
|
||||
unsigned portBASE_TYPE ux;
|
||||
|
||||
/* If the semaphore count is zero then we should not be able to 'take'
|
||||
the semaphore. */
|
||||
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
|
||||
for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
|
||||
{
|
||||
if( xSemaphoreGive( xSemaphore ) != pdPASS )
|
||||
{
|
||||
/* We expected to be able to take the semaphore. */
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
( *puxLoopCounter )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the semaphore count is at its maximum then we should not be able to
|
||||
'give' the semaphore. */
|
||||
if( xSemaphoreGive( xSemaphore ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCountingSemaphoreTask( void *pvParameters )
|
||||
{
|
||||
xCountSemStruct *pxParameter;
|
||||
|
||||
#ifdef USE_STDIO
|
||||
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
|
||||
|
||||
const portCHAR * const pcTaskStartMsg = "Counting semaphore demo started.\r\n";
|
||||
|
||||
/* Queue a message for printing to say the task has started. */
|
||||
vPrintDisplayMessage( &pcTaskStartMsg );
|
||||
#endif
|
||||
|
||||
/* The semaphore to be used was passed as the parameter. */
|
||||
pxParameter = ( xCountSemStruct * ) pvParameters;
|
||||
|
||||
/* Did we expect to find the semaphore already at its max count value, or
|
||||
at zero? */
|
||||
if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
|
||||
{
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
|
||||
/* Now we expect the semaphore count to be 0, so this time there is an
|
||||
error if we can take the semaphore. */
|
||||
if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
|
||||
{
|
||||
xErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreCountingSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static unsigned portBASE_TYPE uxLastCount0 = 0, uxLastCount1 = 0;
|
||||
portBASE_TYPE xReturn = pdPASS;
|
||||
|
||||
/* Return fail if any 'give' or 'take' did not result in the expected
|
||||
behaviour. */
|
||||
if( xErrorDetected != pdFALSE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
|
||||
/* Return fail if either task is not still incrementing its loop counter. */
|
||||
if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount0 = xParameters[ 0 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastCount1 = xParameters[ 1 ].uxLoopCounter;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
228
20091005/Demo/Common/Minimal/crflash.c
Normal file
228
20091005/Demo/Common/Minimal/crflash.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo application file demonstrates the use of queues to pass data
|
||||
* between co-routines.
|
||||
*
|
||||
* N represents the number of 'fixed delay' co-routines that are created and
|
||||
* is set during initialisation.
|
||||
*
|
||||
* N 'fixed delay' co-routines are created that just block for a fixed
|
||||
* period then post the number of an LED onto a queue. Each such co-routine
|
||||
* uses a different block period. A single 'flash' co-routine is also created
|
||||
* that blocks on the same queue, waiting for the number of the next LED it
|
||||
* should flash. Upon receiving a number it simply toggle the instructed LED
|
||||
* then blocks on the queue once more. In this manner each LED from LED 0 to
|
||||
* LED N-1 is caused to flash at a different rate.
|
||||
*
|
||||
* The 'fixed delay' co-routines are created with co-routine priority 0. The
|
||||
* flash co-routine is created with co-routine priority 1. This means that
|
||||
* the queue should never contain more than a single item. This is because
|
||||
* posting to the queue will unblock the 'flash' co-routine, and as this has
|
||||
* a priority greater than the tasks posting to the queue it is guaranteed to
|
||||
* have emptied the queue and blocked once again before the queue can contain
|
||||
* any more date. An error is indicated if an attempt to post data to the
|
||||
* queue fails - indicating that the queue is already full.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "partest.h"
|
||||
#include "crflash.h"
|
||||
|
||||
/* The queue should only need to be of length 1. See the description at the
|
||||
top of the file. */
|
||||
#define crfQUEUE_LENGTH 1
|
||||
|
||||
#define crfFIXED_DELAY_PRIORITY 0
|
||||
#define crfFLASH_PRIORITY 1
|
||||
|
||||
/* Only one flash co-routine is created so the index is not significant. */
|
||||
#define crfFLASH_INDEX 0
|
||||
|
||||
/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
|
||||
created. */
|
||||
#define crfMAX_FLASH_TASKS 8
|
||||
|
||||
/* We don't want to block when posting to the queue. */
|
||||
#define crfPOSTING_BLOCK_TIME 0
|
||||
|
||||
/*
|
||||
* The 'fixed delay' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFixedDelayCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
|
||||
|
||||
/*
|
||||
* The 'flash' co-routine as described at the top of the file.
|
||||
*/
|
||||
static void prvFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
|
||||
|
||||
/* The queue used to pass data between the 'fixed delay' co-routines and the
|
||||
'flash' co-routine. */
|
||||
static xQueueHandle xFlashQueue;
|
||||
|
||||
/* This will be set to pdFALSE if we detect an error. */
|
||||
static portBASE_TYPE xCoRoutineFlashStatus = pdPASS;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* See the header file for details.
|
||||
*/
|
||||
void vStartFlashCoRoutines( unsigned portBASE_TYPE uxNumberToCreate )
|
||||
{
|
||||
unsigned portBASE_TYPE uxIndex;
|
||||
|
||||
if( uxNumberToCreate > crfMAX_FLASH_TASKS )
|
||||
{
|
||||
uxNumberToCreate = crfMAX_FLASH_TASKS;
|
||||
}
|
||||
|
||||
/* Create the queue used to pass data between the co-routines. */
|
||||
xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
if( xFlashQueue )
|
||||
{
|
||||
/* Create uxNumberToCreate 'fixed delay' co-routines. */
|
||||
for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ )
|
||||
{
|
||||
xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex );
|
||||
}
|
||||
|
||||
/* Create the 'flash' co-routine. */
|
||||
xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFixedDelayCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the xResult variable does not need to be
|
||||
static as we do not need it to maintain its state between blocks. */
|
||||
signed portBASE_TYPE xResult;
|
||||
/* The uxIndex parameter of the co-routine function is used as an index into
|
||||
the xFlashRates array to obtain the delay period to use. */
|
||||
static const portTickType xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_RATE_MS,
|
||||
200 / portTICK_RATE_MS,
|
||||
250 / portTICK_RATE_MS,
|
||||
300 / portTICK_RATE_MS,
|
||||
350 / portTICK_RATE_MS,
|
||||
400 / portTICK_RATE_MS,
|
||||
450 / portTICK_RATE_MS,
|
||||
500 / portTICK_RATE_MS };
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Post our uxIndex value onto the queue. This is used as the LED to
|
||||
flash. */
|
||||
crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* For the reasons stated at the top of the file we should always
|
||||
find that we can post to the queue. If we could not then an error
|
||||
has occurred. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
|
||||
crDELAY( xHandle, xFlashRates[ uxIndex ] );
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
|
||||
{
|
||||
/* Even though this is a co-routine the variable do not need to be
|
||||
static as we do not need it to maintain their state between blocks. */
|
||||
signed portBASE_TYPE xResult;
|
||||
unsigned portBASE_TYPE uxLEDToFlash;
|
||||
|
||||
/* Co-routines MUST start with a call to crSTART. */
|
||||
crSTART( xHandle );
|
||||
( void ) uxIndex;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Block to wait for the number of the LED to flash. */
|
||||
crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
|
||||
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* We would not expect to wake unless we received something. */
|
||||
xCoRoutineFlashStatus = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We received the number of an LED to flash - flash it! */
|
||||
vParTestToggleLED( uxLEDToFlash );
|
||||
}
|
||||
}
|
||||
|
||||
/* Co-routines MUST end with a call to crEND. */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreFlashCoRoutinesStillRunning( void )
|
||||
{
|
||||
/* Return pdPASS or pdFAIL depending on whether an error has been detected
|
||||
or not. */
|
||||
return xCoRoutineFlashStatus;
|
||||
}
|
||||
|
||||
252
20091005/Demo/Common/Minimal/crhook.c
Normal file
252
20091005/Demo/Common/Minimal/crhook.c
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This demo file demonstrates how to send data between an ISR and a
|
||||
* co-routine. A tick hook function is used to periodically pass data between
|
||||
* the RTOS tick and a set of 'hook' co-routines.
|
||||
*
|
||||
* hookNUM_HOOK_CO_ROUTINES co-routines are created. Each co-routine blocks
|
||||
* to wait for a character to be received on a queue from the tick ISR, checks
|
||||
* to ensure the character received was that expected, then sends the number
|
||||
* back to the tick ISR on a different queue.
|
||||
*
|
||||
* The tick ISR checks the numbers received back from the 'hook' co-routines
|
||||
* matches the number previously sent.
|
||||
*
|
||||
* If at any time a queue function returns unexpectedly, or an incorrect value
|
||||
* is received either by the tick hook or a co-routine then an error is
|
||||
* latched.
|
||||
*
|
||||
* This demo relies on each 'hook' co-routine to execute between each
|
||||
* hookTICK_CALLS_BEFORE_POST tick interrupts. This and the heavy use of
|
||||
* queues from within an interrupt may result in an error being detected on
|
||||
* slower targets simply due to timing.
|
||||
*/
|
||||
|
||||
/* Scheduler includes. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "croutine.h"
|
||||
#include "queue.h"
|
||||
|
||||
/* Demo application includes. */
|
||||
#include "crhook.h"
|
||||
|
||||
/* The number of 'hook' co-routines that are to be created. */
|
||||
#define hookNUM_HOOK_CO_ROUTINES ( 4 )
|
||||
|
||||
/* The number of times the tick hook should be called before a character is
|
||||
posted to the 'hook' co-routines. */
|
||||
#define hookTICK_CALLS_BEFORE_POST ( 500 )
|
||||
|
||||
/* There should never be more than one item in any queue at any time. */
|
||||
#define hookHOOK_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/* Don't block when initially posting to the queue. */
|
||||
#define hookNO_BLOCK_TIME ( 0 )
|
||||
|
||||
/* The priority relative to other co-routines (rather than tasks) that the
|
||||
'hook' co-routines should take. */
|
||||
#define mainHOOK_CR_PRIORITY ( 1 )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* The co-routine function itself.
|
||||
*/
|
||||
static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
|
||||
|
||||
|
||||
/*
|
||||
* The tick hook function. This receives a number from each 'hook' co-routine
|
||||
* then sends a number to each co-routine. An error is flagged if a send or
|
||||
* receive fails, or an unexpected number is received.
|
||||
*/
|
||||
void vApplicationTickHook( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Queues used to send data FROM a co-routine TO the tick hook function.
|
||||
The hook functions received (Rx's) on these queues. One queue per
|
||||
'hook' co-routine. */
|
||||
static xQueueHandle xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Queues used to send data FROM the tick hook TO a co-routine function.
|
||||
The hood function transmits (Tx's) on these queues. One queue per
|
||||
'hook' co-routine. */
|
||||
static xQueueHandle xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
|
||||
/* Set to true if an error is detected at any time. */
|
||||
static portBASE_TYPE xCoRoutineErrorDetected = pdFALSE;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartHookCoRoutines( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxIndex, uxValueToPost = 0;
|
||||
|
||||
for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
|
||||
{
|
||||
/* Create a queue to transmit to and receive from each 'hook'
|
||||
co-routine. */
|
||||
xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
|
||||
xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
|
||||
|
||||
/* To start things off the tick hook function expects the queue it
|
||||
uses to receive data to contain a value. */
|
||||
xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
|
||||
|
||||
/* Create the 'hook' co-routine itself. */
|
||||
xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static unsigned portBASE_TYPE uxCallCounter = 0, uxNumberToPost = 0;
|
||||
void vApplicationTickHook( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxReceivedNumber;
|
||||
signed portBASE_TYPE xIndex, xCoRoutineWoken;
|
||||
|
||||
/* Is it time to talk to the 'hook' co-routines again? */
|
||||
uxCallCounter++;
|
||||
if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
|
||||
{
|
||||
uxCallCounter = 0;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
xCoRoutineWoken = pdFALSE;
|
||||
if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
|
||||
{
|
||||
/* There is no reason why we would not expect the queue to
|
||||
contain a value. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Each queue used to receive data from the 'hook' co-routines
|
||||
should contain the number we last posted to the same co-routine. */
|
||||
if( uxReceivedNumber != uxNumberToPost )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Nothing should be blocked waiting to post to the queue. */
|
||||
if( xCoRoutineWoken != pdFALSE )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Start the next cycle by posting the next number onto each Tx queue. */
|
||||
uxNumberToPost++;
|
||||
|
||||
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
|
||||
{
|
||||
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
|
||||
{
|
||||
/* Posting to the queue should have woken the co-routine that
|
||||
was blocked on the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
|
||||
{
|
||||
static unsigned portBASE_TYPE uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
|
||||
portBASE_TYPE xResult;
|
||||
|
||||
/* Each co-routine MUST start with a call to crSTART(); */
|
||||
crSTART( xHandle );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Wait to receive a value from the tick hook. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
|
||||
|
||||
/* There is no reason why we should not have received something on
|
||||
the queue. */
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
|
||||
/* Send the same number back to the idle hook so it can verify it. */
|
||||
xResult = pdFAIL;
|
||||
crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
|
||||
if( xResult != pdPASS )
|
||||
{
|
||||
/* There is no reason why we should not have been able to post to
|
||||
the queue. */
|
||||
xCoRoutineErrorDetected = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Each co-routine MUST end with a call to crEND(). */
|
||||
crEND();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xAreHookCoRoutinesStillRunning( void )
|
||||
{
|
||||
if( xCoRoutineErrorDetected )
|
||||
{
|
||||
return pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
242
20091005/Demo/Common/Minimal/death.c
Normal file
242
20091005/Demo/Common/Minimal/death.c
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a single persistent task which periodically dynamically creates another
|
||||
* two tasks. The original task is called the creator task, the two tasks it
|
||||
* creates are called suicidal tasks.
|
||||
*
|
||||
* One of the created suicidal tasks kill one other suicidal task before killing
|
||||
* itself - leaving just the original task remaining.
|
||||
*
|
||||
* The creator task must be spawned after all of the other demo application tasks
|
||||
* as it keeps a check on the number of tasks under the scheduler control. The
|
||||
* number of tasks it expects to see running should never be greater than the
|
||||
* number of tasks that were in existence when the creator task was spawned, plus
|
||||
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
|
||||
*
|
||||
* \page DeathC death.c
|
||||
* \ingroup DemoFiles
|
||||
* <HR>
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V3.0.0
|
||||
+ CreationCount sizes changed from unsigned portBASE_TYPE to
|
||||
unsigned portSHORT to minimize the risk of overflowing.
|
||||
|
||||
+ Reset of usLastCreationCount added
|
||||
|
||||
Changes from V3.1.0
|
||||
+ Changed the dummy calculation to use variables of type long, rather than
|
||||
float. This allows the file to be used with ports that do not support
|
||||
floating point.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "death.h"
|
||||
|
||||
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
|
||||
|
||||
/* The task originally created which is responsible for periodically dynamically
|
||||
creating another four tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
|
||||
|
||||
/* The task function of the dynamically created tasks. */
|
||||
static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );
|
||||
|
||||
/* A variable which is incremented every time the dynamic tasks are created. This
|
||||
is used to check that the task is still running. */
|
||||
static volatile unsigned portSHORT usCreationCount = 0;
|
||||
|
||||
/* Used to store the number of tasks that were originally running so the creator
|
||||
task can tell if any of the suicidal tasks have failed to die.
|
||||
*/
|
||||
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
|
||||
|
||||
/* Tasks are deleted by the idle task. Under heavy load the idle task might
|
||||
not get much processing time, so it would be legitimate for several tasks to
|
||||
remain undeleted for a short period. */
|
||||
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 2;
|
||||
|
||||
/* Used to store a handle to the task that should be killed by a suicidal task,
|
||||
before it kills itself. */
|
||||
xTaskHandle xCreatedTask;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
unsigned portBASE_TYPE *puxPriority;
|
||||
|
||||
/* Create the Creator tasks - passing in as a parameter the priority at which
|
||||
the suicidal tasks should be created. */
|
||||
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
|
||||
*puxPriority = uxPriority;
|
||||
|
||||
xTaskCreate( vCreateTasks, ( signed portCHAR * ) "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
|
||||
|
||||
/* Record the number of tasks that are running now so we know if any of the
|
||||
suicidal tasks have failed to be killed. */
|
||||
uxTasksRunningAtStart = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();
|
||||
|
||||
/* FreeRTOS.org versions before V3.0 started the idle-task as the very
|
||||
first task. The idle task was then already included in uxTasksRunningAtStart.
|
||||
From FreeRTOS V3.0 on, the idle task is started when the scheduler is
|
||||
started. Therefore the idle task is not yet accounted for. We correct
|
||||
this by increasing uxTasksRunningAtStart by 1. */
|
||||
uxTasksRunningAtStart++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vSuicidalTask, pvParameters )
|
||||
{
|
||||
volatile portLONG l1, l2;
|
||||
xTaskHandle xTaskToKill;
|
||||
const portTickType xDelay = ( portTickType ) 200 / portTICK_RATE_MS;
|
||||
|
||||
if( pvParameters != NULL )
|
||||
{
|
||||
/* This task is periodically created four times. Two created tasks are
|
||||
passed a handle to the other task so it can kill it before killing itself.
|
||||
The other task is passed in null. */
|
||||
xTaskToKill = *( xTaskHandle* )pvParameters;
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskToKill = NULL;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Do something random just to use some stack and registers. */
|
||||
l1 = 2;
|
||||
l2 = 89;
|
||||
l2 *= l1;
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
if( xTaskToKill != NULL )
|
||||
{
|
||||
/* Make sure the other task has a go before we delete it. */
|
||||
vTaskDelay( ( portTickType ) 0 );
|
||||
|
||||
/* Kill the other task that was created by vCreateTasks(). */
|
||||
vTaskDelete( xTaskToKill );
|
||||
|
||||
/* Kill ourselves. */
|
||||
vTaskDelete( NULL );
|
||||
}
|
||||
}
|
||||
}/*lint !e818 !e550 Function prototype must be as per standard for task functions. */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCreateTasks, pvParameters )
|
||||
{
|
||||
const portTickType xDelay = ( portTickType ) 1000 / portTICK_RATE_MS;
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
|
||||
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
|
||||
vPortFree( pvParameters );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just loop round, delaying then creating the four suicidal tasks. */
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
xCreatedTask = NULL;
|
||||
|
||||
xTaskCreate( vSuicidalTask, ( signed portCHAR * ) "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
|
||||
xTaskCreate( vSuicidalTask, ( signed portCHAR * ) "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
|
||||
|
||||
++usCreationCount;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that the creator task is still running and that there
|
||||
are not any more than four extra tasks. */
|
||||
portBASE_TYPE xIsCreateTaskStillRunning( void )
|
||||
{
|
||||
static unsigned portSHORT usLastCreationCount = 0xfff;
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
static unsigned portBASE_TYPE uxTasksRunningNow;
|
||||
|
||||
if( usLastCreationCount == usCreationCount )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
usLastCreationCount = usCreationCount;
|
||||
}
|
||||
|
||||
uxTasksRunningNow = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();
|
||||
|
||||
if( uxTasksRunningNow < uxTasksRunningAtStart )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Everything is okay. */
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
421
20091005/Demo/Common/Minimal/dynamic.c
Normal file
421
20091005/Demo/Common/Minimal/dynamic.c
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The first test creates three tasks - two counter tasks (one continuous count
|
||||
* and one limited count) and one controller. A "count" variable is shared
|
||||
* between all three tasks. The two counter tasks should never be in a "ready"
|
||||
* state at the same time. The controller task runs at the same priority as
|
||||
* the continuous count task, and at a lower priority than the limited count
|
||||
* task.
|
||||
*
|
||||
* One counter task loops indefinitely, incrementing the shared count variable
|
||||
* on each iteration. To ensure it has exclusive access to the variable it
|
||||
* raises it's priority above that of the controller task before each
|
||||
* increment, lowering it again to it's original priority before starting the
|
||||
* next iteration.
|
||||
*
|
||||
* The other counter task increments the shared count variable on each
|
||||
* iteration of it's loop until the count has reached a limit of 0xff - at
|
||||
* which point it suspends itself. It will not start a new loop until the
|
||||
* controller task has made it "ready" again by calling vTaskResume ().
|
||||
* This second counter task operates at a higher priority than controller
|
||||
* task so does not need to worry about mutual exclusion of the counter
|
||||
* variable.
|
||||
*
|
||||
* The controller task is in two sections. The first section controls and
|
||||
* monitors the continuous count task. When this section is operational the
|
||||
* limited count task is suspended. Likewise, the second section controls
|
||||
* and monitors the limited count task. When this section is operational the
|
||||
* continuous count task is suspended.
|
||||
*
|
||||
* In the first section the controller task first takes a copy of the shared
|
||||
* count variable. To ensure mutual exclusion on the count variable it
|
||||
* suspends the continuous count task, resuming it again when the copy has been
|
||||
* taken. The controller task then sleeps for a fixed period - during which
|
||||
* the continuous count task will execute and increment the shared variable.
|
||||
* When the controller task wakes it checks that the continuous count task
|
||||
* has executed by comparing the copy of the shared variable with its current
|
||||
* value. This time, to ensure mutual exclusion, the scheduler itself is
|
||||
* suspended with a call to vTaskSuspendAll (). This is for demonstration
|
||||
* purposes only and is not a recommended technique due to its inefficiency.
|
||||
*
|
||||
* After a fixed number of iterations the controller task suspends the
|
||||
* continuous count task, and moves on to its second section.
|
||||
*
|
||||
* At the start of the second section the shared variable is cleared to zero.
|
||||
* The limited count task is then woken from it's suspension by a call to
|
||||
* vTaskResume (). As this counter task operates at a higher priority than
|
||||
* the controller task the controller task should not run again until the
|
||||
* shared variable has been counted up to the limited value causing the counter
|
||||
* task to suspend itself. The next line after vTaskResume () is therefore
|
||||
* a check on the shared variable to ensure everything is as expected.
|
||||
*
|
||||
*
|
||||
* The second test consists of a couple of very simple tasks that post onto a
|
||||
* queue while the scheduler is suspended. This test was added to test parts
|
||||
* of the scheduler not exercised by the first test.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "dynamic.h"
|
||||
|
||||
/* Function that implements the "limited count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the "continuous count" task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
|
||||
|
||||
/* Function that implements the controller task as described above. */
|
||||
static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
|
||||
|
||||
static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
|
||||
|
||||
/* Demo task specific constants. */
|
||||
#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
|
||||
#define priSLEEP_TIME ( ( portTickType ) 128 / portTICK_RATE_MS )
|
||||
#define priLOOPS ( 5 )
|
||||
#define priMAX_COUNT ( ( unsigned portLONG ) 0xff )
|
||||
#define priNO_BLOCK ( ( portTickType ) 0 )
|
||||
#define priSUSPENDED_QUEUE_LENGTH ( 1 )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Handles to the two counter tasks. These could be passed in as parameters
|
||||
to the controller task to prevent them having to be file scope. */
|
||||
static xTaskHandle xContinousIncrementHandle, xLimitedIncrementHandle;
|
||||
|
||||
/* The shared counter variable. This is passed in as a parameter to the two
|
||||
counter variables for demonstration purposes. */
|
||||
static unsigned portLONG ulCounter;
|
||||
|
||||
/* Variables used to check that the tasks are still operating without error.
|
||||
Each complete iteration of the controller task increments this variable
|
||||
provided no errors have been found. The variable maintaining the same value
|
||||
is therefore indication of an error. */
|
||||
static volatile unsigned portSHORT usCheckVariable = ( unsigned portSHORT ) 0;
|
||||
static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
|
||||
static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
|
||||
|
||||
/* Queue used by the second test. */
|
||||
xQueueHandle xSuspendedTestQueue;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
/*
|
||||
* Start the three tasks as described at the top of the file.
|
||||
* Note that the limited count task is given a higher priority.
|
||||
*/
|
||||
void vStartDynamicPriorityTasks( void )
|
||||
{
|
||||
xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned portLONG ) );
|
||||
|
||||
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is
|
||||
in use. The queue registry is provided as a means for kernel aware
|
||||
debuggers to locate queues and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( xSuspendedTestQueue, ( signed portCHAR * ) "Suspended_Test_Queue" );
|
||||
|
||||
xTaskCreate( vContinuousIncrementTask, ( signed portCHAR * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinousIncrementHandle );
|
||||
xTaskCreate( vLimitedIncrementTask, ( signed portCHAR * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
|
||||
xTaskCreate( vCounterControlTask, ( signed portCHAR * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueSendWhenSuspendedTask, ( signed portCHAR * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed portCHAR * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just loops around incrementing the shared variable until the limit has been
|
||||
* reached. Once the limit has been reached it suspends itself.
|
||||
*/
|
||||
static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
|
||||
{
|
||||
unsigned portLONG *pulCounter;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned portLONG * ) pvParameters;
|
||||
|
||||
/* This will run before the control task, so the first thing it does is
|
||||
suspend - the control task will resume it when ready. */
|
||||
vTaskSuspend( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Just count up to a value then suspend. */
|
||||
( *pulCounter )++;
|
||||
|
||||
if( *pulCounter >= priMAX_COUNT )
|
||||
{
|
||||
vTaskSuspend( NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Just keep counting the shared variable up. The control task will suspend
|
||||
* this task when it wants.
|
||||
*/
|
||||
static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
|
||||
{
|
||||
unsigned portLONG *pulCounter;
|
||||
unsigned portBASE_TYPE uxOurPriority;
|
||||
|
||||
/* Take a pointer to the shared variable from the parameters passed into
|
||||
the task. */
|
||||
pulCounter = ( unsigned portLONG * ) pvParameters;
|
||||
|
||||
/* Query our priority so we can raise it when exclusive access to the
|
||||
shared variable is required. */
|
||||
uxOurPriority = uxTaskPriorityGet( NULL );
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Raise our priority above the controller task to ensure a context
|
||||
switch does not occur while we are accessing this variable. */
|
||||
vTaskPrioritySet( NULL, uxOurPriority + 1 );
|
||||
( *pulCounter )++;
|
||||
vTaskPrioritySet( NULL, uxOurPriority );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Controller task as described above.
|
||||
*/
|
||||
static portTASK_FUNCTION( vCounterControlTask, pvParameters )
|
||||
{
|
||||
unsigned portLONG ulLastCounter;
|
||||
portSHORT sLoops;
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Start with the counter at zero. */
|
||||
ulCounter = ( unsigned portLONG ) 0;
|
||||
|
||||
/* First section : */
|
||||
|
||||
/* Check the continuous count task is running. */
|
||||
for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
|
||||
{
|
||||
/* Suspend the continuous count task so we can take a mirror of the
|
||||
shared variable without risk of corruption. */
|
||||
vTaskSuspend( xContinousIncrementHandle );
|
||||
ulLastCounter = ulCounter;
|
||||
vTaskResume( xContinousIncrementHandle );
|
||||
|
||||
/* Now delay to ensure the other task has processor time. */
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
/* Check the shared variable again. This time to ensure mutual
|
||||
exclusion the whole scheduler will be locked. This is just for
|
||||
demo purposes! */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
if( ulLastCounter == ulCounter )
|
||||
{
|
||||
/* The shared variable has not changed. There is a problem
|
||||
with the continuous count task so flag an error. */
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
|
||||
|
||||
/* Second section: */
|
||||
|
||||
/* Suspend the continuous counter task so it stops accessing the shared variable. */
|
||||
vTaskSuspend( xContinousIncrementHandle );
|
||||
|
||||
/* Reset the variable. */
|
||||
ulCounter = ( unsigned portLONG ) 0;
|
||||
|
||||
/* Resume the limited count task which has a higher priority than us.
|
||||
We should therefore not return from this call until the limited count
|
||||
task has suspended itself with a known value in the counter variable. */
|
||||
vTaskResume( xLimitedIncrementHandle );
|
||||
|
||||
/* Does the counter variable have the expected value? */
|
||||
if( ulCounter != priMAX_COUNT )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If no errors have occurred then increment the check variable. */
|
||||
portENTER_CRITICAL();
|
||||
usCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Resume the continuous count task and do it all again. */
|
||||
vTaskResume( xContinousIncrementHandle );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
static unsigned portLONG ulValueToSend = ( unsigned portLONG ) 0;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* We must not block while the scheduler is suspended! */
|
||||
if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
|
||||
{
|
||||
xSuspendedQueueSendError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
vTaskDelay( priSLEEP_TIME );
|
||||
|
||||
++ulValueToSend;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
|
||||
{
|
||||
static unsigned portLONG ulExpectedValue = ( unsigned portLONG ) 0, ulReceivedValue;
|
||||
portBASE_TYPE xGotValue;
|
||||
|
||||
/* Just to stop warning messages. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
do
|
||||
{
|
||||
/* Suspending the scheduler here is fairly pointless and
|
||||
undesirable for a normal application. It is done here purely
|
||||
to test the scheduler. The inner xTaskResumeAll() should
|
||||
never return pdTRUE as the scheduler is still locked by the
|
||||
outer call. */
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
|
||||
}
|
||||
if( xTaskResumeAll() )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
} while( xGotValue == pdFALSE );
|
||||
|
||||
if( ulReceivedValue != ulExpectedValue )
|
||||
{
|
||||
xSuspendedQueueReceiveError = pdTRUE;
|
||||
}
|
||||
|
||||
++ulExpectedValue;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Called to check that all the created tasks are still running without error. */
|
||||
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if it has been incremented
|
||||
since the last call. */
|
||||
static unsigned portSHORT usLastTaskCheck = ( unsigned portSHORT ) 0;
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
|
||||
/* Check the tasks are still running by ensuring the check variable
|
||||
is still incrementing. */
|
||||
|
||||
if( usCheckVariable == usLastTaskCheck )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueSendError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
if( xSuspendedQueueReceiveError == pdTRUE )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck = usCheckVariable;
|
||||
return xReturn;
|
||||
}
|
||||
139
20091005/Demo/Common/Minimal/flash.c
Normal file
139
20091005/Demo/Common/Minimal/flash.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This version of flash .c is for use on systems that have limited stack space
|
||||
* and no display facilities. The complete version can be found in the
|
||||
* Demo/Common/Full directory.
|
||||
*
|
||||
* Three tasks are created, each of which flash an LED at a different rate. The first
|
||||
* LED flashes every 200ms, the second every 400ms, the third every 600ms.
|
||||
*
|
||||
* The LED flash tasks provide instant visual feedback. They show that the scheduler
|
||||
* is still operational.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "partest.h"
|
||||
#include "flash.h"
|
||||
|
||||
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define ledNUMBER_OF_LEDS ( 3 )
|
||||
#define ledFLASH_RATE_BASE ( ( portTickType ) 333 )
|
||||
|
||||
/* Variable used by the created tasks to calculate the LED number to use, and
|
||||
the rate at which they should flash the LED. */
|
||||
static volatile unsigned portBASE_TYPE uxFlashTaskNumber = 0;
|
||||
|
||||
/* The task that is created three times. */
|
||||
static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
signed portBASE_TYPE xLEDTask;
|
||||
|
||||
/* Create the three tasks. */
|
||||
for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )
|
||||
{
|
||||
/* Spawn the task. */
|
||||
xTaskCreate( vLEDFlashTask, ( signed portCHAR * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
|
||||
{
|
||||
portTickType xFlashRate, xLastFlashTime;
|
||||
unsigned portBASE_TYPE uxLED;
|
||||
|
||||
/* The parameters are not used. */
|
||||
( void ) pvParameters;
|
||||
|
||||
/* Calculate the LED and flash rate. */
|
||||
portENTER_CRITICAL();
|
||||
{
|
||||
/* See which of the eight LED's we should use. */
|
||||
uxLED = uxFlashTaskNumber;
|
||||
|
||||
/* Update so the next task uses the next LED. */
|
||||
uxFlashTaskNumber++;
|
||||
}
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( portTickType ) uxLED );
|
||||
xFlashRate /= portTICK_RATE_MS;
|
||||
|
||||
/* We will turn the LED on and off again in the delay period, so each
|
||||
delay is only half the total period. */
|
||||
xFlashRate /= ( portTickType ) 2;
|
||||
|
||||
/* We need to initialise xLastFlashTime prior to the first call to
|
||||
vTaskDelayUntil(). */
|
||||
xLastFlashTime = xTaskGetTickCount();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Delay for half the flash period then turn the LED on. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
|
||||
/* Delay for half the flash period then turn the LED off. */
|
||||
vTaskDelayUntil( &xLastFlashTime, xFlashRate );
|
||||
vParTestToggleLED( uxLED );
|
||||
}
|
||||
} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */
|
||||
|
||||
345
20091005/Demo/Common/Minimal/flop.c
Normal file
345
20091005/Demo/Common/Minimal/flop.c
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates eight tasks, each of which loops continuously performing an (emulated)
|
||||
* floating point calculation.
|
||||
*
|
||||
* All the tasks run at the idle priority and never block or yield. This causes
|
||||
* all eight tasks to time slice with the idle task. Running at the idle priority
|
||||
* means that these tasks will get pre-empted any time another task is ready to run
|
||||
* or a time slice occurs. More often than not the pre-emption will occur mid
|
||||
* calculation, creating a good test of the schedulers context switch mechanism - a
|
||||
* calculation producing an unexpected result could be a symptom of a corruption in
|
||||
* the context of a task.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "flop.h"
|
||||
|
||||
#define mathSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
#define mathNUMBER_OF_TASKS ( 8 )
|
||||
|
||||
/* Four tasks, each of which performs a different floating point calculation.
|
||||
Each of the four is created twice. */
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
|
||||
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
|
||||
|
||||
/* These variables are used to check that all the tasks are still running. If a
|
||||
task gets a calculation wrong it will
|
||||
stop incrementing its check variable. */
|
||||
static volatile unsigned portSHORT usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xTaskCreate( vCompetingMathTask1, ( signed portCHAR * ) "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, ( signed portCHAR * ) "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, ( signed portCHAR * ) "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, ( signed portCHAR * ) "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask1, ( signed portCHAR * ) "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask2, ( signed portCHAR * ) "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask3, ( signed portCHAR * ) "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
|
||||
xTaskCreate( vCompetingMathTask4, ( signed portCHAR * ) "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
volatile portDOUBLE dAnswer;
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
dAnswer = ( d1 + d2 ) * d3;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for(;;)
|
||||
{
|
||||
d1 = 123.4567;
|
||||
d2 = 2345.6789;
|
||||
d3 = -918.222;
|
||||
|
||||
d4 = ( d1 + d2 ) * d3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE d1, d2, d3, d4;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
volatile portDOUBLE dAnswer;
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
dAnswer = ( d1 / d2 ) * d3;
|
||||
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
d1 = -389.38;
|
||||
d2 = 32498.2;
|
||||
d3 = -2.0001;
|
||||
|
||||
d4 = ( d1 / d2 ) * d3;
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
/* If the calculation does not match the expected constant, stop the
|
||||
increment of the check variable. */
|
||||
if( fabs( d4 - dAnswer ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know
|
||||
this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5;
|
||||
dTotal1 += ( portDOUBLE ) xPosition + 5.5;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ xPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
|
||||
{
|
||||
volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
|
||||
volatile unsigned portSHORT *pusTaskCheckVariable;
|
||||
const size_t xArraySize = 10;
|
||||
size_t xPosition;
|
||||
portSHORT sError = pdFALSE;
|
||||
|
||||
/* The variable this task increments to show it is still running is passed in
|
||||
as the parameter. */
|
||||
pusTaskCheckVariable = ( unsigned portSHORT * ) pvParameters;
|
||||
|
||||
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
|
||||
|
||||
/* Keep filling an array, keeping a running total of the values placed in the
|
||||
array. Then run through the array adding up all the values. If the two totals
|
||||
do not match, stop the check variable from incrementing. */
|
||||
for( ;; )
|
||||
{
|
||||
dTotal1 = 0.0;
|
||||
dTotal2 = 0.0;
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
pdArray[ xPosition ] = ( portDOUBLE ) xPosition * 12.123;
|
||||
dTotal1 += ( portDOUBLE ) xPosition * 12.123;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
for( xPosition = 0; xPosition < xArraySize; xPosition++ )
|
||||
{
|
||||
dTotal2 += pdArray[ xPosition ];
|
||||
}
|
||||
|
||||
dDifference = dTotal1 - dTotal2;
|
||||
if( fabs( dDifference ) > 0.001 )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
taskYIELD();
|
||||
#endif
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* If the calculation has always been correct, increment the check
|
||||
variable so we know this task is still running okay. */
|
||||
( *pusTaskCheckVariable )++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreMathsTaskStillRunning( void )
|
||||
{
|
||||
/* Keep a history of the check variables so we know if they have been incremented
|
||||
since the last call. */
|
||||
static unsigned portSHORT usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned portSHORT ) 0 };
|
||||
portBASE_TYPE xReturn = pdTRUE, xTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still incrementing. */
|
||||
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
|
||||
{
|
||||
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
206
20091005/Demo/Common/Minimal/integer.c
Normal file
206
20091005/Demo/Common/Minimal/integer.c
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This version of integer. c is for use on systems that have limited stack
|
||||
* space and no display facilities. The complete version can be found in
|
||||
* the Demo/Common/Full directory.
|
||||
*
|
||||
* As with the full version, the tasks created in this file are a good test
|
||||
* of the scheduler context switch mechanism. The processor has to access
|
||||
* 32bit variables in two or four chunks (depending on the processor). The low
|
||||
* priority of these tasks means there is a high probability that a context
|
||||
* switch will occur mid calculation. See flop. c documentation for
|
||||
* more information.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes from V1.2.1
|
||||
|
||||
+ The constants used in the calculations are larger to ensure the
|
||||
optimiser does not truncate them to 16 bits.
|
||||
|
||||
Changes from V1.2.3
|
||||
|
||||
+ uxTaskCheck is now just used as a boolean. Instead of incrementing
|
||||
the variable each cycle of the task, the variable is simply set to
|
||||
true. sAreIntegerMathsTaskStillRunning() sets it back to false and
|
||||
expects it to have been set back to true by the time it is called
|
||||
again.
|
||||
+ A division has been included in the calculation.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
|
||||
/* Demo program include files. */
|
||||
#include "integer.h"
|
||||
|
||||
/* The constants used in the calculation. */
|
||||
#define intgCONST1 ( ( portLONG ) 123 )
|
||||
#define intgCONST2 ( ( portLONG ) 234567 )
|
||||
#define intgCONST3 ( ( portLONG ) -3 )
|
||||
#define intgCONST4 ( ( portLONG ) 7 )
|
||||
#define intgEXPECTED_ANSWER ( ( ( intgCONST1 + intgCONST2 ) * intgCONST3 ) / intgCONST4 )
|
||||
|
||||
#define intgSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
/* As this is the minimal version, we will only create one task. */
|
||||
#define intgNUMBER_OF_TASKS ( 1 )
|
||||
|
||||
/* The task function. Repeatedly performs a 32 bit calculation, checking the
|
||||
result against the expected result. If the result is incorrect then the
|
||||
context switch must have caused some corruption. */
|
||||
static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters );
|
||||
|
||||
/* Variables that are set to true within the calculation task to indicate
|
||||
that the task is still executing. The check task sets the variable back to
|
||||
false, flagging an error if the variable is still false the next time it
|
||||
is called. */
|
||||
static volatile signed portBASE_TYPE xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( signed portBASE_TYPE ) pdFALSE };
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
portSHORT sTask;
|
||||
|
||||
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
|
||||
{
|
||||
xTaskCreate( vCompeteingIntMathTask, ( signed portCHAR * ) "IntMath", intgSTACK_SIZE, ( void * ) &( xTaskCheck[ sTask ] ), uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters )
|
||||
{
|
||||
/* These variables are all effectively set to constants so they are volatile to
|
||||
ensure the compiler does not just get rid of them. */
|
||||
volatile portLONG lValue;
|
||||
portSHORT sError = pdFALSE;
|
||||
volatile signed portBASE_TYPE *pxTaskHasExecuted;
|
||||
|
||||
/* Set a pointer to the variable we are going to set to true each
|
||||
iteration. This is also a good test of the parameter passing mechanism
|
||||
within each port. */
|
||||
pxTaskHasExecuted = ( volatile signed portBASE_TYPE * ) pvParameters;
|
||||
|
||||
/* Keep performing a calculation and checking the result against a constant. */
|
||||
for( ;; )
|
||||
{
|
||||
/* Perform the calculation. This will store partial value in
|
||||
registers, resulting in a good test of the context switch mechanism. */
|
||||
lValue = intgCONST1;
|
||||
lValue += intgCONST2;
|
||||
|
||||
/* Yield in case cooperative scheduling is being used. */
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Finish off the calculation. */
|
||||
lValue *= intgCONST3;
|
||||
lValue /= intgCONST4;
|
||||
|
||||
/* If the calculation is found to be incorrect we stop setting the
|
||||
TaskHasExecuted variable so the check task can see an error has
|
||||
occurred. */
|
||||
if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
/* We have not encountered any errors, so set the flag that show
|
||||
we are still executing. This will be periodically cleared by
|
||||
the check task. */
|
||||
portENTER_CRITICAL();
|
||||
*pxTaskHasExecuted = pdTRUE;
|
||||
portEXIT_CRITICAL();
|
||||
}
|
||||
|
||||
/* Yield in case cooperative scheduling is being used. */
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
|
||||
{
|
||||
portBASE_TYPE xReturn = pdTRUE;
|
||||
portSHORT sTask;
|
||||
|
||||
/* Check the maths tasks are still running by ensuring their check variables
|
||||
are still being set to true. */
|
||||
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
|
||||
{
|
||||
if( xTaskCheck[ sTask ] == pdFALSE )
|
||||
{
|
||||
/* The check has not incremented so an error exists. */
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
/* Reset the check variable so we can tell if it has been set by
|
||||
the next time around. */
|
||||
xTaskCheck[ sTask ] = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
363
20091005/Demo/Common/Minimal/recmutex.c
Normal file
363
20091005/Demo/Common/Minimal/recmutex.c
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
The tasks defined on this page demonstrate the use of recursive mutexes.
|
||||
|
||||
For recursive mutex functionality the created mutex should be created using
|
||||
xSemaphoreCreateRecursiveMutex(), then be manipulated
|
||||
using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
|
||||
functions.
|
||||
|
||||
This demo creates three tasks all of which access the same recursive mutex:
|
||||
|
||||
prvRecursiveMutexControllingTask() has the highest priority so executes
|
||||
first and grabs the mutex. It then performs some recursive accesses -
|
||||
between each of which it sleeps for a short period to let the lower
|
||||
priority tasks execute. When it has completed its demo functionality
|
||||
it gives the mutex back before suspending itself.
|
||||
|
||||
prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
|
||||
a blocking 'take'. The blocking task has a lower priority than the
|
||||
controlling task so by the time it executes the mutex has already been
|
||||
taken by the controlling task, causing the blocking task to block. It
|
||||
does not unblock until the controlling task has given the mutex back,
|
||||
and it does not actually run until the controlling task has suspended
|
||||
itself (due to the relative priorities). When it eventually does obtain
|
||||
the mutex all it does is give the mutex back prior to also suspending
|
||||
itself. At this point both the controlling task and the blocking task are
|
||||
suspended.
|
||||
|
||||
prvRecursiveMutexPollingTask() runs at the idle priority. It spins round
|
||||
a tight loop attempting to obtain the mutex with a non-blocking call. As
|
||||
the lowest priority task it will not successfully obtain the mutex until
|
||||
both the controlling and blocking tasks are suspended. Once it eventually
|
||||
does obtain the mutex it first unsuspends both the controlling task and
|
||||
blocking task prior to giving the mutex back - resulting in the polling
|
||||
task temporarily inheriting the controlling tasks priority.
|
||||
*/
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "recmutex.h"
|
||||
|
||||
/* Priorities assigned to the three tasks. */
|
||||
#define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
|
||||
#define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
||||
#define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 )
|
||||
|
||||
/* The recursive call depth. */
|
||||
#define recmuMAX_COUNT ( 10 )
|
||||
|
||||
/* Misc. */
|
||||
#define recmuSHORT_DELAY ( 20 / portTICK_RATE_MS )
|
||||
#define recmuNO_DELAY ( ( portTickType ) 0 )
|
||||
#define recmuTWO_TICK_DELAY ( ( portTickType ) 2 )
|
||||
|
||||
/* The three tasks as described at the top of this file. */
|
||||
static void prvRecursiveMutexControllingTask( void *pvParameters );
|
||||
static void prvRecursiveMutexBlockingTask( void *pvParameters );
|
||||
static void prvRecursiveMutexPollingTask( void *pvParameters );
|
||||
|
||||
/* The mutex used by the demo. */
|
||||
static xSemaphoreHandle xMutex;
|
||||
|
||||
/* Variables used to detect and latch errors. */
|
||||
static volatile portBASE_TYPE xErrorOccurred = pdFALSE, xControllingIsSuspended = pdFALSE, xBlockingIsSuspended = pdFALSE;
|
||||
static volatile unsigned portBASE_TYPE uxControllingCycles = 0, uxBlockingCycles, uxPollingCycles = 0;
|
||||
|
||||
/* Handles of the two higher priority tasks, required so they can be resumed
|
||||
(unsuspended). */
|
||||
static xTaskHandle xControllingTaskHandle, xBlockingTaskHandle;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartRecursiveMutexTasks( void )
|
||||
{
|
||||
/* Just creates the mutex and the three tasks. */
|
||||
|
||||
xMutex = xSemaphoreCreateRecursiveMutex();
|
||||
|
||||
/* vQueueAddToRegistry() adds the mutex to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate mutex and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Recursive_Mutex" );
|
||||
|
||||
|
||||
if( xMutex != NULL )
|
||||
{
|
||||
xTaskCreate( prvRecursiveMutexControllingTask, ( signed portCHAR * ) "Rec1", configMINIMAL_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
|
||||
xTaskCreate( prvRecursiveMutexBlockingTask, ( signed portCHAR * ) "Rec2", configMINIMAL_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );
|
||||
xTaskCreate( prvRecursiveMutexPollingTask, ( signed portCHAR * ) "Rec3", configMINIMAL_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexControllingTask( void *pvParameters )
|
||||
{
|
||||
unsigned portBASE_TYPE ux;
|
||||
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Should not be able to 'give' the mutex, as we have not yet 'taken'
|
||||
it. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
for( ux = 0; ux < recmuMAX_COUNT; ux++ )
|
||||
{
|
||||
/* We should now be able to take the mutex as many times as
|
||||
we like. A one tick delay is used so the polling task will
|
||||
inherit our priority on all but the first cycle of this task.
|
||||
If we did not block attempting to receive the mutex then no
|
||||
priority inheritance would occur. */
|
||||
if( xSemaphoreTakeRecursive( xMutex, recmuTWO_TICK_DELAY ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Ensure the other task attempting to access the mutex (and the
|
||||
other demo tasks) are able to execute. */
|
||||
vTaskDelay( recmuSHORT_DELAY );
|
||||
}
|
||||
|
||||
/* For each time we took the mutex, give it back. */
|
||||
for( ux = 0; ux < recmuMAX_COUNT; ux++ )
|
||||
{
|
||||
/* Ensure the other task attempting to access the mutex (and the
|
||||
other demo tasks) are able to execute. */
|
||||
vTaskDelay( recmuSHORT_DELAY );
|
||||
|
||||
/* We should now be able to give the mutex as many times as we
|
||||
took it. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Having given it back the same number of times as it was taken, we
|
||||
should no longer be the mutex owner, so the next give sh ould fail. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Keep count of the number of cycles this task has performed so a
|
||||
stall can be detected. */
|
||||
uxControllingCycles++;
|
||||
|
||||
/* Suspend ourselves to the blocking task can execute. */
|
||||
xControllingIsSuspended = pdTRUE;
|
||||
vTaskSuspend( NULL );
|
||||
xControllingIsSuspended = pdFALSE;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexBlockingTask( void *pvParameters )
|
||||
{
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Attempt to obtain the mutex. We should block until the
|
||||
controlling task has given up the mutex, and not actually execute
|
||||
past this call until the controlling task is suspended. */
|
||||
if( xSemaphoreTakeRecursive( xMutex, portMAX_DELAY ) == pdPASS )
|
||||
{
|
||||
if( xControllingIsSuspended != pdTRUE )
|
||||
{
|
||||
/* Did not expect to execute until the controlling task was
|
||||
suspended. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Give the mutex back before suspending ourselves to allow
|
||||
the polling task to obtain the mutex. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
xBlockingIsSuspended = pdTRUE;
|
||||
vTaskSuspend( NULL );
|
||||
xBlockingIsSuspended = pdFALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should not leave the xSemaphoreTakeRecursive() function
|
||||
until the mutex was obtained. */
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* The controlling and blocking tasks should be in lock step. */
|
||||
if( uxControllingCycles != ( uxBlockingCycles + 1 ) )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
|
||||
/* Keep count of the number of cycles this task has performed so a
|
||||
stall can be detected. */
|
||||
uxBlockingCycles++;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvRecursiveMutexPollingTask( void *pvParameters )
|
||||
{
|
||||
/* Just to remove compiler warning. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Keep attempting to obtain the mutex. We should only obtain it when
|
||||
the blocking task has suspended itself. */
|
||||
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
|
||||
{
|
||||
/* Is the blocking task suspended? */
|
||||
if( xBlockingIsSuspended != pdTRUE )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Keep count of the number of cycles this task has performed so
|
||||
a stall can be detected. */
|
||||
uxPollingCycles++;
|
||||
|
||||
/* We can resume the other tasks here even though they have a
|
||||
higher priority than the polling task. When they execute they
|
||||
will attempt to obtain the mutex but fail because the polling
|
||||
task is still the mutex holder. The polling task (this task)
|
||||
will then inherit the higher priority. */
|
||||
vTaskResume( xBlockingTaskHandle );
|
||||
vTaskResume( xControllingTaskHandle );
|
||||
|
||||
/* Release the mutex, disinheriting the higher priority again. */
|
||||
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if configUSE_PREEMPTION == 0
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreRecursiveMutexTasksStillRunning( void )
|
||||
{
|
||||
portBASE_TYPE xReturn;
|
||||
static unsigned portBASE_TYPE uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;
|
||||
|
||||
/* Is the controlling task still cycling? */
|
||||
if( uxLastControllingCycles == uxControllingCycles )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastControllingCycles = uxControllingCycles;
|
||||
}
|
||||
|
||||
/* Is the blocking task still cycling? */
|
||||
if( uxLastBlockingCycles == uxBlockingCycles )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastBlockingCycles = uxBlockingCycles;
|
||||
}
|
||||
|
||||
/* Is the polling task still cycling? */
|
||||
if( uxLastPollingCycles == uxPollingCycles )
|
||||
{
|
||||
xErrorOccurred = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
uxLastPollingCycles = uxPollingCycles;
|
||||
}
|
||||
|
||||
if( xErrorOccurred == pdTRUE )
|
||||
{
|
||||
xReturn = pdFAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
278
20091005/Demo/Common/Minimal/semtest.c
Normal file
278
20091005/Demo/Common/Minimal/semtest.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
FreeRTOS V5.4.2 - Copyright (C) 2009 Real Time Engineers Ltd.
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation and modified by the FreeRTOS exception.
|
||||
**NOTE** The exception to the GPL is included to allow you to distribute a
|
||||
combined work that includes FreeRTOS without being obliged to provide the
|
||||
source code for proprietary components outside of the FreeRTOS kernel.
|
||||
Alternative commercial license and support terms are also available upon
|
||||
request. See the licensing section of http://www.FreeRTOS.org for full
|
||||
license details.
|
||||
|
||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with FreeRTOS; if not, write to the Free Software Foundation, Inc., 59
|
||||
Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* Looking for a quick start? Then check out the FreeRTOS eBook! *
|
||||
* See http://www.FreeRTOS.org/Documentation for details *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
Please ensure to read the configuration and relevant port sections of the
|
||||
online documentation.
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Creates two sets of two tasks. The tasks within a set share a variable, access
|
||||
* to which is guarded by a semaphore.
|
||||
*
|
||||
* Each task starts by attempting to obtain the semaphore. On obtaining a
|
||||
* semaphore a task checks to ensure that the guarded variable has an expected
|
||||
* value. It then clears the variable to zero before counting it back up to the
|
||||
* expected value in increments of 1. After each increment the variable is checked
|
||||
* to ensure it contains the value to which it was just set. When the starting
|
||||
* value is again reached the task releases the semaphore giving the other task in
|
||||
* the set a chance to do exactly the same thing. The starting value is high
|
||||
* enough to ensure that a tick is likely to occur during the incrementing loop.
|
||||
*
|
||||
* An error is flagged if at any time during the process a shared variable is
|
||||
* found to have a value other than that expected. Such an occurrence would
|
||||
* suggest an error in the mutual exclusion mechanism by which access to the
|
||||
* variable is restricted.
|
||||
*
|
||||
* The first set of two tasks poll their semaphore. The second set use blocking
|
||||
* calls.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Scheduler include files. */
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
|
||||
/* Demo app include files. */
|
||||
#include "semtest.h"
|
||||
|
||||
/* The value to which the shared variables are counted. */
|
||||
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned portLONG ) 0xfff )
|
||||
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned portLONG ) 0xff )
|
||||
|
||||
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
|
||||
|
||||
#define semtstNUM_TASKS ( 4 )
|
||||
|
||||
#define semtstDELAY_FACTOR ( ( portTickType ) 10 )
|
||||
|
||||
/* The task function as described at the top of the file. */
|
||||
static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );
|
||||
|
||||
/* Structure used to pass parameters to each task. */
|
||||
typedef struct SEMAPHORE_PARAMETERS
|
||||
{
|
||||
xSemaphoreHandle xSemaphore;
|
||||
volatile unsigned portLONG *pulSharedVariable;
|
||||
portTickType xBlockTime;
|
||||
} xSemaphoreParameters;
|
||||
|
||||
/* Variables used to check that all the tasks are still running without errors. */
|
||||
static volatile portSHORT sCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
static volatile portSHORT sNextCheckVariable = 0;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
|
||||
{
|
||||
xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;
|
||||
const portTickType xBlockTime = ( portTickType ) 100;
|
||||
|
||||
/* Create the structure used to pass parameters to the first two tasks. */
|
||||
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
|
||||
if( pxFirstSemaphoreParameters != NULL )
|
||||
{
|
||||
/* Create the semaphore used by the first two tasks. */
|
||||
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
/* Create the variable which is to be shared by the first two tasks. */
|
||||
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
|
||||
|
||||
/* Initialise the share variable to the value the tasks expect. */
|
||||
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
|
||||
/* The first two tasks do not block on semaphore calls. */
|
||||
pxFirstSemaphoreParameters->xBlockTime = ( portTickType ) 0;
|
||||
|
||||
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
|
||||
xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do exactly the same to create the second set of tasks, only this time
|
||||
provide a block time for the semaphore calls. */
|
||||
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
|
||||
if( pxSecondSemaphoreParameters != NULL )
|
||||
{
|
||||
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
|
||||
|
||||
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
|
||||
{
|
||||
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned portLONG * ) pvPortMalloc( sizeof( unsigned portLONG ) );
|
||||
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
|
||||
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;
|
||||
|
||||
xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
|
||||
xTaskCreate( prvSemaphoreTest, ( signed portCHAR * ) "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
|
||||
}
|
||||
}
|
||||
|
||||
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is
|
||||
in use. The registry is provided as a means for kernel aware
|
||||
debuggers to locate semaphores and has no purpose if a kernel aware debugger
|
||||
is not being used. The call to vQueueAddToRegistry() will be removed
|
||||
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
|
||||
defined to be less than 1. */
|
||||
vQueueAddToRegistry( ( xQueueHandle ) pxFirstSemaphoreParameters->xSemaphore, ( signed portCHAR * ) "Counting_Sem_1" );
|
||||
vQueueAddToRegistry( ( xQueueHandle ) pxSecondSemaphoreParameters->xSemaphore, ( signed portCHAR * ) "Counting_Sem_2" );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTASK_FUNCTION( prvSemaphoreTest, pvParameters )
|
||||
{
|
||||
xSemaphoreParameters *pxParameters;
|
||||
volatile unsigned portLONG *pulSharedVariable, ulExpectedValue;
|
||||
unsigned portLONG ulCounter;
|
||||
portSHORT sError = pdFALSE, sCheckVariableToUse;
|
||||
|
||||
/* See which check variable to use. sNextCheckVariable is not semaphore
|
||||
protected! */
|
||||
portENTER_CRITICAL();
|
||||
sCheckVariableToUse = sNextCheckVariable;
|
||||
sNextCheckVariable++;
|
||||
portEXIT_CRITICAL();
|
||||
|
||||
/* A structure is passed in as the parameter. This contains the shared
|
||||
variable being guarded. */
|
||||
pxParameters = ( xSemaphoreParameters * ) pvParameters;
|
||||
pulSharedVariable = pxParameters->pulSharedVariable;
|
||||
|
||||
/* If we are blocking we use a much higher count to ensure loads of context
|
||||
switches occur during the count. */
|
||||
if( pxParameters->xBlockTime > ( portTickType ) 0 )
|
||||
{
|
||||
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
|
||||
}
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Try to obtain the semaphore. */
|
||||
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
|
||||
{
|
||||
/* We have the semaphore and so expect any other tasks using the
|
||||
shared variable to have left it in the state we expect to find
|
||||
it. */
|
||||
if( *pulSharedVariable != ulExpectedValue )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
/* Clear the variable, then count it back up to the expected value
|
||||
before releasing the semaphore. Would expect a context switch or
|
||||
two during this time. */
|
||||
for( ulCounter = ( unsigned portLONG ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
|
||||
{
|
||||
*pulSharedVariable = ulCounter;
|
||||
if( *pulSharedVariable != ulCounter )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the semaphore, and if no errors have occurred increment the check
|
||||
variable. */
|
||||
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
|
||||
{
|
||||
sError = pdTRUE;
|
||||
}
|
||||
|
||||
if( sError == pdFALSE )
|
||||
{
|
||||
if( sCheckVariableToUse < semtstNUM_TASKS )
|
||||
{
|
||||
( sCheckVariables[ sCheckVariableToUse ] )++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a block time then we are running at a priority higher
|
||||
than the idle priority. This task takes a long time to complete
|
||||
a cycle (deliberately so to test the guarding) so will be starving
|
||||
out lower priority tasks. Block for some time to allow give lower
|
||||
priority tasks some processor time. */
|
||||
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( pxParameters->xBlockTime == ( portTickType ) 0 )
|
||||
{
|
||||
/* We have not got the semaphore yet, so no point using the
|
||||
processor. We are not blocking when attempting to obtain the
|
||||
semaphore. */
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This is called to check that all the created tasks are still running. */
|
||||
portBASE_TYPE xAreSemaphoreTasksStillRunning( void )
|
||||
{
|
||||
static portSHORT sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
|
||||
portBASE_TYPE xTask, xReturn = pdTRUE;
|
||||
|
||||
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
|
||||
{
|
||||
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,48 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x21FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x303FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,48 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x23FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,48 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_ROM_start__ = 0x200000;
|
||||
define symbol __ICFEDIT_region_ROM_end__ = 0x27FFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_ROM_start__;
|
||||
export symbol __ICFEDIT_region_ROM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_ROM_start__ size __ICFEDIT_size_startup__];
|
||||
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_ROM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in ROM_region { readonly };
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_SDRAM_start__ = 0x20000000;
|
||||
define symbol __ICFEDIT_region_SDRAM_end__ = 0x21FFFFFF;
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_startup__ = 0x100;
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x1000;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_SDRAM_start__;
|
||||
export symbol __ICFEDIT_region_SDRAM_end__;
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_startup__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region STA_region = mem:[from __ICFEDIT_region_SDRAM_start__ size __ICFEDIT_size_startup__];
|
||||
define region SDRAM_region = mem:[from __ICFEDIT_region_SDRAM_start__+__ICFEDIT_size_startup__ to __ICFEDIT_region_SDRAM_end__];
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
initialize by copy { section .vectors };
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in STA_region { section .cstartup };
|
||||
place in VEC_region { section .vectors };
|
||||
place in SDRAM_region { readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*###ICF### Section handled by ICF editor, don't touch! ****/
|
||||
/*-Editor annotation file-*/
|
||||
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\a_v1_0.xml" */
|
||||
/*-Memory Regions-*/
|
||||
define symbol __ICFEDIT_region_RAM_start__ = 0x300000;
|
||||
define symbol __ICFEDIT_region_RAM_end__ = 0x307FFF;
|
||||
/*-Sizes-*/
|
||||
define symbol __ICFEDIT_size_vectors__ = 0x100;
|
||||
define symbol __ICFEDIT_size_cstack__ = 0x800;
|
||||
define symbol __ICFEDIT_size_svcstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_irqstack__ = 0x60;
|
||||
define symbol __ICFEDIT_size_heap__ = 0x0;
|
||||
/*-Exports-*/
|
||||
export symbol __ICFEDIT_region_RAM_start__;
|
||||
export symbol __ICFEDIT_region_RAM_end__;
|
||||
export symbol __ICFEDIT_size_vectors__;
|
||||
export symbol __ICFEDIT_size_cstack__;
|
||||
export symbol __ICFEDIT_size_svcstack__;
|
||||
export symbol __ICFEDIT_size_irqstack__;
|
||||
export symbol __ICFEDIT_size_heap__;
|
||||
/**** End of ICF editor section. ###ICF###*/
|
||||
|
||||
define memory mem with size = 4G;
|
||||
define region VEC_region = mem:[from __ICFEDIT_region_RAM_start__ size __ICFEDIT_size_vectors__];
|
||||
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__+__ICFEDIT_size_vectors__ to __ICFEDIT_region_RAM_end__];
|
||||
|
||||
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
|
||||
define block SVC_STACK with alignment = 8, size = __ICFEDIT_size_svcstack__ { };
|
||||
define block IRQ_STACK with alignment = 8, size = __ICFEDIT_size_irqstack__ { };
|
||||
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
|
||||
|
||||
do not initialize { section .noinit };
|
||||
|
||||
place in VEC_region { section .vectors };
|
||||
place in RAM_region { section .cstartup, readonly, readwrite, block IRQ_STACK, block SVC_STACK, block CSTACK, block HEAP };
|
||||
|
||||
|
|
@ -0,0 +1,428 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition and functions for using AT91SAM9XE-related features, such
|
||||
/// has PIO pins, memories, etc.
|
||||
///
|
||||
/// !Usage
|
||||
/// -# The code for booting the board is provided by board_cstartup.S and
|
||||
/// board_lowlevel.c.
|
||||
/// -# For using board PIOs, board characteristics (clock, etc.) and external
|
||||
/// components, see board.h.
|
||||
/// -# For manipulating memories (remapping, SDRAM, etc.), see board_memories.h.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \unit
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition of AT91SAM9XE-EK characteristics, AT91SAM9XE-dependant PIOs and
|
||||
/// external components interfacing.
|
||||
///
|
||||
/// !Usage
|
||||
/// -# For operating frequency information, see "SAM9XE-EK - Operating frequencies".
|
||||
/// -# For using portable PIO definitions, see "SAM9XE-EK - PIO definitions".
|
||||
/// -# Several USB definitions are included here (see "SAM9XE-EK - USB device").
|
||||
/// -# For external components definitions, see "SAM79260-EK - External components".
|
||||
/// -# For memory-related definitions, see "SAM79260-EK - Memories".
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BOARD_H
|
||||
#define BOARD_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(at91sam9xe128)
|
||||
#include "at91sam9xe128/AT91SAM9XE128.h"
|
||||
#elif defined(at91sam9xe256)
|
||||
#include "at91sam9xe256/AT91SAM9XE256.h"
|
||||
#elif defined(at91sam9xe512)
|
||||
#include "at91sam9xe512/AT91SAM9XE512.h"
|
||||
#else
|
||||
#error Board does not support the specified chip.
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Board Description"
|
||||
/// This page lists several definition related to the board description.
|
||||
///
|
||||
/// !Definitions
|
||||
/// - BOARD_NAME
|
||||
|
||||
/// Name of the board.
|
||||
#define BOARD_NAME "AT91SAM9XE-EK"
|
||||
/// Board definition.
|
||||
#define at91sam9xeek
|
||||
/// Family definition.
|
||||
#define at91sam9xe
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Operating frequencies"
|
||||
/// This page lists several definition related to the board operating frequency
|
||||
/// (when using the initialization done by board_lowlevel.c).
|
||||
///
|
||||
/// !Definitions
|
||||
/// - BOARD_MAINOSC
|
||||
/// - BOARD_MCK
|
||||
|
||||
/// Frequency of the board main oscillator.
|
||||
#define BOARD_MAINOSC 18432000
|
||||
|
||||
/// Master clock frequency (when using board_lowlevel.c).
|
||||
#define BOARD_MCK ((18432000 * 97 / 9) / 2)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - USB device"
|
||||
/// This page lists constants describing several characteristics (controller
|
||||
/// type, D+ pull-up type, etc.) of the USB device controller of the chip/board.
|
||||
///
|
||||
/// !Constants
|
||||
/// - BOARD_USB_UDP
|
||||
/// - BOARD_USB_PULLUP_INTERNAL
|
||||
/// - BOARD_USB_NUMENDPOINTS
|
||||
/// - BOARD_USB_ENDPOINTS_MAXPACKETSIZE
|
||||
/// - BOARD_USB_ENDPOINTS_BANKS
|
||||
/// - BOARD_USB_BMATTRIBUTES
|
||||
|
||||
/// Chip has a UDP controller.
|
||||
#define BOARD_USB_UDP
|
||||
|
||||
/// Indicates the D+ pull-up is internal to the USB controller.
|
||||
#define BOARD_USB_PULLUP_INTERNAL
|
||||
|
||||
/// Number of endpoints in the USB controller.
|
||||
#define BOARD_USB_NUMENDPOINTS 6
|
||||
|
||||
/// Returns the maximum packet size of the given endpoint.
|
||||
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE(i) ((i >= 4) ? 512 : 64)
|
||||
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE_FS 64
|
||||
|
||||
/// Returns the number of FIFO banks for the given endpoint.
|
||||
#define BOARD_USB_ENDPOINTS_BANKS(i) (((i == 0) || (i == 3)) ? 1 : 2)
|
||||
|
||||
/// USB attributes configuration descriptor (bus or self powered, remote wakeup)
|
||||
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_SELFPOWERED_NORWAKEUP
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - PIO definitions"
|
||||
/// This pages lists all the pio definitions contained in board.h. The constants
|
||||
/// are named using the following convention: PIN_* for a constant which defines
|
||||
/// a single Pin instance (but may include several PIOs sharing the same
|
||||
/// controller), and PINS_* for a list of Pin instances.
|
||||
///
|
||||
/// !DBGU
|
||||
/// - PINS_DBGU
|
||||
///
|
||||
/// !LEDs
|
||||
/// - PIN_LED_0
|
||||
/// - PIN_LED_1
|
||||
/// - PINS_LEDS
|
||||
/// - LED_POWER
|
||||
/// - LED_DS1
|
||||
///
|
||||
/// !Push buttons
|
||||
/// - PIN_PUSHBUTTON_1
|
||||
/// - PIN_PUSHBUTTON_2
|
||||
/// - PINS_PUSHBUTTONS
|
||||
/// - PUSHBUTTON_BP1
|
||||
/// - PUSHBUTTON_BP2
|
||||
///
|
||||
/// !USART0
|
||||
/// - PIN_USART0_RXD
|
||||
/// - PIN_USART0_TXD
|
||||
/// - PIN_USART0_SCK
|
||||
///
|
||||
/// !SPI0
|
||||
/// - PIN_SPI0_MISO
|
||||
/// - PIN_SPI0_MOSI
|
||||
/// - PIN_SPI0_SPCK
|
||||
/// - PINS_SPI0
|
||||
/// - PIN_SPI0_NPCS0
|
||||
/// - PIN_SPI0_NPCS1
|
||||
///
|
||||
/// !SSC
|
||||
/// - PINS_SSC_TX
|
||||
///
|
||||
/// !USB
|
||||
/// - PIN_USB_VBUS
|
||||
///
|
||||
/// !MCI
|
||||
/// - PINS_MCI
|
||||
///
|
||||
/// !TWI0
|
||||
/// - PINS_TWI0
|
||||
|
||||
/// List of all DBGU pin definitions.
|
||||
#define PINS_DBGU {(1<<14) | (1<<15), AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// LED #0 pin definition.
|
||||
#define PIN_LED_0 {1 << 9, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/// LED #1 pin definition.
|
||||
#define PIN_LED_1 {1 << 6, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
/// List of all LED definitions.
|
||||
#define PINS_LEDS PIN_LED_0, PIN_LED_1
|
||||
/// Power LED index.
|
||||
#define LED_POWER 0
|
||||
/// DS1 LED index.
|
||||
#define LED_DS1 1
|
||||
|
||||
/// Push button #1 pin definition.
|
||||
#define PIN_PUSHBUTTON_1 {1 << 30, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_PULLUP}
|
||||
/// Pusb button #2 pin definition.
|
||||
#define PIN_PUSHBUTTON_2 {1UL << 31, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_INPUT, PIO_PULLUP}
|
||||
/// List of all pushbutton pin definitions.
|
||||
#define PINS_PUSHBUTTONS PIN_PUSHBUTTON_1, PIN_PUSHBUTTON_2
|
||||
/// Push button #1 index.
|
||||
#define PUSHBUTTON_BP1 0
|
||||
/// Push button #2 index.
|
||||
#define PUSHBUTTON_BP2 1
|
||||
|
||||
/// USART0 TXD pin definition.
|
||||
#define PIN_USART0_TXD {1 << 4, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 RXD pin definition.
|
||||
#define PIN_USART0_RXD {1 << 5, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 RTS pin definition.
|
||||
#define PIN_USART0_RTS {1 << 26, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 CTS pin definition.
|
||||
#define PIN_USART0_CTS {1 << 27, AT91C_BASE_PIOB, AT91C_ID_PIOB, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// USART0 SCK pin definition.
|
||||
#define PIN_USART0_SCK {1UL << 31, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// SPI0 MISO pin definition.
|
||||
#define PIN_SPI0_MISO {1 << 0, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_PULLUP}
|
||||
/// SPI0 MOSI pin definition.
|
||||
#define PIN_SPI0_MOSI {1 << 1, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// SPI0 SPCK pin definition.
|
||||
#define PIN_SPI0_SPCK {1 << 2, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// List of SPI0 pin definitions (MISO, MOSI & SPCK).
|
||||
#define PINS_SPI0 PIN_SPI0_MISO, PIN_SPI0_MOSI, PIN_SPI0_SPCK
|
||||
/// SPI0 chip select 0 pin definition.
|
||||
#define PIN_SPI0_NPCS0 {AT91C_PA3_SPI0_NPCS0, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// SPI0 chip select 1 pin definition.
|
||||
#define PIN_SPI0_NPCS1 {AT91C_PC11_SPI0_NPCS1, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
|
||||
/// SSC transmitter pins definition.
|
||||
#define PINS_SSC_TX {0x00038000, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// USB VBus monitoring pin definition.
|
||||
#define PIN_USB_VBUS {1 << 5, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_INPUT, PIO_DEFAULT}
|
||||
|
||||
/// List of MCI pins definitions.
|
||||
#define PINS_MCI {0x0000003B, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}, \
|
||||
{1 << 8, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
/// TWI0 pins definition.
|
||||
#define PINS_TWI0 {0x01800000, AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - External components"
|
||||
/// This page lists the definitions related to external on-board components
|
||||
/// located in the board.h file for the AT91SAM9XE-EK.
|
||||
///
|
||||
/// !AT45 Dataflash Card (A)
|
||||
/// - BOARD_AT45_A_SPI_BASE
|
||||
/// - BOARD_AT45_A_SPI_ID
|
||||
/// - BOARD_AT45_A_SPI_PINS
|
||||
/// - BOARD_AT45_A_SPI
|
||||
/// - BOARD_AT45_A_NPCS
|
||||
/// - BOARD_AT45_A_NPCS_PIN
|
||||
///
|
||||
/// !AT45 Dataflash (B)
|
||||
/// - BOARD_AT45_B_SPI_BASE
|
||||
/// - BOARD_AT45_B_SPI_ID
|
||||
/// - BOARD_AT45_B_SPI_PINS
|
||||
/// - BOARD_AT45_B_SPI
|
||||
/// - BOARD_AT45_B_NPCS
|
||||
/// - BOARD_AT45_B_NPCS_PIN
|
||||
///
|
||||
/// !SD Card
|
||||
/// - BOARD_SD_MCI_BASE
|
||||
/// - BOARD_SD_MCI_ID
|
||||
/// - BOARD_SD_PINS
|
||||
/// - BOARD_SD_SLOT
|
||||
///
|
||||
///
|
||||
/// !EMAC
|
||||
/// - AT91C_BASE_EMAC
|
||||
/// - BOARD_EMAC_POWER_ALWAYS_ON
|
||||
/// - BOARD_EMAC_MODE_RMII
|
||||
/// - BOARD_EMAC_PINS
|
||||
/// - BOARD_EMAC_PIN_TEST
|
||||
/// - BOARD_EMAC_PIN_RPTR
|
||||
/// - BOARD_EMAC_RST_PINS
|
||||
/// - BOARD_EMAC_RUN_PINS
|
||||
|
||||
|
||||
/// Base address of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_A_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT45_A_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT45_A_NPCS 0
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT45_A_NPCS_PIN PIN_SPI0_NPCS0
|
||||
|
||||
/// Base address of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT45_B_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT45_B_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT45_B_NPCS 1
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT45_B_NPCS_PIN PIN_SPI0_NPCS1
|
||||
|
||||
/// Base address of SPI peripheral connected to the serialflash.
|
||||
#define BOARD_AT26_A_SPI_BASE AT91C_BASE_SPI0
|
||||
/// Identifier of SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT26_A_SPI_ID AT91C_ID_SPI0
|
||||
/// Pins of the SPI peripheral connected to the dataflash.
|
||||
#define BOARD_AT26_A_SPI_PINS PINS_SPI0
|
||||
/// Dataflahs SPI number.
|
||||
#define BOARD_AT26_A_SPI 0
|
||||
/// Chip select connected to the dataflash.
|
||||
#define BOARD_AT26_A_NPCS 0
|
||||
/// Chip select pin connected to the dataflash.
|
||||
#define BOARD_AT26_A_NPCS_PIN PIN_SPI0_NPCS0
|
||||
|
||||
/// Base address of the MCI peripheral connected to the SD card.
|
||||
#define BOARD_SD_MCI_BASE AT91C_BASE_MCI
|
||||
/// Peripheral identifier of the MCI connected to the SD card.
|
||||
#define BOARD_SD_MCI_ID AT91C_ID_MCI
|
||||
/// MCI pins that shall be configured to access the SD card.
|
||||
#define BOARD_SD_PINS PINS_MCI
|
||||
/// MCI slot to which the SD card is connected to.
|
||||
#define BOARD_SD_SLOT MCI_SD_SLOTB
|
||||
|
||||
/// Board EMAC base address
|
||||
#if !defined(AT91C_BASE_EMAC) && defined(AT91C_BASE_EMACB)
|
||||
#define AT91C_BASE_EMAC AT91C_BASE_EMACB
|
||||
#endif
|
||||
/// Board EMAC power control - ALWAYS ON
|
||||
#define BOARD_EMAC_POWER_ALWAYS_ON
|
||||
/// Board EMAC work mode - RMII/MII ( 1 / 0 )
|
||||
#define BOARD_EMAC_MODE_RMII 1
|
||||
/// The PIN list of PIO for EMAC
|
||||
#define BOARD_EMAC_PINS { ((1<<19)|(1<<13)|(1<<12)|(1<<16)|(1<<15)|(1<<14)\
|
||||
|(1<<17)|(1<<18)|(1<<20)|(1<<21)|(1<<7)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT},\
|
||||
{ ((1<<11)|(1<<10)|(1<<26)|(1<<25)|(1<<27)|(1<<22)\
|
||||
|(1<<29)|(1<<28)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
/// The power up reset latch PIO for PHY
|
||||
#define BOARD_EMAC_PIN_TEST {(1<<17), AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
//#define BOARD_EMAC_PIN_RMII : connected to 3v3 (RMII)
|
||||
// We force the address
|
||||
// (1<<14) PHY address 0, (1<<15) PHY address 1 (PIO A, perih A)
|
||||
// (1<<25) PHY address 2, (1<<26) PHY address 3 (PIO A, perih B)
|
||||
#define BOARD_EMAC_PINS_PHYAD { ((1<<14)|(1<<15)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},\
|
||||
{ ((1<<25)|(1<<26)),\
|
||||
AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
//#define BOARD_EMAC_PIN_10BT : not connected
|
||||
#define BOARD_EMAC_PIN_RPTR {(1<<27), AT91C_BASE_PIOA, AT91C_ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
|
||||
/// The PIN Configure list for EMAC on power up reset
|
||||
#define BOARD_EMAC_RST_PINS BOARD_EMAC_PINS_PHYAD,\
|
||||
BOARD_EMAC_PIN_TEST,\
|
||||
BOARD_EMAC_PIN_RPTR
|
||||
/// The runtime pin configure list for EMAC
|
||||
#define BOARD_EMAC_RUN_PINS BOARD_EMAC_PINS
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE-EK - Memories"
|
||||
/// This page lists definitions related to external on-board memories.
|
||||
///
|
||||
/// !Embedded Flash
|
||||
/// - BOARD_FLASH_EEFC
|
||||
///
|
||||
/// !SDRAM
|
||||
/// - BOARD_SDRAM_SIZE
|
||||
/// - PINS_SDRAM
|
||||
///
|
||||
/// !Nandflash
|
||||
/// - PINS_NANDFLASH
|
||||
/// - BOARD_NF_COMMAND_ADDR
|
||||
/// - BOARD_NF_ADDRESS_ADDR
|
||||
/// - BOARD_NF_DATA_ADDR
|
||||
/// - BOARD_NF_CE_PIN
|
||||
/// - BOARD_NF_RB_PIN
|
||||
|
||||
/// Indicates chip has an Enhanced EFC.
|
||||
#define BOARD_FLASH_EEFC
|
||||
/// Address of the IAP function in ROM.
|
||||
#define BOARD_FLASH_IAP_ADDRESS 0x100008
|
||||
|
||||
/// Board SDRAM size
|
||||
#define BOARD_SDRAM_SIZE 0x02000000
|
||||
/// List of all SDRAM pins definitions.
|
||||
#define PINS_SDRAM {0xFFFF0000, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
|
||||
|
||||
/// Nandflash controller peripheral pins definition.
|
||||
#define PINS_NANDFLASH BOARD_NF_CE_PIN, BOARD_NF_RB_PIN
|
||||
/// Nandflash chip enable pin definition.
|
||||
#define BOARD_NF_CE_PIN {1 << 14, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
/// Nandflash ready/busy pin definition.
|
||||
#define BOARD_NF_RB_PIN {1 << 13, AT91C_BASE_PIOC, AT91C_ID_PIOC, PIO_INPUT, PIO_PULLUP}
|
||||
/// Address for transferring command bytes to the nandflash.
|
||||
#define BOARD_NF_COMMAND_ADDR 0x40400000
|
||||
/// Address for transferring address bytes to the nandflash.
|
||||
#define BOARD_NF_ADDRESS_ADDR 0x40200000
|
||||
/// Address for transferring data bytes to the nandflash.
|
||||
#define BOARD_NF_DATA_ADDR 0x40000000
|
||||
|
||||
/// Address for transferring command bytes to the norflash.
|
||||
#define BOARD_NORFLASH_ADDR 0x10000000
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif //#ifndef BOARD_H
|
||||
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "ISR_Support.h"
|
||||
|
||||
/*
|
||||
IAR startup file for AT91SAM9XE microcontrollers.
|
||||
*/
|
||||
|
||||
MODULE ?cstartup
|
||||
|
||||
;; Forward declaration of sections.
|
||||
SECTION IRQ_STACK:DATA:NOROOT(2)
|
||||
SECTION CSTACK:DATA:NOROOT(3)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define __ASSEMBLY__
|
||||
#include "board.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#define ARM_MODE_ABT 0x17
|
||||
#define ARM_MODE_FIQ 0x11
|
||||
#define ARM_MODE_IRQ 0x12
|
||||
#define ARM_MODE_SVC 0x13
|
||||
#define ARM_MODE_SYS 0x1F
|
||||
|
||||
#define I_BIT 0x80
|
||||
#define F_BIT 0x40
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Startup routine
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Exception vectors
|
||||
*/
|
||||
SECTION .vectors:CODE:NOROOT(2)
|
||||
|
||||
PUBLIC resetVector
|
||||
PUBLIC irqHandler
|
||||
|
||||
EXTERN Undefined_Handler
|
||||
EXTERN vPortYieldProcessor
|
||||
EXTERN Prefetch_Handler
|
||||
EXTERN Abort_Handler
|
||||
EXTERN FIQ_Handler
|
||||
|
||||
ARM
|
||||
|
||||
__iar_init$$done: ; The interrupt vector is not needed
|
||||
; until after copy initialization is done
|
||||
|
||||
resetVector:
|
||||
; All default exception handlers (except reset) are
|
||||
; defined as weak symbol definitions.
|
||||
; If a handler is defined by the application it will take precedence.
|
||||
LDR pc, =resetHandler ; Reset
|
||||
LDR pc, Undefined_Addr ; Undefined instructions
|
||||
LDR pc, SWI_Addr ; Software interrupt (SWI/SVC)
|
||||
LDR pc, Prefetch_Addr ; Prefetch abort
|
||||
LDR pc, Abort_Addr ; Data abort
|
||||
B . ; RESERVED
|
||||
LDR pc, =irqHandler ; IRQ
|
||||
LDR pc, FIQ_Addr ; FIQ
|
||||
|
||||
Undefined_Addr: DCD Undefined_Handler
|
||||
SWI_Addr: DCD vPortYieldProcessor
|
||||
Prefetch_Addr: DCD Prefetch_Handler
|
||||
Abort_Addr: DCD Abort_Handler
|
||||
FIQ_Addr: DCD FIQ_Handler
|
||||
|
||||
/*
|
||||
Handles incoming interrupt requests by branching to the corresponding
|
||||
handler, as defined in the AIC. Supports interrupt nesting.
|
||||
*/
|
||||
irqHandler:
|
||||
portSAVE_CONTEXT
|
||||
|
||||
/* Write in the IVR to support Protect Mode */
|
||||
LDR lr, =AT91C_BASE_AIC
|
||||
LDR r0, [r14, #AIC_IVR]
|
||||
STR lr, [r14, #AIC_IVR]
|
||||
|
||||
/* Branch to C portion of the interrupt handler */
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Acknowledge interrupt */
|
||||
LDR lr, =AT91C_BASE_AIC
|
||||
STR lr, [r14, #AIC_EOICR]
|
||||
|
||||
portRESTORE_CONTEXT
|
||||
|
||||
/*
|
||||
After a reset, execution starts here, the mode is ARM, supervisor
|
||||
with interrupts disabled.
|
||||
Initializes the chip and branches to the main() function.
|
||||
*/
|
||||
SECTION .cstartup:CODE:NOROOT(2)
|
||||
|
||||
PUBLIC resetHandler
|
||||
EXTERN LowLevelInit
|
||||
EXTERN ?main
|
||||
REQUIRE resetVector
|
||||
ARM
|
||||
|
||||
resetHandler:
|
||||
|
||||
/* Set pc to actual code location (i.e. not in remap zone) */
|
||||
LDR pc, =label
|
||||
|
||||
/* Perform low-level initialization of the chip using LowLevelInit() */
|
||||
label:
|
||||
LDR r0, =LowLevelInit
|
||||
LDR r4, =SFE(CSTACK)
|
||||
MOV sp, r4
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Set up the interrupt stack pointer. */
|
||||
MSR cpsr_c, #ARM_MODE_IRQ | I_BIT | F_BIT ; Change the mode
|
||||
LDR sp, =SFE(IRQ_STACK)
|
||||
|
||||
/* Set up the SVC stack pointer. */
|
||||
MSR cpsr_c, #ARM_MODE_SVC | F_BIT ; Change the mode
|
||||
LDR sp, =SFE(CSTACK)
|
||||
|
||||
/* Branch to main() */
|
||||
LDR r0, =?main
|
||||
MOV lr, pc
|
||||
BX r0
|
||||
|
||||
/* Loop indefinitely when program is finished */
|
||||
loop4:
|
||||
B loop4
|
||||
|
||||
END
|
||||
|
|
@ -0,0 +1,194 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "board.h"
|
||||
#include "board_memories.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SAM9XE - Oscillator & PLL Parameters"
|
||||
/// This page lists the parameters which are set for the PLL and main
|
||||
/// oscillator configuration.
|
||||
///
|
||||
/// !Parameters
|
||||
/// - BOARD_OSCOUNT
|
||||
/// - BOARD_CKGR_PLLA
|
||||
/// - BOARD_PLLACOUNT
|
||||
/// - BOARD_MULA
|
||||
/// - BOARD_DIVA
|
||||
/// - BOARD_CKGR_PLLB
|
||||
/// - BOARD_PLLBCOUNT
|
||||
/// - BOARD_MULB
|
||||
/// - BOARD_DIVB
|
||||
/// - BOARD_USBDIV
|
||||
/// - BOARD_PRESCALER
|
||||
|
||||
/// Main oscillator startup time (in number of slow clock ticks).
|
||||
#define BOARD_OSCOUNT (AT91C_CKGR_OSCOUNT & (64 << 8))
|
||||
|
||||
/// PLLA frequency range.
|
||||
#define BOARD_CKGR_PLLA (AT91C_CKGR_SRCA | AT91C_CKGR_OUTA_2)
|
||||
/// PLLA startup time (in number of slow clock ticks).
|
||||
#define BOARD_PLLACOUNT (63 << 8)
|
||||
/// PLLA MUL value.
|
||||
#define BOARD_MULA (AT91C_CKGR_MULA & (96 << 16))
|
||||
/// PLLA DIV value.
|
||||
#define BOARD_DIVA (AT91C_CKGR_DIVA & 9)
|
||||
|
||||
/// PLLB frequency range
|
||||
#define BOARD_CKGR_PLLB AT91C_CKGR_OUTB_1
|
||||
/// PLLB startup time (in number of slow clock ticks).
|
||||
#define BOARD_PLLBCOUNT BOARD_PLLACOUNT
|
||||
/// PLLB MUL value.
|
||||
#define BOARD_MULB (124 << 16)
|
||||
/// PLLB DIV value.
|
||||
#define BOARD_DIVB 12
|
||||
|
||||
/// USB PLL divisor value to obtain a 48MHz clock.
|
||||
#define BOARD_USBDIV AT91C_CKGR_USBDIV_2
|
||||
/// Master clock prescaler value.
|
||||
#define BOARD_PRESCALER AT91C_PMC_MDIV_2
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default spurious interrupt handler
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultSpuriousHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default handler for fast interrupt requests.
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultFiqHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Default handler for standard interrupt requests.
|
||||
//------------------------------------------------------------------------------
|
||||
void DefaultIrqHandler(void)
|
||||
{
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Performs the low-level initialization of the chip.
|
||||
//------------------------------------------------------------------------------
|
||||
void LowLevelInit(void)
|
||||
{
|
||||
unsigned char i;
|
||||
|
||||
// Set flash wait states
|
||||
//----------------------
|
||||
AT91C_BASE_EFC->EFC_FMR = 6 << 8;
|
||||
|
||||
//#if !defined(sdram)
|
||||
// Initialize main oscillator
|
||||
//---------------------------
|
||||
AT91C_BASE_PMC->PMC_MOR = BOARD_OSCOUNT | AT91C_CKGR_MOSCEN;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
// Initialize PLLA at 200MHz (198.656)
|
||||
AT91C_BASE_PMC->PMC_PLLAR = BOARD_CKGR_PLLA
|
||||
| BOARD_PLLACOUNT
|
||||
| BOARD_MULA
|
||||
| BOARD_DIVA;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKA));
|
||||
|
||||
// Initialize PLLB for USB usage
|
||||
AT91C_BASE_PMC->PMC_PLLBR = BOARD_USBDIV
|
||||
| BOARD_CKGR_PLLB
|
||||
| BOARD_PLLBCOUNT
|
||||
| BOARD_MULB
|
||||
| BOARD_DIVB;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKB));
|
||||
|
||||
// Wait for the master clock if it was already initialized
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
// Switch to fast clock
|
||||
//---------------------
|
||||
// Switch to main oscillator + prescaler
|
||||
AT91C_BASE_PMC->PMC_MCKR = BOARD_PRESCALER;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
|
||||
// Switch to PLL + prescaler
|
||||
AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLLA_CLK;
|
||||
while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));
|
||||
//#endif //#if !defined(sdram)
|
||||
|
||||
// Initialize AIC
|
||||
//---------------
|
||||
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;
|
||||
AT91C_BASE_AIC->AIC_SVR[0] = (unsigned int) DefaultFiqHandler;
|
||||
for (i = 1; i < 31; i++) {
|
||||
|
||||
AT91C_BASE_AIC->AIC_SVR[i] = (unsigned int) DefaultIrqHandler;
|
||||
}
|
||||
AT91C_BASE_AIC->AIC_SPU = (unsigned int) DefaultSpuriousHandler;
|
||||
|
||||
// Unstack nested interrupts
|
||||
for (i = 0; i < 8 ; i++) {
|
||||
|
||||
AT91C_BASE_AIC->AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
// Watchdog initialization
|
||||
//------------------------
|
||||
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
// Remap
|
||||
//------
|
||||
BOARD_RemapRam();
|
||||
|
||||
// Disable RTT and PIT interrupts (potential problem when program A
|
||||
// configures RTT, then program B wants to use PIT only, interrupts
|
||||
// from the RTT will still occur since they both use AT91C_ID_SYS)
|
||||
AT91C_BASE_RTTC->RTTC_RTMR &= ~(AT91C_RTTC_ALMIEN | AT91C_RTTC_RTTINCIEN);
|
||||
AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITIEN;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,304 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
#include <pio/pio.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local macros
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Reads a register value. Useful to add trace information to read accesses.
|
||||
#define READ(peripheral, register) (peripheral->register)
|
||||
/// Writes data in a register. Useful to add trace information to write accesses.
|
||||
#define WRITE(peripheral, register, value) (peripheral->register = value)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Changes the mapping of the chip so that the remap area mirrors the
|
||||
/// internal ROM or the EBI CS0 (depending on the BMS input).
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_RemapRom(void)
|
||||
{
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_MRCR, 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Changes the mapping of the chip so that the remap area mirrors the
|
||||
/// internal RAM.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_RemapRam(void)
|
||||
{
|
||||
WRITE(AT91C_BASE_MATRIX,
|
||||
MATRIX_MRCR,
|
||||
(AT91C_MATRIX_RCA926I | AT91C_MATRIX_RCA926D));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initialize and configure the external SDRAM.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureSdram(void)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
static const Pin pinsSdram = PINS_SDRAM;
|
||||
volatile unsigned int *pSdram = (unsigned int *) AT91C_EBI_SDRAM;
|
||||
|
||||
// Enable corresponding PIOs
|
||||
PIO_Configure(&pinsSdram, 1);
|
||||
|
||||
// Enable EBI chip select for the SDRAM
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_EBI, AT91C_MATRIX_CS1A_SDRAMC);
|
||||
|
||||
|
||||
// CFG Control Register
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_CR, AT91C_SDRAMC_NC_9
|
||||
| AT91C_SDRAMC_NR_13
|
||||
| AT91C_SDRAMC_CAS_2
|
||||
| AT91C_SDRAMC_NB_4_BANKS
|
||||
| AT91C_SDRAMC_DBW_32_BITS
|
||||
| AT91C_SDRAMC_TWR_2
|
||||
| AT91C_SDRAMC_TRC_7
|
||||
| AT91C_SDRAMC_TRP_2
|
||||
| AT91C_SDRAMC_TRCD_2
|
||||
| AT91C_SDRAMC_TRAS_5
|
||||
| AT91C_SDRAMC_TXSR_8);
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NOP_CMD); // Perform NOP
|
||||
pSdram[0] = 0x00000000;
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_PRCGALL_CMD); // Set PRCHG AL
|
||||
pSdram[0] = 0x00000000; // Perform PRCHG
|
||||
|
||||
for (i = 0; i < 10000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 1st CBR
|
||||
pSdram[1] = 0x00000001; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 2 CBR
|
||||
pSdram[2] = 0x00000002; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 3 CBR
|
||||
pSdram[3] = 0x00000003; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 4 CBR
|
||||
pSdram[4] = 0x00000004; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 5 CBR
|
||||
pSdram[5] = 0x00000005; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 6 CBR
|
||||
pSdram[6] = 0x00000006; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 7 CBR
|
||||
pSdram[7] = 0x00000007; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 8 CBR
|
||||
pSdram[8] = 0x00000008; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_LMR_CMD); // Set LMR operation
|
||||
pSdram[9] = 0xcafedede; // Perform LMR burst=1, lat=2
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_TR, (BOARD_MCK * 7) / 1000000); // Set Refresh Timer
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NORMAL_CMD); // Set Normal mode
|
||||
pSdram[0] = 0x00000000; // Perform Normal mode
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initialize and configure the SDRAM for a 48 MHz MCK (ROM code clock settings).
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureSdram48MHz(void)
|
||||
{
|
||||
volatile unsigned int i;
|
||||
static const Pin pinsSdram = PINS_SDRAM;
|
||||
volatile unsigned int *pSdram = (unsigned int *) AT91C_EBI_SDRAM;
|
||||
|
||||
// Enable corresponding PIOs
|
||||
PIO_Configure(&pinsSdram, 1);
|
||||
|
||||
// Enable EBI chip select for the SDRAM
|
||||
WRITE(AT91C_BASE_MATRIX, MATRIX_EBI, AT91C_MATRIX_CS1A_SDRAMC);
|
||||
|
||||
|
||||
// CFG Control Register
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_CR, AT91C_SDRAMC_NC_9
|
||||
| AT91C_SDRAMC_NR_13
|
||||
| AT91C_SDRAMC_CAS_2
|
||||
| AT91C_SDRAMC_NB_4_BANKS
|
||||
| AT91C_SDRAMC_DBW_32_BITS
|
||||
| AT91C_SDRAMC_TWR_1
|
||||
| AT91C_SDRAMC_TRC_4
|
||||
| AT91C_SDRAMC_TRP_1
|
||||
| AT91C_SDRAMC_TRCD_1
|
||||
| AT91C_SDRAMC_TRAS_2
|
||||
| AT91C_SDRAMC_TXSR_3);
|
||||
|
||||
for (i = 0; i < 1000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NOP_CMD); // Perform NOP
|
||||
pSdram[0] = 0x00000000;
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_PRCGALL_CMD); // Set PRCHG AL
|
||||
pSdram[0] = 0x00000000; // Perform PRCHG
|
||||
|
||||
for (i = 0; i < 10000; i++);
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 1st CBR
|
||||
pSdram[1] = 0x00000001; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 2 CBR
|
||||
pSdram[2] = 0x00000002; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 3 CBR
|
||||
pSdram[3] = 0x00000003; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 4 CBR
|
||||
pSdram[4] = 0x00000004; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 5 CBR
|
||||
pSdram[5] = 0x00000005; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 6 CBR
|
||||
pSdram[6] = 0x00000006; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 7 CBR
|
||||
pSdram[7] = 0x00000007; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD); // Set 8 CBR
|
||||
pSdram[8] = 0x00000008; // Perform CBR
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_LMR_CMD); // Set LMR operation
|
||||
pSdram[9] = 0xcafedede; // Perform LMR burst=1, lat=2
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_TR, (48000000 * 7) / 1000000); // Set Refresh Timer
|
||||
|
||||
WRITE(AT91C_BASE_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NORMAL_CMD); // Set Normal mode
|
||||
pSdram[0] = 0x00000000; // Perform Normal mode
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NandFlash access. Pins must be configured after or
|
||||
/// before calling this function.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNandFlash(unsigned char busWidth)
|
||||
{
|
||||
// Configure EBI
|
||||
AT91C_BASE_MATRIX->MATRIX_EBI |= AT91C_MATRIX_CS3A_SM;
|
||||
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP3 = 0x00000000;
|
||||
AT91C_BASE_SMC->SMC_PULSE3 = 0x00030003;
|
||||
AT91C_BASE_SMC->SMC_CYCLE3 = 0x00050005;
|
||||
AT91C_BASE_SMC->SMC_CTRL3 = 0x00002003;
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NandFlash access at 48MHz. Pins must be configured
|
||||
/// after or before calling this function.
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNandFlash48MHz(unsigned char busWidth)
|
||||
{
|
||||
// Configure EBI
|
||||
AT91C_BASE_CCFG->CCFG_EBICSA |= AT91C_EBI_CS3A_SM;
|
||||
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP3 = 0x00010001;
|
||||
AT91C_BASE_SMC->SMC_PULSE3 = 0x04030302;
|
||||
AT91C_BASE_SMC->SMC_CYCLE3 = 0x00070004;
|
||||
AT91C_BASE_SMC->SMC_CTRL3 = (AT91C_SMC_READMODE
|
||||
| AT91C_SMC_WRITEMODE
|
||||
| AT91C_SMC_NWAITM_NWAIT_DISABLE
|
||||
| ((0x1 << 16) & AT91C_SMC_TDF));
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL3 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the EBI for NorFlash access at 48MHz.
|
||||
/// \Param busWidth Bus width
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureNorFlash48MHz(unsigned char busWidth)
|
||||
{
|
||||
// Configure SMC
|
||||
AT91C_BASE_SMC->SMC_SETUP0 = 0x00000001;
|
||||
AT91C_BASE_SMC->SMC_PULSE0 = 0x07070703;
|
||||
AT91C_BASE_SMC->SMC_CYCLE0 = 0x00070007;
|
||||
AT91C_BASE_SMC->SMC_CTRL0 = (AT91C_SMC_READMODE
|
||||
| AT91C_SMC_WRITEMODE
|
||||
| AT91C_SMC_NWAITM_NWAIT_DISABLE
|
||||
| ((0x1 << 16) & AT91C_SMC_TDF));
|
||||
|
||||
if (busWidth == 8) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_EIGTH_BITS;
|
||||
}
|
||||
else if (busWidth == 16) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS;
|
||||
}
|
||||
else if (busWidth == 32) {
|
||||
|
||||
AT91C_BASE_SMC->SMC_CTRL0 |= AT91C_SMC_DBW_WIDTH_THIRTY_TWO_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Set flash wait states in the EFC for 48MHz
|
||||
//------------------------------------------------------------------------------
|
||||
void BOARD_ConfigureFlash48MHz(void)
|
||||
{
|
||||
// Set flash wait states
|
||||
//----------------------
|
||||
AT91C_BASE_EFC->EFC_FMR = 6 << 8;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef BOARD_MEMORIES_H
|
||||
#define BOARD_MEMORIES_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void BOARD_RemapRom(void);
|
||||
|
||||
extern void BOARD_RemapRam(void);
|
||||
|
||||
extern void BOARD_ConfigureSdram(void);
|
||||
|
||||
extern void BOARD_ConfigureSdram48MHz(void);
|
||||
|
||||
extern void BOARD_ConfigureNandFlash(unsigned char busWidth);
|
||||
|
||||
extern void BOARD_ConfigureNandFlash48MHz(unsigned char busWidth);
|
||||
|
||||
extern void BOARD_ConfigureNorFlash48MHz(unsigned char busWidth);
|
||||
|
||||
extern void BOARD_ConfigureFlash48MHz(void);
|
||||
|
||||
#endif //#ifndef BOARD_MEMORIES_H
|
||||
|
||||
|
|
@ -0,0 +1,679 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "ac97c.h"
|
||||
#include <board.h>
|
||||
#include <aic/aic.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
#include <utility/math.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Maximum size of one PDC buffer (in bytes).
|
||||
#define MAX_PDC_COUNTER 65535
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// AC97 transfer descriptor. Tracks the status and parameters of a transfer
|
||||
/// on the AC97 bus.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct _Ac97Transfer {
|
||||
|
||||
/// Buffer containing the slots to send.
|
||||
unsigned char *pBuffer;
|
||||
/// Total number of samples to send.
|
||||
volatile unsigned int numSamples;
|
||||
/// Optional callback function.
|
||||
Ac97Callback callback;
|
||||
/// Optional argument to the callback function.
|
||||
void *pArg;
|
||||
|
||||
} Ac97Transfer;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// AC97 controller driver structure. Monitors the status of transfers on all
|
||||
/// AC97 channels.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct _Ac97c {
|
||||
|
||||
/// List of transfers occuring on each channel.
|
||||
Ac97Transfer transfers[5];
|
||||
} Ac97c;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Global AC97 controller instance.
|
||||
static Ac97c ac97c;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the size of one sample (in bytes) on the given channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned char GetSampleSize(unsigned char channel)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A)
|
||||
|| (channel == AC97C_CHANNEL_B)
|
||||
|| (channel == AC97C_CHANNEL_CODEC));
|
||||
|
||||
// Check selected channel
|
||||
switch (channel) {
|
||||
case AC97C_CHANNEL_CODEC: return 2;
|
||||
case AC97C_CHANNEL_A: size = (AT91C_BASE_AC97C->AC97C_CAMR & AT91C_AC97C_SIZE) >> 16; break;
|
||||
case AC97C_CHANNEL_B: size = (AT91C_BASE_AC97C->AC97C_CBMR & AT91C_AC97C_SIZE) >> 16; break;
|
||||
}
|
||||
|
||||
// Compute size in bytes given SIZE field
|
||||
if ((size & 2) != 0) {
|
||||
|
||||
return 2;
|
||||
}
|
||||
else {
|
||||
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Interrupt service routine for Codec, is invoked by AC97C_Handler.
|
||||
//------------------------------------------------------------------------------
|
||||
static void CodecHandler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int data;
|
||||
Ac97Transfer *pTransfer = &(ac97c.transfers[AC97C_CODEC_TRANSFER]);
|
||||
|
||||
// Read CODEC status register
|
||||
status = AT91C_BASE_AC97C->AC97C_COSR;
|
||||
status &= AT91C_BASE_AC97C->AC97C_COMR;
|
||||
|
||||
// A sample has been transmitted
|
||||
if (status & AT91C_AC97C_TXRDY) {
|
||||
|
||||
pTransfer->numSamples--;
|
||||
|
||||
// If there are remaining samples, transmit one
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
}
|
||||
// Transfer finished
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_TXRDY);
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A sample has been received
|
||||
if (status & AT91C_AC97C_RXRDY) {
|
||||
|
||||
// Store sample
|
||||
data = AT91C_BASE_AC97C->AC97C_CORHR;
|
||||
*((unsigned int *) pTransfer->pBuffer) = data;
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
pTransfer->numSamples--;
|
||||
|
||||
// Transfer finished
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_IDR = AT91C_AC97C_COEVT;
|
||||
AT91C_BASE_AC97C->AC97C_COMR &= ~(AT91C_AC97C_RXRDY);
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Interrupt service routine for channel A, is invoked by AC97C_Handler.
|
||||
//------------------------------------------------------------------------------
|
||||
static void ChannelAHandler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
Ac97Transfer *pTransmit = &(ac97c.transfers[AC97C_CHANNEL_A_TRANSMIT]);
|
||||
Ac97Transfer *pReceive = &(ac97c.transfers[AC97C_CHANNEL_A_RECEIVE]);
|
||||
|
||||
// Read channel A status register
|
||||
status = AT91C_BASE_AC97C->AC97C_CASR;
|
||||
|
||||
// A buffer has been transmitted
|
||||
if ((status & AT91C_AC97C_ENDTX) != 0) {
|
||||
|
||||
// Update transfer information
|
||||
if (pTransmit->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
pTransmit->numSamples -= MAX_PDC_COUNTER;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransmit->numSamples = 0;
|
||||
}
|
||||
|
||||
// Transmit new buffers if necessary
|
||||
if (pTransmit->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
// Fill next PDC
|
||||
AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransmit->pBuffer;
|
||||
if (pTransmit->numSamples > 2 * MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = MAX_PDC_COUNTER;
|
||||
pTransmit->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = pTransmit->numSamples - MAX_PDC_COUNTER;
|
||||
}
|
||||
}
|
||||
// Only one buffer remaining
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_ENDTX;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_TXBUFE;
|
||||
}
|
||||
}
|
||||
|
||||
// Transmit completed
|
||||
if ((status & AT91C_AC97C_TXBUFE) != 0) {
|
||||
|
||||
pTransmit->numSamples = 0;
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_TXBUFE;
|
||||
if (pTransmit->callback) {
|
||||
|
||||
pTransmit->callback(pTransmit->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// A buffer has been received
|
||||
if (status & AT91C_AC97C_ENDRX) {
|
||||
|
||||
if (pReceive->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
pReceive->numSamples -= MAX_PDC_COUNTER;
|
||||
}
|
||||
else {
|
||||
|
||||
pReceive->numSamples = 0;
|
||||
}
|
||||
|
||||
// Transfer remaining samples
|
||||
if (pReceive->numSamples > MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pReceive->pBuffer;
|
||||
if (pReceive->numSamples > 2 * MAX_PDC_COUNTER) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = MAX_PDC_COUNTER;
|
||||
pReceive->pBuffer += MAX_PDC_COUNTER * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = pReceive->numSamples - MAX_PDC_COUNTER;
|
||||
}
|
||||
}
|
||||
// Only one buffer remaining
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_ENDRX);
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_RXBUFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Receive complete
|
||||
if ((status & AT91C_AC97C_RXBUFF) != 0) {
|
||||
|
||||
pReceive->numSamples = 0;
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~AT91C_AC97C_RXBUFF;
|
||||
if (pReceive->callback) {
|
||||
|
||||
pReceive->callback(pReceive->pArg, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// This handler function must be called by the AC97C interrupt service routine.
|
||||
/// Identifies which event was activated and calls the associated function.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_Handler(void)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
// Get the real interrupt source
|
||||
status = AT91C_BASE_AC97C->AC97C_SR;
|
||||
status &= AT91C_BASE_AC97C->AC97C_IMR;
|
||||
|
||||
// Check if an event on the codec channel is active
|
||||
if ((status & AT91C_AC97C_COEVT) != 0) {
|
||||
|
||||
CodecHandler();
|
||||
}
|
||||
// Check if an event on channel A is active
|
||||
if ((status & AT91C_AC97C_CAEVT) != 0) {
|
||||
|
||||
ChannelAHandler();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts a read or write transfer on the given channel
|
||||
/// \param channel particular channel (AC97C_CHANNEL_A or AC97C_CHANNEL_B).
|
||||
/// \param pBuffer buffer containing the slots to send.
|
||||
/// \param numSamples total number of samples to send.
|
||||
/// \param callback optional callback function.
|
||||
/// \param pArg optional argument to the callback function.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char AC97C_Transfer(
|
||||
unsigned char channel,
|
||||
unsigned char *pBuffer,
|
||||
unsigned int numSamples,
|
||||
Ac97Callback callback,
|
||||
void *pArg)
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int data;
|
||||
Ac97Transfer *pTransfer;
|
||||
|
||||
SANITY_CHECK(channel <= 5);
|
||||
SANITY_CHECK(pBuffer);
|
||||
SANITY_CHECK(numSamples > 0);
|
||||
|
||||
// Check that no transfer is pending on the channel
|
||||
pTransfer = &(ac97c.transfers[channel]);
|
||||
if (pTransfer->numSamples > 0) {
|
||||
|
||||
trace_LOG(trace_WARNING, "-W- AC97C_Transfer: Channel %d is busy\n\r", channel);
|
||||
return AC97C_ERROR_BUSY;
|
||||
}
|
||||
|
||||
// Fill transfer information
|
||||
pTransfer->pBuffer = pBuffer;
|
||||
pTransfer->numSamples = numSamples;
|
||||
pTransfer->callback = callback;
|
||||
pTransfer->pArg = pArg;
|
||||
|
||||
// Transmit or receive over codec channel
|
||||
if (channel == AC97C_CODEC_TRANSFER) {
|
||||
|
||||
// Send command
|
||||
data = *((unsigned int *) pTransfer->pBuffer);
|
||||
AT91C_BASE_AC97C->AC97C_COTHR = data;
|
||||
|
||||
// Check if transfer is read or write
|
||||
if ((data & AT91C_AC97C_READ) != 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_RXRDY;
|
||||
}
|
||||
else {
|
||||
|
||||
pTransfer->pBuffer += sizeof(unsigned int);
|
||||
AT91C_BASE_AC97C->AC97C_COMR |= AT91C_AC97C_TXRDY;
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_COEVT;
|
||||
}
|
||||
// Transmit over channel A
|
||||
else if (channel == AC97C_CHANNEL_A_TRANSMIT) {
|
||||
|
||||
// Disable PDC
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
|
||||
// Fill PDC buffers
|
||||
size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
|
||||
AT91C_BASE_AC97C->AC97C_TPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_TCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
|
||||
size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
|
||||
if (size > 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_TNPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_TNCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDTX;
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
|
||||
|
||||
// Start transfer
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTEN;
|
||||
}
|
||||
// Receive over channel A
|
||||
else if (channel == AC97C_CHANNEL_A_RECEIVE) {
|
||||
|
||||
// Disable PDC
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
|
||||
// Fill PDC buffers
|
||||
size = min(pTransfer->numSamples, MAX_PDC_COUNTER);
|
||||
AT91C_BASE_AC97C->AC97C_RPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_RCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
|
||||
size = min(pTransfer->numSamples - size, MAX_PDC_COUNTER);
|
||||
if (size > 0) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_RNPR = (unsigned int) pTransfer->pBuffer;
|
||||
AT91C_BASE_AC97C->AC97C_RNCR = size;
|
||||
pTransfer->pBuffer += size * GetSampleSize(AC97C_CHANNEL_A);
|
||||
}
|
||||
|
||||
// Enable interrupts
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= AT91C_AC97C_PDCEN | AT91C_AC97C_ENDRX;
|
||||
AT91C_BASE_AC97C->AC97C_IER |= AT91C_AC97C_CAEVT;
|
||||
|
||||
// Start transfer
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Stop read or write transfer on the given channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_CancelTransfer(unsigned char channel)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
Ac97Transfer *pTransfer;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
|
||||
|
||||
// Save remaining size
|
||||
pTransfer = &(ac97c.transfers[channel]);
|
||||
size = pTransfer->numSamples;
|
||||
pTransfer->numSamples = 0;
|
||||
|
||||
// Stop PDC
|
||||
if (channel == AC97C_CHANNEL_A_TRANSMIT) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS;
|
||||
size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_TCR;
|
||||
}
|
||||
if (channel == AC97C_CHANNEL_A_RECEIVE) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_RXTDIS;
|
||||
size -= min(size, MAX_PDC_COUNTER) - AT91C_BASE_AC97C->AC97C_RCR;
|
||||
}
|
||||
|
||||
// Invoke callback if provided
|
||||
if (pTransfer->callback) {
|
||||
|
||||
pTransfer->callback(pTransfer->pArg, AC97C_ERROR_STOPPED, size);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes the AC97 controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_Configure(void)
|
||||
{
|
||||
unsigned char channel;
|
||||
|
||||
// Enable the AC97 controller peripheral clock
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_AC97C);
|
||||
|
||||
// Enable the peripheral and variable rate adjustment
|
||||
AT91C_BASE_AC97C->AC97C_MR = AT91C_AC97C_ENA | AT91C_AC97C_VRA;
|
||||
|
||||
// Unassigns all input & output slots
|
||||
AC97C_AssignInputSlots(0, 0xFFFF);
|
||||
AC97C_AssignOutputSlots(0, 0xFFFF);
|
||||
|
||||
// Install the AC97C interrupt handler
|
||||
AT91C_BASE_AC97C->AC97C_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_AC97C, 0, AC97C_Handler);
|
||||
AIC_EnableIT(AT91C_ID_AC97C);
|
||||
|
||||
// Disable PDC transfers
|
||||
AT91C_BASE_AC97C->AC97C_PTCR = AT91C_PDC_TXTDIS | AT91C_PDC_RXTDIS;
|
||||
|
||||
// Clear channel transfers
|
||||
for (channel = 0; channel < AC97C_CHANNEL_B_TRANSMIT; channel++) {
|
||||
|
||||
ac97c.transfers[channel].numSamples = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the desired channel with the given value.
|
||||
/// \param channel Channel number.
|
||||
/// \param cfg Configuration value.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg)
|
||||
{
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
|
||||
|
||||
if (channel == AC97C_CHANNEL_A) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR = cfg;
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CBMR = cfg;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Assigns the desired input slots to a particular channel.
|
||||
/// \param channel Channel number (or 0 to unassign slots).
|
||||
/// \param slots Bitfield value of slots to assign.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int i;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B);
|
||||
|
||||
// Assign all slots
|
||||
slots >>= 3;
|
||||
for (i = 3; i < 15; i++) {
|
||||
|
||||
// Check if slots is selected
|
||||
if (slots & 1) {
|
||||
|
||||
value = AT91C_BASE_AC97C->AC97C_ICA;
|
||||
value &= ~(0x07 << ((i - 3) * 3));
|
||||
value |= channel << ((i - 3) * 3);
|
||||
AT91C_BASE_AC97C->AC97C_ICA = value;
|
||||
}
|
||||
slots >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Assigns the desired output slots to a particular channel.
|
||||
/// \param channel Channel number (or 0 to unassign slots).
|
||||
/// \param slots Bitfield value of slots to assign.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int i;
|
||||
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B);
|
||||
|
||||
// Assign all slots
|
||||
slots >>= 3;
|
||||
for (i = 3; i < 15; i++) {
|
||||
|
||||
// Check if slots is selected
|
||||
if (slots & 1) {
|
||||
|
||||
value = AT91C_BASE_AC97C->AC97C_OCA;
|
||||
value &= ~(0x07 << ((i - 3) * 3));
|
||||
value |= channel << ((i - 3) * 3);
|
||||
AT91C_BASE_AC97C->AC97C_OCA = value;
|
||||
}
|
||||
slots >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if no transfer is currently pending on the given channel;
|
||||
/// otherwise, returns 0.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char AC97C_IsFinished(unsigned char channel)
|
||||
{
|
||||
SANITY_CHECK(channel <= AC97C_CHANNEL_B_TRANSMIT);
|
||||
|
||||
if (ac97c.transfers[channel].numSamples > 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Convenience function for synchronously sending commands to the codec.
|
||||
/// \param address Register address.
|
||||
/// \param data Command data.
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_WriteCodec(unsigned char address, unsigned short data)
|
||||
{
|
||||
unsigned int sample;
|
||||
|
||||
sample = (address << 16) | data;
|
||||
AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
|
||||
while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Convenience function for receiving data from the AC97 codec.
|
||||
/// \param address Register address.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned short AC97C_ReadCodec(unsigned char address)
|
||||
{
|
||||
unsigned int sample;
|
||||
|
||||
sample = AT91C_AC97C_READ | (address << 16);
|
||||
AC97C_Transfer(AC97C_CODEC_TRANSFER, (unsigned char *) &sample, 1, 0, 0);
|
||||
while (!AC97C_IsFinished(AC97C_CODEC_TRANSFER));
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the size in bits of one sample on the given channel.
|
||||
/// \param channel Channel number.
|
||||
/// \param size Size of one sample in bits (10, 16, 18 or 24).
|
||||
//------------------------------------------------------------------------------
|
||||
void AC97C_SetChannelSize(unsigned char channel, unsigned char size)
|
||||
{
|
||||
unsigned int bits = 0;
|
||||
|
||||
SANITY_CHECK((size == 10) || (size == 16) || (size == 18) || (size == 24));
|
||||
SANITY_CHECK((channel == AC97C_CHANNEL_A) || (channel == AC97C_CHANNEL_B));
|
||||
|
||||
switch (size) {
|
||||
|
||||
case 10 : bits = AT91C_AC97C_SIZE_10_BITS; break;
|
||||
case 16 : bits = AT91C_AC97C_SIZE_16_BITS; break;
|
||||
case 18 : bits = AT91C_AC97C_SIZE_18_BITS; break;
|
||||
case 20 : bits = AT91C_AC97C_SIZE_20_BITS; break;
|
||||
}
|
||||
|
||||
if (channel == AC97C_CHANNEL_A) {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CAMR &= ~(AT91C_AC97C_SIZE);
|
||||
AT91C_BASE_AC97C->AC97C_CAMR |= bits;
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_AC97C->AC97C_CBMR &= ~(AT91C_AC97C_SIZE);
|
||||
AT91C_BASE_AC97C->AC97C_CBMR |= bits;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AC97C_H
|
||||
#define AC97C_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// The channel is already busy with a transfer.
|
||||
#define AC97C_ERROR_BUSY 1
|
||||
/// The transfer has been stopped by the user.
|
||||
#define AC97C_ERROR_STOPPED 2
|
||||
|
||||
/// Codec channel index.
|
||||
#define AC97C_CHANNEL_CODEC 0
|
||||
/// Channel A index.
|
||||
#define AC97C_CHANNEL_A 1
|
||||
/// Channel B index.
|
||||
#define AC97C_CHANNEL_B 2
|
||||
|
||||
/// Codec transmit/receive transfer index.
|
||||
#define AC97C_CODEC_TRANSFER 0
|
||||
/// Channel A receive transfer index.
|
||||
#define AC97C_CHANNEL_A_RECEIVE 1
|
||||
/// Channel A transmit transfer index.
|
||||
#define AC97C_CHANNEL_A_TRANSMIT 2
|
||||
/// Channel B receive transfer index.
|
||||
#define AC97C_CHANNEL_B_RECEIVE 3
|
||||
/// Channel B transmit transfer index.
|
||||
#define AC97C_CHANNEL_B_TRANSMIT 4
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// AC97C transfer callback function.
|
||||
typedef void (*Ac97Callback)(void *pArg,
|
||||
unsigned char status,
|
||||
unsigned int remaining);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void AC97C_Configure();
|
||||
|
||||
extern void AC97C_ConfigureChannel(unsigned char channel, unsigned int cfg);
|
||||
|
||||
extern void AC97C_AssignInputSlots(unsigned char channel, unsigned int slots);
|
||||
|
||||
extern void AC97C_AssignOutputSlots(unsigned char channel, unsigned int slots);
|
||||
|
||||
extern unsigned char AC97C_Transfer(
|
||||
unsigned char channel,
|
||||
unsigned char *pBuffer,
|
||||
unsigned int numSamples,
|
||||
Ac97Callback callback,
|
||||
void *pArg);
|
||||
|
||||
extern unsigned char AC97C_IsFinished(unsigned char channel);
|
||||
|
||||
extern void AC97C_WriteCodec(unsigned char address, unsigned short data);
|
||||
|
||||
extern unsigned short AC97C_ReadCodec(unsigned char address);
|
||||
|
||||
extern void AC97C_SetChannelSize(unsigned char channel, unsigned char size);
|
||||
|
||||
extern void AC97C_CancelTransfer(unsigned char channel);
|
||||
|
||||
#endif //#ifndef AC97C_H
|
||||
|
||||
196
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/aes/aes.c
Normal file
196
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/aes/aes.c
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "aes.h"
|
||||
#include <board.h>
|
||||
#include <utility/trace.h>
|
||||
#include <utility/assert.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the AES peripheral to encrypt/decrypt, start mode (manual, auto,
|
||||
/// PDC) and operating mode (ECB, CBC, OFB, CFB, CTR).
|
||||
/// \param cipher Indicates if the peripheral should encrypt or decrypt data.
|
||||
/// \param smode Start mode.
|
||||
/// \param opmode Operating mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_Configure(
|
||||
unsigned char cipher,
|
||||
unsigned int smode,
|
||||
unsigned int opmode)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_Configure()\n\r");
|
||||
SANITY_CHECK((cipher & 0xFFFFFFFE) == 0);
|
||||
SANITY_CHECK((smode & 0xFFFFFCFF) == 0);
|
||||
SANITY_CHECK((opmode & 0xFFFF8FFF) == 0);
|
||||
|
||||
// Reset the peripheral first
|
||||
AT91C_BASE_AES->AES_CR = AT91C_AES_SWRST;
|
||||
|
||||
// Configure mode register
|
||||
AT91C_BASE_AES->AES_MR = cipher | smode | opmode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the key used by the AES algorithm to cipher the plain text or
|
||||
/// decipher the encrypted text.
|
||||
/// \param pKey Pointer to a 16-bytes cipher key.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_SetKey(const unsigned int *pKey)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_SetKey()\n\r");
|
||||
SANITY_CHECK(pKey);
|
||||
|
||||
AT91C_BASE_AES->AES_KEYWxR[0] = pKey[0];
|
||||
AT91C_BASE_AES->AES_KEYWxR[1] = pKey[1];
|
||||
AT91C_BASE_AES->AES_KEYWxR[2] = pKey[2];
|
||||
AT91C_BASE_AES->AES_KEYWxR[3] = pKey[3];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the initialization vector that is used to encrypt the plain text or
|
||||
/// decrypt the cipher text in chained block modes (CBC, CFB, OFB & CTR).
|
||||
/// \param pVector Pointer to a 16-bytes initialization vector.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_SetVector(const unsigned int *pVector)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_SetVector()\n\r");
|
||||
SANITY_CHECK(pVector);
|
||||
|
||||
AT91C_BASE_AES->AES_IVxR[0] = pVector[0];
|
||||
AT91C_BASE_AES->AES_IVxR[1] = pVector[1];
|
||||
AT91C_BASE_AES->AES_IVxR[2] = pVector[2];
|
||||
AT91C_BASE_AES->AES_IVxR[3] = pVector[3];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the input data of the AES algorithm (i.e. plain text in cipher mode,
|
||||
/// ciphered text in decipher mode). If auto mode is active, the encryption is
|
||||
/// started automatically after writing the last word.
|
||||
/// \param pData Pointer to the 16-bytes data to cipher/decipher.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_SetInputData(const unsigned int *pData)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_SetInputData()\n\r");
|
||||
SANITY_CHECK(pData);
|
||||
|
||||
AT91C_BASE_AES->AES_IDATAxR[0] = pData[0];
|
||||
AT91C_BASE_AES->AES_IDATAxR[1] = pData[1];
|
||||
AT91C_BASE_AES->AES_IDATAxR[2] = pData[2];
|
||||
AT91C_BASE_AES->AES_IDATAxR[3] = pData[3];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Stores the result of the last AES operation (encrypt/decrypt) in the
|
||||
/// provided buffer.
|
||||
/// \param pData Pointer to a 16-bytes buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_GetOutputData(unsigned int *pData)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_GetOutputData()\n\r");
|
||||
SANITY_CHECK(pData);
|
||||
|
||||
pData[0] = AT91C_BASE_AES->AES_ODATAxR[0];
|
||||
pData[1] = AT91C_BASE_AES->AES_ODATAxR[1];
|
||||
pData[2] = AT91C_BASE_AES->AES_ODATAxR[2];
|
||||
pData[3] = AT91C_BASE_AES->AES_ODATAxR[3];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the input buffer to use when in PDC mode.
|
||||
/// \param pInput Pointer to the input buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_SetInputBuffer(const unsigned int *pInput)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_SetInputBuffer()\n\r");
|
||||
SANITY_CHECK(pInput);
|
||||
|
||||
AT91C_BASE_AES->AES_TPR = (unsigned int) pInput;
|
||||
AT91C_BASE_AES->AES_TCR = 4;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the output buffer to use when in PDC mode.
|
||||
/// \param pOutput Pointer to the output buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_SetOutputBuffer(unsigned int *pOutput)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_SetOutputBuffer()\n\r");
|
||||
SANITY_CHECK(pOutput);
|
||||
|
||||
AT91C_BASE_AES->AES_RPR = (unsigned int) pOutput;
|
||||
AT91C_BASE_AES->AES_RCR = 4;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts the encryption/decryption process when in manual or PDC mode. In
|
||||
/// manual mode, the key and input data must have been entered using
|
||||
/// AES_SetKey() and AES_SetInputData(). In PDC mode, the key, input & output
|
||||
/// buffer must have been set using AES_SetKey(), AES_SetInputBuffer() and
|
||||
/// AES_SetOutputBuffer().
|
||||
//------------------------------------------------------------------------------
|
||||
void AES_Start(void)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "AES_Start()\n\r");
|
||||
SANITY_CHECK(((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL)
|
||||
|| ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_PDC));
|
||||
|
||||
// Manual mode
|
||||
if ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL) {
|
||||
|
||||
AT91C_BASE_AES->AES_CR = AT91C_AES_START;
|
||||
}
|
||||
// PDC
|
||||
else {
|
||||
|
||||
AT91C_BASE_AES->AES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the current value of the AES interrupt status register.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int AES_GetStatus(void)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- AES_GetStatus()\n\r");
|
||||
|
||||
return AT91C_BASE_AES->AES_ISR;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef AES_H
|
||||
#define AES_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void AES_Configure(
|
||||
unsigned char cipher,
|
||||
unsigned int smode,
|
||||
unsigned int opmode);
|
||||
|
||||
extern void AES_SetKey(const unsigned int *pKey);
|
||||
|
||||
extern void AES_SetVector(const unsigned int *pVector);
|
||||
|
||||
extern void AES_SetInputData(const unsigned int *pData);
|
||||
|
||||
extern void AES_GetOutputData(unsigned int *pData);
|
||||
|
||||
extern void AES_SetInputBuffer(const unsigned int *pInput);
|
||||
|
||||
extern void AES_SetOutputBuffer(unsigned int *pOutput);
|
||||
|
||||
extern void AES_Start(void);
|
||||
|
||||
extern unsigned int AES_GetStatus(void);
|
||||
|
||||
#endif //#ifndef AES_H
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "aic.h"
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the interrupt associated with the given source, using the
|
||||
/// specified mode and interrupt handler.
|
||||
/// \param source Interrupt source to configure.
|
||||
/// \param mode Triggering mode of the interrupt.
|
||||
/// \param handler Interrupt handler function.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_ConfigureIT(unsigned int source,
|
||||
unsigned int mode,
|
||||
void (*handler)( void ))
|
||||
{
|
||||
// Disable the interrupt first
|
||||
AT91C_BASE_AIC->AIC_IDCR = 1 << source;
|
||||
|
||||
// Configure mode and handler
|
||||
AT91C_BASE_AIC->AIC_SMR[source] = mode;
|
||||
AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) handler;
|
||||
|
||||
// Clear interrupt
|
||||
AT91C_BASE_AIC->AIC_ICCR = 1 << source;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables interrupts coming from the given (unique) source.
|
||||
/// \param source Interrupt source to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_EnableIT(unsigned int source)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_IECR = 1 << source;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables interrupts coming from the given (unique) source.
|
||||
/// \param source Interrupt source to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void AIC_DisableIT(unsigned int source)
|
||||
{
|
||||
AT91C_BASE_AIC->AIC_IDCR = 1 << source;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Methods and definitions for configuring interrupts using the Advanced
|
||||
/// Interrupt Controller (AIC).
|
||||
///
|
||||
/// !Usage
|
||||
/// -# Configure an interrupt source using AIC_ConfigureIT
|
||||
/// -# Enable or disable interrupt generation of a particular source with
|
||||
/// AIC_EnableIT and AIC_DisableIT.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef AIC_H
|
||||
#define AIC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL
|
||||
/// Redefinition of missing constant.
|
||||
#define AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void AIC_ConfigureIT(unsigned int source,
|
||||
unsigned int mode,
|
||||
void (*handler)( void ));
|
||||
|
||||
extern void AIC_EnableIT(unsigned int source);
|
||||
|
||||
extern void AIC_DisableIT(unsigned int source);
|
||||
|
||||
#endif //#ifndef AIC_H
|
||||
|
||||
1042
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/can/can.c
Normal file
1042
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/can/can.c
Normal file
File diff suppressed because it is too large
Load diff
113
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/can/can.h
Normal file
113
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/can/can.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _CAN_H
|
||||
#define _CAN_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
#define AT91C_CAN_TIMEOUT 100000
|
||||
|
||||
#define AT91C_TEST_NOK 0
|
||||
#define AT91C_TEST_OK 1
|
||||
|
||||
#define CAN_STATUS_SUCCESS 0
|
||||
#define CAN_STATUS_LOCKED 1
|
||||
#define CAN_STATUS_ABORTED 2
|
||||
#define CAN_STATUS_RESET 3
|
||||
|
||||
#if defined (AT91C_BASE_CAN)
|
||||
#define AT91C_BASE_CAN0 AT91C_BASE_CAN
|
||||
#endif
|
||||
#if defined (AT91C_ID_CAN)
|
||||
#define AT91C_ID_CAN0 AT91C_ID_CAN
|
||||
#endif
|
||||
#if defined (AT91C_BASE_CAN_MB0)
|
||||
#define AT91C_BASE_CAN0_MB0 AT91C_BASE_CAN_MB0
|
||||
#define AT91C_BASE_CAN0_MB1 AT91C_BASE_CAN_MB1
|
||||
#define AT91C_BASE_CAN0_MB2 AT91C_BASE_CAN_MB2
|
||||
#define AT91C_BASE_CAN0_MB3 AT91C_BASE_CAN_MB3
|
||||
#define AT91C_BASE_CAN0_MB4 AT91C_BASE_CAN_MB4
|
||||
#define AT91C_BASE_CAN0_MB5 AT91C_BASE_CAN_MB5
|
||||
#define AT91C_BASE_CAN0_MB6 AT91C_BASE_CAN_MB6
|
||||
#define AT91C_BASE_CAN0_MB7 AT91C_BASE_CAN_MB7
|
||||
#endif
|
||||
#if defined (AT91C_BASE_CAN_MB8)
|
||||
#define AT91C_BASE_CAN0_MB8 AT91C_BASE_CAN_MB8
|
||||
#define AT91C_BASE_CAN0_MB9 AT91C_BASE_CAN_MB9
|
||||
#define AT91C_BASE_CAN0_MB10 AT91C_BASE_CAN_MB10
|
||||
#define AT91C_BASE_CAN0_MB11 AT91C_BASE_CAN_MB11
|
||||
#define AT91C_BASE_CAN0_MB12 AT91C_BASE_CAN_MB12
|
||||
#define AT91C_BASE_CAN0_MB13 AT91C_BASE_CAN_MB13
|
||||
#define AT91C_BASE_CAN0_MB14 AT91C_BASE_CAN_MB14
|
||||
#define AT91C_BASE_CAN0_MB15 AT91C_BASE_CAN_MB15
|
||||
#endif
|
||||
|
||||
#define NUM_MAILBOX_MAX 16
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct
|
||||
{
|
||||
volatile unsigned char state;
|
||||
volatile unsigned char can_number;
|
||||
volatile unsigned char mailbox_number;
|
||||
volatile unsigned char test_can;
|
||||
volatile unsigned int mode_reg;
|
||||
volatile unsigned int acceptance_mask_reg;
|
||||
volatile unsigned int identifier;
|
||||
volatile unsigned int data_low_reg;
|
||||
volatile unsigned int data_high_reg;
|
||||
volatile unsigned int control_reg;
|
||||
volatile unsigned int mailbox_in_use;
|
||||
volatile int size;
|
||||
} CanTransfer;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern unsigned char CAN_Init( unsigned int baudrate,
|
||||
CanTransfer *canTransferRead,
|
||||
CanTransfer *canTransferWrite );
|
||||
extern void CAN_BasicTestSuite(void);
|
||||
extern void CAN_disable( void );
|
||||
extern void CAN_ResetAllMailbox( void );
|
||||
extern void CAN_ResetTransfer( CanTransfer *pTransfer );
|
||||
extern void CAN_InitMailboxRegisters( CanTransfer *pTransfer );
|
||||
extern unsigned char CAN_IsInIdle( CanTransfer *pTransfer );
|
||||
|
||||
extern unsigned char CAN_Write( CanTransfer *pTransfer );
|
||||
extern unsigned char CAN_Read( CanTransfer *pTransfer );
|
||||
|
||||
extern void CAN_BasicTestSuiteWithoutInterrupt( void );
|
||||
extern unsigned char CAN_IsInIdle( CanTransfer *pTransfer );
|
||||
#endif // _CAN_H
|
||||
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "dbgu.h"
|
||||
#include <stdarg.h>
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes the DBGU with the given parameters, and enables both the
|
||||
/// transmitter and the receiver.
|
||||
/// \param mode Operating mode to configure (see <Modes>).
|
||||
/// \param baudrate Desired baudrate.
|
||||
/// \param mck Frequency of the system master clock.
|
||||
//------------------------------------------------------------------------------
|
||||
void DBGU_Configure(unsigned int mode,
|
||||
unsigned int baudrate,
|
||||
unsigned int mck)
|
||||
{
|
||||
// Reset & disable receiver and transmitter, disable interrupts
|
||||
AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RSTRX | AT91C_US_RSTTX;
|
||||
AT91C_BASE_DBGU->DBGU_IDR = 0xFFFFFFFF;
|
||||
|
||||
// Configure baud rate
|
||||
AT91C_BASE_DBGU->DBGU_BRGR = mck / (baudrate * 16);
|
||||
|
||||
// Configure mode register
|
||||
AT91C_BASE_DBGU->DBGU_MR = mode;
|
||||
|
||||
// Disable DMA channel
|
||||
AT91C_BASE_DBGU->DBGU_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
|
||||
|
||||
// Enable receiver and transmitter
|
||||
AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Outputs a character on the DBGU line.
|
||||
/// \param c Character to send.
|
||||
//------------------------------------------------------------------------------
|
||||
static void DBGU_PutChar(unsigned char c)
|
||||
{
|
||||
// Wait for the transmitter to be ready
|
||||
while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY) == 0);
|
||||
|
||||
// Send character
|
||||
AT91C_BASE_DBGU->DBGU_THR = c;
|
||||
|
||||
// Wait for the transfer to complete
|
||||
while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY) == 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads and returns a character from the DBGU.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char DBGU_GetChar()
|
||||
{
|
||||
while ((AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_RXRDY) == 0);
|
||||
return AT91C_BASE_DBGU->DBGU_RHR;
|
||||
}
|
||||
|
||||
#ifndef NOFPUT
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Implementation of fputc using the DBGU as the standard output. Required
|
||||
/// for printf().
|
||||
/// Returns the character written if successful, or -1 if the output stream is
|
||||
/// not stdout or stderr.
|
||||
/// \param c Character to write.
|
||||
/// \param pStream Output stream.
|
||||
//------------------------------------------------------------------------------
|
||||
signed int fputc(signed int c, FILE *pStream)
|
||||
{
|
||||
if ((pStream == stdout) || (pStream == stderr)) {
|
||||
|
||||
DBGU_PutChar(c);
|
||||
return c;
|
||||
}
|
||||
else {
|
||||
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Implementation of fputs using the DBGU as the standard output. Required
|
||||
/// for printf(). Does NOT currently use the PDC.
|
||||
/// Returns the number of characters written if successful, or -1 if the output
|
||||
/// stream is not stdout or stderr.
|
||||
/// \param pStr String to write.
|
||||
/// \param pStream Output stream.
|
||||
//------------------------------------------------------------------------------
|
||||
signed int fputs(const char *pStr, FILE *pStream)
|
||||
{
|
||||
signed int num = 0;
|
||||
|
||||
while (*pStr != 0) {
|
||||
|
||||
if (fputc(*pStr, pStream) == -1) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
num++;
|
||||
pStr++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
#undef putchar
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Outputs a character on the DBGU. Returns the character itself.
|
||||
/// \param c Character to output.
|
||||
//------------------------------------------------------------------------------
|
||||
signed int putchar(signed int c)
|
||||
{
|
||||
return fputc(c, stdout);
|
||||
}
|
||||
|
||||
#endif //#ifndef NOFPUT
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// This module provides definitions and functions for using the DBGU.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Enable the DBGU pins (see pio.h).
|
||||
/// -# Configure the DBGU using DBGU_Configure.
|
||||
///
|
||||
/// \note Unless specified, all the functions defined here operate synchronously;
|
||||
/// i.e. they all wait the data is sent/received before returning.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef DBGU_H
|
||||
#define DBGU_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page Modes
|
||||
/// This page lists several common operating modes for the DBGU.
|
||||
/// !Modes
|
||||
/// - DBGU_STANDARD
|
||||
|
||||
/// Standard operating mode (asynchronous, 8bit, no parity)
|
||||
#define DBGU_STANDARD AT91C_US_PAR_NONE
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern void DBGU_Configure(unsigned int mode,
|
||||
unsigned int baudrate,
|
||||
unsigned int mck);
|
||||
|
||||
extern unsigned char DBGU_GetChar();
|
||||
|
||||
#endif //#ifndef DBGU_H
|
||||
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL trace_INFO
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "eefc.h"
|
||||
|
||||
#ifdef BOARD_FLASH_EEFC
|
||||
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the flash ready interrupt source on the EEFC peripheral.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_EnableFrdyIt(void)
|
||||
{
|
||||
AT91C_BASE_EFC->EFC_FMR |= AT91C_EFC_FRDY;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the flash ready interrupt source on the EEFC peripheral.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_DisableFrdyIt(void)
|
||||
{
|
||||
AT91C_BASE_EFC->EFC_FMR &= ~AT91C_EFC_FRDY;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Translates the given address page and offset values. The resulting
|
||||
/// values are stored in the provided variables if they are not null.
|
||||
/// \param address Address to translate.
|
||||
/// \param pPage First page accessed.
|
||||
/// \param pOffset Byte offset in first page.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_TranslateAddress(
|
||||
unsigned int address,
|
||||
unsigned short *pPage,
|
||||
unsigned short *pOffset)
|
||||
{
|
||||
unsigned short page;
|
||||
unsigned short offset;
|
||||
|
||||
SANITY_CHECK(address >= AT91C_IFLASH);
|
||||
SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
|
||||
|
||||
// Calculate page & offset
|
||||
page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
|
||||
offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
|
||||
trace_LOG(trace_DEBUG,
|
||||
"-D- Translated 0x%08X to page=%d and offset=%d\n\r",
|
||||
address, page, offset);
|
||||
|
||||
// Store values
|
||||
if (pPage) {
|
||||
|
||||
*pPage = page;
|
||||
}
|
||||
if (pOffset) {
|
||||
|
||||
*pOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Computes the address of a flash access given the page and offset.
|
||||
/// \param page Page number.
|
||||
/// \param offset Byte offset inside page.
|
||||
/// \param pAddress Computed address (optional).
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_ComputeAddress(
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned int *pAddress)
|
||||
{
|
||||
unsigned int address;
|
||||
|
||||
SANITY_CHECK(page <= AT91C_IFLASH_NB_OF_PAGES);
|
||||
SANITY_CHECK(offset < AT91C_IFLASH_PAGE_SIZE);
|
||||
|
||||
// Compute address
|
||||
address = AT91C_IFLASH + page * AT91C_IFLASH_PAGE_SIZE + offset;
|
||||
|
||||
// Store result
|
||||
if (pAddress) {
|
||||
|
||||
*pAddress = address;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts the executing the given command on the EEFC. This function returns
|
||||
/// as soon as the command is started. It does NOT set the FMCN field automatically.
|
||||
/// \param command Command to execute.
|
||||
/// \param argument Command argument (should be 0 if not used).
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_StartCommand(unsigned char command, unsigned short argument)
|
||||
{
|
||||
// Check command & argument
|
||||
switch (command) {
|
||||
|
||||
case AT91C_EFC_FCMD_WP:
|
||||
case AT91C_EFC_FCMD_WPL:
|
||||
case AT91C_EFC_FCMD_EWP:
|
||||
case AT91C_EFC_FCMD_EWPL:
|
||||
case AT91C_EFC_FCMD_EPL:
|
||||
case AT91C_EFC_FCMD_EPA:
|
||||
case AT91C_EFC_FCMD_SLB:
|
||||
case AT91C_EFC_FCMD_CLB:
|
||||
ASSERT(argument < AT91C_IFLASH_NB_OF_PAGES,
|
||||
"-F- Embedded flash has only %d pages\n\r",
|
||||
AT91C_IFLASH_NB_OF_PAGES);
|
||||
break;
|
||||
|
||||
case AT91C_EFC_FCMD_SFB:
|
||||
case AT91C_EFC_FCMD_CFB:
|
||||
ASSERT(argument < EFC_NUM_GPNVMS, "-F- Embedded flash has only %d GPNVMs\n\r", EFC_NUM_GPNVMS);
|
||||
break;
|
||||
|
||||
case AT91C_EFC_FCMD_GETD:
|
||||
case AT91C_EFC_FCMD_EA:
|
||||
case AT91C_EFC_FCMD_GLB:
|
||||
case AT91C_EFC_FCMD_GFB:
|
||||
ASSERT(argument == 0, "-F- Argument is meaningless for the given command.\n\r");
|
||||
break;
|
||||
|
||||
default: ASSERT(0, "-F- Unknown command %d\n\r", command);
|
||||
}
|
||||
|
||||
// Start commandEmbedded flash
|
||||
ASSERT((AT91C_BASE_EFC->EFC_FSR & AT91C_EFC_FRDY) == AT91C_EFC_FRDY, "-F- EEFC is not ready\n\r");
|
||||
AT91C_BASE_EFC->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Performs the given command and wait until its completion (or an error).
|
||||
/// Returns 0 if successful; otherwise returns an error code.
|
||||
/// \param command Command to perform.
|
||||
/// \param argument Optional command argument.
|
||||
//------------------------------------------------------------------------------
|
||||
#ifdef __ICCARM__
|
||||
__ramfunc
|
||||
#else
|
||||
__attribute__ ((section (".ramfunc")))
|
||||
#endif
|
||||
unsigned char EFC_PerformCommand(unsigned char command, unsigned short argument)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
#ifdef BOARD_FLASH_IAP_ADDRESS
|
||||
// Pointer on IAP function in ROM
|
||||
static void (*IAP_PerformCommand)(unsigned int);
|
||||
IAP_PerformCommand = (void (*)(unsigned int)) *((unsigned int *) BOARD_FLASH_IAP_ADDRESS);
|
||||
|
||||
// Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
|
||||
if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
|
||||
(((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
|
||||
|
||||
IAP_PerformCommand((0x5A << 24) | (argument << 8) | command);
|
||||
return (AT91C_BASE_EFC->EFC_FSR & (AT91C_EFC_LOCKE | AT91C_EFC_FCMDE));
|
||||
}
|
||||
#endif
|
||||
|
||||
AT91C_BASE_EFC->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
|
||||
do {
|
||||
|
||||
status = AT91C_BASE_EFC->EFC_FSR;
|
||||
}
|
||||
while ((status & AT91C_EFC_FRDY) != AT91C_EFC_FRDY);
|
||||
|
||||
return (status & (AT91C_EFC_LOCKE | AT91C_EFC_FCMDE));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the current status of the EEFC. Keep in mind that this function clears
|
||||
/// the value of some status bits (LOCKE, PROGE).
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int EFC_GetStatus(void)
|
||||
{
|
||||
return AT91C_BASE_EFC->EFC_FSR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the result of the last executed command.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int EFC_GetResult(void) {
|
||||
|
||||
return AT91C_BASE_EFC->EFC_FRR;
|
||||
}
|
||||
|
||||
#endif //#ifdef BOARD_FLASH_EEFC
|
||||
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef EEFC_H
|
||||
#define EEFC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#ifdef BOARD_FLASH_EEFC
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Number of GPNVMs available on each chip.
|
||||
#if defined(at91sam7l64) || defined(at91sam7l128)
|
||||
|
||||
#define EFC_NUM_GPNVMS 2
|
||||
|
||||
#elif defined(at91sam9xe128) || defined(at91sam9xe256) || defined(at91sam9xe512)
|
||||
|
||||
#define EFC_NUM_GPNVMS 17
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Needed when EEFC is integrated in MC.
|
||||
#if !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_MC)
|
||||
typedef struct _AT91S_EFC {
|
||||
AT91_REG EFC_FMR; // EFC Flash Mode Register
|
||||
AT91_REG EFC_FCR; // EFC Flash Command Register
|
||||
AT91_REG EFC_FSR; // EFC Flash Status Register
|
||||
AT91_REG EFC_FRR; // EFC Flash Result Register
|
||||
AT91_REG EFC_FVR; // EFC Flash Version Register
|
||||
} AT91S_EFC, *AT91PS_EFC;
|
||||
|
||||
#define AT91C_EFC_FRDY AT91C_MC_FRDY
|
||||
#define AT91C_EFC_FWS AT91C_MC_FWS
|
||||
#define AT91C_EFC_FWS_0WS AT91C_MC_FWS_0WS
|
||||
#define AT91C_EFC_FWS_1WS AT91C_MC_FWS_1WS
|
||||
#define AT91C_EFC_FWS_2WS AT91C_MC_FWS_2WS
|
||||
#define AT91C_EFC_FWS_3WS AT91C_MC_FWS_3WS
|
||||
#define AT91C_EFC_FCMD AT91C_MC_FCMD
|
||||
#define AT91C_EFC_FCMD_GETD AT91C_MC_FCMD_GETD
|
||||
#define AT91C_EFC_FCMD_WP AT91C_MC_FCMD_WP
|
||||
#define AT91C_EFC_FCMD_WPL AT91C_MC_FCMD_WPL
|
||||
#define AT91C_EFC_FCMD_EWP AT91C_MC_FCMD_EWP
|
||||
#define AT91C_EFC_FCMD_EWPL AT91C_MC_FCMD_EWPL
|
||||
#define AT91C_EFC_FCMD_EA AT91C_MC_FCMD_EA
|
||||
#define AT91C_EFC_FCMD_EPL AT91C_MC_FCMD_EPL
|
||||
#define AT91C_EFC_FCMD_EPA AT91C_MC_FCMD_EPA
|
||||
#define AT91C_EFC_FCMD_SLB AT91C_MC_FCMD_SLB
|
||||
#define AT91C_EFC_FCMD_CLB AT91C_MC_FCMD_CLB
|
||||
#define AT91C_EFC_FCMD_GLB AT91C_MC_FCMD_GLB
|
||||
#define AT91C_EFC_FCMD_SFB AT91C_MC_FCMD_SFB
|
||||
#define AT91C_EFC_FCMD_CFB AT91C_MC_FCMD_CFB
|
||||
#define AT91C_EFC_FCMD_GFB AT91C_MC_FCMD_GFB
|
||||
#define AT91C_EFC_FARG AT91C_MC_FARG
|
||||
#define AT91C_EFC_FKEY AT91C_MC_FKEY
|
||||
#define AT91C_EFC_FRDY_S AT91C_MC_FRDY_S
|
||||
#define AT91C_EFC_FCMDE AT91C_MC_FCMDE
|
||||
#define AT91C_EFC_LOCKE AT91C_MC_LOCKE
|
||||
#define AT91C_EFC_FVALUE AT91C_MC_FVALUE
|
||||
|
||||
#define AT91C_BASE_EFC (AT91_CAST(AT91PS_EFC) 0xFFFFFF60)
|
||||
|
||||
#endif //#if !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_MC)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void EFC_EnableFrdyIt(void);
|
||||
|
||||
extern void EFC_DisableFrdyIt(void);
|
||||
|
||||
extern void EFC_TranslateAddress(
|
||||
unsigned int address,
|
||||
unsigned short *pPage,
|
||||
unsigned short *pOffset);
|
||||
|
||||
extern void EFC_ComputeAddress(
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned int *pAddress);
|
||||
|
||||
extern void EFC_StartCommand(
|
||||
unsigned char command,
|
||||
unsigned short argument);
|
||||
|
||||
extern unsigned char EFC_PerformCommand(
|
||||
unsigned char command,
|
||||
unsigned short argument);
|
||||
|
||||
extern unsigned int EFC_GetStatus(void);
|
||||
|
||||
extern unsigned int EFC_GetResult(void);
|
||||
|
||||
#endif //#ifdef BOARD_FLASH_EEFC
|
||||
#endif //#ifndef EEFC_H
|
||||
|
||||
387
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/efc/efc.c
Normal file
387
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/efc/efc.c
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL trace_INFO
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "efc.h"
|
||||
|
||||
#ifdef BOARD_FLASH_EFC
|
||||
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Round a number to the nearest integral value (number must have been
|
||||
// multiplied by 10, e.g. to round 10.3 enter 103).
|
||||
#define ROUND(n) ((((n) % 10) >= 5) ? (((n) / 10) + 1) : ((n) / 10))
|
||||
|
||||
// Returns the FMCN field value when manipulating lock bits, given MCK.
|
||||
#if defined(at91sam7a3)
|
||||
#define FMCN_BITS(mck) (ROUND((mck) / 100000) << 16) // <- Not correct according to the datasheet but it works
|
||||
#else
|
||||
#define FMCN_BITS(mck) (ROUND((mck) / 100000) << 16)
|
||||
#endif
|
||||
|
||||
// Returns the FMCN field value when manipulating the rest of the flash.
|
||||
#define FMCN_FLASH(mck) ((((mck) / 2000000) * 3) << 16)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/// Master clock frequency, used to infer the value of the FMCN field.
|
||||
static unsigned int lMck;
|
||||
/// Calculated value of the FMCN field base on Master clock frequency.
|
||||
static unsigned int lMckFMCN;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the system master clock so the FMCN field of the EFC(s) can be
|
||||
/// programmed properly.
|
||||
/// \param mck Master clock frequency in Hz.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_SetMasterClock(unsigned int mck)
|
||||
{
|
||||
lMck = mck;
|
||||
lMckFMCN = FMCN_BITS(lMck);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the given interrupt sources on an EFC peripheral.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param sources Interrupt sources to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_EnableIt(AT91S_EFC *pEfc, unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK(pEfc);
|
||||
SANITY_CHECK((sources & ~0x0000000D) == 0);
|
||||
|
||||
pEfc->EFC_FMR |= sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the given interrupt sources on an EFC peripheral.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param sources Interrupt sources to disable.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_DisableIt(AT91S_EFC *pEfc, unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK(pEfc);
|
||||
SANITY_CHECK((sources & ~(AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE)) == 0);
|
||||
|
||||
pEfc->EFC_FMR &= ~sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables or disable the "Erase before programming" feature of an EFC.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param enable If 1, the feature is enabled; otherwise it is disabled.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_SetEraseBeforeProgramming(AT91S_EFC *pEfc, unsigned char enable)
|
||||
{
|
||||
SANITY_CHECK(pEfc);
|
||||
|
||||
if (enable) {
|
||||
|
||||
pEfc->EFC_FMR &= ~AT91C_MC_NEBP;
|
||||
}
|
||||
else {
|
||||
|
||||
pEfc->EFC_FMR |= AT91C_MC_NEBP;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Translates the given address into EFC, page and offset values. The resulting
|
||||
/// values are stored in the provided variables if they are not null.
|
||||
/// \param address Address to translate.
|
||||
/// \param ppEfc Pointer to target EFC peripheral.
|
||||
/// \param pPage First page accessed.
|
||||
/// \param pOffset Byte offset in first page.
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_TranslateAddress(
|
||||
unsigned int address,
|
||||
AT91S_EFC **ppEfc,
|
||||
unsigned short *pPage,
|
||||
unsigned short *pOffset)
|
||||
{
|
||||
AT91S_EFC *pEfc;
|
||||
unsigned short page;
|
||||
unsigned short offset;
|
||||
|
||||
SANITY_CHECK(address >= AT91C_IFLASH);
|
||||
SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
|
||||
|
||||
#if defined(AT91C_BASE_EFC0)
|
||||
if (address >= (AT91C_IFLASH + AT91C_IFLASH_SIZE / 2)) {
|
||||
|
||||
pEfc = AT91C_BASE_EFC1;
|
||||
page = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) / AT91C_IFLASH_PAGE_SIZE;
|
||||
offset = (address - AT91C_IFLASH - AT91C_IFLASH_SIZE / 2) % AT91C_IFLASH_PAGE_SIZE;
|
||||
}
|
||||
else {
|
||||
|
||||
pEfc = AT91C_BASE_EFC0;
|
||||
page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
|
||||
offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
|
||||
}
|
||||
#else
|
||||
pEfc = AT91C_BASE_EFC;
|
||||
page = (address - AT91C_IFLASH) / AT91C_IFLASH_PAGE_SIZE;
|
||||
offset = (address - AT91C_IFLASH) % AT91C_IFLASH_PAGE_SIZE;
|
||||
#endif
|
||||
trace_LOG(trace_DEBUG,
|
||||
"-D- Translated 0x%08X to EFC=0x%08X, page=%d and offset=%d\n\r",
|
||||
address, (unsigned int) pEfc, page, offset);
|
||||
|
||||
// Store values
|
||||
if (ppEfc) {
|
||||
|
||||
*ppEfc = pEfc;
|
||||
}
|
||||
if (pPage) {
|
||||
|
||||
*pPage = page;
|
||||
}
|
||||
if (pOffset) {
|
||||
|
||||
*pOffset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Computes the address of a flash access given the EFC, page and offset.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param page Page number.
|
||||
/// \param offset Byte offset inside page.
|
||||
/// \param pAddress Computed address (optional).
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_ComputeAddress(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned int *pAddress)
|
||||
{
|
||||
unsigned int address;
|
||||
|
||||
SANITY_CHECK(pEfc);
|
||||
#if defined(AT91C_BASE_EFC1)
|
||||
SANITY_CHECK(page <= (AT91C_IFLASH_NB_OF_PAGES / 2));
|
||||
#else
|
||||
SANITY_CHECK(page <= AT91C_IFLASH_NB_OF_PAGES);
|
||||
#endif
|
||||
SANITY_CHECK(offset < AT91C_IFLASH_PAGE_SIZE);
|
||||
|
||||
// Compute address
|
||||
address = AT91C_IFLASH + page * AT91C_IFLASH_PAGE_SIZE + offset;
|
||||
#if defined(AT91C_BASE_EFC1)
|
||||
if (pEfc == AT91C_BASE_EFC1) {
|
||||
|
||||
address += AT91C_IFLASH_SIZE / 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Store result
|
||||
if (pAddress) {
|
||||
|
||||
*pAddress = address;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts the executing the given command on an EFC. This function returns
|
||||
/// as soon as the command is started. It does NOT set the FMCN field automatically.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param command Command to execute.
|
||||
/// \param argument Command argument (should be 0 if not used).
|
||||
//------------------------------------------------------------------------------
|
||||
void EFC_StartCommand(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned char command,
|
||||
unsigned short argument)
|
||||
{
|
||||
SANITY_CHECK(pEfc);
|
||||
ASSERT(lMck != 0, "-F- Master clock not set.\n\r");
|
||||
|
||||
// Check command & argument
|
||||
switch (command) {
|
||||
|
||||
case AT91C_MC_FCMD_PROG_AND_LOCK:
|
||||
ASSERT(0, "-F- Write and lock command cannot be carried out.\n\r");
|
||||
break;
|
||||
|
||||
case AT91C_MC_FCMD_START_PROG:
|
||||
case AT91C_MC_FCMD_LOCK:
|
||||
case AT91C_MC_FCMD_UNLOCK:
|
||||
ASSERT(argument < AT91C_IFLASH_NB_OF_PAGES,
|
||||
"-F- Maximum number of pages is %d (argument was %d)\n\r",
|
||||
AT91C_IFLASH_NB_OF_PAGES,
|
||||
argument);
|
||||
break;
|
||||
|
||||
#if (EFC_NUM_GPNVMS > 0)
|
||||
case AT91C_MC_FCMD_SET_GP_NVM:
|
||||
case AT91C_MC_FCMD_CLR_GP_NVM:
|
||||
ASSERT(argument < EFC_NUM_GPNVMS, "-F- A maximum of %d GPNVMs are available on the chip.\n\r", EFC_NUM_GPNVMS);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case AT91C_MC_FCMD_ERASE_ALL:
|
||||
|
||||
#if !defined(EFC_NO_SECURITY_BIT)
|
||||
case AT91C_MC_FCMD_SET_SECURITY:
|
||||
#endif
|
||||
ASSERT(argument == 0, "-F- Argument is meaningless for the given command\n\r");
|
||||
break;
|
||||
|
||||
default: ASSERT(0, "-F- Unknown command %d\n\r", command);
|
||||
}
|
||||
|
||||
// Set FMCN
|
||||
switch (command) {
|
||||
|
||||
case AT91C_MC_FCMD_LOCK:
|
||||
case AT91C_MC_FCMD_UNLOCK:
|
||||
#if (EFC_NUM_GPNVMS > 0)
|
||||
case AT91C_MC_FCMD_SET_GP_NVM:
|
||||
case AT91C_MC_FCMD_CLR_GP_NVM:
|
||||
#endif
|
||||
#if !defined(EFC_NO_SECURITY_BIT)
|
||||
case AT91C_MC_FCMD_SET_SECURITY:
|
||||
#endif
|
||||
pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
|
||||
break;
|
||||
|
||||
case AT91C_MC_FCMD_START_PROG:
|
||||
case AT91C_MC_FCMD_ERASE_ALL:
|
||||
pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
|
||||
break;
|
||||
}
|
||||
|
||||
// Start command
|
||||
ASSERT((pEfc->EFC_FSR & AT91C_MC_FRDY) != 0, "-F- Efc is not ready\n\r");
|
||||
pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Performs the given command and wait until its completion (or an error).
|
||||
/// Returns 0 if successful; otherwise returns an error code.
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
/// \param command Command to perform.
|
||||
/// \param argument Optional command argument.
|
||||
//------------------------------------------------------------------------------
|
||||
#ifdef __ICCARM__
|
||||
__ramfunc
|
||||
#else
|
||||
__attribute__ ((section (".ramfunc")))
|
||||
#endif
|
||||
unsigned char EFC_PerformCommand(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned char command,
|
||||
unsigned short argument)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
// Set FMCN
|
||||
switch (command) {
|
||||
|
||||
case AT91C_MC_FCMD_LOCK:
|
||||
case AT91C_MC_FCMD_UNLOCK:
|
||||
#if (EFC_NUM_GPNVMS > 0)
|
||||
case AT91C_MC_FCMD_SET_GP_NVM:
|
||||
case AT91C_MC_FCMD_CLR_GP_NVM:
|
||||
#endif
|
||||
#if !defined(EFC_NO_SECURITY_BIT)
|
||||
case AT91C_MC_FCMD_SET_SECURITY:
|
||||
#endif
|
||||
pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
|
||||
break;
|
||||
|
||||
case AT91C_MC_FCMD_START_PROG:
|
||||
case AT91C_MC_FCMD_ERASE_ALL:
|
||||
pEfc->EFC_FMR = (pEfc->EFC_FMR & ~AT91C_MC_FMCN) | lMckFMCN;
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BOARD_FLASH_IAP_ADDRESS
|
||||
// Pointer on IAP function in ROM
|
||||
static void (*IAP_PerformCommand)(unsigned int, unsigned int);
|
||||
unsigned int index = 0;
|
||||
#ifdef AT91C_BASE_EFC1
|
||||
if (pEfc == AT91C_BASE_EFC1) {
|
||||
|
||||
index = 1;
|
||||
}
|
||||
#endif
|
||||
IAP_PerformCommand = (void (*)(unsigned int, unsigned int)) *((unsigned int *) BOARD_FLASH_IAP_ADDRESS);
|
||||
|
||||
// Check if IAP function is implemented (opcode in SWI != 'b' or 'ldr') */
|
||||
if ((((((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xEA) &&
|
||||
(((unsigned long) IAP_PerformCommand >> 24) & 0xFF) != 0xE5)) {
|
||||
|
||||
IAP_PerformCommand(index, (0x5A << 24) | (argument << 8) | command);
|
||||
return (pEfc->EFC_FSR & (AT91C_MC_LOCKE | AT91C_MC_PROGE));
|
||||
}
|
||||
#endif
|
||||
|
||||
pEfc->EFC_FCR = (0x5A << 24) | (argument << 8) | command;
|
||||
do {
|
||||
|
||||
status = pEfc->EFC_FSR;
|
||||
}
|
||||
while ((status & AT91C_MC_FRDY) == 0);
|
||||
|
||||
return (status & (AT91C_MC_PROGE | AT91C_MC_LOCKE));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the current status of an EFC. Keep in mind that this function clears
|
||||
/// the value of some status bits (LOCKE, PROGE).
|
||||
/// \param pEfc Pointer to an AT91S_EFC structure.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int EFC_GetStatus(AT91S_EFC *pEfc)
|
||||
{
|
||||
return pEfc->EFC_FSR;
|
||||
}
|
||||
|
||||
#endif //#ifdef BOARD_FLASH_EFC
|
||||
|
||||
127
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/efc/efc.h
Normal file
127
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/efc/efc.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef EFC_H
|
||||
#define EFC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#ifdef BOARD_FLASH_EFC
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Number of GPNVMs available on each chip.
|
||||
#if defined(at91sam7s16) || defined(at91sam7s161) || defined(at91sam7s32) \
|
||||
|| defined(at91sam7s321) || defined(at91sam7s64) || defined(at91sam7s128) \
|
||||
|| defined(at91sam7s256) || defined(at91sam7s512)
|
||||
|
||||
#define EFC_NUM_GPNVMS 2
|
||||
|
||||
#elif defined(at91sam7se32) || defined(at91sam7se256) || defined(at91sam7se512) \
|
||||
|| defined(at91sam7x128) || defined(at91sam7x256) || defined(at91sam7x512) \
|
||||
|| defined(at91sam7xc128) || defined(at91sam7xc256) || defined(at91sam7xc512) \
|
||||
|
||||
#define EFC_NUM_GPNVMS 3
|
||||
|
||||
#elif defined(at91sam7a3)
|
||||
|
||||
#define EFC_NUM_GPNVMS 0
|
||||
#endif
|
||||
|
||||
// Missing FRDY bit for SAM7A3
|
||||
#if defined(at91sam7a3)
|
||||
#define AT91C_MC_FRDY (AT91C_MC_EOP | AT91C_MC_EOL)
|
||||
#endif
|
||||
|
||||
// No security bit on SAM7A3
|
||||
#if defined(at91sam7a3)
|
||||
#define EFC_NO_SECURITY_BIT
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// For chips which do not define AT91S_EFC
|
||||
#if !defined(AT91C_BASE_EFC) && !defined(AT91C_BASE_EFC0)
|
||||
typedef struct _AT91S_EFC {
|
||||
|
||||
AT91_REG EFC_FMR;
|
||||
AT91_REG EFC_FCR;
|
||||
AT91_REG EFC_FSR;
|
||||
|
||||
} AT91S_EFC, *AT91PS_EFC;
|
||||
#define AT91C_BASE_EFC (AT91_CAST(AT91PS_EFC) 0xFFFFFF60)
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void EFC_SetMasterClock(unsigned int mck);
|
||||
|
||||
extern void EFC_EnableIt(AT91S_EFC *pEfc, unsigned int sources);
|
||||
|
||||
extern void EFC_DisableIt(AT91S_EFC *pEfc, unsigned int sources);
|
||||
|
||||
extern void EFC_SetEraseBeforeProgramming(AT91S_EFC *pEfc, unsigned char enable);
|
||||
|
||||
extern void EFC_TranslateAddress(
|
||||
unsigned int address,
|
||||
AT91S_EFC **ppEfc,
|
||||
unsigned short *pPage,
|
||||
unsigned short *pOffset);
|
||||
|
||||
extern void EFC_ComputeAddress(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned short page,
|
||||
unsigned short offset,
|
||||
unsigned int *pAddress);
|
||||
|
||||
extern void EFC_StartCommand(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned char command,
|
||||
unsigned short argument);
|
||||
|
||||
extern unsigned char EFC_PerformCommand(
|
||||
AT91S_EFC *pEfc,
|
||||
unsigned char command,
|
||||
unsigned short argument);
|
||||
|
||||
extern unsigned int EFC_GetStatus(AT91S_EFC *pEfc);
|
||||
|
||||
#endif //#ifdef BOARD_FLASH_EFC
|
||||
#endif //#ifndef EFC_H
|
||||
|
||||
|
|
@ -0,0 +1,833 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Headers
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <board.h>
|
||||
#include "emac.h"
|
||||
#include <utility/trace.h>
|
||||
#include <utility/assert.h>
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
/// The buffer addresses written into the descriptors must be aligned so the
|
||||
/// last few bits are zero. These bits have special meaning for the EMAC
|
||||
/// peripheral and cannot be used as part of the address.
|
||||
#define EMAC_ADDRESS_MASK ((unsigned int)0xFFFFFFFC)
|
||||
#define EMAC_LENGTH_FRAME ((unsigned int)0x0FFF) /// Length of frame mask
|
||||
|
||||
// receive buffer descriptor bits
|
||||
#define EMAC_RX_OWNERSHIP_BIT (1UL << 0)
|
||||
#define EMAC_RX_WRAP_BIT (1UL << 1)
|
||||
#define EMAC_RX_SOF_BIT (1UL << 14)
|
||||
#define EMAC_RX_EOF_BIT (1UL << 15)
|
||||
|
||||
// Transmit buffer descriptor bits
|
||||
#define EMAC_TX_LAST_BUFFER_BIT (1UL << 15)
|
||||
#define EMAC_TX_WRAP_BIT (1UL << 30)
|
||||
#define EMAC_TX_USED_BIT (1UL << 31)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Circular buffer management
|
||||
//-----------------------------------------------------------------------------
|
||||
// Return count in buffer
|
||||
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
|
||||
|
||||
// Return space available, 0..size-1
|
||||
// We always leave one free char as a completely full buffer
|
||||
// has head == tail, which is the same as empty
|
||||
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
|
||||
|
||||
// Return count up to the end of the buffer.
|
||||
// Carefully avoid accessing head and tail more than once,
|
||||
// so they can change underneath us without returning inconsistent results
|
||||
#define CIRC_CNT_TO_END(head,tail,size) \
|
||||
({int end = (size) - (tail); \
|
||||
int n = ((head) + end) & ((size)-1); \
|
||||
n < end ? n : end;})
|
||||
|
||||
// Return space available up to the end of the buffer
|
||||
#define CIRC_SPACE_TO_END(head,tail,size) \
|
||||
({int end = (size) - 1 - (head); \
|
||||
int n = (end + (tail)) & ((size)-1); \
|
||||
n <= end ? n : end+1;})
|
||||
|
||||
// Increment head or tail
|
||||
#define CIRC_INC(headortail,size) \
|
||||
headortail++; \
|
||||
if(headortail >= size) { \
|
||||
headortail = 0; \
|
||||
}
|
||||
|
||||
#define CIRC_EMPTY(circ) ((circ)->head == (circ)->tail)
|
||||
#define CIRC_CLEAR(circ) ((circ)->head = (circ)->tail = 0)
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Structures
|
||||
//------------------------------------------------------------------------------
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma pack(4) // IAR
|
||||
#define __attribute__(...) // IAR
|
||||
#endif // IAR
|
||||
/// Describes the type and attribute of Receive Transfer descriptor.
|
||||
typedef struct _EmacRxTDescriptor {
|
||||
unsigned int addr;
|
||||
unsigned int status;
|
||||
} __attribute__((packed, aligned(8))) EmacRxTDescriptor, *PEmacRxTDescriptor;
|
||||
|
||||
/// Describes the type and attribute of Transmit Transfer descriptor.
|
||||
typedef struct _EmacTxTDescriptor {
|
||||
unsigned int addr;
|
||||
unsigned int status;
|
||||
} __attribute__((packed, aligned(8))) EmacTxTDescriptor, *PEmacTxTDescriptor;
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma pack() // IAR
|
||||
#endif // IAR
|
||||
|
||||
/// Descriptors for RX (required aligned by 8)
|
||||
typedef struct {
|
||||
volatile EmacRxTDescriptor td[RX_BUFFERS];
|
||||
EMAC_RxCallback rxCb; /// Callback function to be invoked once a frame has been received
|
||||
unsigned short idx;
|
||||
} RxTd;
|
||||
|
||||
/// Descriptors for TX (required aligned by 8)
|
||||
typedef struct {
|
||||
volatile EmacTxTDescriptor td[TX_BUFFERS];
|
||||
EMAC_TxCallback txCb[TX_BUFFERS]; /// Callback function to be invoked once TD has been processed
|
||||
EMAC_WakeupCallback wakeupCb; /// Callback function to be invoked once several TD have been released
|
||||
unsigned short wakeupThreshold; /// Number of free TD before wakeupCb is invoked
|
||||
unsigned short head; /// Circular buffer head pointer incremented by the upper layer (buffer to be sent)
|
||||
unsigned short tail; /// Circular buffer head pointer incremented by the IT handler (buffer sent)
|
||||
} TxTd;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Internal variables
|
||||
//------------------------------------------------------------------------------
|
||||
// Receive Transfer Descriptor buffer
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma data_alignment=8 // IAR
|
||||
#endif // IAR
|
||||
static volatile RxTd rxTd;
|
||||
// Transmit Transfer Descriptor buffer
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma data_alignment=8 // IAR
|
||||
#endif // IAR
|
||||
static volatile TxTd txTd;
|
||||
/// Send Buffer
|
||||
// Section 3.6 of AMBA 2.0 spec states that burst should not cross 1K Boundaries.
|
||||
// Receive buffer manager writes are burst of 2 words => 3 lsb bits of the address shall be set to 0
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma data_alignment=8 // IAR
|
||||
#endif // IAR
|
||||
static volatile unsigned char pTxBuffer[TX_BUFFERS * EMAC_TX_UNITSIZE] __attribute__((aligned(8)));
|
||||
|
||||
#ifdef __ICCARM__ // IAR
|
||||
#pragma data_alignment=8 // IAR
|
||||
#endif // IAR
|
||||
/// Receive Buffer
|
||||
static volatile unsigned char pRxBuffer[RX_BUFFERS * EMAC_RX_UNITSIZE] __attribute__((aligned(8)));
|
||||
/// Statistics
|
||||
static volatile EmacStats EmacStatistics;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Wait PHY operation complete.
|
||||
/// Return 1 if the operation completed successfully.
|
||||
/// May be need to re-implemented to reduce CPU load.
|
||||
/// \param retry: the retry times, 0 to wait forever until complete.
|
||||
//-----------------------------------------------------------------------------
|
||||
static unsigned char EMAC_WaitPhy( unsigned int retry )
|
||||
{
|
||||
unsigned int retry_count = 0;
|
||||
|
||||
while((AT91C_BASE_EMAC->EMAC_NSR & AT91C_EMAC_IDLE) == 0) {
|
||||
|
||||
// Dead LOOP!
|
||||
if (retry == 0) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Timeout check
|
||||
retry_count++;
|
||||
if(retry_count >= retry) {
|
||||
|
||||
trace_LOG(trace_ERROR, "E: Wait PHY time out\n\r");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PHY management functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Set MDC clock according to current board clock. Per 802.3, MDC should be
|
||||
/// less then 2.5MHz.
|
||||
/// Return 1 if successfully, 0 if MDC clock not found.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char EMAC_SetMdcClock( unsigned int mck )
|
||||
{
|
||||
int clock_dividor;
|
||||
|
||||
if (mck <= 20000000) {
|
||||
clock_dividor = AT91C_EMAC_CLK_HCLK_8; /// MDC clock = MCK/8
|
||||
}
|
||||
else if (mck <= 40000000) {
|
||||
clock_dividor = AT91C_EMAC_CLK_HCLK_16; /// MDC clock = MCK/16
|
||||
}
|
||||
else if (mck <= 80000000) {
|
||||
clock_dividor = AT91C_EMAC_CLK_HCLK_32; /// MDC clock = MCK/32
|
||||
}
|
||||
else if (mck <= 160000000) {
|
||||
clock_dividor = AT91C_EMAC_CLK_HCLK_64; /// MDC clock = MCK/64
|
||||
}
|
||||
else {
|
||||
trace_LOG(trace_ERROR, "E: No valid MDC clock.\n\r");
|
||||
return 0;
|
||||
}
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR = (AT91C_BASE_EMAC->EMAC_NCFGR & (~AT91C_EMAC_CLK))
|
||||
| clock_dividor;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable MDI with PHY
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_EnableMdio( void )
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_MPE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable MDI with PHY
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_DisableMdio( void )
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_NCR &= ~AT91C_EMAC_MPE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable MII mode for EMAC, called once after autonegotiate
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_EnableMII( void )
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable RMII mode for EMAC, called once after autonegotiate
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_EnableRMII( void )
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_USRIO = AT91C_EMAC_CLKEN | AT91C_EMAC_RMII;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Read PHY register.
|
||||
/// Return 1 if successfully, 0 if timeout.
|
||||
/// \param PhyAddress PHY Address
|
||||
/// \param Address Register Address
|
||||
/// \param pValue Pointer to a 32 bit location to store read data
|
||||
/// \param retry The retry times, 0 to wait forever until complete.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char EMAC_ReadPhy(unsigned char PhyAddress,
|
||||
unsigned char Address,
|
||||
unsigned int *pValue,
|
||||
unsigned int retry)
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))
|
||||
| (AT91C_EMAC_CODE & (2 << 16))
|
||||
| (AT91C_EMAC_RW & (2 << 28))
|
||||
| (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))
|
||||
| (AT91C_EMAC_REGA & (Address << 18));
|
||||
|
||||
if ( EMAC_WaitPhy(retry) == 0 ) {
|
||||
|
||||
trace_LOG(trace_ERROR, "TimeOut EMAC_ReadPhy\n\r");
|
||||
return 0;
|
||||
}
|
||||
*pValue = ( AT91C_BASE_EMAC->EMAC_MAN & 0x0000ffff );
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Write PHY register
|
||||
/// Return 1 if successfully, 0 if timeout.
|
||||
/// \param PhyAddress PHY Address
|
||||
/// \param Address Register Address
|
||||
/// \param Value Data to write ( Actually 16 bit data )
|
||||
/// \param retry The retry times, 0 to wait forever until complete.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char EMAC_WritePhy(unsigned char PhyAddress,
|
||||
unsigned char Address,
|
||||
unsigned int Value,
|
||||
unsigned int retry)
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30))
|
||||
| (AT91C_EMAC_CODE & (2 << 16))
|
||||
| (AT91C_EMAC_RW & (1 << 28))
|
||||
| (AT91C_EMAC_PHYA & ((PhyAddress & 0x1f) << 23))
|
||||
| (AT91C_EMAC_REGA & (Address << 18))
|
||||
| (AT91C_EMAC_DATA & Value) ;
|
||||
if ( EMAC_WaitPhy(retry) == 0 ) {
|
||||
|
||||
trace_LOG(trace_ERROR, "TimeOut EMAC_WritePhy\n\r");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Setup the EMAC for the link : speed 100M/10M and Full/Half duplex
|
||||
/// \param speed Link speed, 0 for 10M, 1 for 100M
|
||||
/// \param fullduplex 1 for Full Duplex mode
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_SetLinkSpeed(unsigned char speed, unsigned char fullduplex)
|
||||
{
|
||||
unsigned int ncfgr;
|
||||
|
||||
ncfgr = AT91C_BASE_EMAC->EMAC_NCFGR;
|
||||
ncfgr &= ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
|
||||
if (speed) {
|
||||
|
||||
ncfgr |= AT91C_EMAC_SPD;
|
||||
}
|
||||
if (fullduplex) {
|
||||
|
||||
ncfgr |= AT91C_EMAC_FD;
|
||||
}
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR = ncfgr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// EMAC functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// EMAC Interrupt handler
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_Handler(void)
|
||||
{
|
||||
volatile EmacTxTDescriptor *pTxTd;
|
||||
volatile EMAC_TxCallback *pTxCb;
|
||||
unsigned int isr;
|
||||
unsigned int rsr;
|
||||
unsigned int tsr;
|
||||
unsigned int rxStatusFlag;
|
||||
unsigned int txStatusFlag;
|
||||
|
||||
//trace_LOG(trace_DEBUG, "EMAC_Handler\n\r");
|
||||
isr = AT91C_BASE_EMAC->EMAC_ISR & AT91C_BASE_EMAC->EMAC_IMR;
|
||||
rsr = AT91C_BASE_EMAC->EMAC_RSR;
|
||||
tsr = AT91C_BASE_EMAC->EMAC_TSR;
|
||||
|
||||
// RX packet
|
||||
if ((isr & AT91C_EMAC_RCOMP) || (rsr & AT91C_EMAC_REC)) {
|
||||
rxStatusFlag = AT91C_EMAC_REC;
|
||||
|
||||
// Frame received
|
||||
EmacStatistics.rx_packets++;
|
||||
|
||||
// Check OVR
|
||||
if (rsr & AT91C_EMAC_OVR) {
|
||||
rxStatusFlag |= AT91C_EMAC_OVR;
|
||||
EmacStatistics.rx_ovrs++;
|
||||
}
|
||||
// Check BNA
|
||||
if (rsr & AT91C_EMAC_BNA) {
|
||||
rxStatusFlag |= AT91C_EMAC_BNA;
|
||||
EmacStatistics.rx_bnas++;
|
||||
}
|
||||
// Clear status
|
||||
AT91C_BASE_EMAC->EMAC_RSR |= rxStatusFlag;
|
||||
|
||||
// Invoke callbacks
|
||||
if (rxTd.rxCb) {
|
||||
rxTd.rxCb(rxStatusFlag);
|
||||
}
|
||||
}
|
||||
|
||||
// TX packet
|
||||
if ((isr & AT91C_EMAC_TCOMP) || (tsr & AT91C_EMAC_COMP)) {
|
||||
|
||||
txStatusFlag = AT91C_EMAC_COMP;
|
||||
EmacStatistics.tx_comp ++;
|
||||
|
||||
// A frame transmitted
|
||||
// Check RLE
|
||||
if (tsr & AT91C_EMAC_RLES) {
|
||||
txStatusFlag |= AT91C_EMAC_RLES;
|
||||
EmacStatistics.tx_errors++;
|
||||
}
|
||||
// Check COL
|
||||
if (tsr & AT91C_EMAC_COL) {
|
||||
txStatusFlag |= AT91C_EMAC_COL;
|
||||
EmacStatistics.collisions++;
|
||||
}
|
||||
// Check BEX
|
||||
if (tsr & AT91C_EMAC_BEX) {
|
||||
txStatusFlag |= AT91C_EMAC_BEX;
|
||||
EmacStatistics.tx_exausts++;
|
||||
}
|
||||
// Check UND
|
||||
if (tsr & AT91C_EMAC_UND) {
|
||||
txStatusFlag |= AT91C_EMAC_UND;
|
||||
EmacStatistics.tx_underruns++;
|
||||
}
|
||||
// Clear status
|
||||
AT91C_BASE_EMAC->EMAC_TSR |= txStatusFlag;
|
||||
|
||||
// Sanity check: Tx buffers have to be scheduled
|
||||
ASSERT(!CIRC_EMPTY(&txTd),
|
||||
"-F- EMAC Tx interrupt received meanwhile no TX buffers has been scheduled\n\r");
|
||||
|
||||
// Check the buffers
|
||||
while (CIRC_CNT(txTd.head, txTd.tail, TX_BUFFERS)) {
|
||||
pTxTd = txTd.td + txTd.tail;
|
||||
pTxCb = txTd.txCb + txTd.tail;
|
||||
|
||||
// Exit if buffer has not been sent yet
|
||||
if ((pTxTd->status & EMAC_TX_USED_BIT) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Notify upper layer that packet has been sent
|
||||
if (*pTxCb) {
|
||||
(*pTxCb)(txStatusFlag);
|
||||
}
|
||||
|
||||
CIRC_INC( txTd.tail, TX_BUFFERS );
|
||||
}
|
||||
|
||||
// If a wakeup has been scheduled, notify upper layer that it can send
|
||||
// other packets, send will be successfull.
|
||||
if( (CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) >= txTd.wakeupThreshold)
|
||||
&& txTd.wakeupCb) {
|
||||
txTd.wakeupCb();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Initialize the EMAC with the emac controller address
|
||||
/// \param id HW ID for power management
|
||||
/// \param pTxWakeUpfct Thresold TX Wakeup Callback
|
||||
/// \param pRxfct RX Wakeup Callback
|
||||
/// \param pMacAddress Mac Address
|
||||
/// \param enableCAF enable AT91C_EMAC_CAF if needed by application
|
||||
/// \param enableNBC AT91C_EMAC_NBC if needed by application
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_Init( unsigned char id, const unsigned char *pMacAddress,
|
||||
unsigned char enableCAF, unsigned char enableNBC )
|
||||
{
|
||||
int Index;
|
||||
unsigned int Address;
|
||||
|
||||
// Check parameters
|
||||
ASSERT(RX_BUFFERS * EMAC_RX_UNITSIZE > EMAC_FRAME_LENTGH_MAX,
|
||||
"E: RX buffers too small\n\r");
|
||||
|
||||
trace_LOG(trace_DEBUG, "EMAC_Init\n\r");
|
||||
|
||||
// Power ON
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << id;
|
||||
|
||||
// Disable TX & RX and more
|
||||
AT91C_BASE_EMAC->EMAC_NCR = 0;
|
||||
|
||||
// disable
|
||||
AT91C_BASE_EMAC->EMAC_IDR = ~0;
|
||||
|
||||
rxTd.idx = 0;
|
||||
CIRC_CLEAR(&txTd);
|
||||
|
||||
// Setup the RX descriptors.
|
||||
for(Index = 0; Index < RX_BUFFERS; Index++) {
|
||||
|
||||
Address = (unsigned int)(&(pRxBuffer[Index * EMAC_RX_UNITSIZE]));
|
||||
// Remove EMAC_RX_OWNERSHIP_BIT and EMAC_RX_WRAP_BIT
|
||||
rxTd.td[Index].addr = Address & EMAC_ADDRESS_MASK;
|
||||
rxTd.td[Index].status = 0;
|
||||
}
|
||||
rxTd.td[RX_BUFFERS - 1].addr |= EMAC_RX_WRAP_BIT;
|
||||
|
||||
// Setup the TX descriptors.
|
||||
for(Index = 0; Index < TX_BUFFERS; Index++) {
|
||||
|
||||
Address = (unsigned int)(&(pTxBuffer[Index * EMAC_TX_UNITSIZE]));
|
||||
txTd.td[Index].addr = Address;
|
||||
txTd.td[Index].status = EMAC_TX_USED_BIT;
|
||||
}
|
||||
txTd.td[TX_BUFFERS - 1].status = EMAC_TX_USED_BIT | EMAC_TX_WRAP_BIT;
|
||||
|
||||
// Set the MAC address
|
||||
if( pMacAddress != (unsigned char *)0 ) {
|
||||
AT91C_BASE_EMAC->EMAC_SA1L = ( ((unsigned int)pMacAddress[3] << 24)
|
||||
| ((unsigned int)pMacAddress[2] << 16)
|
||||
| ((unsigned int)pMacAddress[1] << 8 )
|
||||
| pMacAddress[0] );
|
||||
|
||||
AT91C_BASE_EMAC->EMAC_SA1H = ( ((unsigned int)pMacAddress[5] << 8 )
|
||||
| pMacAddress[4] );
|
||||
}
|
||||
// Now setup the descriptors
|
||||
// Receive Buffer Queue Pointer Register
|
||||
AT91C_BASE_EMAC->EMAC_RBQP = (unsigned int) (rxTd.td);
|
||||
// Transmit Buffer Queue Pointer Register
|
||||
AT91C_BASE_EMAC->EMAC_TBQP = (unsigned int) (txTd.td);
|
||||
|
||||
AT91C_BASE_EMAC->EMAC_NCR = AT91C_EMAC_CLRSTAT;
|
||||
|
||||
// Clear all status bits in the receive status register.
|
||||
AT91C_BASE_EMAC->EMAC_RSR = (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
|
||||
|
||||
// Clear all status bits in the transmit status register
|
||||
AT91C_BASE_EMAC->EMAC_TSR = ( AT91C_EMAC_UBR | AT91C_EMAC_COL | AT91C_EMAC_RLES
|
||||
| AT91C_EMAC_BEX | AT91C_EMAC_COMP
|
||||
| AT91C_EMAC_UND );
|
||||
|
||||
// Clear interrupts
|
||||
AT91C_BASE_EMAC->EMAC_ISR;
|
||||
|
||||
// Enable the copy of data into the buffers
|
||||
// ignore broadcasts, and don't copy FCS.
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR |= (AT91C_EMAC_DRFCS | AT91C_EMAC_PAE);
|
||||
|
||||
if( enableCAF == EMAC_CAF_ENABLE ) {
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_CAF;
|
||||
}
|
||||
if( enableNBC == EMAC_NBC_ENABLE ) {
|
||||
AT91C_BASE_EMAC->EMAC_NCFGR |= AT91C_EMAC_NBC;
|
||||
}
|
||||
|
||||
// Enable Rx and Tx, plus the stats register.
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT);
|
||||
|
||||
// Setup the interrupts for TX (and errors)
|
||||
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RXUBR
|
||||
| AT91C_EMAC_TUNDR
|
||||
| AT91C_EMAC_RLEX
|
||||
| AT91C_EMAC_TXERR
|
||||
| AT91C_EMAC_TCOMP
|
||||
| AT91C_EMAC_ROVR
|
||||
| AT91C_EMAC_HRESP;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Get the statstic information & reset it
|
||||
/// \param pStats Pointer to EmacStats structure to copy the informations
|
||||
/// \param reset Reset the statistics after copy it
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset)
|
||||
{
|
||||
unsigned int ncrBackup = 0;
|
||||
|
||||
trace_LOG(trace_DEBUG, "EMAC_GetStatistics\n\r");
|
||||
|
||||
// Sanity check
|
||||
if (pStats == (EmacStats *) 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ncrBackup = AT91C_BASE_EMAC->EMAC_NCR & (AT91C_EMAC_TE | AT91C_EMAC_RE);
|
||||
|
||||
// Disable TX/RX
|
||||
AT91C_BASE_EMAC->EMAC_NCR = ncrBackup & ~(AT91C_EMAC_TE | AT91C_EMAC_RE);
|
||||
|
||||
// Copy the informations
|
||||
memcpy(pStats, (void*)&EmacStatistics, sizeof(EmacStats));
|
||||
|
||||
// Reset the statistics
|
||||
if (reset) {
|
||||
memset((void*)&EmacStatistics, 0x00, sizeof(EmacStats));
|
||||
AT91C_BASE_EMAC->EMAC_NCR = ncrBackup | AT91C_EMAC_CLRSTAT;
|
||||
}
|
||||
|
||||
// restore NCR
|
||||
AT91C_BASE_EMAC->EMAC_NCR = ncrBackup;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Send a packet with EMAC.
|
||||
/// If the packet size is larger than transfer buffer size error returned.
|
||||
/// \param buffer The buffer to be send
|
||||
/// \param size The size of buffer to be send
|
||||
/// \param fEMAC_TxCallback Threshold Wakeup callback
|
||||
/// \param fWakeUpCb TX Wakeup
|
||||
/// \return OK, Busy or invalid packet
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char EMAC_Send(void *pBuffer,
|
||||
unsigned int size,
|
||||
EMAC_TxCallback fEMAC_TxCallback)
|
||||
{
|
||||
volatile EmacTxTDescriptor *pTxTd;
|
||||
volatile EMAC_TxCallback *pTxCb;
|
||||
|
||||
//trace_LOG(trace_DEBUG, "EMAC_Send\n\r");
|
||||
|
||||
// Check parameter
|
||||
if (size > EMAC_TX_UNITSIZE) {
|
||||
|
||||
trace_LOG(trace_ERROR, "-E- EMAC driver does not split send packets.");
|
||||
trace_LOG(trace_ERROR, " It can send %d bytes max in one packet (%u bytes requested)\n\r",
|
||||
EMAC_TX_UNITSIZE, size);
|
||||
return EMAC_TX_INVALID_PACKET;
|
||||
}
|
||||
|
||||
// If no free TxTd, buffer can't be sent, schedule the wakeup callback
|
||||
if( CIRC_SPACE(txTd.head, txTd.tail, TX_BUFFERS) == 0) {
|
||||
return EMAC_TX_BUFFER_BUSY;
|
||||
|
||||
}
|
||||
|
||||
// Pointers to the current TxTd
|
||||
pTxTd = txTd.td + txTd.head;
|
||||
pTxCb = txTd.txCb + txTd.head;
|
||||
|
||||
// Sanity check
|
||||
ASSERT((pTxTd->status & EMAC_TX_USED_BIT) != 0,
|
||||
"-F- Buffer is still under EMAC control\n\r");
|
||||
|
||||
// Setup/Copy data to transmition buffer
|
||||
if (pBuffer && size) {
|
||||
// Driver manage the ring buffer
|
||||
memcpy((void *)pTxTd->addr, pBuffer, size);
|
||||
}
|
||||
|
||||
// Tx Callback
|
||||
*pTxCb = fEMAC_TxCallback;
|
||||
|
||||
// Update TD status
|
||||
// The buffer size defined is length of ethernet frame
|
||||
// so it's always the last buffer of the frame.
|
||||
if (txTd.head == TX_BUFFERS-1) {
|
||||
pTxTd->status =
|
||||
(size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT | EMAC_TX_WRAP_BIT;
|
||||
}
|
||||
else {
|
||||
pTxTd->status = (size & EMAC_LENGTH_FRAME) | EMAC_TX_LAST_BUFFER_BIT;
|
||||
}
|
||||
|
||||
CIRC_INC(txTd.head, TX_BUFFERS)
|
||||
|
||||
// Tx packets count
|
||||
EmacStatistics.tx_packets++;
|
||||
|
||||
// Now start to transmit if it is not already done
|
||||
AT91C_BASE_EMAC->EMAC_NCR |= AT91C_EMAC_TSTART;
|
||||
|
||||
return EMAC_TX_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Receive a packet with EMAC
|
||||
/// If not enough buffer for the packet, the remaining data is lost but right
|
||||
/// frame length is returned.
|
||||
/// \param pFrame Buffer to store the frame
|
||||
/// \param frameSize Size of the frame
|
||||
/// \param pRcvSize Received size
|
||||
/// \return OK, no data, or frame too small
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char EMAC_Poll(unsigned char *pFrame,
|
||||
unsigned int frameSize,
|
||||
unsigned int *pRcvSize)
|
||||
{
|
||||
unsigned short bufferLength;
|
||||
unsigned int tmpFrameSize=0;
|
||||
unsigned char *pTmpFrame=0;
|
||||
unsigned int tmpIdx = rxTd.idx;
|
||||
volatile EmacRxTDescriptor *pRxTd = rxTd.td + rxTd.idx;
|
||||
|
||||
ASSERT(pFrame, "F: EMAC_Poll\n\r");
|
||||
|
||||
char isFrame = 0;
|
||||
// Set the default return value
|
||||
*pRcvSize = 0;
|
||||
|
||||
// Process received RxTd
|
||||
while ((pRxTd->addr & EMAC_RX_OWNERSHIP_BIT) == EMAC_RX_OWNERSHIP_BIT) {
|
||||
|
||||
// A start of frame has been received, discard previous fragments
|
||||
if ((pRxTd->status & EMAC_RX_SOF_BIT) == EMAC_RX_SOF_BIT) {
|
||||
// Skip previous fragment
|
||||
while (tmpIdx != rxTd.idx) {
|
||||
pRxTd = rxTd.td + rxTd.idx;
|
||||
pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
|
||||
CIRC_INC(rxTd.idx, RX_BUFFERS);
|
||||
}
|
||||
// Reset the temporary frame pointer
|
||||
pTmpFrame = pFrame;
|
||||
tmpFrameSize = 0;
|
||||
// Start to gather buffers in a frame
|
||||
isFrame = 1;
|
||||
}
|
||||
|
||||
// Increment the pointer
|
||||
CIRC_INC(tmpIdx, RX_BUFFERS);
|
||||
|
||||
// Copy data in the frame buffer
|
||||
if (isFrame) {
|
||||
if (tmpIdx == rxTd.idx) {
|
||||
trace_LOG(trace_INFO,
|
||||
"I: no EOF (Invalid of buffers too small)\n\r");
|
||||
|
||||
do {
|
||||
|
||||
pRxTd = rxTd.td + rxTd.idx;
|
||||
pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
|
||||
CIRC_INC(rxTd.idx, RX_BUFFERS);
|
||||
} while(tmpIdx != rxTd.idx);
|
||||
return EMAC_RX_NO_DATA;
|
||||
}
|
||||
// Copy the buffer into the application frame
|
||||
bufferLength = EMAC_RX_UNITSIZE;
|
||||
if ((tmpFrameSize + bufferLength) > frameSize) {
|
||||
bufferLength = frameSize - tmpFrameSize;
|
||||
}
|
||||
|
||||
memcpy(pTmpFrame, (void*)(pRxTd->addr & EMAC_ADDRESS_MASK), bufferLength);
|
||||
pTmpFrame += bufferLength;
|
||||
tmpFrameSize += bufferLength;
|
||||
|
||||
// An end of frame has been received, return the data
|
||||
if ((pRxTd->status & EMAC_RX_EOF_BIT) == EMAC_RX_EOF_BIT) {
|
||||
// Frame size from the EMAC
|
||||
*pRcvSize = (pRxTd->status & EMAC_LENGTH_FRAME);
|
||||
|
||||
// Application frame buffer is too small all data have not been copied
|
||||
if (tmpFrameSize < *pRcvSize) {
|
||||
printf("size req %u size allocated %u\n\r", *pRcvSize, frameSize);
|
||||
|
||||
return EMAC_RX_FRAME_SIZE_TOO_SMALL;
|
||||
}
|
||||
|
||||
trace_LOG(trace_INFO, "packet %d-%u (%u)\n\r", rxTd.idx, tmpIdx, *pRcvSize);
|
||||
// All data have been copied in the application frame buffer => release TD
|
||||
while (rxTd.idx != tmpIdx) {
|
||||
pRxTd = rxTd.td + rxTd.idx;
|
||||
pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
|
||||
CIRC_INC(rxTd.idx, RX_BUFFERS);
|
||||
}
|
||||
EmacStatistics.rx_packets++;
|
||||
return EMAC_RX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// SOF has not been detected, skip the fragment
|
||||
else {
|
||||
pRxTd->addr &= ~(EMAC_RX_OWNERSHIP_BIT);
|
||||
rxTd.idx = tmpIdx;
|
||||
}
|
||||
|
||||
// Process the next buffer
|
||||
pRxTd = rxTd.td + tmpIdx;
|
||||
}
|
||||
|
||||
//trace_LOG(trace_DEBUG, "E");
|
||||
return EMAC_RX_NO_DATA;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Registers pRxCb callback. Callback will be invoked after the next received
|
||||
/// frame.
|
||||
/// When EMAC_Poll() returns EMAC_RX_NO_DATA the application task call EMAC_Set_RxCb()
|
||||
/// to register pRxCb() callback and enters suspend state. The callback is in charge
|
||||
/// to resume the task once a new frame has been received. The next time EMAC_Poll()
|
||||
/// is called, it will be successfull.
|
||||
/// \param pRxCb Pointer to callback function
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_Set_RxCb(EMAC_RxCallback pRxCb)
|
||||
{
|
||||
rxTd.rxCb = pRxCb;
|
||||
AT91C_BASE_EMAC->EMAC_IER = AT91C_EMAC_RCOMP;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Remove the RX callback function.
|
||||
/// This function is usually invoked from the RX callback itself. Once the callback
|
||||
/// has resumed the application task, there is no need to invoke the callback again.
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_Clear_RxCb(void)
|
||||
{
|
||||
AT91C_BASE_EMAC->EMAC_IDR = AT91C_EMAC_RCOMP;
|
||||
rxTd.rxCb = (EMAC_RxCallback) 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Registers TX wakeup callback callback. Callback will be invoked once several
|
||||
/// transfer descriptors are available.
|
||||
/// When EMAC_Send() returns EMAC_TX_BUFFER_BUSY (all TD busy) the application
|
||||
/// task calls EMAC_Set_TxWakeUpCb() to register pTxWakeUpCb() callback and
|
||||
/// enters suspend state. The callback is in charge to resume the task once
|
||||
/// several TD have been released. The next time EMAC_Send() will be called, it
|
||||
/// shall be successfull.
|
||||
/// \param pTxWakeUpCb Pointer to callback function
|
||||
/// \param threshold Minimum number of available transfer descriptors before pTxWakeUpCb() is invoked
|
||||
/// \return 0= success, 1 = threshold exceeds nuber of transfer descriptors
|
||||
//-----------------------------------------------------------------------------
|
||||
char EMAC_Set_TxWakeUpCb(EMAC_WakeupCallback pTxWakeUpCb, unsigned short threshold)
|
||||
{
|
||||
if (threshold <= TX_BUFFERS) {
|
||||
txTd.wakeupCb = pTxWakeUpCb;
|
||||
txTd.wakeupThreshold = threshold;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Remove the TX wakeup callback function.
|
||||
/// This function is usually invoked from the TX wakeup callback itself. Once the callback
|
||||
/// has resumed the application task, there is no need to invoke the callback again.
|
||||
//-----------------------------------------------------------------------------
|
||||
void EMAC_Clear_TxWakeUpCb(void)
|
||||
{
|
||||
txTd.wakeupCb = (EMAC_WakeupCallback) 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// peripherals/emac/emac.h
|
||||
|
||||
#ifndef EMAC_H
|
||||
#define EMAC_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition of methods and structures for using EMAC
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Initialize EMAC with EMAC_Init.
|
||||
/// -# Setup EMAC with EMAC_SetupTx, EMAC_SetupRx, EMAC_SetupMacAddress
|
||||
/// and EMAC_SetupStack.
|
||||
/// -# Drive the EMAC status machine by EMAC_Task.
|
||||
/// -# EMAC_GetStatus give EMAC status machine current status
|
||||
/// -# Send a packet to network with EMAC_SendPacket.
|
||||
/// -# Get a packet from network with EMAC_GetPacket.
|
||||
///
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Headers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Number of buffer for RX, be carreful: MUST be 2^n
|
||||
#define RX_BUFFERS 16
|
||||
/// Number of buffer for TX, be carreful: MUST be 2^n
|
||||
#define TX_BUFFERS 8
|
||||
|
||||
/// Buffer Size
|
||||
#define EMAC_RX_UNITSIZE 128 /// Fixed size for RX buffer
|
||||
#define EMAC_TX_UNITSIZE 1518 /// Size for ETH frame length
|
||||
|
||||
// The MAC can support frame lengths up to 1536 bytes.
|
||||
#define EMAC_FRAME_LENTGH_MAX 1536
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Describes the statistics of the EMAC.
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef struct _EmacStats {
|
||||
|
||||
// TX errors
|
||||
unsigned int tx_packets; /// Total Number of packets sent
|
||||
unsigned int tx_comp; /// Packet complete
|
||||
unsigned int tx_errors; /// TX errors ( Retry Limit Exceed )
|
||||
unsigned int collisions; /// Collision
|
||||
unsigned int tx_exausts; /// Buffer exhausted
|
||||
unsigned int tx_underruns; /// Under Run, not able to read from memory
|
||||
// RX errors
|
||||
unsigned int rx_packets; /// Total Number of packets RX
|
||||
unsigned int rx_eof; /// No EOF error
|
||||
unsigned int rx_ovrs; /// Over Run, not able to store to memory
|
||||
unsigned int rx_bnas; /// Buffer is not available
|
||||
|
||||
} EmacStats, *PEmacStats;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PHY Exported functions
|
||||
//-----------------------------------------------------------------------------
|
||||
extern unsigned char EMAC_SetMdcClock( unsigned int mck );
|
||||
|
||||
extern void EMAC_EnableMdio( void );
|
||||
|
||||
extern void EMAC_DisableMdio( void );
|
||||
|
||||
extern void EMAC_EnableMII( void );
|
||||
|
||||
extern void EMAC_EnableRMII( void );
|
||||
|
||||
extern unsigned char EMAC_ReadPhy(unsigned char PhyAddress,
|
||||
unsigned char Address,
|
||||
unsigned int *pValue,
|
||||
unsigned int retry);
|
||||
|
||||
extern unsigned char EMAC_WritePhy(unsigned char PhyAddress,
|
||||
unsigned char Address,
|
||||
unsigned int Value,
|
||||
unsigned int retry);
|
||||
|
||||
extern void EMAC_SetLinkSpeed(unsigned char speed,
|
||||
unsigned char fullduplex);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// EMAC Exported functions
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Callback used by send function
|
||||
typedef void (*EMAC_TxCallback)(unsigned int status);
|
||||
typedef void (*EMAC_RxCallback)(unsigned int status);
|
||||
typedef void (*EMAC_WakeupCallback)(void);
|
||||
|
||||
extern void EMAC_Init( unsigned char id, const unsigned char *pMacAddress,
|
||||
unsigned char enableCAF, unsigned char enableNBC );
|
||||
#define EMAC_CAF_DISABLE 0
|
||||
#define EMAC_CAF_ENABLE 1
|
||||
#define EMAC_NBC_DISABLE 0
|
||||
#define EMAC_NBC_ENABLE 1
|
||||
|
||||
extern void EMAC_Handler(void);
|
||||
|
||||
extern unsigned char EMAC_Send(void *pBuffer,
|
||||
unsigned int size,
|
||||
EMAC_TxCallback fEMAC_TxCallback);
|
||||
/// Return for EMAC_Send function
|
||||
#define EMAC_TX_OK 0
|
||||
#define EMAC_TX_BUFFER_BUSY 1
|
||||
#define EMAC_TX_INVALID_PACKET 2
|
||||
|
||||
|
||||
extern unsigned char EMAC_Poll(unsigned char *pFrame,
|
||||
unsigned int frameSize,
|
||||
unsigned int *pRcvSize);
|
||||
/// Return for EMAC_Poll function
|
||||
#define EMAC_RX_OK 0
|
||||
#define EMAC_RX_NO_DATA 1
|
||||
#define EMAC_RX_FRAME_SIZE_TOO_SMALL 2
|
||||
|
||||
extern void EMAC_GetStatistics(EmacStats *pStats, unsigned char reset);
|
||||
|
||||
#endif // #ifndef EMAC_H
|
||||
|
||||
362
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/lcd/lcd.c
Normal file
362
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/lcd/lcd.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "lcd.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the LCD controller, after waiting for the specified number of
|
||||
/// frames.
|
||||
/// \param frames Number of frames before the LCD is enabled.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_Enable(unsigned int frames)
|
||||
{
|
||||
ASSERT((frames & 0xFFFFFF80) == 0,
|
||||
"LCD_Enable: Wrong frames value.\n\r");
|
||||
AT91C_BASE_LCDC->LCDC_PWRCON = AT91C_LCDC_PWR | (frames << 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the LCD controller, after waiting for the specified number of
|
||||
/// frames.
|
||||
/// \param frames Number of frames before the LCD is shut down.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_Disable(unsigned int frames)
|
||||
{
|
||||
ASSERT((frames & 0xFFFFFF80) == 0,
|
||||
"LCD_Disable: Wrong frames value.\n\r");
|
||||
AT91C_BASE_LCDC->LCDC_PWRCON = frames << 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the DMA of the LCD controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_EnableDma()
|
||||
{
|
||||
AT91C_BASE_LCDC->LCDC_DMACON = AT91C_LCDC_DMAEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the DMA of the LCD controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_DisableDma()
|
||||
{
|
||||
AT91C_BASE_LCDC->LCDC_DMACON = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the internal clock of the LCD controller given the master clock of
|
||||
/// the system and the desired pixel clock in MHz.
|
||||
/// \param masterClock Master clock frequency.
|
||||
/// \param pixelClock Pixel clock frequency.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetPixelClock(unsigned int masterClock, unsigned int pixelClock)
|
||||
{
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON1 = ((masterClock / (2 * pixelClock)) - 1) << 12;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the type of display used with the LCD controller.
|
||||
/// \param displayType Type of display used.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetDisplayType(unsigned int displayType)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((displayType & ~AT91C_LCDC_DISTYPE) == 0,
|
||||
"LCD_SetDisplayType: Wrong display type value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= ~AT91C_LCDC_DISTYPE;
|
||||
value |= displayType;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the scan mode used by the LCD (either single scan or double-scan).
|
||||
/// \param scanMode Scan mode to use.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetScanMode(unsigned int scanMode)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((scanMode & ~AT91C_LCDC_SCANMOD) == 0,
|
||||
"LCD_SetScanMode: Wrong scan mode value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= ~AT91C_LCDC_SCANMOD;
|
||||
value |= scanMode;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the number of bits per pixel used by the LCD display.
|
||||
/// \param bitsPerPixel Number of bits per pixel to use.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetBitsPerPixel(unsigned int bitsPerPixel)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((bitsPerPixel & ~AT91C_LCDC_PIXELSIZE) == 0,
|
||||
"LCD_SetScanMode: Wrong bitsPerPixel value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= ~AT91C_LCDC_PIXELSIZE;
|
||||
value |= bitsPerPixel;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the LCDD, LCDVSYNC, LCDHSYNC, LCDDOTCLK and LCDDEN signal polarities.
|
||||
/// \param lcdd LCDD signal polarity.
|
||||
/// \param lcdvsync LCDVSYNC signal polarity.
|
||||
/// \param lcdhsync LCDHSYNC signal polarity.
|
||||
/// \param lcddotclk LCDDOTCLK signal polarity.
|
||||
/// \param lcdden LCDDEN signal polarity.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetPolarities(
|
||||
unsigned int lcdd,
|
||||
unsigned int lcdvsync,
|
||||
unsigned int lcdhsync,
|
||||
unsigned int lcddotclk,
|
||||
unsigned int lcdden)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((lcdd & ~AT91C_LCDC_INVVD) == 0,
|
||||
"LCD_SetPolarities: Wrong lcdd value.\n\r");
|
||||
ASSERT((lcdvsync & ~AT91C_LCDC_INVFRAME) == 0,
|
||||
"LCD_SetPolarities: Wrong lcdvsync value.\n\r");
|
||||
ASSERT((lcdhsync & ~AT91C_LCDC_INVLINE) == 0,
|
||||
"LCD_SetPolarities: Wrong lcdhsync value.\n\r");
|
||||
ASSERT((lcddotclk & ~AT91C_LCDC_INVCLK) == 0,
|
||||
"LCD_SetPolarities: Wrong lcddotclk value.\n\r");
|
||||
ASSERT((lcdden & ~AT91C_LCDC_INVDVAL) == 0,
|
||||
"LCD_SetPolarities: Wrong lcdden value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= 0xFFFFE0FF;
|
||||
value |= lcdd | lcdvsync | lcdhsync | lcddotclk | lcdden;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the LCD clock mode, i.e. always active or active only during display
|
||||
/// period.
|
||||
/// \param clockMode Clock mode to use.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetClockMode(unsigned int clockMode)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((clockMode & ~AT91C_LCDC_CLKMOD) == 0,
|
||||
"LCD_SetScanMode: Wrong scan mode value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= ~AT91C_LCDC_CLKMOD;
|
||||
value |= clockMode;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the format of the frame buffer memory.
|
||||
/// \param format Memory ordering format.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetMemoryFormat(unsigned int format)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
ASSERT((format & ~AT91C_LCDC_MEMOR) == 0,
|
||||
"LCD_SetMemoryFormat: Wrong memory format value.\n\r");
|
||||
|
||||
value = AT91C_BASE_LCDC->LCDC_LCDCON2;
|
||||
value &= ~AT91C_LCDC_MEMOR;
|
||||
value |= format;
|
||||
AT91C_BASE_LCDC->LCDC_LCDCON2 = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the size in pixel of the LCD display.
|
||||
/// \param width Width in pixel of the LCD display.
|
||||
/// \param height Height in pixel of the LCD display.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetSize(unsigned int width, unsigned int height)
|
||||
{
|
||||
ASSERT(((width - 1) & 0xFFFFF800) == 0,
|
||||
"LCD_SetSize: Wrong width value.\n\r");
|
||||
ASSERT(((height - 1) & 0xFFFFF800) == 0,
|
||||
"LCD_SetSize: Wrong height value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_LCDFRCFG = ((width - 1) << 21) | (height - 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the vertical timings of the LCD controller. Only meaningful when
|
||||
/// using a TFT display.
|
||||
/// \param vfp Number of idle lines at the end of a frame.
|
||||
/// \param vbp Number of idle lines at the beginning of a frame.
|
||||
/// \param vpw Vertical synchronization pulse width in number of lines.
|
||||
/// \param vhdly Delay between LCDVSYNC edge and LCDHSYNC rising edge, in
|
||||
/// LCDDOTCLK cycles.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetVerticalTimings(
|
||||
unsigned int vfp,
|
||||
unsigned int vbp,
|
||||
unsigned int vpw,
|
||||
unsigned int vhdly)
|
||||
{
|
||||
ASSERT((vfp & 0xFFFFFF00) == 0,
|
||||
"LCD_SetVerticalTimings: Wrong vfp value.\n\r");
|
||||
ASSERT((vbp & 0xFFFFFF00) == 0,
|
||||
"LCD_SetVerticalTimings: Wrong vbp value.\n\r");
|
||||
ASSERT(((vpw-1) & 0xFFFFFFC0) == 0,
|
||||
"LCD_SetVerticalTimings: Wrong vpw value.\n\r");
|
||||
ASSERT(((vhdly-1) & 0xFFFFFFF0) == 0,
|
||||
"LCD_SetVerticalTimings: Wrong vhdly value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_TIM1 = vfp
|
||||
| (vbp << 8)
|
||||
| ((vpw-1) << 16)
|
||||
| ((vhdly-1) << 24);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the horizontal timings of the LCD controller. Meaningful for both
|
||||
/// STN and TFT displays.
|
||||
/// \param hbp Number of idle LCDDOTCLK cycles at the beginning of a line.
|
||||
/// \param hpw Width of the LCDHSYNC pulse, in LCDDOTCLK cycles.
|
||||
/// \param hfp Number of idel LCDDOTCLK cycles at the end of a line.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetHorizontalTimings(
|
||||
unsigned int hbp,
|
||||
unsigned int hpw,
|
||||
unsigned int hfp)
|
||||
{
|
||||
ASSERT(((hbp-1) & 0xFFFFFF00) == 0,
|
||||
"LCD_SetHorizontalTimings: Wrong hbp value.\n\r");
|
||||
ASSERT(((hpw-1) & 0xFFFFFFC0) == 0,
|
||||
"LCD_SetHorizontalTimings: Wrong hpw value.\n\r");
|
||||
ASSERT(((hfp-1) & 0xFFFFFF00) == 0,
|
||||
"LCD_SetHorizontalTimings: Wrong hfp value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_TIM2 = (hbp-1) | ((hpw-1) << 8) | ((hfp-1) << 24);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the address of the frame buffer in the LCD controller DMA. When using
|
||||
/// dual-scan mode, this is the upper frame buffer.
|
||||
/// \param address Frame buffer address.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetFrameBufferAddress(void *address)
|
||||
{
|
||||
AT91C_BASE_LCDC->LCDC_BA1 = (unsigned int) address;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the size in pixels of a frame (height * width * bpp).
|
||||
/// \param frameSize Size of frame in pixels.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetFrameSize(unsigned int frameSize)
|
||||
{
|
||||
ASSERT((frameSize & 0xFF800000) == 0,
|
||||
"LCD_SetFrameSize: Wrong frameSize value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_FRMCFG = frameSize | (AT91C_BASE_LCDC->LCDC_FRMCFG & 0xFF000000);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the DMA controller burst length.
|
||||
/// \param burstLength Desired burst length.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetBurstLength(unsigned int burstLength)
|
||||
{
|
||||
ASSERT(((burstLength-1) & 0xFFFFFF80) == 0,
|
||||
"LCD_SetBurstLength: Wrong burstLength value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_FRMCFG &= 0x00FFFFFF;
|
||||
AT91C_BASE_LCDC->LCDC_FRMCFG |= ((burstLength-1) << 24);
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_FIFO = 2048 - (2 * burstLength + 3);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the prescaler value of the contrast control PWM.
|
||||
/// \param prescaler Desired prescaler value.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetContrastPrescaler(unsigned int prescaler)
|
||||
{
|
||||
ASSERT((prescaler & ~AT91C_LCDC_PS) == 0,
|
||||
"LCD_SetContrastPrescaler: Wrong prescaler value\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTCON &= ~AT91C_LCDC_PS;
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTCON |= prescaler;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the polarity of the contrast PWM.
|
||||
/// \param polarity PWM polarity
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetContrastPolarity(unsigned int polarity)
|
||||
{
|
||||
ASSERT((polarity & ~AT91C_LCDC_POL) == 0,
|
||||
"LCD_SetContrastPolarity: Wrong polarity value\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTCON &= ~AT91C_LCDC_POL;
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTCON |= polarity;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the threshold value of the constrast PWM.
|
||||
/// \param value PWM threshold value.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_SetContrastValue(unsigned int value)
|
||||
{
|
||||
ASSERT((value & ~AT91C_LCDC_CVAL) == 0,
|
||||
"LCD_SetContrastValue: Wrong value.\n\r");
|
||||
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTVAL = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the contrast PWM generator.
|
||||
//------------------------------------------------------------------------------
|
||||
void LCD_EnableContrast()
|
||||
{
|
||||
AT91C_BASE_LCDC->LCDC_CTRSTCON |= AT91C_LCDC_ENA_PWMGEMENABLED;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef LCD_H
|
||||
#define LCD_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void LCD_Enable(unsigned int frames);
|
||||
|
||||
extern void LCD_Disable(unsigned int frames);
|
||||
|
||||
extern void LCD_EnableDma();
|
||||
|
||||
extern void LCD_DisableDma();
|
||||
|
||||
extern void LCD_SetPixelClock(unsigned int masterClock, unsigned int pixelClock);
|
||||
|
||||
extern void LCD_SetDisplayType(unsigned int displayType);
|
||||
|
||||
extern void LCD_SetScanMode(unsigned int scanMode);
|
||||
|
||||
extern void LCD_SetBitsPerPixel(unsigned int bitsPerPixel);
|
||||
|
||||
extern void LCD_SetPolarities(
|
||||
unsigned int lcdd,
|
||||
unsigned int lcdvsync,
|
||||
unsigned int lcdhsync,
|
||||
unsigned int lcddotclk,
|
||||
unsigned int lcdden);
|
||||
|
||||
extern void LCD_SetClockMode(unsigned int clockMode);
|
||||
|
||||
extern void LCD_SetMemoryFormat(unsigned int format);
|
||||
|
||||
extern void LCD_SetSize(unsigned int width, unsigned int height);
|
||||
|
||||
extern void LCD_SetVerticalTimings(
|
||||
unsigned int vfp,
|
||||
unsigned int vbp,
|
||||
unsigned int vpw,
|
||||
unsigned int vhdly);
|
||||
|
||||
extern void LCD_SetHorizontalTimings(
|
||||
unsigned int hbp,
|
||||
unsigned int hpw,
|
||||
unsigned int hfp);
|
||||
|
||||
extern void LCD_SetFrameBufferAddress(void *address);
|
||||
|
||||
extern void LCD_SetFrameSize(unsigned int frameSize);
|
||||
|
||||
extern void LCD_SetBurstLength(unsigned int burstLength);
|
||||
|
||||
extern void LCD_SetContrastPrescaler(unsigned int prescaler);
|
||||
|
||||
extern void LCD_SetContrastPolarity(unsigned int polarity);
|
||||
|
||||
extern void LCD_SetContrastValue(unsigned int value);
|
||||
|
||||
extern void LCD_EnableContrast();
|
||||
|
||||
#endif //#ifndef LCD_H
|
||||
|
||||
551
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/mci/mci.c
Normal file
551
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/mci/mci.c
Normal file
|
|
@ -0,0 +1,551 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support - ROUSSET -
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2006, Atmel Corporation
|
||||
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the disclaimer below in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "mci.h"
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Bit mask for status register errors.
|
||||
#define STATUS_ERRORS (AT91C_MCI_UNRE \
|
||||
| AT91C_MCI_OVRE \
|
||||
| AT91C_MCI_DTOE \
|
||||
| AT91C_MCI_DCRCE \
|
||||
| AT91C_MCI_RTOE \
|
||||
| AT91C_MCI_RENDE \
|
||||
| AT91C_MCI_RCRCE \
|
||||
| AT91C_MCI_RDIRE \
|
||||
| AT91C_MCI_RINDE)
|
||||
|
||||
/// MCI data timeout configuration with 1048576 MCK cycles between 2 data transfers.
|
||||
#define DTOR_1MEGA_CYCLES (AT91C_MCI_DTOCYC | AT91C_MCI_DTOMUL)
|
||||
|
||||
#define SDCARD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO )
|
||||
#define MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_OPDCMD)
|
||||
|
||||
|
||||
#define DISABLE 0 // Disable MCI interface
|
||||
#define ENABLE 1 // Enable MCI interface
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local macros
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Used to write in PMC registers.
|
||||
#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
|
||||
|
||||
/// Used to write in MCI registers.
|
||||
#define WRITE_MCI(pMci, regName, value) pMci->regName = (value)
|
||||
|
||||
/// Used to read from MCI registers.
|
||||
#define READ_MCI(pMci, regName) (pMci->regName)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enable/disable a MCI driver instance.
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
/// \param enb 0 for disable MCI and 1 for enable MCI.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_Enable(Mci *pMci, unsigned char enb)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMci->pMciHw);
|
||||
|
||||
// Set the Control Register: Enable/Disable MCI interface clock
|
||||
if(enb == DISABLE) {
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);
|
||||
}
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes a MCI driver instance and the underlying peripheral.
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
/// \param pMciHw Pointer to a MCI peripheral.
|
||||
/// \param mciId MCI peripheral identifier.
|
||||
/// \param mode Slot and type of connected card.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_Init(
|
||||
Mci *pMci,
|
||||
AT91S_MCI *pMciHw,
|
||||
unsigned char mciId,
|
||||
unsigned int mode)
|
||||
{
|
||||
unsigned short clkDiv;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMciHw);
|
||||
SANITY_CHECK((mode == MCI_MMC_SLOTA) || (mode == MCI_MMC_SLOTB)
|
||||
|| (mode == MCI_SD_SLOTA) || (mode == MCI_SD_SLOTB));
|
||||
|
||||
// Initialize the MCI driver structure
|
||||
pMci->pMciHw = pMciHw;
|
||||
pMci->mciId = mciId;
|
||||
pMci->semaphore = 1;
|
||||
pMci->pCommand = 0;
|
||||
|
||||
// Enable the MCI clock
|
||||
WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << mciId));
|
||||
|
||||
// Reset the MCI
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
|
||||
|
||||
// Disable the MCI
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
|
||||
|
||||
// Disable all the interrupts
|
||||
WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
|
||||
|
||||
// Set the Data Timeout Register
|
||||
WRITE_MCI(pMciHw, MCI_DTOR, DTOR_1MEGA_CYCLES);
|
||||
|
||||
// Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)
|
||||
clkDiv = (BOARD_MCK / (400000 * 2)) - 1;
|
||||
WRITE_MCI(pMciHw, MCI_MR, (clkDiv | (AT91C_MCI_PWSDIV & (0x7 << 8))));
|
||||
|
||||
// Set the SDCard Register
|
||||
WRITE_MCI(pMciHw, MCI_SDCR, mode);
|
||||
|
||||
// Enable the MCI and the Power Saving
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);
|
||||
|
||||
// Disable the MCI peripheral clock.
|
||||
WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << mciId));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Close a MCI driver instance and the underlying peripheral.
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
/// \param pMciHw Pointer to a MCI peripheral.
|
||||
/// \param mciId MCI peripheral identifier.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_Close(Mci *pMci)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMciHw);
|
||||
|
||||
// Initialize the MCI driver structure
|
||||
pMci->semaphore = 1;
|
||||
pMci->pCommand = 0;
|
||||
|
||||
// Disable the MCI peripheral clock.
|
||||
WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pMci->mciId));
|
||||
|
||||
// Disable the MCI
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);
|
||||
|
||||
// Disable all the interrupts
|
||||
WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
|
||||
/// MCK/2 and corresponds to CLKDIV = 0
|
||||
/// \param pMci Pointer to the low level MCI driver.
|
||||
/// \param mciSpeed MCI clock speed in Hz.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_SetSpeed(Mci *pMci, unsigned int mciSpeed)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
unsigned int mciMr;
|
||||
unsigned short clkdiv;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMci->pMciHw);
|
||||
|
||||
// Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)
|
||||
mciMr = READ_MCI(pMciHw, MCI_MR) & (~AT91C_MCI_CLKDIV);
|
||||
|
||||
// Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)
|
||||
// divided by (2*(CLKDIV+1))
|
||||
if (mciSpeed > 0) {
|
||||
|
||||
clkdiv = (BOARD_MCK / (mciSpeed * 2));
|
||||
if (clkdiv > 0) {
|
||||
|
||||
clkdiv -= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
clkdiv = 0;
|
||||
}
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_MR, mciMr | clkdiv);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configure the MCI SDCBUS in the MCI_SDCR register. Only two modes available
|
||||
///
|
||||
/// \param pMci Pointer to the low level MCI driver.
|
||||
/// \param busWidth MCI bus width mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
unsigned int mciSdcr;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMci->pMciHw);
|
||||
|
||||
mciSdcr = (READ_MCI(pMciHw, MCI_SDCR) & ~(AT91C_MCI_SCDBUS));
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr | busWidth);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts a MCI transfer. This is a non blocking function. It will return
|
||||
/// as soon as the transfer is started.
|
||||
/// Return 0 if successful; otherwise returns MCI_ERROR_LOCK if the driver is
|
||||
/// already in use.
|
||||
/// \param pMci Pointer to an MCI driver instance.
|
||||
/// \param pCommand Pointer to the command to execute.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pCommand)
|
||||
{
|
||||
AT91PS_MCI pMciHw = pMci->pMciHw;
|
||||
unsigned int mciIer, mciMr;
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMciHw);
|
||||
SANITY_CHECK(pCommand);
|
||||
|
||||
// Try to acquire the MCI semaphore
|
||||
if (pMci->semaphore == 0) {
|
||||
|
||||
return MCI_ERROR_LOCK;
|
||||
}
|
||||
pMci->semaphore--;
|
||||
// trace_LOG(trace_DEBUG, "MCI_SendCommand %x %d\n\r", READ_MCI(pMciHw, MCI_SR), pCommand->cmd & 0x3f);
|
||||
|
||||
// Command is now being executed
|
||||
pMci->pCommand = pCommand;
|
||||
pCommand->status = MCI_STATUS_PENDING;
|
||||
|
||||
// Enable the MCI clock
|
||||
WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pMci->mciId));
|
||||
|
||||
//Disable MCI clock, for multi-block data transfer
|
||||
MCI_Enable(pMci, DISABLE);
|
||||
|
||||
// Set PDC data transfer direction
|
||||
if(pCommand->blockSize > 0) {
|
||||
if(pCommand->isRead) {
|
||||
WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
|
||||
}
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
|
||||
}
|
||||
}
|
||||
// Disable transmitter and receiver
|
||||
WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
|
||||
|
||||
mciMr = READ_MCI(pMciHw, MCI_MR) & (~(AT91C_MCI_BLKLEN | AT91C_MCI_PDCMODE));
|
||||
|
||||
// Command with DATA stage
|
||||
if (pCommand->blockSize > 0) {
|
||||
// Enable PDC mode and set block size
|
||||
if(pCommand->conTrans != MCI_CONTINUE_TRANSFER) {
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_PDCMODE | (pCommand->blockSize << 16));
|
||||
}
|
||||
|
||||
// DATA transfer from card to host
|
||||
if (pCommand->isRead) {
|
||||
WRITE_MCI(pMciHw, MCI_RPR, (int) pCommand->pData);
|
||||
|
||||
// If Multiblock command set the BLKR register
|
||||
/* if (pCommand->nbBlock > 1) {
|
||||
WRITE_MCI(pMciHw, MCI_BLKR, pCommand->nbBlock | (pCommand->blockSize << 16));
|
||||
}
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_BLKR, (pCommand->blockSize << 16));
|
||||
}*/
|
||||
|
||||
// Sanity check
|
||||
if (pCommand->nbBlock == 0)
|
||||
pCommand->nbBlock = 1;
|
||||
////////
|
||||
if ((pCommand->blockSize & 0x3) != 0) {
|
||||
WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);
|
||||
}
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
|
||||
}
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);
|
||||
mciIer = AT91C_MCI_ENDRX | STATUS_ERRORS;
|
||||
// mciIer = AT91C_MCI_RXBUFF | STATUS_ERRORS;
|
||||
}
|
||||
|
||||
// DATA transfer from host to card
|
||||
else {
|
||||
// Sanity check
|
||||
if (pCommand->nbBlock == 0)
|
||||
pCommand->nbBlock = 1;
|
||||
WRITE_MCI(pMciHw, MCI_TPR, (int) pCommand->pData);
|
||||
// Update the PDC counter
|
||||
if ((pCommand->blockSize & 0x3) != 0) {
|
||||
WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);
|
||||
}
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4);
|
||||
}
|
||||
// MCI_BLKE notifies the end of Multiblock command
|
||||
mciIer = AT91C_MCI_BLKE | STATUS_ERRORS;
|
||||
}
|
||||
}
|
||||
// No data transfer: stop at the end of the command
|
||||
else {
|
||||
WRITE_MCI(pMciHw, MCI_MR, mciMr);
|
||||
mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;
|
||||
}
|
||||
// Enable MCI clock
|
||||
MCI_Enable(pMci, ENABLE);
|
||||
|
||||
// Send the command
|
||||
if((pCommand->conTrans != MCI_CONTINUE_TRANSFER)
|
||||
|| (pCommand->blockSize == 0)) {
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_ARGR, pCommand->arg);
|
||||
WRITE_MCI(pMciHw, MCI_CMDR, pCommand->cmd);
|
||||
}
|
||||
|
||||
// In case of transmit, the PDC shall be enabled after sending the command
|
||||
if ((pCommand->blockSize > 0) && !(pCommand->isRead)) {
|
||||
WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);
|
||||
}
|
||||
|
||||
// Ignore data error
|
||||
// if (pCommand->blockSize == 0) {
|
||||
{
|
||||
mciIer &= ~(AT91C_MCI_UNRE | AT91C_MCI_OVRE \
|
||||
| AT91C_MCI_DTOE | AT91C_MCI_DCRCE);
|
||||
}
|
||||
|
||||
// Interrupt enable shall be done after PDC TXTEN and RXTEN
|
||||
WRITE_MCI(pMciHw, MCI_IER, mciIer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Check NOTBUSY and DTIP bits of status register on the given MCI driver.
|
||||
/// Return value, 0 for bus ready, 1 for bus busy
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MCI_CheckBusy(Mci *pMci)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
unsigned int status;
|
||||
|
||||
// Enable MCI clock
|
||||
MCI_Enable(pMci, ENABLE);
|
||||
|
||||
status = READ_MCI(pMciHw, MCI_SR);
|
||||
// trace_LOG(trace_DEBUG, "status %x\n\r",status);
|
||||
|
||||
|
||||
if(((status & AT91C_MCI_NOTBUSY)!=0)
|
||||
&& ((status & AT91C_MCI_DTIP)==0)) {
|
||||
|
||||
// Disable MCI clock
|
||||
MCI_Enable(pMci, DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Check BLKE bit of status register on the given MCI driver.
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MCI_CheckBlke(Mci *pMci)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
unsigned int status;
|
||||
|
||||
status = READ_MCI(pMciHw, MCI_SR);
|
||||
// trace_LOG(trace_DEBUG, "status %x\n\r",status);
|
||||
|
||||
if((status & AT91C_MCI_BLKE)!=0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Processes pending events on the given MCI driver.
|
||||
/// \param pMci Pointer to a MCI driver instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void MCI_Handler(Mci *pMci)
|
||||
{
|
||||
AT91S_MCI *pMciHw = pMci->pMciHw;
|
||||
MciCmd *pCommand = pMci->pCommand;
|
||||
unsigned int status;
|
||||
unsigned char i;
|
||||
#if defined(at91rm9200)
|
||||
unsigned int mciCr, mciSdcr, mciMr, mciDtor;
|
||||
#endif
|
||||
|
||||
SANITY_CHECK(pMci);
|
||||
SANITY_CHECK(pMciHw);
|
||||
SANITY_CHECK(pCommand);
|
||||
|
||||
// Read the status register
|
||||
status = READ_MCI(pMciHw, MCI_SR) & READ_MCI(pMciHw, MCI_IMR);
|
||||
// trace_LOG(trace_DEBUG, "status %x\n\r", status);
|
||||
|
||||
// Check if an error has occured
|
||||
if ((status & STATUS_ERRORS) != 0) {
|
||||
|
||||
// Check error code
|
||||
if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) {
|
||||
|
||||
pCommand->status = MCI_STATUS_NORESPONSE;
|
||||
}
|
||||
// if the command is SEND_OP_COND the CRC error flag is always present
|
||||
// (cf : R3 response)
|
||||
else if (((status & STATUS_ERRORS) != AT91C_MCI_RCRCE)
|
||||
|| ((pCommand->cmd != SDCARD_APP_OP_COND_CMD)
|
||||
&& (pCommand->cmd != MMC_SEND_OP_COND_CMD))) {
|
||||
|
||||
pCommand->status = MCI_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a transfer has been completed
|
||||
if (((status & AT91C_MCI_CMDRDY) != 0)
|
||||
|| ((status & AT91C_MCI_ENDRX) != 0)
|
||||
|| ((status & AT91C_MCI_RXBUFF) != 0)
|
||||
|| ((status & AT91C_MCI_ENDTX) != 0)
|
||||
|| ((status & AT91C_MCI_BLKE) != 0)
|
||||
|| ((status & AT91C_MCI_RTOE) != 0)) {
|
||||
|
||||
if (((status & AT91C_MCI_ENDRX) != 0)
|
||||
|| ((status & AT91C_MCI_RXBUFF) != 0)
|
||||
|| ((status & AT91C_MCI_ENDTX) != 0)) {
|
||||
|
||||
MCI_Enable(pMci, DISABLE);
|
||||
}
|
||||
|
||||
/// On AT91RM9200-EK, if stop transmission, software reset MCI.
|
||||
#if defined(at91rm9200)
|
||||
if ((pCommand->cmd & AT91C_MCI_TRCMD_STOP) != 0) {
|
||||
mciMr = READ_MCI(pMciHw, MCI_MR);
|
||||
mciSdcr = READ_MCI(pMciHw, MCI_SDCR);
|
||||
mciDtor = READ_MCI(pMciHw, MCI_DTOR);
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);
|
||||
// trace_LOG(trace_DEBUG, "reset MCI\n\r");
|
||||
|
||||
WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);
|
||||
WRITE_MCI(pMciHw, MCI_MR, mciMr);
|
||||
WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr);
|
||||
WRITE_MCI(pMciHw, MCI_DTOR, mciDtor);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If no error occured, the transfer is successful
|
||||
if (pCommand->status == MCI_STATUS_PENDING) {
|
||||
pCommand->status = 0;
|
||||
}
|
||||
#if 0
|
||||
if ((status & AT91C_MCI_CMDRDY) != 0)
|
||||
trace_LOG(trace_DEBUG, ".");
|
||||
if ((status & AT91C_MCI_ENDRX) != 0)
|
||||
trace_LOG(trace_DEBUG, "<");
|
||||
if ((status & AT91C_MCI_ENDTX) != 0)
|
||||
trace_LOG(trace_DEBUG, "-");
|
||||
if ((status & AT91C_MCI_BLKE) != 0)
|
||||
trace_LOG(trace_DEBUG, ">");
|
||||
trace_LOG(trace_DEBUG, "\n\r");
|
||||
#endif
|
||||
// Store the card response in the provided buffer
|
||||
if (pCommand->pResp) {
|
||||
|
||||
for (i=0; i < pCommand->resSize; i++) {
|
||||
|
||||
pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Disable interrupts
|
||||
WRITE_MCI(pMciHw, MCI_IDR, READ_MCI(pMciHw, MCI_IMR));
|
||||
|
||||
// Release the semaphore
|
||||
pMci->semaphore++;
|
||||
|
||||
// Invoke the callback associated with the current command (if any)
|
||||
if (pCommand->callback) {
|
||||
(pCommand->callback)(pCommand->status, pCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if the given MCI transfer is complete; otherwise returns 0.
|
||||
/// \param pCommand Pointer to a MciCmd instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char MCI_IsTxComplete(MciCmd *pCommand)
|
||||
{
|
||||
if (pCommand->status != MCI_STATUS_PENDING) {
|
||||
if (pCommand->status != 0)
|
||||
printf("MCI_IsTxComplete %d\n\r", pCommand->status);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
159
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/mci/mci.h
Normal file
159
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/mci/mci.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support - ROUSSET -
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2006, Atmel Corporation
|
||||
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the disclaimer below in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef MCI_H
|
||||
#define MCI_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constants
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Transfer is pending.
|
||||
#define MCI_STATUS_PENDING 1
|
||||
/// Transfer has been aborted because an error occured.
|
||||
#define MCI_STATUS_ERROR 2
|
||||
/// Card did not answer command.
|
||||
#define MCI_STATUS_NORESPONSE 3
|
||||
|
||||
/// MCI driver is currently in use.
|
||||
#define MCI_ERROR_LOCK 1
|
||||
|
||||
/// MCI configuration with 1-bit data bus on slot A (for MMC cards).
|
||||
#define MCI_MMC_SLOTA 0
|
||||
/// MCI configuration with 1-bit data bus on slot B (for MMC cards).
|
||||
#define MCI_MMC_SLOTB 1
|
||||
/// MCI configuration with 4-bit data bus on slot A (for SD cards).
|
||||
#define MCI_SD_SLOTA AT91C_MCI_SCDBUS
|
||||
/// MCI configuration with 4-bit data bus on slot B (for SD cards).
|
||||
#define MCI_SD_SLOTB (AT91C_MCI_SCDBUS | 1)
|
||||
|
||||
/// Start new data transfer
|
||||
#define MCI_NEW_TRANSFER 0
|
||||
/// Continue data transfer
|
||||
#define MCI_CONTINUE_TRANSFER 1
|
||||
|
||||
/// MCI SD Bus Width 1-bit
|
||||
#define MCI_SDCBUS_1BIT (0 << 7)
|
||||
/// MCI SD Bus Width 4-bit
|
||||
#define MCI_SDCBUS_4BIT (1 << 7)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// MCI end-of-transfer callback function.
|
||||
typedef void (*MciCallback)(unsigned char status, void *pCommand);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// MCI Transfer Request prepared by the application upper layer. This structure
|
||||
/// is sent to the MCI_SendCommand function to start the transfer. At the end of
|
||||
/// the transfer, the callback is invoked by the interrupt handler.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct _MciCmd {
|
||||
|
||||
/// Command status.
|
||||
volatile char status;
|
||||
/// Command code.
|
||||
unsigned int cmd;
|
||||
/// Command argument.
|
||||
unsigned int arg;
|
||||
/// Data buffer.
|
||||
unsigned char *pData;
|
||||
/// Size of data buffer in bytes.
|
||||
unsigned short blockSize;
|
||||
/// Number of blocks to be transfered
|
||||
unsigned short nbBlock;
|
||||
/// Indicate if continue to transfer data
|
||||
unsigned char conTrans;
|
||||
/// Indicates if the command is a read operation.
|
||||
unsigned char isRead;
|
||||
/// Response buffer.
|
||||
unsigned int *pResp;
|
||||
/// Size of SD card response in bytes.
|
||||
unsigned char resSize;
|
||||
/// Optional user-provided callback function.
|
||||
MciCallback callback;
|
||||
/// Optional argument to the callback function.
|
||||
void *pArg;
|
||||
|
||||
} MciCmd;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// MCI driver structure. Holds the internal state of the MCI driver and
|
||||
/// prevents parallel access to a MCI peripheral.
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct {
|
||||
|
||||
/// Pointer to a MCI peripheral.
|
||||
AT91S_MCI *pMciHw;
|
||||
/// MCI peripheral identifier.
|
||||
unsigned char mciId;
|
||||
/// Pointer to currently executing command.
|
||||
MciCmd *pCommand;
|
||||
/// Mutex.
|
||||
volatile char semaphore;
|
||||
|
||||
} Mci;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void MCI_Init(
|
||||
Mci *pMci,
|
||||
AT91PS_MCI pMciHw,
|
||||
unsigned char mciId,
|
||||
unsigned int mode);
|
||||
|
||||
extern void MCI_SetSpeed(Mci *pMci, unsigned int mciSpeed);
|
||||
|
||||
extern unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pMciCmd);
|
||||
|
||||
extern void MCI_Handler(Mci *pMci);
|
||||
|
||||
extern unsigned char MCI_IsTxComplete(MciCmd *pMciCmd);
|
||||
|
||||
extern unsigned char MCI_CheckBusy(Mci *pMci);
|
||||
|
||||
extern void MCI_Close(Mci *pMci);
|
||||
|
||||
extern void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth);
|
||||
|
||||
#endif //#ifndef MCI_H
|
||||
|
||||
336
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pio/pio.c
Normal file
336
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pio/pio.c
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pio.h"
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Internal definitions
|
||||
//------------------------------------------------------------------------------
|
||||
/// \internal Returns the current value of a register.
|
||||
#define READ(peripheral, register) (peripheral->register)
|
||||
/// \internal Modifies the current value of a register.
|
||||
#define WRITE(peripheral, register, value) (peripheral->register = value)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Internal functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures one or more pin(s) of a PIO controller as being controlled by
|
||||
/// peripheral A. Optionally, the corresponding internal pull-up(s) can be
|
||||
/// enabled.
|
||||
/// \param pio Pointer to a PIO controller.
|
||||
/// \param mask Bitmask of one or more pin(s) to configure.
|
||||
/// \param enablePullUp Indicates if the pin(s) internal pull-up shall be
|
||||
/// configured.
|
||||
//------------------------------------------------------------------------------
|
||||
static void PIO_SetPeripheralA(AT91S_PIO *pio,
|
||||
unsigned int mask,
|
||||
unsigned char enablePullUp)
|
||||
{
|
||||
// Disable interrupts on the pin(s)
|
||||
WRITE(pio, PIO_IDR, mask);
|
||||
|
||||
// Enable the pull-up(s) if necessary
|
||||
if (enablePullUp) {
|
||||
|
||||
WRITE(pio, PIO_PPUER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_PPUDR, mask);
|
||||
}
|
||||
|
||||
// Configure pin
|
||||
WRITE(pio, PIO_ASR, mask);
|
||||
WRITE(pio, PIO_PDR, mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures one or more pin(s) of a PIO controller as being controlled by
|
||||
/// peripheral A. Optionally, the corresponding internal pull-up(s) can be
|
||||
/// enabled.
|
||||
/// \param pio Pointer to a PIO controller.
|
||||
/// \param mask Bitmask of one or more pin(s) to configure.
|
||||
/// \param enablePullUp Indicates if the pin(s) internal pull-up shall be
|
||||
/// configured.
|
||||
//------------------------------------------------------------------------------
|
||||
static void PIO_SetPeripheralB(AT91S_PIO *pio,
|
||||
unsigned int mask,
|
||||
unsigned char enablePullUp)
|
||||
{
|
||||
// Disable interrupts on the pin(s)
|
||||
WRITE(pio, PIO_IDR, mask);
|
||||
|
||||
// Enable the pull-up(s) if necessary
|
||||
if (enablePullUp) {
|
||||
|
||||
WRITE(pio, PIO_PPUER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_PPUDR, mask);
|
||||
}
|
||||
|
||||
// Configure pin
|
||||
WRITE(pio, PIO_BSR, mask);
|
||||
WRITE(pio, PIO_PDR, mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures one or more pin(s) or a PIO controller as inputs. Optionally,
|
||||
/// the corresponding internal pull-up(s) and glitch filter(s) can be
|
||||
/// enabled.
|
||||
/// \param pio Pointer to a PIO controller.
|
||||
/// \param mask Bitmask indicating which pin(s) to configure as input(s).
|
||||
/// \param enablePullUp Indicates if the internal pull-up(s) must be enabled.
|
||||
/// \param enableFilter Indicates if the glitch filter(s) must be enabled.
|
||||
//------------------------------------------------------------------------------
|
||||
static void PIO_SetInput(AT91S_PIO *pio,
|
||||
unsigned int mask,
|
||||
unsigned char enablePullUp,
|
||||
unsigned char enableFilter)
|
||||
{
|
||||
// Disable interrupts
|
||||
WRITE(pio, PIO_IDR, mask);
|
||||
|
||||
// Enable pull-up(s) if necessary
|
||||
if (enablePullUp) {
|
||||
|
||||
WRITE(pio, PIO_PPUER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_PPUDR, mask);
|
||||
}
|
||||
|
||||
// Enable filter(s) if necessary
|
||||
if (enableFilter) {
|
||||
|
||||
WRITE(pio, PIO_IFER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_IFDR, mask);
|
||||
}
|
||||
|
||||
// Configure pin as input
|
||||
WRITE(pio, PIO_ODR, mask);
|
||||
WRITE(pio, PIO_PER, mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures one or more pin(s) of a PIO controller as outputs, with the
|
||||
/// given default value. Optionally, the multi-drive feature can be enabled
|
||||
/// on the pin(s).
|
||||
/// \param pio Pointer to a PIO controller.
|
||||
/// \param mask Bitmask indicating which pin(s) to configure.
|
||||
/// \param defaultValue Default level on the pin(s).
|
||||
/// \param enableMultiDrive Indicates if the pin(s) shall be configured as
|
||||
/// open-drain.
|
||||
/// \param enablePullUp Indicates if the pin shall have its pull-up activated.
|
||||
//------------------------------------------------------------------------------
|
||||
static void PIO_SetOutput(AT91S_PIO *pio,
|
||||
unsigned int mask,
|
||||
unsigned char defaultValue,
|
||||
unsigned char enableMultiDrive,
|
||||
unsigned char enablePullUp)
|
||||
{
|
||||
// Disable interrupts
|
||||
WRITE(pio, PIO_IDR, mask);
|
||||
|
||||
// Enable pull-up(s) if necessary
|
||||
if (enablePullUp) {
|
||||
|
||||
WRITE(pio, PIO_PPUER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_PPUDR, mask);
|
||||
}
|
||||
|
||||
// Enable multi-drive if necessary
|
||||
if (enableMultiDrive) {
|
||||
|
||||
WRITE(pio, PIO_MDER, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_MDDR, mask);
|
||||
}
|
||||
|
||||
// Set default value
|
||||
if (defaultValue) {
|
||||
|
||||
WRITE(pio, PIO_SODR, mask);
|
||||
}
|
||||
else {
|
||||
|
||||
WRITE(pio, PIO_CODR, mask);
|
||||
}
|
||||
|
||||
// Configure pin(s) as output(s)
|
||||
WRITE(pio, PIO_OER, mask);
|
||||
WRITE(pio, PIO_PER, mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a list of Pin instances, which can either hold a single pin or a
|
||||
/// group of pins, depending on the mask value; all pins are configured by this
|
||||
/// function.
|
||||
/// Returns 1 if the configuration has been performed successfully; otherwise 0.
|
||||
/// \param list Pointer to a list of Pin instances.
|
||||
/// \param size Size of the Pin list (see <PIO_LISTSIZE>).
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char PIO_Configure(const Pin *list, unsigned int size)
|
||||
{
|
||||
// Configure pins
|
||||
while (size > 0) {
|
||||
|
||||
switch (list->type) {
|
||||
|
||||
case PIO_PERIPH_A:
|
||||
PIO_SetPeripheralA(list->pio,
|
||||
list->mask,
|
||||
(list->attribute & PIO_PULLUP) ? 1 : 0);
|
||||
break;
|
||||
|
||||
case PIO_PERIPH_B:
|
||||
PIO_SetPeripheralB(list->pio,
|
||||
list->mask,
|
||||
(list->attribute & PIO_PULLUP) ? 1 : 0);
|
||||
break;
|
||||
|
||||
case PIO_INPUT:
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << list->id;
|
||||
PIO_SetInput(list->pio,
|
||||
list->mask,
|
||||
(list->attribute & PIO_PULLUP) ? 1 : 0,
|
||||
(list->attribute & PIO_DEGLITCH)? 1 : 0);
|
||||
break;
|
||||
|
||||
case PIO_OUTPUT_0:
|
||||
case PIO_OUTPUT_1:
|
||||
PIO_SetOutput(list->pio,
|
||||
list->mask,
|
||||
(list->type == PIO_OUTPUT_1),
|
||||
(list->attribute & PIO_OPENDRAIN) ? 1 : 0,
|
||||
(list->attribute & PIO_PULLUP) ? 1 : 0);
|
||||
break;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
list++;
|
||||
size--;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets a high output level on one or more pin(s) (if configured as output(s)).
|
||||
/// \param pin Pointer to a Pin instance describing one or more pins.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_Set(const Pin *pin)
|
||||
{
|
||||
WRITE(pin->pio, PIO_SODR, pin->mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets a low output level on one or more pin(s) (if configured as output(s)).
|
||||
/// \param pin Pointer to a Pin instance describing one or more pins.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_Clear(const Pin *pin)
|
||||
{
|
||||
WRITE(pin->pio, PIO_CODR, pin->mask);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if one or more PIO of the given Pin instance currently have a high
|
||||
/// level; otherwise returns 0.
|
||||
/// \param pin Pointer to a Pin instance describing one or more pins.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char PIO_Get(const Pin *pin)
|
||||
{
|
||||
unsigned int reg;
|
||||
if ((pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1)) {
|
||||
|
||||
reg = READ(pin->pio, PIO_ODSR);
|
||||
}
|
||||
else {
|
||||
|
||||
reg = READ(pin->pio, PIO_PDSR);
|
||||
}
|
||||
|
||||
if ((reg & pin->mask) == 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if one or more PIO of the given Pin data to be driven on the I/O line
|
||||
/// level; otherwise returns 0.
|
||||
/// \param pin Pointer to a Pin instance describing one or more pins.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char PIO_GetOutputDataStatus(const Pin *pin)
|
||||
{
|
||||
if ((READ(pin->pio, PIO_ODSR) & pin->mask) == 0) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the value of ISR for the PIO controller of the pin.
|
||||
/// Reading this register acknoledges all the ITs.
|
||||
/// \param pin Pointer to a Pin instance describing one or more pins.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int PIO_GetISR(const Pin *pin)
|
||||
{
|
||||
return (READ(pin->pio, PIO_ISR));
|
||||
}
|
||||
|
||||
169
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pio/pio.h
Normal file
169
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pio/pio.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definition of methods and structures for using PIOs in a transparent
|
||||
/// way. The main purpose is to allow portability between several boards.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# To configure and use pins, see pio.h.
|
||||
/// -# To enable and use interrupt generation on PIO status change, see
|
||||
/// pio_it.h.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \unit
|
||||
/// !Purpose
|
||||
///
|
||||
/// Simple & portable usage of PIO pins.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Define a constant pin description array such as the following one:
|
||||
/// \code
|
||||
/// const Pin at91board_dbgu[] = {
|
||||
/// {AT91C_BASE_PIOA, (1 << 30), PIO_PERIPH_A, PIO_DEFAULT},
|
||||
/// {AT91C_BASE_PIOA, (1 << 31), PIO_PERIPH_A, PIO_DEFAULT},
|
||||
/// };
|
||||
/// \endcode
|
||||
/// Alternatively, constants defined in the piodefs.h header file of the
|
||||
/// board module can be used:
|
||||
/// \code
|
||||
/// const Pin at91board_dbgu[] = {PINS_DBGU};
|
||||
/// const Pin at91board_usart[] = {PIN_USART0_RXD, PIN_USART0_TXD};
|
||||
/// \endcode
|
||||
/// It is possible to group multiple pins if they share the same
|
||||
/// attributes, to save memory. Here is the previous DBGU example
|
||||
/// rewritten in such a way:
|
||||
/// \code
|
||||
/// const Pin at91board_dbgu[] = {
|
||||
/// {AT91C_BASE_PIOA, 0xC0000000, PIO_PERIPH_A, PIO_DEFAULT}
|
||||
/// };
|
||||
/// \endcode
|
||||
/// -# For pins configured as inputs, the PIO controller must be enabled
|
||||
/// in the PMC (*enabled by PIO_Configure at the moment*).
|
||||
/// -# Configure a pin array by calling PIO_Configure, using
|
||||
/// the PIO_LISTSIZE macro to calculate the array size if needed. Do not
|
||||
/// forget to check the return value for any error.
|
||||
/// -# Set and get the value of a pin using the PIO_Set, PIO_Clear and
|
||||
/// PIO_Get methods.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef PIO_H
|
||||
#define PIO_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "Pin types"
|
||||
/// This page lists the available types for a Pin instance (in its type field).
|
||||
/// !Types
|
||||
/// - PIO_PERIPH_A
|
||||
/// - PIO_PERIPH_B
|
||||
/// - PIO_INPUT
|
||||
/// - PIO_OUTPUT_0
|
||||
/// - PIO_OUTPUT_1
|
||||
|
||||
/// The pin is controlled by the associated signal of peripheral A.
|
||||
#define PIO_PERIPH_A 0
|
||||
/// The pin is controlled by the associated signal of peripheral B.
|
||||
#define PIO_PERIPH_B 1
|
||||
/// The pin is an input.
|
||||
#define PIO_INPUT 2
|
||||
/// The pin is an output and has a default level of 0.
|
||||
#define PIO_OUTPUT_0 3
|
||||
/// The pin is an output and has a default level of 1.
|
||||
#define PIO_OUTPUT_1 4
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "Pin attributes"
|
||||
/// This page lists the valid values for the attribute field of a Pin instance.
|
||||
/// !Attributes
|
||||
/// - PIO_DEFAULT
|
||||
/// - PIO_PULLUP
|
||||
/// - PIO_DEGLITCH
|
||||
/// - PIO_OPENDRAIN
|
||||
|
||||
/// Default pin configuration (no attribute).
|
||||
#define PIO_DEFAULT (0 << 0)
|
||||
/// The internal pin pull-up is active.
|
||||
#define PIO_PULLUP (1 << 0)
|
||||
/// The internal glitch filter is active.
|
||||
#define PIO_DEGLITCH (1 << 1)
|
||||
/// The pin is open-drain.
|
||||
#define PIO_OPENDRAIN (1 << 2)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Calculates the size of a Pin instances array. The array must be local (i.e.
|
||||
/// not a pointer), otherwise the computation will not be correct.
|
||||
#define PIO_LISTSIZE(list) (sizeof(list) / sizeof(Pin))
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Describes the type and attribute of one PIO pin or a group of similar pins.
|
||||
typedef struct {
|
||||
/// Bitmask indicating which pin(s) to configure.
|
||||
unsigned int mask;
|
||||
/// Pointer to the PIO controller which has the pin(s).
|
||||
AT91S_PIO *pio;
|
||||
/// Peripheral ID of the PIO controller which has the pin(s).
|
||||
unsigned char id;
|
||||
/// Pin type (see "Pin types").
|
||||
unsigned char type;
|
||||
/// Pin attribute (see "Pin attributes").
|
||||
unsigned char attribute;
|
||||
} Pin;
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern unsigned char PIO_Configure(const Pin *list, unsigned int size);
|
||||
extern void PIO_Set(const Pin *pin );
|
||||
extern void PIO_Clear(const Pin *pin);
|
||||
extern unsigned char PIO_Get(const Pin *pin);
|
||||
extern unsigned int PIO_GetISR(const Pin *pin);
|
||||
extern unsigned char PIO_GetOutputDataStatus(const Pin *pin);
|
||||
|
||||
#endif //#ifndef PIO_H
|
||||
|
||||
|
|
@ -0,0 +1,387 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/// Disable traces for this file
|
||||
#ifndef NOTRACE
|
||||
#define NOTRACE
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pio_it.h"
|
||||
#include "pio.h"
|
||||
#include <aic/aic.h>
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Returns the current value of a register.
|
||||
#define READ(peripheral, register) (peripheral->register)
|
||||
/// Modifies the current value of a register.
|
||||
#define WRITE(peripheral, register, value) (peripheral->register = value)
|
||||
|
||||
/// Maximum number of interrupt sources that can be defined.
|
||||
#define MAX_INTERRUPT_SOURCES 7
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Describes a PIO interrupt source, including the PIO instance triggering the
|
||||
/// interrupt and the associated interrupt handler.
|
||||
typedef struct _InterruptSource {
|
||||
|
||||
/// Interrupt source pin.
|
||||
const Pin *pPin;
|
||||
|
||||
/// Interrupt handler.
|
||||
void (*handler)(const Pin *);
|
||||
|
||||
} InterruptSource;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local variables
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// List of interrupt sources.
|
||||
static InterruptSource pSources[MAX_INTERRUPT_SOURCES];
|
||||
|
||||
/// Number of currently defined interrupt sources.
|
||||
static unsigned int numSources;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Handles all interrupts on the given PIO controller.
|
||||
/// \param id PIO controller ID.
|
||||
/// \param pBase PIO controller base address.
|
||||
//------------------------------------------------------------------------------
|
||||
void PioInterruptHandler(unsigned int id, AT91S_PIO *pBase)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int i;
|
||||
|
||||
// Check PIO controller status
|
||||
status = pBase->PIO_ISR;
|
||||
status &= pBase->PIO_IMR;
|
||||
if (status != 0) {
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO interrupt on PIO controller #%d\n\r", id);
|
||||
|
||||
// Check all sources
|
||||
i = 0;
|
||||
while (status != 0) {
|
||||
|
||||
// There cannot be an unconfigured source enabled.
|
||||
SANITY_CHECK(i < numSources);
|
||||
|
||||
// Source if configured on PIOA
|
||||
if (pSources[i].pPin->id == id) {
|
||||
|
||||
// Source has PIOs which have changed
|
||||
if ((status & pSources[i].pPin->mask) != 0) {
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- Interrupt source #%d triggered\n\r", i);
|
||||
|
||||
pSources[i].handler(pSources[i].pPin);
|
||||
status &= ~(pSources[i].pPin->mask);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Generic PIO interrupt handler. Single entry point for interrupts coming
|
||||
/// from any PIO controller (PIO A, B, C ...). Dispatches the interrupt to
|
||||
/// the user-configured handlers.
|
||||
//------------------------------------------------------------------------------
|
||||
void InterruptHandler()
|
||||
{
|
||||
#if defined(AT91C_ID_PIOA)
|
||||
// Treat PIOA interrupts
|
||||
PioInterruptHandler(AT91C_ID_PIOA, AT91C_BASE_PIOA);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOB)
|
||||
// Treat PIOB interrupts
|
||||
PioInterruptHandler(AT91C_ID_PIOB, AT91C_BASE_PIOB);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOC)
|
||||
// Treat PIOC interrupts
|
||||
PioInterruptHandler(AT91C_ID_PIOC, AT91C_BASE_PIOC);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOD)
|
||||
// Treat PIOD interrupts
|
||||
PioInterruptHandler(AT91C_ID_PIOD, AT91C_BASE_PIOD);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOE)
|
||||
// Treat PIOE interrupts
|
||||
PioInterruptHandler(AT91C_ID_PIOE, AT91C_BASE_PIOE);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOABCD)
|
||||
// Treat PIOABCD interrupts
|
||||
#if !defined(AT91C_ID_PIOA)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOA);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOB)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOB);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOC)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOC);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOD)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCD, AT91C_BASE_PIOD);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOABCDE)
|
||||
// Treat PIOABCDE interrupts
|
||||
#if !defined(AT91C_ID_PIOA)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOA);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOB)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOB);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOC)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOC);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOD)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOD);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOE)
|
||||
PioInterruptHandler(AT91C_ID_PIOABCDE, AT91C_BASE_PIOE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOCDE)
|
||||
// Treat PIOCDE interrupts
|
||||
#if !defined(AT91C_ID_PIOC)
|
||||
PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOC);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOD)
|
||||
PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOD);
|
||||
#endif
|
||||
#if !defined(AT91C_ID_PIOE)
|
||||
PioInterruptHandler(AT91C_ID_PIOCDE, AT91C_BASE_PIOE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes the PIO interrupt management logic.
|
||||
/// \param priority PIO controller interrupts priority.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_InitializeInterrupts(unsigned int priority)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize()\n\r");
|
||||
|
||||
SANITY_CHECK((priority & ~AT91C_AIC_PRIOR) == 0);
|
||||
|
||||
// Reset sources
|
||||
numSources = 0;
|
||||
|
||||
#ifdef AT91C_ID_PIOA
|
||||
// Configure PIO interrupt sources
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOA\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
|
||||
AT91C_BASE_PIOA->PIO_ISR;
|
||||
AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOA, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOA);
|
||||
#endif
|
||||
|
||||
#ifdef AT91C_ID_PIOB
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOB\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOB;
|
||||
AT91C_BASE_PIOB->PIO_ISR;
|
||||
AT91C_BASE_PIOB->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOB, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOB);
|
||||
#endif
|
||||
|
||||
#ifdef AT91C_ID_PIOC
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOC\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOC;
|
||||
AT91C_BASE_PIOC->PIO_ISR;
|
||||
AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOC, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOC);
|
||||
#endif
|
||||
|
||||
#ifdef AT91C_ID_PIOD
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOD\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOD;
|
||||
AT91C_BASE_PIOC->PIO_ISR;
|
||||
AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOD, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOD);
|
||||
#endif
|
||||
|
||||
#ifdef AT91C_ID_PIOE
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOE\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOE;
|
||||
AT91C_BASE_PIOC->PIO_ISR;
|
||||
AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOE, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOE);
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOABCD)
|
||||
// Treat PIOABCD interrupts
|
||||
#if !defined(AT91C_ID_PIOA) \
|
||||
&& !defined(AT91C_ID_PIOB) \
|
||||
&& !defined(AT91C_ID_PIOC) \
|
||||
&& !defined(AT91C_ID_PIOD)
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOABCD\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCD;
|
||||
AT91C_BASE_PIOA->PIO_ISR;
|
||||
AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOABCD, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOABCD);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOABCDE)
|
||||
// Treat PIOABCDE interrupts
|
||||
#if !defined(AT91C_ID_PIOA) \
|
||||
&& !defined(AT91C_ID_PIOB) \
|
||||
&& !defined(AT91C_ID_PIOC) \
|
||||
&& !defined(AT91C_ID_PIOD) \
|
||||
&& !defined(AT91C_ID_PIOE)
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOABCDE\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOABCDE;
|
||||
AT91C_BASE_PIOA->PIO_ISR;
|
||||
AT91C_BASE_PIOA->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOABCDE, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOABCDE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(AT91C_ID_PIOCDE)
|
||||
// Treat PIOCDE interrupts
|
||||
#if !defined(AT91C_ID_PIOC) \
|
||||
&& !defined(AT91C_ID_PIOD) \
|
||||
&& !defined(AT91C_ID_PIOE)
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_Initialize: Configuring PIOC\n\r");
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOCDE;
|
||||
AT91C_BASE_PIOC->PIO_ISR;
|
||||
AT91C_BASE_PIOC->PIO_IDR = 0xFFFFFFFF;
|
||||
AIC_ConfigureIT(AT91C_ID_PIOCDE, priority, InterruptHandler);
|
||||
AIC_EnableIT(AT91C_ID_PIOCDE);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures an interrupt source.
|
||||
/// \param pPin Interrupt source.
|
||||
/// \param handler Desired interrupt handler for the source.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *))
|
||||
{
|
||||
InterruptSource *pSource;
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_ConfigureIt()\n\r");
|
||||
|
||||
SANITY_CHECK(pPin);
|
||||
ASSERT(numSources < MAX_INTERRUPT_SOURCES,
|
||||
"-F- PIO_ConfigureIt: Increase MAX_INTERRUPT_SOURCES\n\r");
|
||||
|
||||
// Define new source
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_ConfigureIt: Defining new source #%d.\n\r", numSources);
|
||||
|
||||
pSource = &(pSources[numSources]);
|
||||
pSource->pPin = pPin;
|
||||
pSource->handler = handler;
|
||||
numSources++;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the given interrupt source if it has been configured.
|
||||
/// \param pPin Interrupt source to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_EnableIt(const Pin *pPin)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_EnableIt()\n\r");
|
||||
|
||||
SANITY_CHECK(pPin);
|
||||
|
||||
#ifndef NOASSERT
|
||||
unsigned int i = 0;
|
||||
unsigned char found = 0;
|
||||
while ((i < numSources) && !found) {
|
||||
|
||||
if (pSources[i].pPin == pPin) {
|
||||
|
||||
found = 1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ASSERT(found, "-F- PIO_EnableIt: Interrupt source has not been configured\n\r");
|
||||
#endif
|
||||
|
||||
pPin->pio->PIO_ISR;
|
||||
pPin->pio->PIO_IER = pPin->mask;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables a given interrupt source.
|
||||
/// \param pPin Interrupt source to disable.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIO_DisableIt(const Pin *pPin)
|
||||
{
|
||||
SANITY_CHECK(pPin);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- PIO_DisableIt()\n\r");
|
||||
|
||||
pPin->pio->PIO_IDR = pPin->mask;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \unit
|
||||
/// !Purpose
|
||||
///
|
||||
/// Configuration and handling of interrupts on PIO status changes.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Configure an status change interrupt on one or more pin(s) with
|
||||
/// PIO_ConfigureIt.
|
||||
/// -# Enable & disable interrupts on pins using PIO_EnableIt and
|
||||
/// PIO_DisableIt.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pio.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void PIO_InitializeInterrupts(unsigned int priority);
|
||||
|
||||
extern void PIO_ConfigureIt(const Pin *pPin, void (*handler)(const Pin *));
|
||||
|
||||
extern void PIO_EnableIt(const Pin *pPin);
|
||||
|
||||
extern void PIO_DisableIt(const Pin *pPin);
|
||||
|
||||
115
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pit/pit.c
Normal file
115
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pit/pit.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pit.h"
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initialize the System timer for a period in µsecond with a system clock
|
||||
/// freq in MHz
|
||||
/// \param period Period in µsecond.
|
||||
/// \param pit_frequency System clock frequency in MHz.
|
||||
//------------------------------------------------------------------------------
|
||||
void PIT_Init(unsigned int period,
|
||||
unsigned int pit_frequency)
|
||||
{
|
||||
AT91C_BASE_PITC->PITC_PIMR = period? (period * pit_frequency + 8) >> 4 : 0; // +8 to avoid %10 and /10
|
||||
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Set the PIT Periodic Interval Value
|
||||
//------------------------------------------------------------------------------
|
||||
void PIT_SetPIV(unsigned int piv)
|
||||
{
|
||||
AT91C_BASE_PITC->PITC_PIMR = piv | (AT91C_BASE_PITC->PITC_PIMR & (AT91C_PITC_PITEN | AT91C_PITC_PITIEN));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enable the PIT
|
||||
//------------------------------------------------------------------------------
|
||||
void PIT_Enable(void)
|
||||
{
|
||||
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// Enable PIT periodic interrupt
|
||||
//----------------------------------------------------------------------------
|
||||
void PIT_EnableIT(void)
|
||||
{
|
||||
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITIEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disable PIT periodic interrupt
|
||||
//------------------------------------------------------------------------------
|
||||
void PIT_DisableIT(void)
|
||||
{
|
||||
AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITIEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Read PIT mode register
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int PIT_GetMode(void)
|
||||
{
|
||||
return(AT91C_BASE_PITC->PITC_PIMR);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Read PIT status register
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int PIT_GetStatus(void)
|
||||
{
|
||||
return(AT91C_BASE_PITC->PITC_PISR);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Read PIT CPIV and PICNT without ressetting the counters
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int PIT_GetPIIR(void)
|
||||
{
|
||||
return(AT91C_BASE_PITC->PITC_PIIR);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Read System timer CPIV and PICNT without ressetting the counters
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int PIT_GetPIVR(void)
|
||||
{
|
||||
return(AT91C_BASE_PITC->PITC_PIVR);
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \unit
|
||||
/// !Purpose
|
||||
///
|
||||
/// Configuration and handling of PIT.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Initialize System timer for a period in µsecond with
|
||||
/// PIT_Init
|
||||
/// -# Set the PIT Periodic Interval Value with PIT_SetPIV
|
||||
/// -# Enable the PIT with PIT_Enable
|
||||
/// -# Enable & disable PIT interrupts using PIT_EnableInt and
|
||||
/// PIT_DisableInt
|
||||
/// -# Read PIT mode register
|
||||
/// PIT_GetMode
|
||||
/// -# Read PIT status register
|
||||
/// PIT_GetStatus
|
||||
/// -# Read PIT CPIV and PICNT without ressetting the counters
|
||||
/// PIT_GetPIIR
|
||||
/// -# Read System timer CPIV and PICNT without ressetting the counters
|
||||
/// PIT_GetPIVR
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef PIT_H
|
||||
#define PIT_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern void PIT_Init(unsigned int period, unsigned int pit_frequency);
|
||||
extern void PIT_SetPIV(unsigned int piv);
|
||||
extern void PIT_Enable(void);
|
||||
extern void PIT_EnableIT(void);
|
||||
extern void PIT_DisableIT(void);
|
||||
extern unsigned int PIT_GetMode(void);
|
||||
extern unsigned int PIT_GetStatus(void);
|
||||
extern unsigned int PIT_GetPIIR(void);
|
||||
extern unsigned int PIT_GetPIVR(void);
|
||||
|
||||
#endif //#ifndef PIT_H
|
||||
133
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pmc/pmc.c
Normal file
133
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/pmc/pmc.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pmc.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(at91sam7l64) || defined(at91sam7l128)
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the fast wake-up inputs that can get the device out of Wait mode.
|
||||
/// \param inputs Fast wake-up inputs to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_SetFastWakeUpInputs(unsigned int inputs)
|
||||
{
|
||||
SANITY_CHECK((inputs & ~0xFF) == 0);
|
||||
AT91C_BASE_PMC->PMC_FSMR = inputs;
|
||||
}
|
||||
|
||||
#if !defined(__ICCARM__)
|
||||
__attribute__ ((section (".ramfunc"))) // GCC
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the main oscillator, making the device enter Wait mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_DisableMainOscillatorForWaitMode(void)
|
||||
{
|
||||
AT91C_BASE_PMC->PMC_MOR = 0x37 << 16;
|
||||
while ((AT91C_BASE_PMC->PMC_MOR & AT91C_PMC_MAINSELS) != AT91C_PMC_MAINSELS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(at91sam7l)
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the main oscillator when NOT running on it.
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_DisableMainOscillator(void)
|
||||
{
|
||||
AT91C_BASE_PMC->PMC_MOR = 0x37 << 16;
|
||||
while ((AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MAINSELS) == AT91C_PMC_MAINSELS);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the processor clock, making the device enter Idle mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_DisableProcessorClock(void)
|
||||
{
|
||||
AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_PCK;
|
||||
while ((AT91C_BASE_PMC->PMC_SCSR & AT91C_PMC_PCK) != AT91C_PMC_PCK);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the clock of a peripheral. The peripheral ID (AT91C_ID_xxx) is used
|
||||
/// to identify which peripheral is targetted.
|
||||
/// Note that the ID must NOT be shifted (i.e. 1 << AT91C_ID_xxx).
|
||||
/// \param id Peripheral ID (AT91C_ID_xxx).
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_EnablePeripheral(unsigned int id)
|
||||
{
|
||||
SANITY_CHECK(id < 32);
|
||||
|
||||
if ((AT91C_BASE_PMC->PMC_PCSR & (1 << id)) == (1 << id)) {
|
||||
|
||||
trace_LOG(trace_INFO,
|
||||
"-I- PMC_EnablePeripheral: clock of peripheral"
|
||||
" %u is already enabled\n\r",
|
||||
id);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << id;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the clock of a peripheral. The peripheral ID (AT91C_ID_xxx) is used
|
||||
/// to identify which peripheral is targetted.
|
||||
/// Note that the ID must NOT be shifted (i.e. 1 << AT91C_ID_xxx).
|
||||
/// \param id Peripheral ID (AT91C_ID_xxx).
|
||||
//------------------------------------------------------------------------------
|
||||
void PMC_DisablePeripheral(unsigned int id)
|
||||
{
|
||||
SANITY_CHECK(id < 32);
|
||||
|
||||
if ((AT91C_BASE_PMC->PMC_PCSR & (1 << id)) != (1 << id)) {
|
||||
|
||||
trace_LOG(trace_INFO,
|
||||
"-I- PMC_DisablePeripheral: clock of peripheral"
|
||||
" %u is not enabled\n\r",
|
||||
id);
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_PMC->PMC_PCDR = 1 << id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef PMC_H
|
||||
#define PMC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(at91sam7l64) || defined(at91sam7l128)
|
||||
extern void PMC_SetFastWakeUpInputs(unsigned int inputs);
|
||||
extern void PMC_DisableMainOscillator(void);
|
||||
extern
|
||||
#ifdef __ICCARM__
|
||||
__ramfunc
|
||||
#endif
|
||||
void PMC_DisableMainOscillatorForWaitMode(void);
|
||||
#endif
|
||||
|
||||
extern void PMC_DisableProcessorClock(void);
|
||||
|
||||
extern void PMC_EnablePeripheral(unsigned int id);
|
||||
|
||||
extern void PMC_DisablePeripheral(unsigned int id);
|
||||
#endif //#ifndef PMC_H
|
||||
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "pwmc.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Finds a prescaler/divisor couple to generate the desired frequency from
|
||||
/// MCK.
|
||||
/// Returns the value to enter in PWMC_MR or 0 if the configuration cannot be
|
||||
/// met.
|
||||
/// \param frequency Desired frequency in Hz.
|
||||
/// \param mck Master clock frequency in Hz.
|
||||
//------------------------------------------------------------------------------
|
||||
static unsigned short FindClockConfiguration(
|
||||
unsigned int frequency,
|
||||
unsigned int mck)
|
||||
{
|
||||
unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
|
||||
unsigned char divisor = 0;
|
||||
unsigned int prescaler;
|
||||
|
||||
SANITY_CHECK(frequency < mck);
|
||||
|
||||
// Find prescaler and divisor values
|
||||
prescaler = (mck / divisors[divisor]) / frequency;
|
||||
while ((prescaler > 255) && (divisor < 11)) {
|
||||
|
||||
divisor++;
|
||||
prescaler = (mck / divisors[divisor]) / frequency;
|
||||
}
|
||||
|
||||
// Return result
|
||||
if (divisor < 11) {
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- Found divisor=%u and prescaler=%u for freq=%uHz\n\r",
|
||||
divisors[divisor], prescaler, frequency);
|
||||
return prescaler | (divisor << 8);
|
||||
}
|
||||
else {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures PWM a channel with the given parameters.
|
||||
/// The PWM controller must have been clocked in the PMC prior to calling this
|
||||
/// function.
|
||||
/// \param channel Channel number.
|
||||
/// \param prescaler Channel prescaler.
|
||||
/// \param alignment Channel alignment.
|
||||
/// \param polarity Channel polarity.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_ConfigureChannel(
|
||||
unsigned char channel,
|
||||
unsigned int prescaler,
|
||||
unsigned int alignment,
|
||||
unsigned int polarity)
|
||||
{
|
||||
SANITY_CHECK(prescaler < AT91C_PWMC_CPRE_MCKB);
|
||||
SANITY_CHECK((alignment & ~AT91C_PWMC_CALG) == 0);
|
||||
SANITY_CHECK((polarity & ~AT91C_PWMC_CPOL) == 0);
|
||||
|
||||
// Disable channel
|
||||
AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
|
||||
|
||||
// Configure channel
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR = prescaler | alignment | polarity;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures PWM clocks A & B to run at the given frequencies. This function
|
||||
/// finds the best MCK divisor and prescaler values automatically.
|
||||
/// \param clka Desired clock A frequency (0 if not used).
|
||||
/// \param clkb Desired clock B frequency (0 if not used).
|
||||
/// \param mck Master clock frequency.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)
|
||||
{
|
||||
unsigned int mode = 0;
|
||||
unsigned int result;
|
||||
|
||||
// Clock A
|
||||
if (clka != 0) {
|
||||
|
||||
result = FindClockConfiguration(clka, mck);
|
||||
ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clka);
|
||||
mode |= result;
|
||||
}
|
||||
|
||||
// Clock B
|
||||
if (clkb != 0) {
|
||||
|
||||
result = FindClockConfiguration(clkb, mck);
|
||||
ASSERT(result != 0, "-F- Could not generate the desired PWM frequency (%uHz)\n\r", clkb);
|
||||
mode |= (result << 16);
|
||||
}
|
||||
|
||||
// Configure clocks
|
||||
trace_LOG(trace_DEBUG, "-D- Setting PWMC_MR = 0x%08X\n\r", mode);
|
||||
AT91C_BASE_PWMC->PWMC_MR = mode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the period value used by a PWM channel. This function writes directly
|
||||
/// to the CPRD register if the channel is disabled; otherwise, it uses the
|
||||
/// update register CUPD.
|
||||
/// \param channel Channel number.
|
||||
/// \param period Period value.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_SetPeriod(unsigned char channel, unsigned short period)
|
||||
{
|
||||
// If channel is disabled, write to CPRD
|
||||
if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
|
||||
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR = period;
|
||||
}
|
||||
// Otherwise use update register
|
||||
else {
|
||||
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR |= AT91C_PWMC_CPD;
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CUPDR = period;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the duty cycle used by a PWM channel. This function writes directly to
|
||||
/// the CDTY register if the channel is disabled; otherwise it uses the
|
||||
/// update register CUPD.
|
||||
/// Note that the duty cycle must always be inferior or equal to the channel
|
||||
/// period.
|
||||
/// \param channel Channel number.
|
||||
/// \param duty Duty cycle value.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)
|
||||
{
|
||||
SANITY_CHECK(duty <= AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CPRDR);
|
||||
|
||||
// SAM7S errata
|
||||
#if defined(at91sam7s16) || defined(at91sam7s161) || defined(at91sam7s32) \
|
||||
|| defined(at91sam7s321) || defined(at91sam7s64) || defined(at91sam7s128) \
|
||||
|| defined(at91sam7s256) || defined(at91sam7s512)
|
||||
ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");
|
||||
ASSERT((duty > 1) || (AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR & AT91C_PWMC_CALG),
|
||||
"-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");
|
||||
#endif
|
||||
|
||||
// If channel is disabled, write to CDTY
|
||||
if ((AT91C_BASE_PWMC->PWMC_SR & (1 << channel)) == 0) {
|
||||
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CDTYR = duty;
|
||||
}
|
||||
// Otherwise use update register
|
||||
else {
|
||||
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CMR &= ~AT91C_PWMC_CPD;
|
||||
AT91C_BASE_PWMC->PWMC_CH[channel].PWMC_CUPDR = duty;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the given PWM channel. This does NOT enable the corresponding pin;
|
||||
/// this must be done in the user code.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_EnableChannel(unsigned char channel)
|
||||
{
|
||||
AT91C_BASE_PWMC->PWMC_ENA = 1 << channel;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the given PWM channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_DisableChannel(unsigned char channel)
|
||||
{
|
||||
AT91C_BASE_PWMC->PWMC_DIS = 1 << channel;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the period interrupt for the given PWM channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_EnableChannelIt(unsigned char channel)
|
||||
{
|
||||
AT91C_BASE_PWMC->PWMC_IER = 1 << channel;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the period interrupt for the given PWM channel.
|
||||
/// \param channel Channel number.
|
||||
//------------------------------------------------------------------------------
|
||||
void PWMC_DisableChannelIt(unsigned char channel)
|
||||
{
|
||||
AT91C_BASE_PWMC->PWMC_IDR = 1 << channel;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef PWMC_H
|
||||
#define PWMC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void PWMC_ConfigureChannel(
|
||||
unsigned char channel,
|
||||
unsigned int prescaler,
|
||||
unsigned int alignment,
|
||||
unsigned int polarity);
|
||||
|
||||
extern void PWMC_ConfigureClocks
|
||||
(unsigned int clka,
|
||||
unsigned int clkb,
|
||||
unsigned int mck);
|
||||
|
||||
extern void PWMC_SetPeriod(unsigned char channel, unsigned short period);
|
||||
|
||||
extern void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty);
|
||||
|
||||
extern void PWMC_EnableChannel(unsigned char channel);
|
||||
|
||||
extern void PWMC_DisableChannel(unsigned char channel);
|
||||
|
||||
extern void PWMC_EnableChannelIt(unsigned char channel);
|
||||
|
||||
extern void PWMC_DisableChannelIt(unsigned char channel);
|
||||
|
||||
#endif //#ifndef PWMC_H
|
||||
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Headers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Macros
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/// WRITE_RSTC: Write RSTC register
|
||||
#define WRITE_RSTC(pRstc, regName, value) pRstc->regName = (value)
|
||||
|
||||
/// READ_RSTC: Read RSTC registers
|
||||
#define READ_RSTC(pRstc, regName) (pRstc->regName)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Defines
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/// Keywords to write to the reset registers
|
||||
#define RSTC_KEY_PASSWORD (0xA5UL << 24)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Configure the mode of the RSTC peripheral.
|
||||
/// The configuration is computed by the lib (AT91C_RSTC_*).
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
/// \param rmr Desired mode configuration.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_ConfigureMode(AT91PS_RSTC rstc, unsigned int rmr)
|
||||
{
|
||||
rmr &= ~AT91C_RSTC_KEY;
|
||||
WRITE_RSTC(rstc, RSTC_RMR, rmr | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable/Disable the detection of a low level on the pin NRST as User Reset
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
/// \param enable 1 to enable & 0 to disable.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_SetUserResetEnable(AT91PS_RSTC rstc, unsigned char enable)
|
||||
{
|
||||
unsigned int rmr = READ_RSTC(rstc, RSTC_RMR) & (~AT91C_RSTC_KEY);
|
||||
if (enable) {
|
||||
|
||||
rmr |= AT91C_RSTC_URSTEN;
|
||||
}
|
||||
else {
|
||||
|
||||
rmr &= ~AT91C_RSTC_URSTEN;
|
||||
}
|
||||
WRITE_RSTC(rstc, RSTC_RMR, rmr | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enable/Disable the interrupt of a User Reset (USRTS bit in RSTC_RST).
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
/// \param enable 1 to enable & 0 to disable.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_SetUserResetInterruptEnable(AT91PS_RSTC rstc, unsigned char enable)
|
||||
{
|
||||
unsigned int rmr = READ_RSTC(rstc, RSTC_RMR) & (~AT91C_RSTC_KEY);
|
||||
if (enable) {
|
||||
|
||||
rmr |= AT91C_RSTC_URSTIEN;
|
||||
}
|
||||
else {
|
||||
|
||||
rmr &= ~AT91C_RSTC_URSTIEN;
|
||||
}
|
||||
WRITE_RSTC(rstc, RSTC_RMR, rmr | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Setup the external reset length. The length is asserted during a time of
|
||||
/// pow(2, powl+1) Slow Clock(32KHz). The duration is between 60us and 2s.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
/// \param powl Power length defined.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_SetExtResetLength(AT91PS_RSTC rstc, unsigned char powl)
|
||||
{
|
||||
unsigned int rmr = READ_RSTC(rstc, RSTC_RMR);
|
||||
rmr &= ~(AT91C_RSTC_KEY | AT91C_RSTC_ERSTL);
|
||||
rmr |= (powl << 8) & AT91C_RSTC_ERSTL;
|
||||
WRITE_RSTC(rstc, RSTC_RMR, rmr | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Resets the processor.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_ProcessorReset(AT91PS_RSTC rstc)
|
||||
{
|
||||
WRITE_RSTC(rstc, RSTC_RCR, AT91C_RSTC_PROCRST | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Resets the peripherals.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_PeripheralReset(AT91PS_RSTC rstc)
|
||||
{
|
||||
WRITE_RSTC(rstc, RSTC_RCR, AT91C_RSTC_PERRST | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Asserts the NRST pin for external resets.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
void RSTC_ExtReset(AT91PS_RSTC rstc)
|
||||
{
|
||||
WRITE_RSTC(rstc, RSTC_RCR, AT91C_RSTC_EXTRST | RSTC_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Return NRST pin level ( 1 or 0 ).
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char RSTC_GetNrstLevel(AT91PS_RSTC rstc)
|
||||
{
|
||||
if (READ_RSTC(rstc, RSTC_RSR) & AT91C_RSTC_NRSTL) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns 1 if at least one high-to-low transition of NRST (User Reset) has
|
||||
/// been detected since the last read of RSTC_RSR.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char RSTC_IsUserReseetDetected(AT91PS_RSTC rstc)
|
||||
{
|
||||
if (READ_RSTC(rstc, RSTC_RSR) & AT91C_RSTC_URSTS) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Return 1 if a software reset command is being performed by the reset
|
||||
/// controller. The reset controller is busy.
|
||||
/// \param rstc Pointer to an RSTC peripheral.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char RSTC_IsBusy(AT91PS_RSTC rstc)
|
||||
{
|
||||
if (READ_RSTC(rstc, RSTC_RSR) & AT91C_RSTC_SRCMP) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef _RSTC_H
|
||||
#define _RSTC_H
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
extern void RSTC_ConfigureMode(AT91PS_RSTC rstc, unsigned int rmr);
|
||||
|
||||
extern void RSTC_SetUserResetEnable(AT91PS_RSTC rstc, unsigned char enable);
|
||||
|
||||
extern void RSTC_SetUserResetInterruptEnable(AT91PS_RSTC rstc,
|
||||
unsigned char enable);
|
||||
|
||||
extern void RSTC_SetExtResetLength(AT91PS_RSTC rstc, unsigned char powl);
|
||||
|
||||
extern void RSTC_ProcessorReset(AT91PS_RSTC rstc);
|
||||
|
||||
extern void RSTC_PeripheralReset(AT91PS_RSTC rstc);
|
||||
|
||||
extern void RSTC_ExtReset(AT91PS_RSTC rstc);
|
||||
|
||||
extern unsigned char RSTC_GetNrstLevel(AT91PS_RSTC rstc);
|
||||
|
||||
extern unsigned char RSTC_IsUserReseetDetected(AT91PS_RSTC rstc);
|
||||
|
||||
extern unsigned char RSTC_IsBusy(AT91PS_RSTC rstc);
|
||||
|
||||
#endif // #ifndef _RSTC_H
|
||||
338
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/rtc/rtc.c
Normal file
338
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/rtc/rtc.c
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL trace_INFO
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "rtc.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the RTC in either 12- or 24-hour mode.
|
||||
/// \param mode Hour mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_SetHourMode(unsigned int mode)
|
||||
{
|
||||
SANITY_CHECK((mode & 0xFFFFFFFE) == 0);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_SetHourMode()\n\r");
|
||||
|
||||
AT91C_BASE_RTC->RTC_MR = mode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the selected interrupt sources of the RTC.
|
||||
/// \param sources Interrupt sources to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_EnableIt(unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK((sources & ~0x1F) == 0);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_EnableIt()\n\r");
|
||||
|
||||
AT91C_BASE_RTC->RTC_IER = sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the selected interrupt sources of the RTC.
|
||||
/// \param sources Interrupt sources to disable.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_DisableIt(unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK((sources & ~0x1F) == 0);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_DisableIt()\n\r");
|
||||
|
||||
AT91C_BASE_RTC->RTC_IDR = sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the current time in the RTC.
|
||||
/// \param hour Current hour.
|
||||
/// \param minute Current minute.
|
||||
/// \param second Current second.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_SetTime(unsigned char hour, unsigned char minute, unsigned char second)
|
||||
{
|
||||
unsigned int time;
|
||||
|
||||
SANITY_CHECK(hour < 24);
|
||||
SANITY_CHECK(minute < 60);
|
||||
SANITY_CHECK(second < 60);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_SetTime(%02d:%02d:%02d)\n\r", hour, minute, second);
|
||||
|
||||
time = (second % 10) | ((second / 10) << 4)
|
||||
| ((minute % 10) << 8) | ((minute / 10) << 12);
|
||||
|
||||
// 12-hour mode
|
||||
if ((AT91C_BASE_RTC->RTC_MR & AT91C_RTC_HRMOD) == AT91C_RTC_HRMOD) {
|
||||
|
||||
if (hour > 12) {
|
||||
|
||||
hour -= 12;
|
||||
time |= AT91C_RTC_AMPM;
|
||||
}
|
||||
}
|
||||
|
||||
time |= ((hour % 10) << 16) | ((hour / 10) << 20);
|
||||
|
||||
// Set time
|
||||
AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDTIM;
|
||||
while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD);
|
||||
AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD;
|
||||
AT91C_BASE_RTC->RTC_TIMR = time;
|
||||
AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDTIM;
|
||||
SANITY_CHECK((AT91C_BASE_RTC->RTC_CR & AT91C_RTC_UPDTIM) != AT91C_RTC_UPDTIM);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Retrieves the current time as stored in the RTC in several variables.
|
||||
/// \param pHour If not null, current hour is stored in this variable.
|
||||
/// \param pMinute If not null, current minute is stored in this variable.
|
||||
/// \param pSecond If not null, current second is stored in this variable.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_GetTime(
|
||||
unsigned char *pHour,
|
||||
unsigned char *pMinute,
|
||||
unsigned char *pSecond)
|
||||
{
|
||||
unsigned int time;
|
||||
|
||||
SANITY_CHECK(pHour || pMinute || pSecond);
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_GetTime()\n\r");
|
||||
|
||||
// Get current RTC time
|
||||
time = AT91C_BASE_RTC->RTC_TIMR;
|
||||
while (time != AT91C_BASE_RTC->RTC_TIMR) {
|
||||
|
||||
time = AT91C_BASE_RTC->RTC_TIMR;
|
||||
}
|
||||
|
||||
// Hour
|
||||
if (pHour) {
|
||||
|
||||
*pHour = ((time & 0x00300000) >> 20) * 10
|
||||
+ ((time & 0x000F0000) >> 16);
|
||||
if ((time & AT91C_RTC_AMPM) == AT91C_RTC_AMPM) {
|
||||
|
||||
*pHour += 12;
|
||||
}
|
||||
}
|
||||
|
||||
// Minute
|
||||
if (pMinute) {
|
||||
|
||||
*pMinute = ((time & 0x00007000) >> 12) * 10
|
||||
+ ((time & 0x00000F00) >> 8);
|
||||
}
|
||||
|
||||
// Second
|
||||
if (pSecond) {
|
||||
|
||||
*pSecond = ((time & 0x00000070) >> 4) * 10
|
||||
+ (time & 0x0000000F);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets a time alarm on the RTC. The match is performed only on the provided
|
||||
/// variables; setting all pointers to 0 disables the time alarm.
|
||||
/// Note: in AM/PM mode, the hour value must have bit #7 set for PM, cleared for
|
||||
/// AM (as expected in the time registers).
|
||||
/// \param pHour If not null, the time alarm will hour-match this value.
|
||||
/// \param pMinute If not null, the time alarm will minute-match this value.
|
||||
/// \param pSecond If not null, the time alarm will second-match this value.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_SetTimeAlarm(
|
||||
unsigned char *pHour,
|
||||
unsigned char *pMinute,
|
||||
unsigned char *pSecond)
|
||||
{
|
||||
unsigned int alarm = 0;
|
||||
|
||||
SANITY_CHECK(!pHour || ((*pHour & 0x80) == 0));
|
||||
SANITY_CHECK(!pMinute || (*pMinute < 60));
|
||||
SANITY_CHECK(!pSecond || (*pSecond < 60));
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_SetTimeAlarm()\n\r");
|
||||
|
||||
// Hour
|
||||
if (pHour) {
|
||||
|
||||
alarm |= AT91C_RTC_HOUREN | ((*pHour / 10) << 20) | ((*pHour % 10) << 16);
|
||||
}
|
||||
|
||||
// Minute
|
||||
if (pMinute) {
|
||||
|
||||
alarm |= AT91C_RTC_MINEN | ((*pMinute / 10) << 12) | ((*pMinute % 10) << 8);
|
||||
}
|
||||
|
||||
// Second
|
||||
if (pSecond) {
|
||||
|
||||
alarm |= AT91C_RTC_SECEN | ((*pSecond / 10) << 4) | (*pSecond % 10);
|
||||
}
|
||||
|
||||
AT91C_BASE_RTC->RTC_TIMALR = alarm;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Retrieves the current year, month and day from the RTC. Month, day and week
|
||||
/// values are numbered starting at 1.
|
||||
/// \param pYear Current year (optional).
|
||||
/// \param pMonth Current month (optional).
|
||||
/// \param pDay Current day (optional).
|
||||
/// \param pWeek Current day in current week (optional).
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_GetDate(
|
||||
unsigned short *pYear,
|
||||
unsigned char *pMonth,
|
||||
unsigned char *pDay,
|
||||
unsigned char *pWeek)
|
||||
{
|
||||
unsigned int date;
|
||||
|
||||
// Get current date (multiple reads are necessary to insure a stable value)
|
||||
do {
|
||||
|
||||
date = AT91C_BASE_RTC->RTC_CALR;
|
||||
}
|
||||
while (date != AT91C_BASE_RTC->RTC_CALR);
|
||||
|
||||
// Retrieve year
|
||||
if (pYear) {
|
||||
|
||||
*pYear = (((date >> 4) & 0x7) * 1000)
|
||||
+ ((date & 0xF) * 100)
|
||||
+ (((date >> 12) & 0xF) * 10)
|
||||
+ ((date >> 8) & 0xF);
|
||||
}
|
||||
|
||||
// Retrieve month
|
||||
if (pMonth) {
|
||||
|
||||
*pMonth = (((date >> 20) & 1) * 10) + ((date >> 16) & 0xF);
|
||||
}
|
||||
|
||||
// Retrieve day
|
||||
if (pDay) {
|
||||
|
||||
*pDay = (((date >> 28) & 0x3) * 10) + ((date >> 24) & 0xF);
|
||||
}
|
||||
|
||||
// Retrieve week
|
||||
if (pWeek) {
|
||||
|
||||
*pWeek = ((date >> 21) & 0x7);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the current year, month and day in the RTC. Month, day and week values
|
||||
/// must be numbered starting from 1.
|
||||
/// \param year Current year.
|
||||
/// \param month Current month.
|
||||
/// \param day Current day.
|
||||
/// \param week Day number in current week.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_SetDate(
|
||||
unsigned short year,
|
||||
unsigned char month,
|
||||
unsigned char day,
|
||||
unsigned char week)
|
||||
{
|
||||
unsigned int date;
|
||||
|
||||
SANITY_CHECK((year >= 1900) && (year <= 2099));
|
||||
SANITY_CHECK((month >= 1) && (month <= 12));
|
||||
SANITY_CHECK((day >= 1) && (day <= 31));
|
||||
SANITY_CHECK((week >= 1) && (week <= 7));
|
||||
|
||||
// Convert values to date register value
|
||||
date = ((year / 100) % 10)
|
||||
| ((year / 1000) << 4)
|
||||
| ((year % 10) << 8)
|
||||
| (((year / 10) % 10) << 12)
|
||||
| ((month % 10) << 16)
|
||||
| ((month / 10) << 20)
|
||||
| (week << 21)
|
||||
| ((day % 10) << 24)
|
||||
| ((day / 10) << 28);
|
||||
|
||||
// Update calendar register
|
||||
AT91C_BASE_RTC->RTC_CR |= AT91C_RTC_UPDCAL;
|
||||
while ((AT91C_BASE_RTC->RTC_SR & AT91C_RTC_ACKUPD) != AT91C_RTC_ACKUPD);
|
||||
AT91C_BASE_RTC->RTC_SCCR = AT91C_RTC_ACKUPD;
|
||||
AT91C_BASE_RTC->RTC_CALR = date;
|
||||
AT91C_BASE_RTC->RTC_CR &= ~AT91C_RTC_UPDCAL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets a date alarm in the RTC. The alarm will match only the provided values;
|
||||
/// passing a null-pointer disables the corresponding field match.
|
||||
/// \param pMonth If not null, the RTC alarm will month-match this value.
|
||||
/// \param pDay If not null, the RTC alarm will day-match this value.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTC_SetDateAlarm(unsigned char *pMonth, unsigned char *pDay)
|
||||
{
|
||||
unsigned int alarm = 0;
|
||||
|
||||
SANITY_CHECK(!pMonth || ((*pMonth >= 1) && (*pMonth <= 12)));
|
||||
SANITY_CHECK(!pDay || ((*pDay >= 1) && (*pDay <= 31)));
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- RTC_SetDateAlarm()\n\r");
|
||||
|
||||
// Compute alarm field value
|
||||
if (pMonth) {
|
||||
|
||||
alarm |= AT91C_RTC_MONTHEN | ((*pMonth / 10) << 20) | ((*pMonth % 10) << 16);
|
||||
}
|
||||
if (pDay) {
|
||||
|
||||
alarm |= AT91C_RTC_DATEEN | ((*pDay / 10) << 28) | ((*pDay % 10) << 24);
|
||||
}
|
||||
|
||||
// Set alarm
|
||||
AT91C_BASE_RTC->RTC_CALALR = alarm;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTC_H
|
||||
#define RTC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void RTC_SetHourMode(unsigned int mode);
|
||||
|
||||
extern void RTC_EnableIt(unsigned int sources);
|
||||
|
||||
extern void RTC_DisableIt(unsigned int sources);
|
||||
|
||||
extern void RTC_SetTime(
|
||||
unsigned char hour,
|
||||
unsigned char minute,
|
||||
unsigned char second);
|
||||
|
||||
extern void RTC_GetTime(
|
||||
unsigned char *pHour,
|
||||
unsigned char *pMinute,
|
||||
unsigned char *pSecond);
|
||||
|
||||
extern void RTC_SetTimeAlarm(
|
||||
unsigned char *pHour,
|
||||
unsigned char *pMinute,
|
||||
unsigned char *pSecond);
|
||||
|
||||
void RTC_GetDate(
|
||||
unsigned short *pYear,
|
||||
unsigned char *pMonth,
|
||||
unsigned char *pDay,
|
||||
unsigned char *pWeek);
|
||||
|
||||
extern void RTC_SetDate(
|
||||
unsigned short year,
|
||||
unsigned char month,
|
||||
unsigned char day,
|
||||
unsigned char week);
|
||||
|
||||
extern void RTC_SetDateAlarm(unsigned char *pMonth, unsigned char *pDay);
|
||||
|
||||
#endif //#ifndef RTC_H
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "rtt.h"
|
||||
#include <utility/assert.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Changes the prescaler value of the given RTT and restarts it. This function
|
||||
/// disables RTT interrupt sources.
|
||||
/// \param rtt Pointer to a AT91S_RTTC instance.
|
||||
/// \param prescaler Prescaler value for the RTT.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTT_SetPrescaler(AT91S_RTTC *rtt, unsigned short prescaler)
|
||||
{
|
||||
rtt->RTTC_RTMR = (prescaler | AT91C_RTTC_RTTRST);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the current value of the RTT timer value.
|
||||
/// \param rtt Pointer to a AT91S_RTTC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int RTT_GetTime(AT91S_RTTC *rtt)
|
||||
{
|
||||
return rtt->RTTC_RTVR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the specified RTT interrupt sources.
|
||||
/// \param rtt Pointer to a AT91S_RTTC instance.
|
||||
/// \param sources Bitmask of interrupts to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTT_EnableIT(AT91S_RTTC *rtt, unsigned int sources)
|
||||
{
|
||||
ASSERT((sources & 0x0004FFFF) == 0,
|
||||
"RTT_EnableIT: Wrong sources value.\n\r");
|
||||
rtt->RTTC_RTMR |= sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the status register value of the given RTT.
|
||||
/// \param rtt Pointer to an AT91S_RTTC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int RTT_GetStatus(AT91S_RTTC *rtt)
|
||||
{
|
||||
return rtt->RTTC_RTSR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the RTT to generate an alarm at the given time.
|
||||
/// \param pRtt Pointer to an AT91S_RTTC instance.
|
||||
/// \param time Alarm time.
|
||||
//------------------------------------------------------------------------------
|
||||
void RTT_SetAlarm(AT91S_RTTC *pRtt, unsigned int time)
|
||||
{
|
||||
SANITY_CHECK(time > 0);
|
||||
|
||||
pRtt->RTTC_RTAR = time - 1;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef RTT_H
|
||||
#define RTT_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef AT91C_BASE_RTTC
|
||||
#define AT91C_BASE_RTTC AT91C_BASE_RTTC0
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void RTT_SetPrescaler(AT91S_RTTC *rtt, unsigned short prescaler);
|
||||
|
||||
extern unsigned int RTT_GetTime(AT91S_RTTC *rtt);
|
||||
|
||||
extern void RTT_EnableIT(AT91S_RTTC *rtt, unsigned int sources);
|
||||
|
||||
extern unsigned int RTT_GetStatus(AT91S_RTTC *rtt);
|
||||
|
||||
extern void RTT_SetAlarm(AT91S_RTTC *pRtt, unsigned int time);
|
||||
|
||||
#endif //#ifndef RTT_H
|
||||
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "slcdc.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Size of SLCDC buffer in bytes.
|
||||
#define BUFFER_SIZE 320
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Initializes the Segment LCD controller.
|
||||
/// \param commons Number of commons used by the display.
|
||||
/// \param segments Number of segments used by the display.
|
||||
/// \param bias Bias value.
|
||||
/// \param timeSetting Buffer timing value.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_Configure(
|
||||
unsigned int commons,
|
||||
unsigned int segments,
|
||||
unsigned int bias,
|
||||
unsigned int timeSetting)
|
||||
{
|
||||
SANITY_CHECK((commons > 0) && (commons <= 10));
|
||||
SANITY_CHECK((segments > 0) && (segments <= 40));
|
||||
SANITY_CHECK((bias & ~AT91C_SLCDC_BIAS) == 0);
|
||||
SANITY_CHECK((timeSetting & ~(0xF << 16)) == 0);
|
||||
SANITY_CHECK((timeSetting >> 16) < 0x0A);
|
||||
|
||||
// Enable peripheral clock
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SLCD;
|
||||
AT91C_BASE_SLCDC->SLCDC_MR = (commons - 1) | ((segments - 1) << 8) | bias | timeSetting;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Clears the SLCD display buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_Clear(void)
|
||||
{
|
||||
memset((void *) AT91C_BASE_SLCDC->SLCDC_MEM, 0, BUFFER_SIZE);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the SLCD controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_Enable(void)
|
||||
{
|
||||
AT91C_BASE_SLCDC->SLCDC_CR = AT91C_SLCDC_LCDEN;
|
||||
while (AT91C_BASE_SLCDC -> SLCDC_SR != AT91C_SLCDC_ENA);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the SLCD controller.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_Disable(void)
|
||||
{
|
||||
AT91C_BASE_SLCDC->SLCDC_CR = AT91C_SLCDC_LCDDIS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the SLCD low power mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_EnableLowPowerMode(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = AT91C_BASE_SLCDC->SLCDC_MR;
|
||||
value &= ~AT91C_SLCDC_LPMODE;
|
||||
value |=AT91C_SLCDC_LPMODE;
|
||||
AT91C_BASE_SLCDC->SLCDC_MR = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the SLCD low power mode
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_DisableLowPowerMode(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = AT91C_BASE_SLCDC->SLCDC_MR;
|
||||
value &= ~AT91C_SLCDC_LPMODE;
|
||||
AT91C_BASE_SLCDC->SLCDC_MR = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Adjusts the frame frequency. Frequency = FsCLK / (prescaler * divider . NCOM)
|
||||
/// \param prescalerValue Prescaler value
|
||||
/// \param dividerValue Divider value
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_SetFrameFreq(unsigned int prescalerValue, unsigned int dividerValue)
|
||||
{
|
||||
SANITY_CHECK((prescalerValue & ~AT91C_SLCDC_PRESC) == 0);
|
||||
SANITY_CHECK((dividerValue & (~(0x07 << 8))) == 0);
|
||||
|
||||
AT91C_BASE_SLCDC->SLCDC_FRR = prescalerValue | dividerValue;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the display mode (normal/force off/force on/blinking).
|
||||
/// \param mode Display mode to be set
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_SetDisplayMode(unsigned int mode)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
SANITY_CHECK(mode < 8);
|
||||
|
||||
value = AT91C_BASE_SLCDC->SLCDC_DR;
|
||||
value &= ~AT91C_SLCDC_DISPMODE;
|
||||
value |= mode;
|
||||
AT91C_BASE_SLCDC->SLCDC_DR = value;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Adjusts the display blinking frequency.
|
||||
/// Blinking frequency = Frame Frequency / LCDBLKFREQ.
|
||||
/// \param frequency Frequency value.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_SetBlinkFreq(unsigned int frequency)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
SANITY_CHECK((frequency & ~(0xFF << 8)) == 0);
|
||||
|
||||
value = AT91C_BASE_SLCDC->SLCDC_DR;
|
||||
value &= ~AT91C_SLCDC_BLKFREQ;
|
||||
value |= frequency;
|
||||
AT91C_BASE_SLCDC->SLCDC_DR = frequency;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the selected SLCDC interrupt sources.
|
||||
/// \param sources Interrupt sources to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_EnableInterrupts(unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK((sources & 0xFFFFFFFA) == 0);
|
||||
|
||||
AT91C_BASE_SLCDC->SLCDC_IER = sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the selected SLCDC interrupt sources.
|
||||
/// \param sources Interrupt sources to disable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SLCDC_DisableInterrupts(unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK((sources & 0xFFFFFFFA) == 0);
|
||||
|
||||
AT91C_BASE_SLCDC->SLCDC_IDR = sources;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef SLCDC_H
|
||||
#define SLCDC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Number of segments in SLCD.
|
||||
#define S7LEKLCD_NUM_SEGMENTS 40
|
||||
/// Number of commons in SLCD.
|
||||
#define S7LEKLCD_NUM_COMMONS 10
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void SLCDC_Configure(
|
||||
unsigned int commons,
|
||||
unsigned int segments,
|
||||
unsigned int bias,
|
||||
unsigned int timeSetting);
|
||||
|
||||
extern void SLCDC_Clear(void);
|
||||
|
||||
extern void SLCDC_Enable(void);
|
||||
|
||||
extern void SLCDC_Disable(void);
|
||||
|
||||
extern void SLCDC_SetFrameFreq(
|
||||
unsigned int prescalerValue,
|
||||
unsigned int dividerValue);
|
||||
|
||||
extern void SLCDC_SetDisplayMode(unsigned int mode);
|
||||
|
||||
extern void SLCDC_SetBlinkFreq(unsigned int frequency);
|
||||
|
||||
extern void SLCDC_EnableInterrupts(unsigned int sources);
|
||||
|
||||
extern void SLCDC_DisableInterrupts(unsigned int sources);
|
||||
|
||||
#endif //#ifndef SLCDC_H
|
||||
|
||||
189
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/spi/spi.c
Normal file
189
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/spi/spi.c
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "spi.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables a SPI peripheral
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SPI_Enable(AT91S_SPI *spi)
|
||||
{
|
||||
spi->SPI_CR = AT91C_SPI_SPIEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables a SPI peripheral.
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SPI_Disable(AT91S_SPI *spi)
|
||||
{
|
||||
spi->SPI_CR = AT91C_SPI_SPIDIS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a SPI peripheral as specified. The configuration can be computed
|
||||
/// using several macros (see "SPI configuration macros") and the constants
|
||||
/// defined in LibV3 (AT91C_SPI_*).
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
/// \param id Peripheral ID of the SPI.
|
||||
/// \param configuration Value of the SPI configuration register.
|
||||
//------------------------------------------------------------------------------
|
||||
void SPI_Configure(AT91S_SPI *spi,
|
||||
unsigned int id,
|
||||
unsigned int configuration)
|
||||
{
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << id;
|
||||
spi->SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST;
|
||||
spi->SPI_MR = configuration;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a chip select of a SPI peripheral. The chip select configuration
|
||||
/// is computed using the definition provided by the LibV3 (AT91C_SPI_*).
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
/// \param npcs Chip select to configure (1, 2, 3 or 4).
|
||||
/// \param configuration Desired chip select configuration.
|
||||
//------------------------------------------------------------------------------
|
||||
void SPI_ConfigureNPCS(AT91S_SPI *spi,
|
||||
unsigned int npcs,
|
||||
unsigned int configuration)
|
||||
{
|
||||
spi->SPI_CSR[npcs] = configuration;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends data through a SPI peripheral. If the SPI is configured to use a fixed
|
||||
/// peripheral select, the npcs value is meaningless. Otherwise, it identifies
|
||||
/// the component which shall be addressed.
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
/// \param npcs Chip select of the component to address (1, 2, 3 or 4).
|
||||
/// \param data Word of data to send.
|
||||
//------------------------------------------------------------------------------
|
||||
void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data)
|
||||
{
|
||||
// Discard contents of RDR register
|
||||
//volatile unsigned int discard = spi->SPI_RDR;
|
||||
|
||||
// Send data
|
||||
while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
|
||||
spi->SPI_TDR = data | SPI_PCS(npcs);
|
||||
while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends the contents of buffer through a SPI peripheral, using the PDC to
|
||||
/// take care of the transfer.
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
/// \param buffer Data buffer to send.
|
||||
/// \param length Length of the data buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char SPI_WriteBuffer(AT91S_SPI *spi,
|
||||
void *buffer,
|
||||
unsigned int length)
|
||||
{
|
||||
// Check if first bank is free
|
||||
if (spi->SPI_TCR == 0) {
|
||||
|
||||
spi->SPI_TPR = (unsigned int) buffer;
|
||||
spi->SPI_TCR = length;
|
||||
spi->SPI_PTCR = AT91C_PDC_TXTEN;
|
||||
return 1;
|
||||
}
|
||||
// Check if second bank is free
|
||||
else if (spi->SPI_TNCR == 0) {
|
||||
|
||||
spi->SPI_TNPR = (unsigned int) buffer;
|
||||
spi->SPI_TNCR = length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No free banks
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if there is no pending write operation on the SPI; otherwise
|
||||
/// returns 0.
|
||||
/// \param pSpi Pointer to an AT91S_SPI instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char SPI_IsFinished(AT91S_SPI *pSpi)
|
||||
{
|
||||
return ((pSpi->SPI_SR & AT91C_SPI_TXEMPTY) != 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads and returns the last word of data received by a SPI peripheral. This
|
||||
/// method must be called after a successful SPI_Write call.
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned short SPI_Read(AT91S_SPI *spi)
|
||||
{
|
||||
while ((spi->SPI_SR & AT91C_SPI_RDRF) == 0);
|
||||
return spi->SPI_RDR & 0xFFFF;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads data from a SPI peripheral until the provided buffer is filled. This
|
||||
/// method does NOT need to be called after SPI_Write or SPI_WriteBuffer.
|
||||
/// \param spi Pointer to an AT91S_SPI instance.
|
||||
/// \param buffer Data buffer to store incoming bytes.
|
||||
/// \param length Length in bytes of the data buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char SPI_ReadBuffer(AT91S_SPI *spi,
|
||||
void *buffer,
|
||||
unsigned int length)
|
||||
{
|
||||
// Check if the first bank is free
|
||||
if (spi->SPI_RCR == 0) {
|
||||
|
||||
spi->SPI_RPR = (unsigned int) buffer;
|
||||
spi->SPI_RCR = length;
|
||||
spi->SPI_PTCR = AT91C_PDC_RXTEN;
|
||||
return 1;
|
||||
}
|
||||
// Check if second bank is free
|
||||
else if (spi->SPI_RNCR == 0) {
|
||||
|
||||
spi->SPI_RNPR = (unsigned int) buffer;
|
||||
spi->SPI_RNCR = length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No free bank
|
||||
return 0;
|
||||
}
|
||||
|
||||
114
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/spi/spi.h
Normal file
114
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/spi/spi.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Definitions for SPI peripheral usage.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Enable the SPI pins required by the application (see pio.h).
|
||||
/// -# Configure the SPI using the SPI_Configure function. This enables the
|
||||
/// peripheral clock. The mode register is loaded with the given value.
|
||||
/// -# Configure all the necessary chip selects with SPI_ConfigureNPCS.
|
||||
/// -# Enable the SPI by calling SPI_Enable.
|
||||
/// -# Send/receive data using SPI_Write and SPI_Read. Note that SPI_Read
|
||||
/// must be called after SPI_Write to retrieve the last value read.
|
||||
/// -# Send/receive data using the PDC with the SPI_WriteBuffer and
|
||||
/// SPI_ReadBuffer functions.
|
||||
/// -# Disable the SPI by calling SPI_Disable.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef SPI_H
|
||||
#define SPI_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SPI configuration macros"
|
||||
/// This page lists several macros which should be used when configuring a SPI
|
||||
/// peripheral.
|
||||
///
|
||||
/// !Macros
|
||||
/// - SPI_PCS
|
||||
/// - SPI_SCBR
|
||||
/// - SPI_DLYBS
|
||||
/// - SPI_DLYBCT
|
||||
|
||||
/// Calculate the PCS field value given the chip select NPCS value
|
||||
#define SPI_PCS(npcs) ((~(1 << npcs) & 0xF) << 16)
|
||||
|
||||
/// Calculates the value of the CSR SCBR field given the baudrate and MCK.
|
||||
#define SPI_SCBR(baudrate, masterClock) \
|
||||
((unsigned int) (masterClock / baudrate) << 8)
|
||||
|
||||
/// Calculates the value of the CSR DLYBS field given the desired delay (in ns)
|
||||
#define SPI_DLYBS(delay, masterClock) \
|
||||
((unsigned int) (((masterClock / 1000000) * delay) / 1000) << 16)
|
||||
|
||||
/// Calculates the value of the CSR DLYBCT field given the desired delay (in ns)
|
||||
#define SPI_DLYBCT(delay, masterClock) \
|
||||
((unsigned int) (((masterClock / 1000000) * delay) / 32000) << 16)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern void SPI_Enable(AT91S_SPI *spi);
|
||||
extern void SPI_Disable(AT91S_SPI *spi);
|
||||
extern void SPI_Configure(AT91S_SPI *spi,
|
||||
unsigned int id,
|
||||
unsigned int configuration);
|
||||
extern void SPI_ConfigureNPCS(AT91S_SPI *spi,
|
||||
unsigned int npcs,
|
||||
unsigned int configuration);
|
||||
extern void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data);
|
||||
extern unsigned char SPI_WriteBuffer(AT91S_SPI *spi,
|
||||
void *buffer,
|
||||
unsigned int length);
|
||||
|
||||
extern unsigned char SPI_IsFinished(AT91S_SPI *pSpi);
|
||||
|
||||
extern unsigned short SPI_Read(AT91S_SPI *spi);
|
||||
extern unsigned char SPI_ReadBuffer(AT91S_SPI *spi,
|
||||
void *buffer,
|
||||
unsigned int length);
|
||||
|
||||
#endif //#ifndef SPI_H
|
||||
|
||||
243
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/ssc/ssc.c
Normal file
243
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/ssc/ssc.c
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "ssc.h"
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a SSC peripheral. If the divided clock is not used, the master
|
||||
/// clock frequency can be set to 0.
|
||||
/// \note The emitter and transmitter are disabled by this function.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param id Peripheral ID of the SSC.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_Configure(AT91S_SSC *ssc,
|
||||
unsigned int id,
|
||||
unsigned int bitRate,
|
||||
unsigned int masterClock)
|
||||
{
|
||||
// Enable SSC peripheral clock
|
||||
AT91C_BASE_PMC->PMC_PCER = 1 << id;
|
||||
|
||||
// Reset, disable receiver & transmitter
|
||||
ssc->SSC_CR = AT91C_SSC_RXDIS | AT91C_SSC_TXDIS | AT91C_SSC_SWRST;
|
||||
ssc->SSC_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
|
||||
|
||||
// Configure clock frequency
|
||||
if (bitRate != 0) {
|
||||
|
||||
ssc->SSC_CMR = masterClock / (2 * bitRate);
|
||||
}
|
||||
else {
|
||||
|
||||
ssc->SSC_CMR = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the transmitter of a SSC peripheral. Several macros can be used
|
||||
/// to compute the values of the Transmit Clock Mode Register (TCMR) and the
|
||||
/// Transmit Frame Mode Register (TFMR) (see "SSC configuration macros").
|
||||
/// \param ssc Pointer to a AT91S_SSC instance.
|
||||
/// \param tcmr Transmit Clock Mode Register value.
|
||||
/// \param tfmr Transmit Frame Mode Register value.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_ConfigureTransmitter(AT91S_SSC *ssc,
|
||||
unsigned int tcmr,
|
||||
unsigned int tfmr)
|
||||
{
|
||||
ssc->SSC_TCMR = tcmr;
|
||||
ssc->SSC_TFMR = tfmr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the receiver of a SSC peripheral. Several macros can be used
|
||||
/// to compute the values of the Receive Clock Mode Register (TCMR) and the
|
||||
/// Receive Frame Mode Register (TFMR) (see "SSC configuration macros").
|
||||
/// \param ssc Pointer to a AT91S_SSC instance.
|
||||
/// \param rcmr Receive Clock Mode Register value.
|
||||
/// \param rfmr Receive Frame Mode Register value.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_ConfigureReceiver(AT91S_SSC *ssc,
|
||||
unsigned int rcmr,
|
||||
unsigned int rfmr)
|
||||
{
|
||||
ssc->SSC_RCMR = rcmr;
|
||||
ssc->SSC_RFMR = rfmr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the transmitter of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_EnableTransmitter(AT91S_SSC *ssc)
|
||||
{
|
||||
ssc->SSC_CR = AT91C_SSC_TXEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the transmitter of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_DisableTransmitter(AT91S_SSC *ssc)
|
||||
{
|
||||
ssc->SSC_CR = AT91C_SSC_TXDIS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the receiver of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_EnableReceiver(AT91S_SSC *ssc)
|
||||
{
|
||||
ssc->SSC_CR = AT91C_SSC_RXEN;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the receiver of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_DisableReceiver(AT91S_SSC *ssc)
|
||||
{
|
||||
ssc->SSC_CR = AT91C_SSC_RXDIS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables one or more interrupt sources of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param sources Interrupt sources to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_EnableInterrupts(AT91S_SSC *ssc, unsigned int sources)
|
||||
{
|
||||
ssc->SSC_IER = sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables one or more interrupt sources of a SSC peripheral.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param sources Interrupt source to disable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_DisableInterrupts(AT91S_SSC *ssc, unsigned int sources)
|
||||
{
|
||||
ssc->SSC_IDR = sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends one data frame through a SSC peripheral. If another frame is currently
|
||||
/// being sent, this function waits for the previous transfer to complete.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param frame Data frame to send.
|
||||
//------------------------------------------------------------------------------
|
||||
void SSC_Write(AT91S_SSC *ssc, unsigned int frame)
|
||||
{
|
||||
while ((ssc->SSC_SR & AT91C_SSC_TXRDY) == 0);
|
||||
ssc->SSC_THR = frame;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends the contents of a data buffer a SSC peripheral, using the PDC. Returns
|
||||
/// true if the buffer has been queued for transmission; otherwise returns
|
||||
/// false.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param buffer Data buffer to send.
|
||||
/// \param length Size of the data buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char SSC_WriteBuffer(AT91S_SSC *ssc,
|
||||
void *buffer,
|
||||
unsigned int length)
|
||||
{
|
||||
// Check if first bank is free
|
||||
if (ssc->SSC_TCR == 0) {
|
||||
|
||||
ssc->SSC_TPR = (unsigned int) buffer;
|
||||
ssc->SSC_TCR = length;
|
||||
ssc->SSC_PTCR = AT91C_PDC_TXTEN;
|
||||
return 1;
|
||||
}
|
||||
// Check if second bank is free
|
||||
else if (ssc->SSC_TNCR == 0) {
|
||||
|
||||
ssc->SSC_TNPR = (unsigned int) buffer;
|
||||
ssc->SSC_TNCR = length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No free banks
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Waits until one frame is received on a SSC peripheral, and returns it.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int SSC_Read(AT91S_SSC *ssc)
|
||||
{
|
||||
while ((ssc->SSC_SR & AT91C_SSC_RXRDY) == 0);
|
||||
return ssc->SSC_RHR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads data coming from a SSC peripheral receiver and stores it into the
|
||||
/// provided buffer. Returns true if the buffer has been queued for reception;
|
||||
/// otherwise returns false.
|
||||
/// \param ssc Pointer to an AT91S_SSC instance.
|
||||
/// \param buffer Data buffer used for reception.
|
||||
/// \param length Size in bytes of the data buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char SSC_ReadBuffer(AT91S_SSC *ssc,
|
||||
void *buffer,
|
||||
unsigned int length)
|
||||
{
|
||||
// Check if the first bank is free
|
||||
if (ssc->SSC_RCR == 0) {
|
||||
|
||||
ssc->SSC_RPR = (unsigned int) buffer;
|
||||
ssc->SSC_RCR = length;
|
||||
ssc->SSC_PTCR = AT91C_PDC_RXTEN;
|
||||
return 1;
|
||||
}
|
||||
// Check if second bank is free
|
||||
else if (ssc->SSC_RNCR == 0) {
|
||||
|
||||
ssc->SSC_RNPR = (unsigned int) buffer;
|
||||
ssc->SSC_RNCR = length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// No free bank
|
||||
return 0;
|
||||
}
|
||||
|
||||
133
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/ssc/ssc.h
Normal file
133
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/ssc/ssc.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \dir
|
||||
/// !Purpose
|
||||
///
|
||||
/// Set of functions and definition for using a SSC
|
||||
/// peripheral.
|
||||
///
|
||||
/// !Usage
|
||||
///
|
||||
/// -# Configure the SSC to operate at a specific frequency by calling
|
||||
/// SSC_Configure(). This function enables the peripheral clock of the SSC,
|
||||
/// but not its PIOs.
|
||||
/// -# Configure the transmitter and/or the receiver using the
|
||||
/// SSC_ConfigureTransmitter() and SSC_ConfigureEmitter() functions.
|
||||
/// -# Enable the PIOs or the transmitter and/or the received using
|
||||
/// CHIP_EnableSSCTransmitter() and CHIP_EnableSSCReceiver().
|
||||
/// -# Enable the transmitter and/or the receiver using SSC_EnableTransmitter()
|
||||
/// and SSC_EnableReceiver()
|
||||
/// -# Send data through the transmitter using SSC_Write() and SSC_WriteBuffer()
|
||||
/// -# Receive data from the receiver using SSC_Read() and SSC_ReadBuffer()
|
||||
/// -# Disable the transmitter and/or the receiver using SSC_DisableTransmitter()
|
||||
/// and SSC_DisableReceiver()
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef SSC_H
|
||||
#define SSC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// \page "SSC configuration macros"
|
||||
/// This page lists several macros which are used when configuring a SSC
|
||||
/// peripheral.
|
||||
///
|
||||
/// !Macros
|
||||
/// - SSC_STTDLY
|
||||
/// - SSC_PERIOD
|
||||
/// - SSC_DATLEN
|
||||
/// - SSC_DATNB
|
||||
/// - SSC_FSLEN
|
||||
|
||||
/// Calculates the value of the STTDLY field given the number of clock cycles
|
||||
/// before the first bit of a new frame is transmitted.
|
||||
#define SSC_STTDLY(bits) (bits << 16)
|
||||
|
||||
/// Calculates the value of the PERIOD field of the Transmit Clock Mode Register
|
||||
/// of an SSC interface, given the desired clock divider.
|
||||
#define SSC_PERIOD(divider) (((divider / 2) - 1) << 24)
|
||||
|
||||
/// Calculates the value of the DATLEN field of the Transmit Frame Mode Register
|
||||
/// of an SSC interface, given the number of bits in one sample.
|
||||
#define SSC_DATLEN(bits) (bits - 1)
|
||||
|
||||
/// Calculates the value of the DATNB field of the Transmit Frame Mode Register
|
||||
/// of an SSC interface, given the number of samples in one frame.
|
||||
#define SSC_DATNB(samples) ((samples -1) << 8)
|
||||
|
||||
/// Calculates the value of the FSLEN field of the Transmit Frame Mode Register
|
||||
/// of an SSC interface, given the number of transmit clock periods that the
|
||||
/// frame sync signal should take.
|
||||
#define SSC_FSLEN(periods) ((periods - 1) << 16)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
extern void SSC_Configure(AT91S_SSC *ssc,
|
||||
unsigned int id,
|
||||
unsigned int bitRate,
|
||||
unsigned int masterClock);
|
||||
extern void SSC_ConfigureTransmitter(AT91S_SSC *ssc,
|
||||
unsigned int tcmr,
|
||||
unsigned int tfmr);
|
||||
extern void SSC_ConfigureReceiver(AT91S_SSC *ssc,
|
||||
unsigned int rcmr,
|
||||
unsigned int rfmr);
|
||||
|
||||
extern void SSC_EnableTransmitter(AT91S_SSC *ssc);
|
||||
extern void SSC_DisableTransmitter(AT91S_SSC *ssc);
|
||||
extern void SSC_EnableReceiver(AT91S_SSC *ssc);
|
||||
extern void SSC_DisableReceiver(AT91S_SSC *ssc);
|
||||
|
||||
extern void SSC_EnableInterrupts(AT91S_SSC *ssc, unsigned int sources);
|
||||
extern void SSC_DisableInterrupts(AT91S_SSC *ssc, unsigned int sources);
|
||||
|
||||
extern void SSC_Write(AT91S_SSC *ssc, unsigned int frame);
|
||||
extern unsigned char SSC_WriteBuffer(AT91S_SSC *ssc,
|
||||
void *buffer,
|
||||
unsigned int length);
|
||||
extern unsigned int SSC_Read(AT91S_SSC *ssc);
|
||||
extern unsigned char SSC_ReadBuffer(AT91S_SSC *ssc,
|
||||
void *buffer,
|
||||
unsigned int length);
|
||||
|
||||
#endif //#ifndef SSC_H
|
||||
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "supc.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Local definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Key value for the SUPC_MR register.
|
||||
#define SUPC_KEY ((unsigned int) (0xA5 << 24))
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the SLCD power supply.
|
||||
/// \param internal If 1, the power supply is configured as internal; otherwise
|
||||
/// it is set at external.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_EnableSlcd(unsigned char internal)
|
||||
{
|
||||
if (internal) {
|
||||
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE) | AT91C_SUPC_LCDMODE_INTERNAL;
|
||||
}
|
||||
else {
|
||||
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE) | AT91C_SUPC_LCDMODE_EXTERNAL;
|
||||
}
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_LCDS) != AT91C_SUPC_LCDS);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the SLCD power supply.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_DisableSlcd(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDMODE);
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_LCDS) == AT91C_SUPC_LCDS);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the output voltage of the SLCD charge pump.
|
||||
/// \param voltage Output voltage.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_SetSlcdVoltage(unsigned int voltage)
|
||||
{
|
||||
SANITY_CHECK((voltage & ~AT91C_SUPC_LCDOUT) == 0);
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_LCDOUT) | voltage;
|
||||
}
|
||||
|
||||
#if !defined(__ICCARM__)
|
||||
__attribute__ ((section (".ramfunc"))) // GCC
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables the flash power supply with the given wake-up setting.
|
||||
/// \param time Wake-up time.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_EnableFlash(unsigned int time)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_FWUTR = time;
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_FLASHON;
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_FLASHS) != AT91C_SUPC_FLASHS);
|
||||
}
|
||||
|
||||
#if !defined(__ICCARM__)
|
||||
__attribute__ ((section (".ramfunc"))) // GCC
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the flash power supply.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_DisableFlash(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_FLASHON);
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_FLASHS) == AT91C_SUPC_FLASHS);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the voltage regulator output voltage.
|
||||
/// \param voltage Voltage to set.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_SetVoltageOutput(unsigned int voltage)
|
||||
{
|
||||
SANITY_CHECK((voltage & ~AT91C_SUPC_VRVDD) == 0);
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_VRVDD) | voltage;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Puts the voltage regulator in deep mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_EnableDeepMode(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_VRDEEP;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Puts the voltage regulator in normal mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_DisableDeepMode(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_VRDEEP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enables the backup SRAM power supply, so its data is saved while the device
|
||||
/// is in backup mode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SUPC_EnableSram(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_SRAMON;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Disables the backup SRAM power supply.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SUPC_DisableSram(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_SRAMON);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enables the RTC power supply.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SUPC_EnableRtc(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | AT91C_BASE_SUPC->SUPC_MR | AT91C_SUPC_RTCON;
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_RTS) != AT91C_SUPC_RTS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Disables the RTC power supply.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SUPC_DisableRtc(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_MR = SUPC_KEY | (AT91C_BASE_SUPC->SUPC_MR & ~AT91C_SUPC_RTCON);
|
||||
while ((AT91C_BASE_SUPC->SUPC_SR & AT91C_SUPC_RTS) == AT91C_SUPC_RTS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Sets the BOD sampling mode (or disables it).
|
||||
/// \param mode BOD sampling mode.
|
||||
//-----------------------------------------------------------------------------
|
||||
void SUPC_SetBodSampling(unsigned int mode)
|
||||
{
|
||||
SANITY_CHECK((mode & ~AT91C_SUPC_BODSMPL) == 0);
|
||||
AT91C_BASE_SUPC->SUPC_BOMR &= ~AT91C_SUPC_BODSMPL;
|
||||
AT91C_BASE_SUPC->SUPC_BOMR |= mode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Disables the voltage regulator, which makes the device enter backup mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_DisableVoltageRegulator(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_CR = SUPC_KEY | AT91C_SUPC_VROFF;
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Shuts the device down so it enters Off mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_Shutdown(void)
|
||||
{
|
||||
AT91C_BASE_SUPC->SUPC_CR = SUPC_KEY | AT91C_SUPC_SHDW;
|
||||
while (1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the wake-up sources when in backup mode.
|
||||
/// \param sources Wake-up sources to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_SetWakeUpSources(unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK((sources & ~0x0000000B) == 0);
|
||||
AT91C_BASE_SUPC->SUPC_WUMR &= ~0x0000000B;
|
||||
AT91C_BASE_SUPC->SUPC_WUMR |= sources;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the wake-up inputs when in backup mode.
|
||||
/// \param inputs Wake up inputs to enable.
|
||||
//------------------------------------------------------------------------------
|
||||
void SUPC_SetWakeUpInputs(unsigned int inputs)
|
||||
{
|
||||
SANITY_CHECK((inputs & ~0xFFFF) == 0);
|
||||
AT91C_BASE_SUPC->SUPC_WUIR &= ~0xFFFF;
|
||||
AT91C_BASE_SUPC->SUPC_WUIR |= inputs;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef SUPC_H
|
||||
#define SUPC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void SUPC_EnableSlcd(unsigned char internal);
|
||||
|
||||
extern void SUPC_DisableSlcd(void);
|
||||
|
||||
extern void SUPC_SetSlcdVoltage(unsigned int voltage);
|
||||
|
||||
extern
|
||||
#ifdef __ICCARM__
|
||||
__ramfunc // IAR
|
||||
#endif
|
||||
void SUPC_EnableFlash(unsigned int time);
|
||||
|
||||
extern
|
||||
#ifdef __ICCARM__
|
||||
__ramfunc // IAR
|
||||
#endif
|
||||
void SUPC_DisableFlash(void);
|
||||
|
||||
extern void SUPC_SetVoltageOutput(unsigned int voltage);
|
||||
|
||||
extern void SUPC_EnableDeepMode(void);
|
||||
|
||||
extern void SUPC_EnableSram(void);
|
||||
|
||||
extern void SUPC_DisableSram(void);
|
||||
|
||||
extern void SUPC_EnableRtc(void);
|
||||
|
||||
extern void SUPC_DisableRtc(void);
|
||||
|
||||
extern void SUPC_SetBodSampling(unsigned int mode);
|
||||
|
||||
extern void SUPC_DisableDeepMode(void);
|
||||
|
||||
extern void SUPC_DisableVoltageRegulator(void);
|
||||
|
||||
extern void SUPC_Shutdown(void);
|
||||
|
||||
extern void SUPC_SetWakeUpSources(unsigned int sources);
|
||||
|
||||
extern void SUPC_SetWakeUpInputs(unsigned int inputs);
|
||||
|
||||
#endif //#ifndef SUPC_H
|
||||
|
||||
140
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/tc/tc.c
Normal file
140
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/tc/tc.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "tc.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a Timer Counter to operate in the given mode. Timer is stopped
|
||||
/// after configuration and must be restarted with TC_Start().
|
||||
/// to obtain the target frequency.
|
||||
/// \param pTc Pointer to an AT91S_TC instance.
|
||||
/// \param mode Operating mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void TC_Configure(AT91S_TC *pTc, unsigned int mode)
|
||||
{
|
||||
// Disable TC clock
|
||||
pTc->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
// Disable interrupts
|
||||
pTc->TC_IDR = 0xFFFFFFFF;
|
||||
|
||||
// Clear status register
|
||||
pTc->TC_SR;
|
||||
|
||||
// Set mode
|
||||
pTc->TC_CMR = mode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts the timer clock.
|
||||
/// \param pTc Pointer to an AT91S_TC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void TC_Start(AT91S_TC *pTc)
|
||||
{
|
||||
pTc->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Stops the timer clock.
|
||||
/// \param pTc Pointer to an AT91S_TC instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void TC_Stop(AT91S_TC *pTc)
|
||||
{
|
||||
pTc->TC_CCR = AT91C_TC_CLKDIS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Finds the best MCK divisor given the timer frequency and MCK. The result
|
||||
/// is guaranteed to satisfy the following equation:
|
||||
/// (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
|
||||
/// with DIV being the highest possible value.
|
||||
/// Returns 1 if a divisor could be found; otherwise returns 0.
|
||||
/// \param freq Desired timer frequency.
|
||||
/// \param mck Master clock frequency.
|
||||
/// \param div Divisor value.
|
||||
/// \param tcclks TCCLKS field value for divisor.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char TC_FindMckDivisor(
|
||||
unsigned int freq,
|
||||
unsigned int mck,
|
||||
unsigned int *div,
|
||||
unsigned int *tcclks)
|
||||
{
|
||||
const unsigned int divisors[5] = {2, 8, 32, 128,
|
||||
#if defined(at91sam9260) || defined(at91sam9261) || defined(at91sam9263) \
|
||||
|| defined(at91sam9xe) || defined(at91sam9rl64) || defined(at91cap9)
|
||||
BOARD_MCK / 32768};
|
||||
#else
|
||||
1024};
|
||||
#endif
|
||||
unsigned int index = 0;
|
||||
|
||||
// Satisfy lower bound
|
||||
while (freq < ((mck / divisors[index]) / 65536)) {
|
||||
|
||||
index++;
|
||||
|
||||
// If no divisor can be found, return 0
|
||||
if (index == 5) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Try to maximise DIV while satisfying upper bound
|
||||
while (index < 4) {
|
||||
|
||||
if (freq > (mck / divisors[index + 1])) {
|
||||
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// Store results
|
||||
if (div) {
|
||||
|
||||
*div = divisors[index];
|
||||
}
|
||||
if (tcclks) {
|
||||
|
||||
*tcclks = index;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef TC_H
|
||||
#define TC_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
#if !defined(AT91C_ID_TC0) && defined(AT91C_ID_TC012)
|
||||
#define AT91C_ID_TC0 AT91C_ID_TC012
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void TC_Configure(AT91S_TC *pTc, unsigned int mode);
|
||||
|
||||
extern void TC_Start(AT91S_TC *pTc);
|
||||
|
||||
extern void TC_Stop(AT91S_TC *pTc);
|
||||
|
||||
extern unsigned char TC_FindMckDivisor(
|
||||
unsigned int freq,
|
||||
unsigned int mck,
|
||||
unsigned int *div,
|
||||
unsigned int *tcclks);
|
||||
|
||||
#endif //#ifndef TC_H
|
||||
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "tdes.h"
|
||||
#include <board.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures the triple-DES peripheral to cipher/decipher, use single-DES or
|
||||
/// triple-DES, use two or three keys (when in triple-DES mode), start manually,
|
||||
/// automatically or via the PDC and use the given operating mode (ECB, CBC,
|
||||
/// CFB or OFB).
|
||||
/// \param cipher Encrypts if 1, decrypts if 0.
|
||||
/// \param tdesmod Single- or triple-DES mode.
|
||||
/// \param keymod Use two or three keys (must be 0 in single-DES mode).
|
||||
/// \param smod Start mode.
|
||||
/// \param opmod Encryption/decryption mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_Configure(
|
||||
unsigned char cipher,
|
||||
unsigned int tdesmod,
|
||||
unsigned int keymod,
|
||||
unsigned int smod,
|
||||
unsigned int opmod)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_Configure()\n\r");
|
||||
SANITY_CHECK((cipher & 0xFFFFFFFE) == 0);
|
||||
SANITY_CHECK((tdesmod & 0xFFFFFFFD) == 0);
|
||||
SANITY_CHECK((keymod & 0xFFFFFFEF) == 0);
|
||||
SANITY_CHECK((smod & 0xFFFFFCFF) == 0);
|
||||
SANITY_CHECK((opmod & 0xFFFFCFFF) == 0);
|
||||
|
||||
// Reset peripheral
|
||||
AT91C_BASE_TDES->TDES_CR = AT91C_TDES_SWRST;
|
||||
|
||||
// Configure mode register
|
||||
AT91C_BASE_TDES->TDES_MR = cipher | tdesmod | keymod | smod | opmod;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts the encryption or decryption process if the TDES peripheral is
|
||||
/// configured in manual or PDC mode.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_Start(void)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_Start()\n\r");
|
||||
SANITY_CHECK(((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL)
|
||||
|| ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_PDC));
|
||||
|
||||
// Manual mode
|
||||
if ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_SMOD) == AT91C_TDES_SMOD_MANUAL) {
|
||||
|
||||
AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START;
|
||||
}
|
||||
// PDC mode
|
||||
else {
|
||||
|
||||
AT91C_BASE_TDES->TDES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns the current status register value of the TDES peripheral.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned int TDES_GetStatus(void)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_GetStatus()\n\r");
|
||||
|
||||
return AT91C_BASE_TDES->TDES_ISR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the 64-bits keys (one, two or three depending on the configuration)
|
||||
/// that shall be used by the TDES algorithm.
|
||||
/// \param pKey1 Pointer to key #1.
|
||||
/// \param pKey2 Pointer to key #2 (shall be 0 in single-DES mode).
|
||||
/// \param pKey3 Pointer to key #3 (shall be 0 when using two keys).
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_SetKeys(
|
||||
const unsigned int *pKey1,
|
||||
const unsigned int *pKey2,
|
||||
const unsigned int *pKey3)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_SetKeys()\n\r");
|
||||
SANITY_CHECK(pKey1);
|
||||
SANITY_CHECK((pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD))
|
||||
|| (!pKey2 && ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0)));
|
||||
SANITY_CHECK((pKey3
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD)
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0))
|
||||
||
|
||||
(!pKey3
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == AT91C_TDES_TDESMOD)
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == AT91C_TDES_KEYMOD))
|
||||
||
|
||||
(!pKey3
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_TDESMOD) == 0)
|
||||
&& ((AT91C_BASE_TDES->TDES_MR & AT91C_TDES_KEYMOD) == 0)));
|
||||
|
||||
// Write key #1
|
||||
if (pKey1) {
|
||||
|
||||
AT91C_BASE_TDES->TDES_KEY1WxR[0] = pKey1[0];
|
||||
AT91C_BASE_TDES->TDES_KEY1WxR[1] = pKey1[1];
|
||||
}
|
||||
|
||||
// Write key #2
|
||||
if (pKey1) {
|
||||
|
||||
AT91C_BASE_TDES->TDES_KEY2WxR[0] = pKey2[0];
|
||||
AT91C_BASE_TDES->TDES_KEY2WxR[1] = pKey2[1];
|
||||
}
|
||||
|
||||
// Write key #2
|
||||
if (pKey1) {
|
||||
|
||||
AT91C_BASE_TDES->TDES_KEY3WxR[0] = pKey3[0];
|
||||
AT91C_BASE_TDES->TDES_KEY3WxR[1] = pKey3[1];
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the input data to encrypt/decrypt using TDES.
|
||||
/// \param pInput Pointer to the 64-bits input data.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_SetInputData(const unsigned int *pInput)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_SetInputData()\n\r");
|
||||
SANITY_CHECK(pInput);
|
||||
|
||||
AT91C_BASE_TDES->TDES_IDATAxR[0] = pInput[0];
|
||||
AT91C_BASE_TDES->TDES_IDATAxR[1] = pInput[1];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the input data buffer to encrypt/decrypt when in PDC mode.
|
||||
/// \param pInput Pointer to the input data.
|
||||
/// \param size Size of buffer in bytes.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_SetInputBuffer(const unsigned int *pInput, unsigned int size)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_SetInputBuffer()\n\r");
|
||||
SANITY_CHECK(pInput);
|
||||
SANITY_CHECK((size > 0) && ((size % 8) == 0));
|
||||
|
||||
AT91C_BASE_TDES->TDES_TPR = (unsigned int) pInput;
|
||||
AT91C_BASE_TDES->TDES_TCR = size / 4;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Stores the output data from the last TDES operation into the given 64-bits
|
||||
/// buffers.
|
||||
/// \param pOutput Pointer to a 64-bits output buffer.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_GetOutputData(unsigned int *pOutput)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_GetOutputData()\n\r");
|
||||
SANITY_CHECK(pOutput);
|
||||
|
||||
pOutput[0] = AT91C_BASE_TDES->TDES_ODATAxR[0];
|
||||
pOutput[1] = AT91C_BASE_TDES->TDES_ODATAxR[1];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the output buffer which will receive the encrypted/decrypted data when
|
||||
/// using the PDC.
|
||||
/// \param pOutput Pointer to the output data.
|
||||
/// \param size Size of buffer in bytes.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_SetOutputBuffer(unsigned int *pOutput, unsigned int size)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_SetOutputBuffer()\n\r");
|
||||
SANITY_CHECK(pOutput);
|
||||
SANITY_CHECK((size > 0) && ((size % 8) == 0));
|
||||
|
||||
AT91C_BASE_TDES->TDES_RPR = (unsigned int) pOutput;
|
||||
AT91C_BASE_TDES->TDES_RCR = size / 4;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sets the initialization vector to use when the TDES algorithm is configured
|
||||
/// in a chained block mode (CBC, CFB or OFB).
|
||||
/// \param pVector Pointer to the 64-bits vector.
|
||||
//------------------------------------------------------------------------------
|
||||
void TDES_SetVector(const unsigned int *pVector)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TDES_SetVector()\n\r");
|
||||
SANITY_CHECK(pVector);
|
||||
|
||||
AT91C_BASE_TDES->TDES_IVxR[0] = pVector[0];
|
||||
AT91C_BASE_TDES->TDES_IVxR[1] = pVector[1];
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef TDES_H
|
||||
#define TDES_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void TDES_Configure(
|
||||
unsigned char cipher,
|
||||
unsigned int tdesmod,
|
||||
unsigned int keymod,
|
||||
unsigned int smod,
|
||||
unsigned int opmod);
|
||||
|
||||
extern void TDES_Start(void);
|
||||
|
||||
extern unsigned int TDES_GetStatus(void);
|
||||
|
||||
extern void TDES_SetKeys(
|
||||
const unsigned int *pKey1,
|
||||
const unsigned int *pKey2,
|
||||
const unsigned int *pKey3);
|
||||
|
||||
extern void TDES_SetInputData(const unsigned int *pInput);
|
||||
|
||||
extern void TDES_SetInputBuffer(const unsigned int *pInput, unsigned int size);
|
||||
|
||||
extern void TDES_GetOutputData(unsigned int *pOutput);
|
||||
|
||||
extern void TDES_SetOutputBuffer(unsigned int *pOutput, unsigned int size);
|
||||
|
||||
extern void TDES_SetVector(const unsigned int *pVector);
|
||||
|
||||
#endif //#ifndef TDES_H
|
||||
281
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/twi/twi.c
Normal file
281
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/twi/twi.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef trace_LEVEL
|
||||
#define trace_LEVEL 1
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "twi.h"
|
||||
#include <utility/math.h>
|
||||
#include <utility/assert.h>
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures a TWI peripheral to operate in master mode, at the given
|
||||
/// frequency (in Hz). The duty cycle of the TWI clock is set to 50%.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param twck Desired TWI clock frequency.
|
||||
/// \param mck Master clock frequency.
|
||||
//------------------------------------------------------------------------------
|
||||
void TWI_Configure(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck)
|
||||
{
|
||||
unsigned int ckdiv = 0;
|
||||
unsigned int cldiv;
|
||||
unsigned char ok = 0;
|
||||
|
||||
trace_LOG(trace_DEBUG, "-D- TWI_Configure()\n\r");
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
// Reset the TWI
|
||||
pTwi->TWI_CR = AT91C_TWI_SWRST;
|
||||
|
||||
// Set master mode
|
||||
pTwi->TWI_CR = AT91C_TWI_MSEN;
|
||||
|
||||
// Configure clock
|
||||
while (!ok) {
|
||||
|
||||
cldiv = ((mck / (2 * twck)) - 3) / power(2, ckdiv);
|
||||
if (cldiv <= 255) {
|
||||
|
||||
ok = 1;
|
||||
}
|
||||
else {
|
||||
|
||||
ckdiv++;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(ckdiv < 8, "-F- Cannot find valid TWI clock parameters\n\r");
|
||||
trace_LOG(trace_INFO, "-D- Using CKDIV = %u and CLDIV/CHDIV = %u\n\r", ckdiv, cldiv);
|
||||
pTwi->TWI_CWGR = (ckdiv << 16) | (cldiv << 8) | cldiv;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends a STOP condition on the TWI.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//------------------------------------------------------------------------------
|
||||
void TWI_Stop(AT91S_TWI *pTwi)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
pTwi->TWI_CR = AT91C_TWI_STOP;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Starts a read operation on the TWI bus with the specified slave, and returns
|
||||
/// immediately. Data must then be read using TWI_ReadByte() whenever a byte is
|
||||
/// available (poll using TWI_ByteReceived()).
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param address Slave address on the bus.
|
||||
/// \param iaddress Optional internal address bytes.
|
||||
/// \param isize Number of internal address bytes.
|
||||
//-----------------------------------------------------------------------------
|
||||
void TWI_StartRead(
|
||||
AT91S_TWI *pTwi,
|
||||
unsigned char address,
|
||||
unsigned int iaddress,
|
||||
unsigned char isize)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TWI_StartRead()\n\r");
|
||||
SANITY_CHECK(pTwi);
|
||||
SANITY_CHECK((address & 0x80) == 0);
|
||||
SANITY_CHECK((iaddress & 0xFF000000) == 0);
|
||||
SANITY_CHECK(isize < 4);
|
||||
|
||||
// Set slave address and number of internal address bytes
|
||||
pTwi->TWI_MMR = (isize << 8) | AT91C_TWI_MREAD | (address << 16);
|
||||
|
||||
// Set internal address bytes
|
||||
pTwi->TWI_IADR = iaddress;
|
||||
|
||||
// Send START condition
|
||||
pTwi->TWI_CR = AT91C_TWI_START;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Reads a byte from the TWI bus. The read operation must have been started
|
||||
/// using TWI_StartRead() and a byte must be available (check with
|
||||
/// TWI_ByteReceived()).
|
||||
/// Returns the byte read.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char TWI_ReadByte(AT91S_TWI *pTwi)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
return pTwi->TWI_RHR;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Sends a byte of data to one of the TWI slaves on the bus. This function
|
||||
/// must be called once before TWI_StartWrite() with the first byte of data
|
||||
/// to send, then it shall be called repeatedly after that to send the
|
||||
/// remaining bytes.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param byte Byte to send.
|
||||
//-----------------------------------------------------------------------------
|
||||
void TWI_WriteByte(AT91S_TWI *pTwi, unsigned char byte)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
pTwi->TWI_THR = byte;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Starts a write operation on the TWI to access the selected slave, then
|
||||
/// returns immediately. A byte of data must be provided to start the write;
|
||||
/// other bytes are written next.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param address Address of slave to acccess on the bus.
|
||||
/// \param iaddress Optional slave internal address.
|
||||
/// \param isize Number of internal address bytes.
|
||||
/// \param byte First byte to send.
|
||||
//-----------------------------------------------------------------------------
|
||||
void TWI_StartWrite(
|
||||
AT91S_TWI *pTwi,
|
||||
unsigned char address,
|
||||
unsigned int iaddress,
|
||||
unsigned char isize,
|
||||
unsigned char byte)
|
||||
{
|
||||
trace_LOG(trace_DEBUG, "-D- TWI_StartWrite()\n\r");
|
||||
SANITY_CHECK(pTwi);
|
||||
SANITY_CHECK((address & 0x80) == 0);
|
||||
SANITY_CHECK((iaddress & 0xFF000000) == 0);
|
||||
SANITY_CHECK(isize < 4);
|
||||
|
||||
// Set slave address and number of internal address bytes
|
||||
pTwi->TWI_MMR = (isize << 8) | (address << 16);
|
||||
|
||||
// Set internal address bytes
|
||||
pTwi->TWI_IADR = iaddress;
|
||||
|
||||
// Write first byte to send
|
||||
TWI_WriteByte(pTwi, byte);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns 1 if a byte has been received and can be read on the given TWI
|
||||
/// peripheral; otherwise, returns 0. This function resets the status register
|
||||
/// of the TWI.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char TWI_ByteReceived(AT91S_TWI *pTwi)
|
||||
{
|
||||
return ((pTwi->TWI_SR & AT91C_TWI_RXRDY) == AT91C_TWI_RXRDY);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns 1 if a byte has been sent, so another one can be stored for
|
||||
/// transmission; otherwise returns 0. This function clears the status register
|
||||
/// of the TWI.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char TWI_ByteSent(AT91S_TWI *pTwi)
|
||||
{
|
||||
return ((pTwi->TWI_SR & AT91C_TWI_TXRDY) == AT91C_TWI_TXRDY);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns 1 if the current transmission is complete (the STOP has been sent);
|
||||
/// otherwise returns 0.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned char TWI_TransferComplete(AT91S_TWI *pTwi)
|
||||
{
|
||||
return ((pTwi->TWI_SR & AT91C_TWI_TXCOMP) == AT91C_TWI_TXCOMP);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Enables the selected interrupts sources on a TWI peripheral.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param sources Bitwise OR of selected interrupt sources.
|
||||
//-----------------------------------------------------------------------------
|
||||
void TWI_EnableIt(AT91S_TWI *pTwi, unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
SANITY_CHECK((sources & 0xFFFFFEF8) == 0);
|
||||
|
||||
pTwi->TWI_IER = sources;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Disables the selected interrupts sources on a TWI peripheral.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
/// \param sources Bitwise OR of selected interrupt sources.
|
||||
//-----------------------------------------------------------------------------
|
||||
void TWI_DisableIt(AT91S_TWI *pTwi, unsigned int sources)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
SANITY_CHECK((sources & 0xFFFFFEF8) == 0);
|
||||
|
||||
pTwi->TWI_IDR = sources;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns the current status register of the given TWI peripheral. This
|
||||
/// resets the internal value of the status register, so further read may yield
|
||||
/// different values.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int TWI_GetStatus(AT91S_TWI *pTwi)
|
||||
{
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
return pTwi->TWI_SR;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// Returns the current status register of the given TWI peripheral, but
|
||||
/// masking interrupt sources which are not currently enabled.
|
||||
/// This resets the internal value of the status register, so further read may
|
||||
/// yield different values.
|
||||
/// \param pTwi Pointer to an AT91S_TWI instance.
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int TWI_GetMaskedStatus(AT91S_TWI *pTwi)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
SANITY_CHECK(pTwi);
|
||||
|
||||
status = pTwi->TWI_SR;
|
||||
status &= pTwi->TWI_IMR;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
108
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/twi/twi.h
Normal file
108
20091005/Demo/Common/drivers/Atmel/at91lib/peripherals/twi/twi.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef TWI_H
|
||||
#define TWI_H
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <board.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global definitions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Missing AT91C_TWI_TXRDY definition.
|
||||
#ifndef AT91C_TWI_TXRDY
|
||||
#define AT91C_TWI_TXRDY AT91C_TWI_TXRDY_MASTER
|
||||
#endif
|
||||
|
||||
// Missing AT91C_TWI_TXCOMP definition.
|
||||
#ifndef AT91C_TWI_TXCOMP
|
||||
#define AT91C_TWI_TXCOMP AT91C_TWI_TXCOMP_MASTER
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global macros
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/// Returns 1 if the TXRDY bit (ready to transmit data) is set in the given
|
||||
/// status register value.
|
||||
#define TWI_STATUS_TXRDY(status) ((status & AT91C_TWI_TXRDY) == AT91C_TWI_TXRDY)
|
||||
|
||||
/// Returns 1 if the RXRDY bit (ready to receive data) is set in the given
|
||||
/// status register value.
|
||||
#define TWI_STATUS_RXRDY(status) ((status & AT91C_TWI_RXRDY) == AT91C_TWI_RXRDY)
|
||||
|
||||
/// Returns 1 if the TXCOMP bit (transfer complete) is set in the given
|
||||
/// status register value.
|
||||
#define TWI_STATUS_TXCOMP(status) ((status & AT91C_TWI_TXCOMP) == AT91C_TWI_TXCOMP)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Global functions
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
extern void TWI_Configure(AT91S_TWI *pTwi, unsigned int twck, unsigned int mck);
|
||||
|
||||
extern void TWI_Stop(AT91S_TWI *pTwi);
|
||||
|
||||
extern void TWI_StartRead(
|
||||
AT91S_TWI *pTwi,
|
||||
unsigned char address,
|
||||
unsigned int iaddress,
|
||||
unsigned char isize);
|
||||
|
||||
extern unsigned char TWI_ReadByte(AT91S_TWI *pTwi);
|
||||
|
||||
extern void TWI_WriteByte(AT91S_TWI *pTwi, unsigned char byte);
|
||||
|
||||
extern void TWI_StartWrite(
|
||||
AT91S_TWI *pTwi,
|
||||
unsigned char address,
|
||||
unsigned int iaddress,
|
||||
unsigned char isize,
|
||||
unsigned char byte);
|
||||
|
||||
extern unsigned char TWI_ByteReceived(AT91S_TWI *pTwi);
|
||||
|
||||
extern unsigned char TWI_ByteSent(AT91S_TWI *pTwi);
|
||||
|
||||
extern unsigned char TWI_TransferComplete(AT91S_TWI *pTwi);
|
||||
|
||||
extern void TWI_EnableIt(AT91S_TWI *pTwi, unsigned int sources);
|
||||
|
||||
extern void TWI_DisableIt(AT91S_TWI *pTwi, unsigned int sources);
|
||||
|
||||
extern unsigned int TWI_GetStatus(AT91S_TWI *pTwi);
|
||||
|
||||
extern unsigned int TWI_GetMaskedStatus(AT91S_TWI *pTwi);
|
||||
|
||||
#endif //#ifndef TWI_H
|
||||
|
|
@ -0,0 +1,259 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2008, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "usart.h"
|
||||
#include <utility/trace.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Exported functions
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
/// Configures an USART peripheral with the specified parameters.
|
||||
/// \param usart Pointer to the USART peripheral to configure.
|
||||
/// \param mode Desired value for the USART mode register (see the datasheet).
|
||||
/// \param baudrate Baudrate at which the USART should operate (in Hz).
|
||||
/// \param masterClock Frequency of the system master clock (in Hz).
|
||||
//------------------------------------------------------------------------------
|
||||
void USART_Configure(AT91S_USART *usart,
|
||||
unsigned int mode,
|
||||
unsigned int baudrate,
|
||||
unsigned int masterClock)
|
||||
{
|
||||
// Reset and disable receiver & transmitter
|
||||
usart->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX
|
||||
| AT91C_US_RXDIS | AT91C_US_TXDIS;
|
||||
|
||||
// Configure mode
|
||||
usart->US_MR = mode;
|
||||
|
||||
// Configure baudrate
|
||||
// Asynchronous, no oversampling
|
||||
if (((mode & AT91C_US_SYNC) == 0)
|
||||
&& ((mode & AT91C_US_OVER) == 0)) {
|
||||
|
||||
usart->US_BRGR = (masterClock / baudrate) / 16;
|
||||
}
|
||||
// TODO other modes
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables or disables the transmitter of an USART peripheral.
|
||||
/// \param usart Pointer to an USART peripheral
|
||||
/// \param enabled If true, the transmitter is enabled; otherwise it is
|
||||
/// disabled.
|
||||
//------------------------------------------------------------------------------
|
||||
void USART_SetTransmitterEnabled(AT91S_USART *usart,
|
||||
unsigned char enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
|
||||
usart->US_CR = AT91C_US_TXEN;
|
||||
}
|
||||
else {
|
||||
|
||||
usart->US_CR = AT91C_US_TXDIS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Enables or disables the receiver of an USART peripheral
|
||||
/// \param usart Pointer to an USART peripheral
|
||||
/// \param enabled If true, the receiver is enabled; otherwise it is disabled.
|
||||
//------------------------------------------------------------------------------
|
||||
void USART_SetReceiverEnabled(AT91S_USART *usart,
|
||||
unsigned char enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
|
||||
usart->US_CR = AT91C_US_RXEN;
|
||||
}
|
||||
else {
|
||||
|
||||
usart->US_CR = AT91C_US_RXDIS;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends one packet of data through the specified USART peripheral. This
|
||||
/// function operates synchronously, so it only returns when the data has been
|
||||
/// actually sent.
|
||||
/// \param usart Pointer to an USART peripheral.
|
||||
/// \param data Data to send including 9nth bit and sync field if necessary (in
|
||||
/// the same format as the US_THR register in the datasheet).
|
||||
/// \param timeOut Time out value (0 = no timeout).
|
||||
//------------------------------------------------------------------------------
|
||||
void USART_Write(
|
||||
AT91S_USART *usart,
|
||||
unsigned short data,
|
||||
volatile unsigned int timeOut)
|
||||
{
|
||||
if (timeOut == 0) {
|
||||
|
||||
while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0);
|
||||
}
|
||||
else {
|
||||
|
||||
while ((usart->US_CSR & AT91C_US_TXEMPTY) == 0) {
|
||||
|
||||
if (timeOut == 0) {
|
||||
|
||||
trace_LOG(trace_ERROR, "-E- USART_Write: Timed out.\n\r");
|
||||
return;
|
||||
}
|
||||
timeOut--;
|
||||
}
|
||||
}
|
||||
|
||||
usart->US_THR = data;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Sends the contents of a data buffer through the specified USART peripheral.
|
||||
/// This function returns immediately (1 if the buffer has been queued, 0
|
||||
/// otherwise); poll the ENDTX and TXBUFE bits of the USART status register
|
||||
/// to check for the transfer completion.
|
||||
/// \param usart Pointer to an USART peripheral.
|
||||
/// \param buffer Pointer to the data buffer to send.
|
||||
/// \param size Size of the data buffer (in bytes).
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char USART_WriteBuffer(
|
||||
AT91S_USART *usart,
|
||||
void *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
// Check if the first PDC bank is free
|
||||
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
|
||||
|
||||
usart->US_TPR = (unsigned int) buffer;
|
||||
usart->US_TCR = size;
|
||||
usart->US_PTCR = AT91C_PDC_TXTEN;
|
||||
|
||||
return 1;
|
||||
}
|
||||
// Check if the second PDC bank is free
|
||||
else if (usart->US_TNCR == 0) {
|
||||
|
||||
usart->US_TNPR = (unsigned int) buffer;
|
||||
usart->US_TNCR = size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads and return a packet of data on the specified USART peripheral. This
|
||||
/// function operates asynchronously, so it waits until some data has been
|
||||
/// received.
|
||||
/// \param usart Pointer to an USART peripheral.
|
||||
/// \param timeOut Time out value (0 -> no timeout).
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned short USART_Read(
|
||||
AT91S_USART *usart,
|
||||
volatile unsigned int timeOut)
|
||||
{
|
||||
if (timeOut == 0) {
|
||||
|
||||
while ((usart->US_CSR & AT91C_US_RXRDY) == 0);
|
||||
}
|
||||
else {
|
||||
|
||||
while ((usart->US_CSR & AT91C_US_RXRDY) == 0) {
|
||||
|
||||
if (timeOut == 0) {
|
||||
|
||||
trace_LOG(trace_ERROR, "-E- USART_Read: Timed out.\n\r");
|
||||
return 0;
|
||||
}
|
||||
timeOut--;
|
||||
}
|
||||
}
|
||||
|
||||
return usart->US_RHR;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Reads data from an USART peripheral, filling the provided buffer until it
|
||||
/// becomes full. This function returns immediately with 1 if the buffer has
|
||||
/// been queued for transmission; otherwise 0.
|
||||
/// \param usart Pointer to an USART peripheral.
|
||||
/// \param buffer Pointer to the buffer where the received data will be stored.
|
||||
/// \param size Size of the data buffer (in bytes).
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char USART_ReadBuffer(AT91S_USART *usart,
|
||||
void *buffer,
|
||||
unsigned int size)
|
||||
{
|
||||
// Check if the first PDC bank is free
|
||||
if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
|
||||
|
||||
usart->US_RPR = (unsigned int) buffer;
|
||||
usart->US_RCR = size;
|
||||
usart->US_PTCR = AT91C_PDC_RXTEN;
|
||||
|
||||
return 1;
|
||||
}
|
||||
// Check if the second PDC bank is free
|
||||
else if (usart->US_RNCR == 0) {
|
||||
|
||||
usart->US_RNPR = (unsigned int) buffer;
|
||||
usart->US_RNCR = size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Returns 1 if some data has been received and can be read from an USART;
|
||||
/// otherwise returns 0.
|
||||
/// \param usart Pointer to an AT91S_USART instance.
|
||||
//------------------------------------------------------------------------------
|
||||
unsigned char USART_IsDataAvailable(AT91S_USART *usart)
|
||||
{
|
||||
if ((usart->US_CSR & AT91C_US_RXRDY) != 0) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue