--- /dev/null
+SRC_FILES=croutine.c list.c queue.c tasks.c
+
+SUBDIRS=portable
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+ @for i in $(SUBDIRS); do \
+ (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/* Lists for ready and blocked co-routines. --------------------*/
+static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
+static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */
+static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
+static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
+static xList xPendingReadyList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
+
+/* Other file private variables. --------------------------------*/
+corCRCB * pxCurrentCoRoutine = NULL;
+static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
+static portTickType xCoRoutineTickCount = 0;
+
+/* The initial state of the co-routine when it is created. */
+#define corINITIAL_STATE ( 0 )
+
+/*
+ * Place the co-routine represented by pxCRCB into the appropriate ready queue
+ * for the priority. It is inserted at the end of the list.
+ *
+ * This macro accesses the co-routine ready lists and therefore must not be
+ * used from within an ISR.
+ */
+#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
+{ \
+ if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
+ { \
+ uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
+ } \
+ vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
+}
+
+/*
+ * Utility to ready all the lists used by the scheduler. This is called
+ * automatically upon the creation of the first co-routine.
+ */
+static void prvInitialiseCoRoutineLists( void );
+
+/*
+ * Co-routines that are readied by an interrupt cannot be placed directly into
+ * the ready lists (there is no mutual exclusion). Instead they are placed in
+ * in the pending ready list in order that they can later be moved to the ready
+ * list by the co-routine scheduler.
+ */
+static inline void prvCheckPendingReadyList( void );
+
+/*
+ * Macro that looks at the list of co-routines that are currently delayed to
+ * see if any require waking.
+ *
+ * Co-routines are stored in the queue in the order of their wake time -
+ * meaning once one co-routine has been found whose timer has not expired
+ * we need not look any further down the list.
+ */
+static inline void prvCheckDelayedList( void );
+
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
+{
+signed portBASE_TYPE xReturn;
+corCRCB *pxCoRoutine;
+
+ /* Allocate the memory that will store the co-routine control block. */
+ pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
+ if( pxCoRoutine )
+ {
+ /* If pxCurrentCoRoutine is NULL then this is the first co-routine to
+ be created and the co-routine data structures need initialising. */
+ if( pxCurrentCoRoutine == NULL )
+ {
+ pxCurrentCoRoutine = pxCoRoutine;
+ prvInitialiseCoRoutineLists();
+ }
+
+ /* Check the priority is within limits. */
+ if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
+ {
+ uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
+ }
+
+ /* Fill out the co-routine control block from the function parameters. */
+ pxCoRoutine->uxState = corINITIAL_STATE;
+ pxCoRoutine->uxPriority = uxPriority;
+ pxCoRoutine->uxIndex = uxIndex;
+ pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
+
+ /* Initialise all the other co-routine control block parameters. */
+ vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
+ vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
+
+ /* Set the co-routine control block as a link back from the xListItem.
+ This is so we can get back to the containing CRCB from a generic item
+ in a list. */
+ listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
+ listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
+
+ /* Event lists are always in priority order. */
+ listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+
+ /* Now the co-routine has been initialised it can be added to the ready
+ list at the correct priority. */
+ prvAddCoRoutineToReadyQueue( pxCoRoutine );
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
+{
+portTickType xTimeToWake;
+
+ /* Calculate the time to wake - this may overflow but this is
+ not a problem. */
+ xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xCoRoutineTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the
+ overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the
+ current block list. */
+ vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
+ }
+
+ if( pxEventList )
+ {
+ /* Also add the co-routine to an event list. If this is done then the
+ function must be called with interrupts disabled. */
+ vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static inline void prvCheckPendingReadyList( void )
+{
+ /* Are there any co-routines waiting to get moved to the ready list? These
+ are co-routines that have been readied by an ISR. The ISR cannot access
+ the ready lists itself. */
+ while( !listLIST_IS_EMPTY( &xPendingReadyList ) )
+ {
+ corCRCB *pxUnblockedCRCB;
+
+ /* The pending ready list can be accessed by an ISR. */
+ portDISABLE_INTERRUPTS();
+ {
+ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyList) );
+ vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+ }
+ portENABLE_INTERRUPTS();
+
+ vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
+ prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static inline void prvCheckDelayedList( void )
+{
+static portTickType xLastTickCount, xPassedTicks;
+corCRCB *pxCRCB;
+
+ xPassedTicks = xTaskGetTickCount() - xLastTickCount;
+ while( xPassedTicks )
+ {
+ xCoRoutineTickCount++;
+ xPassedTicks--;
+
+ /* If the tick count has overflowed we need to swap the ready lists. */
+ if( xCoRoutineTickCount == 0 )
+ {
+ xList * pxTemp;
+
+ /* Tick count has overflowed so we need to swap the delay lists. If there are
+ any items in pxDelayedCoRoutineList here then there is an error! */
+ pxTemp = pxDelayedCoRoutineList;
+ pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
+ pxOverflowDelayedCoRoutineList = pxTemp;
+ }
+
+ /* See if this tick has made a timeout expire. */
+ while( ( pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList ) ) != NULL )
+ {
+ if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
+ {
+ /* Timeout not yet expired. */
+ break;
+ }
+
+ portDISABLE_INTERRUPTS();
+ {
+ /* The event could have occurred just before this critical
+ section. If this is the case then the generic list item will
+ have been moved to the pending ready list and the following
+ line is still valid. Also the pvContainer parameter will have
+ been set to NULL so the following lines are also valid. */
+ vListRemove( &( pxCRCB->xGenericListItem ) );
+
+ /* Is the co-routine waiting on an event also? */
+ if( pxCRCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxCRCB->xEventListItem ) );
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ prvAddCoRoutineToReadyQueue( pxCRCB );
+ }
+ }
+
+ xLastTickCount = xCoRoutineTickCount;
+}
+/*-----------------------------------------------------------*/
+
+void vCoRoutineSchedule( void )
+{
+ /* See if any co-routines readied by events need moving to the ready lists. */
+ prvCheckPendingReadyList();
+
+ /* See if any delayed co-routines have timed out. */
+ prvCheckDelayedList();
+
+ /* Find the highest priority queue that contains ready co-routines. */
+ while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
+ {
+ if( uxTopCoRoutineReadyPriority == 0 )
+ {
+ /* No more co-routines to check. */
+ return;
+ }
+ --uxTopCoRoutineReadyPriority;
+ }
+
+ /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
+ of the same priority get an equal share of the processor time. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
+
+ /* Call the co-routine. */
+ ( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
+
+ return;
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseCoRoutineLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+ for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
+ {
+ vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
+ }
+
+ vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
+ vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
+ vListInitialise( ( xList * ) &xPendingReadyList );
+
+ /* Start with pxDelayedCoRoutineList using list1 and the
+ pxOverflowDelayedCoRoutineList using list2. */
+ pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
+ pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
+{
+corCRCB *pxUnblockedCRCB;
+signed portBASE_TYPE xReturn;
+
+ /* This function is called from within an interrupt. It can only access
+ event lists and the pending ready list. */
+ pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+ vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedCRCB->xEventListItem ) );
+
+ if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
+ {
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#ifndef INC_FREERTOS_H
+#define INC_FREERTOS_H
+
+
+/*
+ * Include the generic headers required for the FreeRTOS port being used.
+ */
+#include <stddef.h>
+
+/* Basic FreeRTOS definitions. */
+#include "projdefs.h"
+
+/* Application specific configuration options. */
+#include "FreeRTOSConfig.h"
+
+/* Definitions specific to the port being used. */
+#include "portable.h"
+
+
+
+
+
+
+
+/*
+ * Check all the required application specific macros have been defined.
+ * These macros are application specific and (as downloaded) are defined
+ * within FreeRTOSConfig.h.
+ */
+
+#ifndef configUSE_PREEMPTION
+ #error Missing definition: configUSE_PREEMPTION should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_IDLE_HOOK
+ #error Missing definition: configUSE_IDLE_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_TICK_HOOK
+ #error Missing definition: configUSE_TICK_HOOK should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_CO_ROUTINES
+ #error Missing definition: configUSE_CO_ROUTINES should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskPrioritySet
+ #error Missing definition: INCLUDE_vTaskPrioritySet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_uxTaskPriorityGet
+ #error Missing definition: INCLUDE_uxTaskPriorityGet should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelete
+ #error Missing definition: INCLUDE_vTaskDelete should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskCleanUpResources
+ #error Missing definition: INCLUDE_vTaskCleanUpResources should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskSuspend
+ #error Missing definition: INCLUDE_vTaskSuspend should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelayUntil
+ #error Missing definition: INCLUDE_vTaskDelayUntil should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef INCLUDE_vTaskDelay
+ #error Missing definition: INCLUDE_vTaskDelay should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#ifndef configUSE_16_BIT_TICKS
+ #error Missing definition: configUSE_16_BIT_TICKS should be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
+#endif
+
+#endif
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+#ifndef CO_ROUTINE_H
+#define CO_ROUTINE_H
+
+#include "list.h"
+
+/* Used to hide the implementation of the co-routine control block. The
+control block structure however has to be included in the header due to
+the macro implementation of the co-routine functionality. */
+typedef void * xCoRoutineHandle;
+
+/* Defines the prototype to which co-routine functions must conform. */
+typedef void (*crCOROUTINE_CODE)( xCoRoutineHandle, unsigned portBASE_TYPE );
+
+typedef struct corCoRoutineControlBlock
+{
+ crCOROUTINE_CODE pxCoRoutineFunction;
+ xListItem xGenericListItem; /*< List item used to place the CRCB in ready and blocked queues. */
+ xListItem xEventListItem; /*< List item used to place the CRCB in event lists. */
+ unsigned portBASE_TYPE uxPriority; /*< The priority of the co-routine in relation to other co-routines. */
+ unsigned portBASE_TYPE uxIndex; /*< Used to distinguish between co-routines when multiple co-routines use the same co-routine function. */
+ unsigned portSHORT uxState; /*< Used internally by the co-routine implementation. */
+} corCRCB; /* Co-routine control block. Note must be identical in size down to uxPriority with tskTCB. */
+
+/**
+ * croutine. h
+ *<pre>
+ portBASE_TYPE xCoRoutineCreate(
+ crCOROUTINE_CODE pxCoRoutineCode,
+ unsigned portBASE_TYPE uxPriority,
+ unsigned portBASE_TYPE uxIndex
+ );</pre>
+ *
+ * Create a new co-routine and add it to the list of co-routines that are
+ * ready to run.
+ *
+ * @param pxCoRoutineCode Pointer to the co-routine function. Co-routine
+ * functions require special syntax - see the co-routine section of the WEB
+ * documentation for more information.
+ *
+ * @param uxPriority The priority with respect to other co-routines at which
+ * the co-routine will run.
+ *
+ * @param uxIndex Used to distinguish between different co-routines that
+ * execute the same function. See the example below and the co-routine section
+ * of the WEB documentation for further information.
+ *
+ * @return pdPASS if the co-routine was successfully created and added to a ready
+ * list, otherwise an error code defined with ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ static const char cLedToFlash[ 2 ] = { 5, 6 };
+ static const portTickType xTimeToDelay[ 2 ] = { 200, 400 };
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // This co-routine just delays for a fixed period, then toggles
+ // an LED. Two co-routines are created using this function, so
+ // the uxIndex parameter is used to tell the co-routine which
+ // LED to flash and how long to delay. This assumes xQueue has
+ // already been created.
+ vParTestToggleLED( cLedToFlash[ uxIndex ] );
+ crDELAY( xHandle, uxFlashRates[ uxIndex ] );
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }
+
+ // Function that creates two co-routines.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+ // Create two co-routines at priority 0. The first is given index 0
+ // so (from the code above) toggles LED 5 every 200 ticks. The second
+ // is given index 1 so toggles LED 6 every 400 ticks.
+ for( uxIndex = 0; uxIndex < 2; uxIndex++ )
+ {
+ xCoRoutineCreate( vFlashCoRoutine, 0, uxIndex );
+ }
+ }
+ </pre>
+ * \defgroup xCoRoutineCreate xCoRoutineCreate
+ * \ingroup Tasks
+ */
+signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex );
+
+
+/**
+ * croutine. h
+ *<pre>
+ void vCoRoutineSchedule( void );</pre>
+ *
+ * Run a co-routine.
+ *
+ * vCoRoutineSchedule() executes the highest priority co-routine that is able
+ * to run. The co-routine will execute until it either blocks, yields or is
+ * preempted by a task. Co-routines execute cooperatively so one
+ * co-routine cannot be preempted by another, but can be preempted by a task.
+ *
+ * If an application comprises of both tasks and co-routines then
+ * vCoRoutineSchedule should be called from the idle task (in an idle task
+ * hook).
+ *
+ * Example usage:
+ <pre>
+ // This idle task hook will schedule a co-routine each time it is called.
+ // The rest of the idle task will execute between co-routine calls.
+ void vApplicationIdleHook( void )
+ {
+ vCoRoutineSchedule();
+ }
+
+ // Alternatively, if you do not require any other part of the idle task to
+ // execute, the idle task hook can call vCoRoutineScheduler() within an
+ // infinite loop.
+ void vApplicationIdleHook( void )
+ {
+ for( ;; )
+ {
+ vCoRoutineSchedule();
+ }
+ }
+ </pre>
+ * \defgroup vCoRoutineSchedule vCoRoutineSchedule
+ * \ingroup Tasks
+ */
+void vCoRoutineSchedule( void );
+
+/**
+ * croutine. h
+ * <pre>
+ crSTART( xCoRoutineHandle xHandle );</pre>
+ *
+ * This macro MUST always be called at the start of a co-routine function.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portLONG ulAVariable;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Co-routine functionality goes here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crSTART( pxCRCB ) switch( ( ( corCRCB * )pxCRCB )->uxState ) { case 0:
+
+/**
+ * croutine. h
+ * <pre>
+ crEND();</pre>
+ *
+ * This macro MUST always be called at the end of a co-routine function.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portLONG ulAVariable;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Co-routine functionality goes here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crSTART crSTART
+ * \ingroup Tasks
+ */
+#define crEND() }
+
+/*
+ * These macros are intended for internal use by the co-routine implementation
+ * only. The macros should not be used directly by application writers.
+ */
+#define crSET_STATE0( xHandle ) ( ( corCRCB * )xHandle)->uxState = (__LINE__ * 2); return; case (__LINE__ * 2):
+#define crSET_STATE1( xHandle ) ( ( corCRCB * )xHandle)->uxState = ((__LINE__ * 2)+1); return; case ((__LINE__ * 2)+1):
+
+/**
+ * croutine. h
+ *<pre>
+ crDELAY( xCoRoutineHandle xHandle, portTickType xTicksToDelay );</pre>
+ *
+ * Delay a co-routine for a fixed period of time.
+ *
+ * crDELAY can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * @param xHandle The handle of the co-routine to delay. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should delay
+ * for. The actual amount of time this equates to is defined by
+ * configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant portTICK_RATE_MS
+ * can be used to convert ticks to milliseconds.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine to be created.
+ void vACoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ // This may not be necessary for const variables.
+ // We are to delay for 200ms.
+ static const xTickType xDelayTime = 200 / portTICK_RATE_MS;
+
+ // Must start every co-routine with a call to crSTART();
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Delay for 200ms.
+ crDELAY( xHandle, xDelayTime );
+
+ // Do something here.
+ }
+
+ // Must end every co-routine with a call to crEND();
+ crEND();
+ }</pre>
+ * \defgroup crDELAY crDELAY
+ * \ingroup Tasks
+ */
+#define crDELAY( xHandle, xTicksToDelay ) \
+ if( xTicksToDelay > 0 ) \
+ { \
+ vCoRoutineAddToDelayedList( xTicksToDelay, NULL ); \
+ } \
+ crSET_STATE0( xHandle );
+
+/**
+ * <pre>
+ crQUEUE_SEND(
+ xCoRoutineHandle xHandle,
+ xQueueHandle pxQueue,
+ void *pvItemToQueue,
+ portTickType xTicksToWait,
+ portBASE_TYPE *pxResult
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_SEND can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue on which the data will be posted.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvItemToQueue A pointer to the data being posted onto the queue.
+ * The number of bytes of each queued item is specified when the queue is
+ * created. This number of bytes is copied from pvItemToQueue into the queue
+ * itself.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for space to become available on the queue, should space not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see example
+ * below).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully posted onto the queue, otherwise it will be set to an
+ * error defined within ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // Co-routine function that blocks for a fixed period then posts a number onto
+ // a queue.
+ static void prvCoRoutineFlashTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xNumberToPost = 0;
+ static portBASE_TYPE xResult;
+
+ // Co-routines must begin with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // This assumes the queue has already been created.
+ crQUEUE_SEND( xHandle, xCoRoutineQueue, &xNumberToPost, NO_DELAY, &xResult );
+
+ if( xResult != pdPASS )
+ {
+ // The message was not posted!
+ }
+
+ // Increment the number to be posted onto the queue.
+ xNumberToPost++;
+
+ // Delay for 100 ticks.
+ crDELAY( xHandle, 100 );
+ }
+
+ // Co-routines must end with a call to crEND().
+ crEND();
+ }</pre>
+ * \defgroup crQUEUE_SEND crQUEUE_SEND
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND( xHandle, pxQueue, pvItemToQueue, xTicksToWait, pxResult ) \
+{ \
+ *pxResult = xQueueCRSend( pxQueue, pvItemToQueue, xTicksToWait ); \
+ if( *pxResult == errQUEUE_BLOCKED ) \
+ { \
+ crSET_STATE0( xHandle ); \
+ *pxResult = xQueueCRSend( pxQueue, pvItemToQueue, 0 ); \
+ } \
+ if( *pxResult == errQUEUE_YIELD ) \
+ { \
+ crSET_STATE1( xHandle ); \
+ *pxResult = pdPASS; \
+ } \
+}
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_RECEIVE(
+ xCoRoutineHandle xHandle,
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait,
+ portBASE_TYPE *pxResult
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND() and crQUEUE_RECEIVE() are the co-routine
+ * equivalent to the xQueueSend() and xQueueReceive() functions used by tasks.
+ *
+ * crQUEUE_SEND and crQUEUE_RECEIVE can only be used from a co-routine whereas
+ * xQueueSend() and xQueueReceive() can only be used from tasks.
+ *
+ * crQUEUE_RECEIVE can only be called from the co-routine function itself - not
+ * from within a function called by the co-routine function. This is because
+ * co-routines do not maintain their own stack.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xHandle The handle of the calling co-routine. This is the xHandle
+ * parameter of the co-routine function.
+ *
+ * @param pxQueue The handle of the queue from which the data will be received.
+ * The handle is obtained as the return value when the queue is created using
+ * the xQueueCreate() API function.
+ *
+ * @param pvBuffer The buffer into which the received item is to be copied.
+ * The number of bytes of each queued item is specified when the queue is
+ * created. This number of bytes is copied into pvBuffer.
+ *
+ * @param xTickToDelay The number of ticks that the co-routine should block
+ * to wait for data to become available from the queue, should data not be
+ * available immediately. The actual amount of time this equates to is defined
+ * by configTICK_RATE_HZ (set in FreeRTOSConfig.h). The constant
+ * portTICK_RATE_MS can be used to convert ticks to milliseconds (see the
+ * crQUEUE_SEND example).
+ *
+ * @param pxResult The variable pointed to by pxResult will be set to pdPASS if
+ * data was successfully retrieved from the queue, otherwise it will be set to
+ * an error code as defined within ProjDefs.h.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine receives the number of an LED to flash from a queue. It
+ // blocks on the queue until the number is received.
+ static void prvCoRoutineFlashWorkTask( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // Variables in co-routines must be declared static if they must maintain value across a blocking call.
+ static portBASE_TYPE xResult;
+ static unsigned portBASE_TYPE uxLEDToFlash;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Wait for data to become available on the queue.
+ crQUEUE_RECEIVE( xHandle, xCoRoutineQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+ if( xResult == pdPASS )
+ {
+ // We received the LED to flash - flash it!
+ vParTestToggleLED( uxLEDToFlash );
+ }
+ }
+
+ crEND();
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE crQUEUE_RECEIVE
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE( xHandle, pxQueue, pvBuffer, xTicksToWait, pxResult ) \
+{ \
+ *pxResult = xQueueCRReceive( pxQueue, pvBuffer, xTicksToWait ); \
+ if( *pxResult == errQUEUE_BLOCKED ) \
+ { \
+ crSET_STATE0( xHandle ); \
+ *pxResult = xQueueCRReceive( pxQueue, pvBuffer, 0 ); \
+ } \
+ if( *pxResult == errQUEUE_YIELD ) \
+ { \
+ crSET_STATE1( xHandle ); \
+ *pxResult = pdPASS; \
+ } \
+}
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_SEND_FROM_ISR(
+ xQueueHandle pxQueue,
+ void *pvItemToQueue,
+ portBASE_TYPE xCoRoutinePreviouslyWoken
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_SEND_FROM_ISR can only be called from an ISR to send data to a queue
+ * that is being used from within a co-routine.
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xCoRoutinePreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call.
+ *
+ * @return pdTRUE if a co-routine was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that blocks on a queue waiting for characters to be received.
+ static void vReceivingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ portCHAR cRxedChar;
+ portBASE_TYPE xResult;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Wait for data to become available on the queue. This assumes the
+ // queue xCommsRxQueue has already been created!
+ crQUEUE_RECEIVE( xHandle, xCommsRxQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+ // Was a character received?
+ if( xResult == pdPASS )
+ {
+ // Process the character here.
+ }
+ }
+
+ // All co-routines must end with a call to crEND().
+ crEND();
+ }
+
+ // An ISR that uses a queue to send characters received on a serial port to
+ // a co-routine.
+ void vUART_ISR( void )
+ {
+ portCHAR cRxedChar;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+ // We loop around reading characters until there are none left in the UART.
+ while( UART_RX_REG_NOT_EMPTY() )
+ {
+ // Obtain the character from the UART.
+ cRxedChar = UART_RX_REG;
+
+ // Post the character onto a queue. xCRWokenByPost will be pdFALSE
+ // the first time around the loop. If the post causes a co-routine
+ // to be woken (unblocked) then xCRWokenByPost will be set to pdTRUE.
+ // In this manner we can ensure that if more than one co-routine is
+ // blocked on the queue only one is woken by this ISR no matter how
+ // many characters are posted to the queue.
+ xCRWokenByPost = crQUEUE_SEND_FROM_ISR( xCommsRxQueue, &cRxedChar, xCRWokenByPost );
+ }
+ }</pre>
+ * \defgroup crQUEUE_SEND_FROM_ISR crQUEUE_SEND_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_SEND_FROM_ISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken ) xQueueCRSendFromISR( pxQueue, pvItemToQueue, xCoRoutinePreviouslyWoken )
+
+
+/**
+ * croutine. h
+ * <pre>
+ crQUEUE_SEND_FROM_ISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE * pxCoRoutineWoken
+ )</pre>
+ *
+ * The macro's crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() are the
+ * co-routine equivalent to the xQueueSendFromISR() and xQueueReceiveFromISR()
+ * functions used by tasks.
+ *
+ * crQUEUE_SEND_FROM_ISR() and crQUEUE_RECEIVE_FROM_ISR() can only be used to
+ * pass data between a co-routine and and ISR, whereas xQueueSendFromISR() and
+ * xQueueReceiveFromISR() can only be used to pass data between a task and and
+ * ISR.
+ *
+ * crQUEUE_RECEIVE_FROM_ISR can only be called from an ISR to receive data
+ * from a queue that is being used from within a co-routine (a co-routine
+ * posted to the queue).
+ *
+ * See the co-routine section of the WEB documentation for information on
+ * passing data between tasks and co-routines and between ISR's and
+ * co-routines.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvBuffer A pointer to a buffer into which the received item will be
+ * placed. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from the queue into
+ * pvBuffer.
+ *
+ * @param pxCoRoutineWoken A co-routine may be blocked waiting for space to become
+ * available on the queue. If crQUEUE_RECEIVE_FROM_ISR causes such a
+ * co-routine to unblock *pxCoRoutineWoken will get set to pdTRUE, otherwise
+ * *pxCoRoutineWoken will remain unchanged.
+ *
+ * @return pdTRUE an item was successfully received from the queue, otherwise
+ * pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ // A co-routine that posts a character to a queue then blocks for a fixed
+ // period. The character is incremented each time.
+ static void vSendingCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+ {
+ // cChar holds its value while this co-routine is blocked and must therefore
+ // be declared static.
+ static portCHAR cCharToTx = 'a';
+ portBASE_TYPE xResult;
+
+ // All co-routines must start with a call to crSTART().
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ // Send the next character to the queue.
+ crQUEUE_SEND( xHandle, xCoRoutineQueue, &cCharToTx, NO_DELAY, &xResult );
+
+ if( xResult == pdPASS )
+ {
+ // The character was successfully posted to the queue.
+ }
+ else
+ {
+ // Could not post the character to the queue.
+ }
+
+ // Enable the UART Tx interrupt to cause an interrupt in this
+ // hypothetical UART. The interrupt will obtain the character
+ // from the queue and send it.
+ ENABLE_RX_INTERRUPT();
+
+ // Increment to the next character then block for a fixed period.
+ // cCharToTx will maintain its value across the delay as it is
+ // declared static.
+ cCharToTx++;
+ if( cCharToTx > 'x' )
+ {
+ cCharToTx = 'a';
+ }
+ crDELAY( 100 );
+ }
+
+ // All co-routines must end with a call to crEND().
+ crEND();
+ }
+
+ // An ISR that uses a queue to receive characters to send on a UART.
+ void vUART_ISR( void )
+ {
+ portCHAR cCharToTx;
+ portBASE_TYPE xCRWokenByPost = pdFALSE;
+
+ while( UART_TX_REG_EMPTY() )
+ {
+ // Are there any characters in the queue waiting to be sent?
+ // xCRWokenByPost will automatically be set to pdTRUE if a co-routine
+ // is woken by the post - ensuring that only a single co-routine is
+ // woken no matter how many times we go around this loop.
+ if( crQUEUE_RECEIVE_FROM_ISR( pxQueue, &cCharToTx, &xCRWokenByPost ) )
+ {
+ SEND_CHARACTER( cCharToTx );
+ }
+ }
+ }</pre>
+ * \defgroup crQUEUE_RECEIVE_FROM_ISR crQUEUE_RECEIVE_FROM_ISR
+ * \ingroup Tasks
+ */
+#define crQUEUE_RECEIVE_FROM_ISR( pxQueue, pvBuffer, pxCoRoutineWoken ) xQueueCRReceiveFromISR( pxQueue, pvBuffer, pxCoRoutineWoken )
+
+/*
+ * This function is intended for internal use by the co-routine macros only.
+ * The macro nature of the co-routine implementation requires that the
+ * prototype appears here. The function should not be used by application
+ * writers.
+ *
+ * Removes the current co-routine from its ready list and places it in the
+ * appropriate delayed list.
+ */
+void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList );
+
+/*
+ * This function is intended for internal use by the queue implementation only.
+ * The function should not be used by application writers.
+ *
+ * Removes the highest priority co-routine from the event list and places it in
+ * the pending ready list.
+ */
+signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList );
+
+
+#endif /* CO_ROUTINE_H */
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+ * This is the list implementation used by the scheduler. While it is tailored
+ * heavily for the schedulers needs, it is also available for use by
+ * application code.
+ *
+ * xLists can only store pointers to xListItems. Each xListItem contains a
+ * numeric value (xItemValue). Most of the time the lists are sorted in
+ * descending item value order.
+ *
+ * Lists are created already containing one list item. The value of this
+ * item is the maximum possible that can be stored, it is therefore always at
+ * the end of the list and acts as a marker. The list member pxHead always
+ * points to this marker - even though it is at the tail of the list. This
+ * is because the tail contains a wrap back pointer to the true head of
+ * the list.
+ *
+ * In addition to it's value, each list item contains a pointer to the next
+ * item in the list (pxNext), a pointer to the list it is in (pxContainer)
+ * and a pointer to back to the object that contains it. These later two
+ * pointers are included for efficiency of list manipulation. There is
+ * effectively a two way link between the object containing the list item and
+ * the list item itself.
+ *
+ *
+ * \page ListIntroduction List Implementation
+ * \ingroup FreeRTOSIntro
+ */
+
+/*
+ Changes from V4.3.1
+
+ + Included local const within listGET_OWNER_OF_NEXT_ENTRY() to assist
+ compiler with optimisation. Thanks B.R.
+*/
+
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Definition of the only type of object that a list can contain.
+ */
+struct xLIST_ITEM
+{
+ portTickType xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
+ volatile struct xLIST_ITEM * pxNext; /*< Pointer to the next xListItem in the list. */
+ volatile struct xLIST_ITEM * pxPrevious;/*< Pointer to the previous xListItem in the list. */
+ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
+ void * pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
+};
+typedef struct xLIST_ITEM xListItem; /* For some reason lint wants this as two separate definitions. */
+
+struct xMINI_LIST_ITEM
+{
+ portTickType xItemValue;
+ volatile struct xLIST_ITEM *pxNext;
+ volatile struct xLIST_ITEM *pxPrevious;
+};
+typedef struct xMINI_LIST_ITEM xMiniListItem;
+
+/*
+ * Definition of the type of queue used by the scheduler.
+ */
+typedef struct xLIST
+{
+ volatile unsigned portBASE_TYPE uxNumberOfItems;
+ volatile xListItem * pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to pvListGetOwnerOfNextEntry (). */
+ volatile xMiniListItem xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
+} xList;
+
+/*
+ * Access macro to set the owner of a list item. The owner of a list item
+ * is the object (usually a TCB) that contains the list item.
+ *
+ * \page listSET_LIST_ITEM_OWNER listSET_LIST_ITEM_OWNER
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner ) ( pxListItem )->pvOwner = ( void * ) pxOwner
+
+/*
+ * Access macro to set the value of the list item. In most cases the value is
+ * used to sort the list in descending order.
+ *
+ * \page listSET_LIST_ITEM_VALUE listSET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listSET_LIST_ITEM_VALUE( pxListItem, xValue ) ( pxListItem )->xItemValue = xValue
+
+/*
+ * Access macro the retrieve the value of the list item. The value can
+ * represent anything - for example a the priority of a task, or the time at
+ * which a task should be unblocked.
+ *
+ * \page listGET_LIST_ITEM_VALUE listGET_LIST_ITEM_VALUE
+ * \ingroup LinkedList
+ */
+#define listGET_LIST_ITEM_VALUE( pxListItem ) ( ( pxListItem )->xItemValue )
+
+/*
+ * Access macro to determine if a list contains any items. The macro will
+ * only have the value true if the list is empty.
+ *
+ * \page listLIST_IS_EMPTY listLIST_IS_EMPTY
+ * \ingroup LinkedList
+ */
+#define listLIST_IS_EMPTY( pxList ) ( ( pxList )->uxNumberOfItems == ( unsigned portBASE_TYPE ) 0 )
+
+/*
+ * Access macro to return the number of items in the list.
+ */
+#define listCURRENT_LIST_LENGTH( pxList ) ( ( pxList )->uxNumberOfItems )
+
+/*
+ * Access function to obtain the owner of the next entry in a list.
+ *
+ * The list member pxIndex is used to walk through a list. Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pxIndex to the next item in the list
+ * and returns that entries pxOwner parameter. Using multiple calls to this
+ * function it is therefore possible to move through every item contained in
+ * a list.
+ *
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item. In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the next item owner is to be returned.
+ *
+ * \page listGET_OWNER_OF_NEXT_ENTRY listGET_OWNER_OF_NEXT_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \
+{ \
+xList * const pxConstList = pxList; \
+ /* Increment the index to the next item and return the item, ensuring */ \
+ /* we don't return the marker used at the end of the list. */ \
+ ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
+ if( ( pxConstList )->pxIndex == ( xListItem * ) &( ( pxConstList )->xListEnd ) ) \
+ { \
+ ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \
+ } \
+ pxTCB = ( pxConstList )->pxIndex->pvOwner; \
+}
+
+
+/*
+ * Access function to obtain the owner of the first entry in a list. Lists
+ * are normally sorted in ascending item value order.
+ *
+ * This function returns the pxOwner member of the first item in the list.
+ * The pxOwner parameter of a list item is a pointer to the object that owns
+ * the list item. In the scheduler this is normally a task control block.
+ * The pxOwner parameter effectively creates a two way link between the list
+ * item and its owner.
+ *
+ * @param pxList The list from which the owner of the head item is to be
+ * returned.
+ *
+ * \page listGET_OWNER_OF_HEAD_ENTRY listGET_OWNER_OF_HEAD_ENTRY
+ * \ingroup LinkedList
+ */
+#define listGET_OWNER_OF_HEAD_ENTRY( pxList ) ( ( pxList->uxNumberOfItems != ( unsigned portBASE_TYPE ) 0 ) ? ( (&( pxList->xListEnd ))->pxNext->pvOwner ) : ( NULL ) )
+
+/*
+ * Check to see if a list item is within a list. The list item maintains a
+ * "container" pointer that points to the list it is in. All this macro does
+ * is check to see if the container and the list match.
+ *
+ * @param pxList The list we want to know if the list item is within.
+ * @param pxListItem The list item we want to know if is in the list.
+ * @return pdTRUE is the list item is in the list, otherwise pdFALSE.
+ * pointer against
+ */
+#define listIS_CONTAINED_WITHIN( pxList, pxListItem ) ( ( pxListItem )->pvContainer == ( void * ) pxList )
+
+/*
+ * Must be called before a list is used! This initialises all the members
+ * of the list structure and inserts the xListEnd item into the list as a
+ * marker to the back of the list.
+ *
+ * @param pxList Pointer to the list being initialised.
+ *
+ * \page vListInitialise vListInitialise
+ * \ingroup LinkedList
+ */
+void vListInitialise( xList *pxList );
+
+/*
+ * Must be called before a list item is used. This sets the list container to
+ * null so the item does not think that it is already contained in a list.
+ *
+ * @param pxItem Pointer to the list item being initialised.
+ *
+ * \page vListInitialiseItem vListInitialiseItem
+ * \ingroup LinkedList
+ */
+void vListInitialiseItem( xListItem *pxItem );
+
+/*
+ * Insert a list item into a list. The item will be inserted into the list in
+ * a position determined by its item value (descending item value order).
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The item to that is to be placed in the list.
+ *
+ * \page vListInsert vListInsert
+ * \ingroup LinkedList
+ */
+void vListInsert( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Insert a list item into a list. The item will be inserted in a position
+ * such that it will be the last item within the list returned by multiple
+ * calls to listGET_OWNER_OF_NEXT_ENTRY.
+ *
+ * The list member pvIndex is used to walk through a list. Calling
+ * listGET_OWNER_OF_NEXT_ENTRY increments pvIndex to the next item in the list.
+ * Placing an item in a list using vListInsertEnd effectively places the item
+ * in the list position pointed to by pvIndex. This means that every other
+ * item within the list will be returned by listGET_OWNER_OF_NEXT_ENTRY before
+ * the pvIndex parameter again points to the item being inserted.
+ *
+ * @param pxList The list into which the item is to be inserted.
+ *
+ * @param pxNewListItem The list item to be inserted into the list.
+ *
+ * \page vListInsertEnd vListInsertEnd
+ * \ingroup LinkedList
+ */
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem );
+
+/*
+ * Remove an item from a list. The list item has a pointer to the list that
+ * it is in, so only the list item need be passed into the function.
+ *
+ * @param vListRemove The item to be removed. The item will remove itself from
+ * the list pointed to by it's pxContainer parameter.
+ *
+ * \page vListRemove vListRemove
+ * \ingroup LinkedList
+ */
+void vListRemove( xListItem *pxItemToRemove );
+
+
+
+#endif
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http:www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http:www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*-----------------------------------------------------------
+ * Portable layer API. Each function must be defined for each port.
+ *----------------------------------------------------------*/
+
+#ifndef PORTABLE_H
+#define PORTABLE_H
+
+/* Include the macro file relevant to the port being used. */
+
+#ifdef OPEN_WATCOM_INDUSTRIAL_PC_PORT
+ #include "..\..\source\portable\owatcom\16bitdos\pc\portmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef OPEN_WATCOM_FLASH_LITE_186_PORT
+ #include "..\..\source\portable\owatcom\16bitdos\flsh186\portmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef GCC_MEGA_AVR
+ #include "../portable/GCC/ATMega323/portmacro.h"
+#endif
+
+#ifdef IAR_MEGA_AVR
+ #include "../portable/IAR/ATMega323/portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC24_PORT
+ #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_DSPIC_PORT
+ #include "..\..\Source\portable\MPLAB\PIC24_dsPIC\portmacro.h"
+#endif
+
+#ifdef MPLAB_PIC18F_PORT
+ #include "..\..\source\portable\MPLAB\PIC18F\portmacro.h"
+#endif
+
+#ifdef _FEDPICC
+ #include "libFreeRTOS/Include/portmacro.h"
+#endif
+
+#ifdef SDCC_CYGNAL
+ #include "../../Source/portable/SDCC/Cygnal/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7
+ #include "FreeRTOS/portable/GCC/ARM7_LPC2000/portmacro.h"
+#endif
+
+#ifdef GCC_ARM7_ECLIPSE
+ #include "portmacro.h"
+#endif
+
+#ifdef ROWLEY_LPC23xx
+ #include "../../Source/portable/GCC/ARM7_LPC23xx/portmacro.h"
+#endif
+
+#ifdef GCC_MSP430
+ #include "../../Source/portable/GCC/MSP430F449/portmacro.h"
+#endif
+
+#ifdef ROWLEY_MSP430
+ #include "../../Source/portable/Rowley/MSP430F449/portmacro.h"
+#endif
+
+#ifdef KEIL_ARM7
+ #include "..\..\Source\portable\Keil\ARM7\portmacro.h"
+#endif
+
+#ifdef SAM7_GCC
+ #include "../../Source/portable/GCC/ARM7_AT91SAM7S/portmacro.h"
+#endif
+
+#ifdef SAM7_IAR
+ #include "..\..\Source\portable\IAR\AtmelSAM7S64\portmacro.h"
+#endif
+
+#ifdef LPC2000_IAR
+ #include "..\..\Source\portable\IAR\LPC2000\portmacro.h"
+#endif
+
+#ifdef STR71X_IAR
+ #include "..\..\Source\portable\IAR\STR71x\portmacro.h"
+#endif
+
+#ifdef STR75X_IAR
+ #include "..\..\Source\portable\IAR\STR75x\portmacro.h"
+#endif
+
+#ifdef STR75X_GCC
+ #include "..\..\Source\portable\GCC\STR75x\portmacro.h"
+#endif
+
+#ifdef STR91X_IAR
+ #include "..\..\Source\portable\IAR\STR91x\portmacro.h"
+#endif
+
+#ifdef GCC_H8S
+ #include "../../Source/portable/GCC/H8S2329/portmacro.h"
+#endif
+
+#ifdef GCC_AT91FR40008
+ #include "../../Source/portable/GCC/ARM7_AT91FR40008/portmacro.h"
+#endif
+
+#ifdef RVDS_ARMCM3_LM3S102
+ #include "../../Source/portable/RVDS/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef GCC_ARMCM3_LM3S102
+ #include "../../Source/portable/GCC/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef IAR_ARM_CM3
+ #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef IAR_ARMCM3_LM
+ #include "../../Source/portable/IAR/ARM_CM3/portmacro.h"
+#endif
+
+#ifdef HCS12_CODE_WARRIOR
+ #include "../../Source/portable/CodeWarrior/HCS12/portmacro.h"
+#endif
+
+#ifdef MICROBLAZE_GCC
+ #include "../../Source/portable/GCC/MicroBlaze/portmacro.h"
+#endif
+
+#ifdef TERN_EE
+ #include "..\..\Source\portable\Paradigm\Tern_EE\small\portmacro.h"
+#endif
+
+#ifdef GCC_HCS12
+ #include "../../Source/portable/GCC/HCS12/portmacro.h"
+#endif
+
+#ifdef GCC_MCF5235
+ #include "../../Source/portable/GCC/MCF5235/portmacro.h"
+#endif
+
+#ifdef BCC_INDUSTRIAL_PC_PORT
+ /* A short file name has to be used in place of the normal
+ FreeRTOSConfig.h when using the Borland compiler. */
+ #include "frconfig.h"
+ #include "..\portable\BCC\16BitDOS\PC\prtmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef BCC_FLASH_LITE_186_PORT
+ /* A short file name has to be used in place of the normal
+ FreeRTOSConfig.h when using the Borland compiler. */
+ #include "frconfig.h"
+ #include "..\portable\BCC\16BitDOS\flsh186\prtmacro.h"
+ typedef void ( __interrupt __far *pxISR )();
+#endif
+
+#ifdef __GNUC__
+ #ifdef __AVR32_AVR32A__
+ #include "portmacro.h"
+ #endif
+#endif
+
+#ifdef __ICCAVR32__
+ #ifdef __CORE__
+ #if __CORE__ == __AVR32A__
+ #include "portmacro.h"
+ #endif
+ #endif
+#endif
+
+/*
+ * Setup the stack of a new task so it is ready to be placed under the
+ * scheduler control. The registers have to be placed on the stack in
+ * the order that the port expects to find them.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters );
+
+/*
+ * Map to the memory management routines required for the port.
+ */
+void vPortUsedMem(int *bytesFree, int *bytesUsed, int *blocksFree);
+void *pvPortMalloc( size_t xSize );
+void vPortFree( void *pv );
+void vPortInitialiseBlocks( void );
+
+/*
+ * Setup the hardware ready for the scheduler to take control. This generally
+ * sets up a tick interrupt and sets timers for the correct tick frequency.
+ */
+portBASE_TYPE xPortStartScheduler( void );
+
+/*
+ * Undo any hardware/ISR setup that was performed by xPortStartScheduler() so
+ * the hardware is left in its original condition after the scheduler stops
+ * executing.
+ */
+void vPortEndScheduler( void );
+
+
+#endif /* PORTABLE_H */
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#ifndef PROJDEFS_H
+#define PROJDEFS_H
+
+/* Defines to prototype to which task functions must conform. */
+typedef void (*pdTASK_CODE)( void * );
+
+#define pdTRUE ( 1 )
+#define pdFALSE ( 0 )
+
+#define pdPASS ( 1 )
+#define pdFAIL ( 0 )
+#define errQUEUE_EMPTY ( 0 )
+#define errQUEUE_FULL ( 0 )
+
+/* Error definitions. */
+#define errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ( -1 )
+#define errNO_TASK_TO_RUN ( -2 )
+#define errQUEUE_BLOCKED ( -4 )
+#define errQUEUE_YIELD ( -5 )
+
+#endif /* PROJDEFS_H */
+
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef void * xQueueHandle;
+
+/**
+ * queue. h
+ * <pre>
+ xQueueHandle xQueueCreate(
+ unsigned portBASE_TYPE uxQueueLength,
+ unsigned portBASE_TYPE uxItemSize
+ );
+ * </pre>
+ *
+ * Creates a new queue instance. This allocates the storage required by the
+ * new queue and returns a handle for the queue.
+ *
+ * @param uxQueueLength The maximum number of items that the queue can contain.
+ *
+ * @param uxItemSize The number of bytes each item in the queue will require.
+ * Items are queued by copy, not by reference, so this is the number of bytes
+ * that will be copied for each posted item. Each item on the queue must be
+ * the same size.
+ *
+ * @return If the queue is successfully create then a handle to the newly
+ * created queue is returned. If the queue cannot be created then 0 is
+ * returned.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ };
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+ if( xQueue1 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue2 == 0 )
+ {
+ // Queue was not created and must not be used.
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueCreate xQueueCreate
+ * \ingroup QueueManagement
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSend(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ portTickType xTicksToWait
+ );
+ * </pre>
+ *
+ * Post an item on a queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueSendFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for space to become available on the queue, should it already
+ * be full. The call will return immediately if this is set to 0. The
+ * time is defined in tick periods so the constant portTICK_RATE_MS
+ * should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if the item was successfully posted, otherwise errQUEUE_FULL.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ unsigned portLONG ulVar = 10UL;
+
+ void vATask( void *pvParameters )
+ {
+ xQueueHandle xQueue1, xQueue2;
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 unsigned long values.
+ xQueue1 = xQueueCreate( 10, sizeof( unsigned portLONG ) );
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue2 = xQueueCreate( 10, sizeof( struct AMessage * ) );
+
+ // ...
+
+ if( xQueue1 != 0 )
+ {
+ // Send an unsigned long. Wait for 10 ticks for space to become
+ // available if necessary.
+ if( xQueueSend( xQueue1, ( void * ) &ulVar, ( portTickType ) 10 ) != pdPASS )
+ {
+ // Failed to post the message, even after 10 ticks.
+ }
+ }
+
+ if( xQueue2 != 0 )
+ {
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue2, ( void * ) &pxMessage, ( portTickType ) 0 );
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueSend xQueueSend
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceive(
+ xQueueHandle xQueue,
+ void *pvBuffer,
+ portTickType xTicksToWait
+ );</pre>
+ *
+ * Receive an item from a queue. The item is received by copy so a buffer of
+ * adequate size must be provided. The number of bytes copied into the buffer
+ * was defined when the queue was created.
+ *
+ * This function must not be used in an interrupt service routine. See
+ * xQueueReceiveFromISR for an alternative that can.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param xTicksToWait The maximum amount of time the task should block
+ * waiting for an item to receive should the queue be empty at the time
+ * of the call. The time is defined in tick periods so the constant
+ * portTICK_RATE_MS should be used to convert to real time if this is required.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+ struct AMessage
+ {
+ portCHAR ucMessageID;
+ portCHAR ucData[ 20 ];
+ } xMessage;
+
+ xQueueHandle xQueue;
+
+ // Task to create a queue and post a value.
+ void vATask( void *pvParameters )
+ {
+ struct AMessage *pxMessage;
+
+ // Create a queue capable of containing 10 pointers to AMessage structures.
+ // These should be passed by pointer as they contain a lot of data.
+ xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Send a pointer to a struct AMessage object. Don't block if the
+ // queue is already full.
+ pxMessage = & xMessage;
+ xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );
+
+ // ... Rest of task code.
+ }
+
+ // Task to receive from the queue.
+ void vADifferentTask( void *pvParameters )
+ {
+ struct AMessage *pxRxedMessage;
+
+ if( xQueue != 0 )
+ {
+ // Receive a message on the created queue. Block for 10 ticks if a
+ // message is not immediately available.
+ if( xQueueReceive( xQueue, &( pxRxedMessage ), ( portTickType ) 10 ) )
+ {
+ // pcRxedMessage now points to the struct AMessage variable posted
+ // by vATask.
+ }
+ }
+
+ // ... Rest of task code.
+ }
+ </pre>
+ * \defgroup xQueueReceive xQueueReceive
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceive( xQueueHandle xQueue, void *pvBuffer, portTickType xTicksToWait );
+
+/**
+ * queue. h
+ * <pre>unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );</pre>
+ *
+ * Return the number of messages stored in a queue.
+ *
+ * @param xQueue A handle to the queue being queried.
+ *
+ * @return The number of messages available in the queue.
+ *
+ * \page uxQueueMessagesWaiting uxQueueMessagesWaiting
+ * \ingroup QueueManagement
+ */
+unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );
+
+/**
+ * queue. h
+ * <pre>void vQueueDelete( xQueueHandle xQueue );</pre>
+ *
+ * Delete a queue - freeing all the memory allocated for storing of items
+ * placed on the queue.
+ *
+ * @param xQueue A handle to the queue to be deleted.
+ *
+ * \page vQueueDelete vQueueDelete
+ * \ingroup QueueManagement
+ */
+void vQueueDelete( xQueueHandle xQueue );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueSendFromISR(
+ xQueueHandle pxQueue,
+ const void *pvItemToQueue,
+ portBASE_TYPE xTaskPreviouslyWoken
+ );
+ </pre>
+ *
+ * Post an item on a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * Items are queued by copy not reference so it is preferable to only
+ * queue small items, especially when called from an ISR. In most cases
+ * it would be preferable to store a pointer to the item being queued.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @param cTaskPreviouslyWoken This is included so an ISR can post onto
+ * the same queue multiple times from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call. See the file serial .c in the
+ * PC port for a good example of this mechanism.
+ *
+ * @return pdTRUE if a task was woken by posting onto the queue. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage for buffered IO (where the ISR can obtain more than one value
+ * per call):
+ <pre>
+ void vBufferISR( void )
+ {
+ portCHAR cIn;
+ portBASE_TYPE xTaskWokenByPost;
+
+ // We have not woken a task at the start of the ISR.
+ cTaskWokenByPost = pdFALSE;
+
+ // Loop until the buffer is empty.
+ do
+ {
+ // Obtain a byte from the buffer.
+ cIn = portINPUT_BYTE( RX_REGISTER_ADDRESS );
+
+ // Post the byte. The first time round the loop cTaskWokenByPost
+ // will be pdFALSE. If the queue send causes a task to wake we do
+ // not want the task to run until we have finished the ISR, so
+ // xQueueSendFromISR does not cause a context switch. Also we
+ // don't want subsequent posts to wake any other tasks, so we store
+ // the return value back into cTaskWokenByPost so xQueueSendFromISR
+ // knows not to wake any task the next iteration of the loop.
+ xTaskWokenByPost = xQueueSendFromISR( xRxQueue, &cIn, cTaskWokenByPost );
+
+ } while( portINPUT_BYTE( BUFFER_COUNT ) );
+
+ // Now the buffer is empty we can switch context if necessary.
+ if( cTaskWokenByPost )
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ *
+ * \defgroup xQueueSendFromISR xQueueSendFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
+
+/**
+ * queue. h
+ * <pre>
+ portBASE_TYPE xQueueReceiveFromISR(
+ xQueueHandle pxQueue,
+ void *pvBuffer,
+ portBASE_TYPE *pxTaskWoken
+ );
+ * </pre>
+ *
+ * Receive an item from a queue. It is safe to use this function from within an
+ * interrupt service routine.
+ *
+ * @param pxQueue The handle to the queue from which the item is to be
+ * received.
+ *
+ * @param pvBuffer Pointer to the buffer into which the received item will
+ * be copied.
+ *
+ * @param pxTaskWoken A task may be blocked waiting for space to become
+ * available on the queue. If xQueueReceiveFromISR causes such a task to
+ * unblock *pxTaskWoken will get set to pdTRUE, otherwise *pxTaskWoken will
+ * remain unchanged.
+ *
+ * @return pdTRUE if an item was successfully received from the queue,
+ * otherwise pdFALSE.
+ *
+ * Example usage:
+ <pre>
+
+ xQueueHandle xQueue;
+
+ // Function to create a queue and post some values.
+ void vAFunction( void *pvParameters )
+ {
+ portCHAR cValueToPost;
+ const portTickType xBlockTime = ( portTickType )0xff;
+
+ // Create a queue capable of containing 10 characters.
+ xQueue = xQueueCreate( 10, sizeof( portCHAR ) );
+ if( xQueue == 0 )
+ {
+ // Failed to create the queue.
+ }
+
+ // ...
+
+ // Post some characters that will be used within an ISR. If the queue
+ // is full then this task will block for xBlockTime ticks.
+ cValueToPost = 'a';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ cValueToPost = 'b';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+
+ // ... keep posting characters ... this task may block when the queue
+ // becomes full.
+
+ cValueToPost = 'c';
+ xQueueSend( xQueue, ( void * ) &cValueToPost, xBlockTime );
+ }
+
+ // ISR that outputs all the characters received on the queue.
+ void vISR_Routine( void )
+ {
+ portBASE_TYPE xTaskWokenByReceive = pdFALSE;
+ portCHAR cRxedChar;
+
+ while( xQueueReceiveFromISR( xQueue, ( void * ) &cRxedChar, &xTaskWokenByReceive) )
+ {
+ // A character was received. Output the character now.
+ vOutputCharacter( cRxedChar );
+
+ // If removing the character from the queue woke the task that was
+ // posting onto the queue cTaskWokenByReceive will have been set to
+ // pdTRUE. No matter how many times this loop iterates only one
+ // task will be woken.
+ }
+
+ if( cTaskWokenByPost != ( portCHAR ) pdFALSE;
+ {
+ taskYIELD ();
+ }
+ }
+ </pre>
+ * \defgroup xQueueReceiveFromISR xQueueReceiveFromISR
+ * \ingroup QueueManagement
+ */
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+
+/*
+ * The functions defined above are for passing data to and from tasks. The
+ * functions below are the equivalents for passing data to and from
+ * co-rtoutines.
+ *
+ * These functions are called from the co-routine macro implementation and
+ * should not be called directly from application code. Instead use the macro
+ * wrappers defined within croutine.h.
+ */
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+
+#endif
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#include "queue.h"
+
+#ifndef SEMAPHORE_H
+#define SEMAPHORE_H
+
+typedef xQueueHandle xSemaphoreHandle;
+
+#define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( unsigned portCHAR ) 1 )
+#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( unsigned portCHAR ) 0 )
+#define semGIVE_BLOCK_TIME ( ( portTickType ) 0 )
+
+
+/**
+ * semphr. h
+ * <pre>vSemaphoreCreateBinary( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> that implements a semaphore by using the existing queue mechanism.
+ * The queue length is 1 as this is a binary semaphore. The data size is 0
+ * as we don't want to actually store any data - we just want to know if the
+ * queue is empty or full.
+ *
+ * @param xSemaphore Handle to the created semaphore. Should be of type xSemaphoreHandle.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore;
+
+ void vATask( void * pvParameters )
+ {
+ // Semaphore cannot be used before a call to vSemaphoreCreateBinary ().
+ // This is a macro so pass the variable in directly.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ // The semaphore was created successfully.
+ // The semaphore can now be used.
+ }
+ }
+ </pre>
+ * \defgroup vSemaphoreCreateBinary vSemaphoreCreateBinary
+ * \ingroup Semaphores
+ */
+#define vSemaphoreCreateBinary( xSemaphore ) { \
+ xSemaphore = xQueueCreate( ( unsigned portCHAR ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH ); \
+ if( xSemaphore != NULL ) \
+ { \
+ xSemaphoreGive( xSemaphore ); \
+ } \
+ }
+
+/**
+ * semphr. h
+ * xSemaphoreTake(
+ * xSemaphoreHandle xSemaphore,
+ * portTickType xBlockTime
+ * )</pre>
+ *
+ * <i>Macro</i> to obtain a semaphore. The semaphore must of been created using
+ * vSemaphoreCreateBinary ().
+ *
+ * @param xSemaphore A handle to the semaphore being obtained. This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @param xBlockTime The time in ticks to wait for the semaphore to become
+ * available. The macro portTICK_RATE_MS can be used to convert this to a
+ * real time. A block time of zero can be used to poll the semaphore.
+ *
+ * @return pdTRUE if the semaphore was obtained. pdFALSE if xBlockTime
+ * expired without the semaphore becoming available.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // A task that creates a semaphore.
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+ }
+
+ // A task that uses the semaphore.
+ void vAnotherTask( void * pvParameters )
+ {
+ // ... Do other things.
+
+ if( xSemaphore != NULL )
+ {
+ // See if we can obtain the semaphore. If the semaphore is not available
+ // wait 10 ticks to see if it becomes free.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 10 ) == pdTRUE )
+ {
+ // We were able to obtain the semaphore and can now access the
+ // shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource. Release the
+ // semaphore.
+ xSemaphoreGive( xSemaphore );
+ }
+ else
+ {
+ // We could not obtain the semaphore and can therefore not access
+ // the shared resource safely.
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreTake xSemaphoreTake
+ * \ingroup Semaphores
+ */
+#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueReceive( ( xQueueHandle ) xSemaphore, NULL, xBlockTime )
+
+/**
+ * semphr. h
+ * <pre>xSemaphoreGive( xSemaphoreHandle xSemaphore )</pre>
+ *
+ * <i>Macro</i> to release a semaphore. The semaphore must of been created using
+ * vSemaphoreCreateBinary (), and obtained using sSemaphoreTake ().
+ *
+ * This must not be used from an ISR. See xSemaphoreGiveFromISR () for
+ * an alternative which can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @return pdTRUE if the semaphore was released. pdFALSE if an error occurred.
+ * Semaphores are implemented using queues. An error can occur if there is
+ * no space on the queue to post a message - indicating that the
+ * semaphore was not first obtained correctly.
+ *
+ * Example usage:
+ <pre>
+ xSemaphoreHandle xSemaphore = NULL;
+
+ void vATask( void * pvParameters )
+ {
+ // Create the semaphore to guard a shared resource.
+ vSemaphoreCreateBinary( xSemaphore );
+
+ if( xSemaphore != NULL )
+ {
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would expect this call to fail because we cannot give
+ // a semaphore without first "taking" it!
+ }
+
+ // Obtain the semaphore - don't block if the semaphore is not
+ // immediately available.
+ if( xSemaphoreTake( xSemaphore, ( portTickType ) 0 ) )
+ {
+ // We now have the semaphore and can access the shared resource.
+
+ // ...
+
+ // We have finished accessing the shared resource so can free the
+ // semaphore.
+ if( xSemaphoreGive( xSemaphore ) != pdTRUE )
+ {
+ // We would not expect this call to fail because we must have
+ // obtained the semaphore to get here.
+ }
+ }
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreGive xSemaphoreGive
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGive( xSemaphore ) xQueueSend( ( xQueueHandle ) xSemaphore, NULL, semGIVE_BLOCK_TIME )
+
+/**
+ * semphr. h
+ * <pre>
+ xSemaphoreGiveFromISR(
+ xSemaphoreHandle xSemaphore,
+ portSHORT sTaskPreviouslyWoken
+ )</pre>
+ *
+ * <i>Macro</i> to release a semaphore. The semaphore must of been created using
+ * vSemaphoreCreateBinary (), and obtained using xSemaphoreTake ().
+ *
+ * This macro can be used from an ISR.
+ *
+ * @param xSemaphore A handle to the semaphore being released. This is the
+ * handle returned by vSemaphoreCreateBinary ();
+ *
+ * @param sTaskPreviouslyWoken This is included so an ISR can make multiple calls
+ * to xSemaphoreGiveFromISR () from a single interrupt. The first call
+ * should always pass in pdFALSE. Subsequent calls should pass in
+ * the value returned from the previous call. See the file serial .c in the
+ * PC port for a good example of using xSemaphoreGiveFromISR ().
+ *
+ * @return pdTRUE if a task was woken by releasing the semaphore. This is
+ * used by the ISR to determine if a context switch may be required following
+ * the ISR.
+ *
+ * Example usage:
+ <pre>
+ #define LONG_TIME 0xffff
+ #define TICKS_TO_WAIT 10
+ xSemaphoreHandle xSemaphore = NULL;
+
+ // Repetitive task.
+ void vATask( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // We want this task to run every 10 ticks or a timer. The semaphore
+ // was created before this task was started
+
+ // Block waiting for the semaphore to become available.
+ if( xSemaphoreTake( xSemaphore, LONG_TIME ) == pdTRUE )
+ {
+ // It is time to execute.
+
+ // ...
+
+ // We have finished our task. Return to the top of the loop where
+ // we will block on the semaphore until it is time to execute
+ // again.
+ }
+ }
+ }
+
+ // Timer ISR
+ void vTimerISR( void * pvParameters )
+ {
+ static unsigned portCHAR ucLocalTickCount = 0;
+
+ // A timer tick has occurred.
+
+ // ... Do other time functions.
+
+ // Is it time for vATask () to run?
+ ucLocalTickCount++;
+ if( ucLocalTickCount >= TICKS_TO_WAIT )
+ {
+ // Unblock the task by releasing the semaphore.
+ xSemaphoreGive( xSemaphore );
+
+ // Reset the count so we release the semaphore again in 10 ticks time.
+ ucLocalTickCount = 0;
+ }
+ }
+ </pre>
+ * \defgroup xSemaphoreGiveFromISR xSemaphoreGiveFromISR
+ * \ingroup Semaphores
+ */
+#define xSemaphoreGiveFromISR( xSemaphore, xTaskPreviouslyWoken ) xQueueSendFromISR( ( xQueueHandle ) xSemaphore, NULL, xTaskPreviouslyWoken )
+
+
+#endif
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+Changes since V4.3.1:
+
+ + Added xTaskGetSchedulerState() function.
+*/
+
+#ifndef TASK_H
+#define TASK_H
+
+#include "portable.h"
+#include "list.h"
+
+/*-----------------------------------------------------------
+ * MACROS AND DEFINITIONS
+ *----------------------------------------------------------*/
+
+#define tskKERNEL_VERSION_NUMBER "V4.4.0"
+
+/**
+ * task. h
+ *
+ * Type by which tasks are referenced. For example, a call to xTaskCreate
+ * returns (via a pointer parameter) an xTaskHandle variable that can then
+ * be used as a parameter to vTaskDelete to delete the task.
+ *
+ * \page xTaskHandle xTaskHandle
+ * \ingroup Tasks
+ */
+typedef void * xTaskHandle;
+
+/*
+ * Used internally only.
+ */
+typedef struct xTIME_OUT
+{
+ portBASE_TYPE xOverflowCount;
+ portTickType xTimeOnEntering;
+} xTimeOutType;
+
+/*
+ * Defines the priority used by the idle task. This must not be modified.
+ *
+ * \ingroup TaskUtils
+ */
+#define tskIDLE_PRIORITY ( ( unsigned portBASE_TYPE ) 0 )
+
+/**
+ * task. h
+ *
+ * Macro for forcing a context switch.
+ *
+ * \page taskYIELD taskYIELD
+ * \ingroup SchedulerControl
+ */
+#define taskYIELD() portYIELD()
+
+/**
+ * task. h
+ *
+ * Macro to mark the start of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskENTER_CRITICAL taskENTER_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskENTER_CRITICAL() portENTER_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to mark the end of a critical code region. Preemptive context
+ * switches cannot occur when in a critical region.
+ *
+ * NOTE: This may alter the stack (depending on the portable implementation)
+ * so must be used with care!
+ *
+ * \page taskEXIT_CRITICAL taskEXIT_CRITICAL
+ * \ingroup SchedulerControl
+ */
+#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
+
+/**
+ * task. h
+ *
+ * Macro to disable all maskable interrupts.
+ *
+ * \page taskDISABLE_INTERRUPTS taskDISABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
+
+/**
+ * task. h
+ *
+ * Macro to enable microcontroller interrupts.
+ *
+ * \page taskENABLE_INTERRUPTS taskENABLE_INTERRUPTS
+ * \ingroup SchedulerControl
+ */
+#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
+
+/* Definitions returned by xTaskGetSchedulerState(). */
+#define taskSCHEDULER_NOT_STARTED 0
+#define taskSCHEDULER_RUNNING 1
+#define taskSCHEDULER_SUSPENDED 2
+
+/*-----------------------------------------------------------
+ * TASK CREATION API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ *<pre>
+ portBASE_TYPE xTaskCreate(
+ pdTASK_CODE pvTaskCode,
+ const portCHAR * const pcName,
+ unsigned portSHORT usStackDepth,
+ void *pvParameters,
+ unsigned portBASE_TYPE uxPriority,
+ xTaskHandle *pvCreatedTask
+ );</pre>
+ *
+ * Create a new task and add it to the list of tasks that are ready to run.
+ *
+ * @param pvTaskCode Pointer to the task entry function. Tasks
+ * must be implemented to never return (i.e. continuous loop).
+ *
+ * @param pcName A descriptive name for the task. This is mainly used to
+ * facilitate debugging. Max length defined by tskMAX_TASK_NAME_LEN - default
+ * is 16.
+ *
+ * @param usStackDepth The size of the task stack specified as the number of
+ * variables the stack can hold - not the number of bytes. For example, if
+ * the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
+ * will be allocated for stack storage.
+ *
+ * @param pvParameters Pointer that will be used as the parameter for the task
+ * being created.
+ *
+ * @param uxPriority The priority at which the task should run.
+ *
+ * @param pvCreatedTask Used to pass back a handle by which the created task
+ * can be referenced.
+ *
+ * @return pdPASS if the task was successfully created and added to a ready
+ * list, otherwise an error code defined in the file errors. h
+ *
+ * Example usage:
+ <pre>
+ // Task to be created.
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+ }
+ }
+
+ // Function that creates a task.
+ void vOtherFunction( void )
+ {
+ unsigned char ucParameterToPass;
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+ </pre>
+ * \defgroup xTaskCreate xTaskCreate
+ * \ingroup Tasks
+ */
+signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pvCreatedTask );
+
+/**
+ * task. h
+ * <pre>void vTaskDelete( xTaskHandle pxTask );</pre>
+ *
+ * INCLUDE_vTaskDelete must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Remove a task from the RTOS real time kernels management. The task being
+ * deleted will be removed from all ready, blocked, suspended and event lists.
+ *
+ * NOTE: The idle task is responsible for freeing the kernel allocated
+ * memory from tasks that have been deleted. It is therefore important that
+ * the idle task is not starved of microcontroller processing time if your
+ * application makes any calls to vTaskDelete (). Memory allocated by the
+ * task code is not automatically freed, and should be freed before the task
+ * is deleted.
+ *
+ * See the demo application file death.c for sample code that utilises
+ * vTaskDelete ().
+ *
+ * @param pxTask The handle of the task to be deleted. Passing NULL will
+ * cause the calling task to be deleted.
+ *
+ * Example usage:
+ <pre>
+ void vOtherFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create the task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // Use the handle to delete the task.
+ vTaskDelete( xHandle );
+ }
+ </pre>
+ * \defgroup vTaskDelete vTaskDelete
+ * \ingroup Tasks
+ */
+void vTaskDelete( xTaskHandle pxTask );
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskDelay( portTickType xTicksToDelay );</pre>
+ *
+ * Delay a task for a given number of ticks. The actual time that the
+ * task remains blocked depends on the tick rate. The constant
+ * portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * INCLUDE_vTaskDelay must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * @param xTicksToDelay The amount of time, in tick periods, that
+ * the calling task should block.
+ *
+ * Example usage:
+ <pre>
+ // Wait 10 ticks before performing an action.
+ // NOTE:
+ // This is for demonstration only and would be better achieved
+ // using vTaskDelayUntil ().
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xDelay, xNextTime;
+
+ // Calc the time at which we want to perform the action
+ // next.
+ xNextTime = xTaskGetTickCount () + ( portTickType ) 10;
+
+ for( ;; )
+ {
+ xDelay = xNextTime - xTaskGetTickCount ();
+ xNextTime += ( portTickType ) 10;
+
+ // Guard against overflow
+ if( xDelay <= ( portTickType ) 10 )
+ {
+ vTaskDelay( xDelay );
+ }
+
+ // Perform action here.
+ }
+ }
+ </pre>
+ * \defgroup vTaskDelay vTaskDelay
+ * \ingroup TaskCtrl
+ */
+void vTaskDelay( portTickType xTicksToDelay );
+
+/**
+ * task. h
+ * <pre>void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );</pre>
+ *
+ * INCLUDE_vTaskDelayUntil must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Delay a task until a specified time. This function can be used by cyclical
+ * tasks to ensure a constant execution frequency.
+ *
+ * This function differs from vTaskDelay () in one important aspect: vTaskDelay () will
+ * cause a task to block for the specified number of ticks from the time vTaskDelay () is
+ * called. It is therefore difficult to use vTaskDelay () by itself to generate a fixed
+ * execution frequency as the time between a task starting to execute and that task
+ * calling vTaskDelay () may not be fixed [the task may take a different path though the
+ * code between calls, or may get interrupted or preempted a different number of times
+ * each time it executes].
+ *
+ * Whereas vTaskDelay () specifies a wake time relative to the time at which the function
+ * is called, vTaskDelayUntil () specifies the absolute (exact) time at which it wishes to
+ * unblock.
+ *
+ * The constant portTICK_RATE_MS can be used to calculate real time from the tick
+ * rate - with the resolution of one tick period.
+ *
+ * @param pxPreviousWakeTime Pointer to a variable that holds the time at which the
+ * task was last unblocked. The variable must be initialised with the current time
+ * prior to its first use (see the example below). Following this the variable is
+ * automatically updated within vTaskDelayUntil ().
+ *
+ * @param xTimeIncrement The cycle time period. The task will be unblocked at
+ * time *pxPreviousWakeTime + xTimeIncrement. Calling vTaskDelayUntil with the
+ * same xTimeIncrement parameter value will cause the task to execute with
+ * a fixed interface period.
+ *
+ * Example usage:
+ <pre>
+ // Perform an action every 10 ticks.
+ void vTaskFunction( void * pvParameters )
+ {
+ portTickType xLastWakeTime;
+ const portTickType xFrequency = 10;
+
+ // Initialise the xLastWakeTime variable with the current time.
+ xLastWakeTime = xTaskGetTickCount ();
+ for( ;; )
+ {
+ // Wait for the next cycle.
+ vTaskDelayUntil( &xLastWakeTime, xFrequency );
+
+ // Perform action here.
+ }
+ }
+ </pre>
+ * \defgroup vTaskDelayUntil vTaskDelayUntil
+ * \ingroup TaskCtrl
+ */
+void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement );
+
+/**
+ * task. h
+ * <pre>unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );</pre>
+ *
+ * INCLUDE_xTaskPriorityGet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Obtain the priority of any task.
+ *
+ * @param pxTask Handle of the task to be queried. Passing a NULL
+ * handle results in the priority of the calling task being returned.
+ *
+ * @return The priority of pxTask.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to obtain the priority of the created task.
+ // It was created with tskIDLE_PRIORITY, but may have changed
+ // it itself.
+ if( uxTaskPriorityGet( xHandle ) != tskIDLE_PRIORITY )
+ {
+ // The task has changed it's priority.
+ }
+
+ // ...
+
+ // Is our priority higher than the created task?
+ if( uxTaskPriorityGet( xHandle ) < uxTaskPriorityGet( NULL ) )
+ {
+ // Our priority (obtained using NULL handle) is higher.
+ }
+ }
+ </pre>
+ * \defgroup uxTaskPriorityGet uxTaskPriorityGet
+ * \ingroup TaskCtrl
+ */
+unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask );
+
+/**
+ * task. h
+ * <pre>void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );</pre>
+ *
+ * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Set the priority of any task.
+ *
+ * A context switch will occur before the function returns if the priority
+ * being set is higher than the currently executing task.
+ *
+ * @param pxTask Handle to the task for which the priority is being set.
+ * Passing a NULL handle results in the priority of the calling task being set.
+ *
+ * @param uxNewPriority The priority to which the task will be set.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to raise the priority of the created task.
+ vTaskPrioritySet( xHandle, tskIDLE_PRIORITY + 1 );
+
+ // ...
+
+ // Use a NULL handle to raise our priority to the same value.
+ vTaskPrioritySet( NULL, tskIDLE_PRIORITY + 1 );
+ }
+ </pre>
+ * \defgroup vTaskPrioritySet vTaskPrioritySet
+ * \ingroup TaskCtrl
+ */
+void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
+
+/**
+ * task. h
+ * <pre>void vTaskSuspend( xTaskHandle pxTaskToSuspend );</pre>
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Suspend any task. When suspended a task will never get any microcontroller
+ * processing time, no matter what its priority.
+ *
+ * Calls to vTaskSuspend are not accumulative -
+ * i.e. calling vTaskSuspend () twice on the same task still only requires one
+ * call to vTaskResume () to ready the suspended task.
+ *
+ * @param pxTaskToSuspend Handle to the task being suspended. Passing a NULL
+ * handle will cause the calling task to be suspended.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Suspend ourselves.
+ vTaskSuspend( NULL );
+
+ // We cannot get here unless another task calls vTaskResume
+ // with our handle as the parameter.
+ }
+ </pre>
+ * \defgroup vTaskSuspend vTaskSuspend
+ * \ingroup TaskCtrl
+ */
+void vTaskSuspend( xTaskHandle pxTaskToSuspend );
+
+/**
+ * task. h
+ * <pre>void vTaskResume( xTaskHandle pxTaskToResume );</pre>
+ *
+ * INCLUDE_vTaskSuspend must be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Resumes a suspended task.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * vTaskResume ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ xTaskHandle xHandle;
+
+ // Create a task, storing the handle.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
+
+ // ...
+
+ // Use the handle to suspend the created task.
+ vTaskSuspend( xHandle );
+
+ // ...
+
+ // The created task will not run during this period, unless
+ // another task calls vTaskResume( xHandle ).
+
+ //...
+
+
+ // Resume the suspended task ourselves.
+ vTaskResume( xHandle );
+
+ // The created task will once again get microcontroller processing
+ // time in accordance with it priority within the system.
+ }
+ </pre>
+ * \defgroup vTaskResume vTaskResume
+ * \ingroup TaskCtrl
+ */
+void vTaskResume( xTaskHandle pxTaskToResume );
+
+/**
+ * task. h
+ * <pre>void xTaskResumeFromISR( xTaskHandle pxTaskToResume );</pre>
+ *
+ * INCLUDE_xTaskResumeFromISR must be defined as 1 for this function to be
+ * available. See the configuration section for more information.
+ *
+ * An implementation of vTaskResume() that can be called from within an ISR.
+ *
+ * A task that has been suspended by one of more calls to vTaskSuspend ()
+ * will be made available for running again by a single call to
+ * xTaskResumeFromISR ().
+ *
+ * @param pxTaskToResume Handle to the task being readied.
+ *
+ * \defgroup vTaskResumeFromISR vTaskResumeFromISR
+ * \ingroup TaskCtrl
+ */
+portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume );
+
+/*-----------------------------------------------------------
+ * SCHEDULER CONTROL
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <pre>void vTaskStartScheduler( void );</pre>
+ *
+ * Starts the real time kernel tick processing. After calling the kernel
+ * has control over which tasks are executed and when. This function
+ * does not return until an executing task calls vTaskEndScheduler ().
+ *
+ * At least one task should be created via a call to xTaskCreate ()
+ * before calling vTaskStartScheduler (). The idle task is created
+ * automatically when the first application task is created.
+ *
+ * See the demo application file main.c for an example of creating
+ * tasks and starting the kernel.
+ *
+ * Example usage:
+ <pre>
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will not get here unless a task calls vTaskEndScheduler ()
+ }
+ </pre>
+ *
+ * \defgroup vTaskStartScheduler vTaskStartScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskStartScheduler( void );
+
+/**
+ * task. h
+ * <pre>void vTaskEndScheduler( void );</pre>
+ *
+ * Stops the real time kernel tick. All created tasks will be automatically
+ * deleted and multitasking (either preemptive or cooperative) will
+ * stop. Execution then resumes from the point where vTaskStartScheduler ()
+ * was called, as if vTaskStartScheduler () had just returned.
+ *
+ * See the demo application file main. c in the demo/PC directory for an
+ * example that uses vTaskEndScheduler ().
+ *
+ * vTaskEndScheduler () requires an exit function to be defined within the
+ * portable layer (see vPortEndScheduler () in port. c for the PC port). This
+ * performs hardware specific operations such as stopping the kernel tick.
+ *
+ * vTaskEndScheduler () will cause all of the resources allocated by the
+ * kernel to be freed - but will not free resources allocated by application
+ * tasks.
+ *
+ * Example usage:
+ <pre>
+ void vTaskCode( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // At some point we want to end the real time kernel processing
+ // so call ...
+ vTaskEndScheduler ();
+ }
+ }
+
+ void vAFunction( void )
+ {
+ // Create at least one task before starting the kernel.
+ xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ // Start the real time kernel with preemption.
+ vTaskStartScheduler ();
+
+ // Will only get here when the vTaskCode () task has called
+ // vTaskEndScheduler (). When we get here we are back to single task
+ // execution.
+ }
+ </pre>
+ *
+ * \defgroup vTaskEndScheduler vTaskEndScheduler
+ * \ingroup SchedulerControl
+ */
+void vTaskEndScheduler( void );
+
+/**
+ * task. h
+ * <pre>void vTaskSuspendAll( void );</pre>
+ *
+ * Suspends all real time kernel activity while keeping interrupts (including the
+ * kernel tick) enabled.
+ *
+ * After calling vTaskSuspendAll () the calling task will continue to execute
+ * without risk of being swapped out until a call to xTaskResumeAll () has been
+ * made.
+ *
+ * Example usage:
+ <pre>
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the kernel
+ // tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel.
+ xTaskResumeAll ();
+ }
+ }
+ </pre>
+ * \defgroup vTaskSuspendAll vTaskSuspendAll
+ * \ingroup SchedulerControl
+ */
+void vTaskSuspendAll( void );
+
+/**
+ * task. h
+ * <pre>portCHAR xTaskResumeAll( void );</pre>
+ *
+ * Resumes real time kernel activity following a call to vTaskSuspendAll ().
+ * After a call to vTaskSuspendAll () the kernel will take control of which
+ * task is executing at any time.
+ *
+ * @return If resuming the scheduler caused a context switch then pdTRUE is
+ * returned, otherwise pdFALSE is returned.
+ *
+ * Example usage:
+ <pre>
+ void vTask1( void * pvParameters )
+ {
+ for( ;; )
+ {
+ // Task code goes here.
+
+ // ...
+
+ // At some point the task wants to perform a long operation during
+ // which it does not want to get swapped out. It cannot use
+ // taskENTER_CRITICAL ()/taskEXIT_CRITICAL () as the length of the
+ // operation may cause interrupts to be missed - including the
+ // ticks.
+
+ // Prevent the real time kernel swapping out the task.
+ vTaskSuspendAll ();
+
+ // Perform the operation here. There is no need to use critical
+ // sections as we have all the microcontroller processing time.
+ // During this time interrupts will still operate and the real
+ // time kernel tick count will be maintained.
+
+ // ...
+
+ // The operation is complete. Restart the kernel. We want to force
+ // a context switch - but there is no point if resuming the scheduler
+ // caused a context switch already.
+ if( !xTaskResumeAll () )
+ {
+ taskYIELD ();
+ }
+ }
+ }
+ </pre>
+ * \defgroup xTaskResumeAll xTaskResumeAll
+ * \ingroup SchedulerControl
+ */
+signed portBASE_TYPE xTaskResumeAll( void );
+
+
+/*-----------------------------------------------------------
+ * TASK UTILITIES
+ *----------------------------------------------------------*/
+
+/**
+ * task. h
+ * <PRE>volatile portTickType xTaskGetTickCount( void );</PRE>
+ *
+ * @return The count of ticks since vTaskStartScheduler was called.
+ *
+ * \page xTaskGetTickCount xTaskGetTickCount
+ * \ingroup TaskUtils
+ */
+portTickType xTaskGetTickCount( void );
+
+/**
+ * task. h
+ * <PRE>unsigned portSHORT uxTaskGetNumberOfTasks( void );</PRE>
+ *
+ * @return The number of tasks that the real time kernel is currently managing.
+ * This includes all ready, blocked and suspended tasks. A task that
+ * has been deleted but not yet freed by the idle task will also be
+ * included in the count.
+ *
+ * \page uxTaskGetNumberOfTasks uxTaskGetNumberOfTasks
+ * \ingroup TaskUtils
+ */
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void );
+
+/**
+ * task. h
+ * <PRE>void vTaskList( portCHAR *pcWriteBuffer );</PRE>
+ *
+ * configUSE_TRACE_FACILITY, INCLUDE_vTaskDelete and INCLUDE_vTaskSuspend
+ * must all be defined as 1 for this function to be available.
+ * See the configuration section for more information.
+ *
+ * NOTE: This function will disable interrupts for its duration. It is
+ * not intended for normal application runtime use but as a debug aid.
+ *
+ * Lists all the current tasks, along with their current state and stack
+ * usage high water mark.
+ *
+ * Tasks are reported as blocked ('B'), ready ('R'), deleted ('D') or
+ * suspended ('S').
+ *
+ * @param pcWriteBuffer A buffer into which the above mentioned details
+ * will be written, in ascii form. This buffer is assumed to be large
+ * enough to contain the generated report. Approximately 40 bytes per
+ * task should be sufficient.
+ *
+ * \page vTaskList vTaskList
+ * \ingroup TaskUtils
+ */
+void vTaskList( signed portCHAR *pcWriteBuffer );
+
+/**
+ * task. h
+ * <PRE>void vTaskStartTrace( portCHAR * pcBuffer, unsigned portBASE_TYPE uxBufferSize );</PRE>
+ *
+ * Starts a real time kernel activity trace. The trace logs the identity of
+ * which task is running when.
+ *
+ * The trace file is stored in binary format. A separate DOS utility called
+ * convtrce.exe is used to convert this into a tab delimited text file which
+ * can be viewed and plotted in a spread sheet.
+ *
+ * @param pcBuffer The buffer into which the trace will be written.
+ *
+ * @param ulBufferSize The size of pcBuffer in bytes. The trace will continue
+ * until either the buffer in full, or ulTaskEndTrace () is called.
+ *
+ * \page vTaskStartTrace vTaskStartTrace
+ * \ingroup TaskUtils
+ */
+void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize );
+
+/**
+ * task. h
+ * <PRE>unsigned portLONG ulTaskEndTrace( void );</PRE>
+ *
+ * Stops a kernel activity trace. See vTaskStartTrace ().
+ *
+ * @return The number of bytes that have been written into the trace buffer.
+ *
+ * \page usTaskEndTrace usTaskEndTrace
+ * \ingroup TaskUtils
+ */
+unsigned portLONG ulTaskEndTrace( void );
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ *----------------------------------------------------------*/
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Called from the real time kernel tick (either preemptive or cooperative),
+ * this increments the tick count and checks if any tasks that are blocked
+ * for a finite period required removing from a blocked list and placing on
+ * a ready list.
+ */
+inline void vTaskIncrementTick( void );
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes the calling task from the ready list and places it both
+ * on the list of tasks waiting for a particular event, and the
+ * list of delayed tasks. The task will be removed from both lists
+ * and replaced on the ready list should either the event occur (and
+ * there be no higher priority tasks waiting on the same event) or
+ * the delay period expires.
+ *
+ * @param pxEventList The list containing tasks that are blocked waiting
+ * for the event to occur.
+ *
+ * @param xTicksToWait The maximum amount of time that the task should wait
+ * for the event to occur. This is specified in kernel ticks,the constant
+ * portTICK_RATE_MS can be used to convert kernel ticks into a real time
+ * period.
+ */
+void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait );
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED.
+ *
+ * Removes a task from both the specified event list and the list of blocked
+ * tasks, and places it on a ready queue.
+ *
+ * xTaskRemoveFromEventList () will be called if either an event occurs to
+ * unblock a task, or the block timeout period expires.
+ *
+ * @return pdTRUE if the task being removed has a higher priority than the task
+ * making the call, otherwise pdFALSE.
+ */
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList );
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
+ * INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * INCLUDE_vTaskCleanUpResources and INCLUDE_vTaskSuspend must be defined as 1
+ * for this function to be available.
+ * See the configuration section for more information.
+ *
+ * Empties the ready and delayed queues of task control blocks, freeing the
+ * memory allocated for the task control block and task stacks as it goes.
+ */
+void vTaskCleanUpResources( void );
+
+/*
+ * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
+ * INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
+ * AN INTERFACE WHICH IS FOR THE EXCLUSIVE USE OF THE SCHEDULER.
+ *
+ * Sets the pointer to the current TCB to the TCB of the highest priority task
+ * that is ready to run.
+ */
+inline void vTaskSwitchContext( void );
+
+/*
+ * Return the handle of the calling task.
+ */
+xTaskHandle xTaskGetCurrentTaskHandle( void );
+
+/*
+ * Capture the current time status for future reference.
+ */
+void vTaskSetTimeOutState( xTimeOutType *pxTimeOut );
+
+/*
+ * Compare the time status now with that previously captured to see if the
+ * timeout has expired.
+ */
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait );
+
+/*
+ * Shortcut used by the queue implementation to prevent unnecessary call to
+ * taskYIELD();
+ */
+void vTaskMissedYield( void );
+
+/*
+ * Returns the scheduler state as taskSCHEDULER_RUNNING,
+ * taskSCHEDULER_NOT_STARTED or taskSCHEDULER_SUSPENDED.
+ */
+portBASE_TYPE xTaskGetSchedulerState( void );
+
+#endif /* TASK_H */
+
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+Changes from V1.2.0
+
+ + Removed the volatile modifier from the function parameters. This was
+ only ever included to prevent compiler warnings. Now warnings are
+ removed by casting parameters where the calls are made.
+
+ + prvListGetOwnerOfNextEntry() and prvListGetOwnerOfHeadEntry() have been
+ removed from the c file and added as macros to the h file.
+
+ + uxNumberOfItems has been added to the list structure. This removes the
+ need for a pointer comparison when checking if a list is empty, and so
+ is slightly faster.
+
+ + Removed the NULL check in vListRemove(). This makes the call faster but
+ necessitates any application code utilising the list implementation to
+ ensure NULL pointers are not passed.
+
+Changes from V2.0.0
+
+ + Double linked the lists to allow faster removal item removal.
+
+Changes from V2.6.1
+
+ + Make use of the new portBASE_TYPE definition where ever appropriate.
+
+Changes from V3.0.0
+
+ + API changes as described on the FreeRTOS.org WEB site.
+
+Changes from V3.2.4
+
+ + Removed the pxHead member of the xList structure. This always pointed
+ to the same place so has been removed to free a few bytes of RAM.
+
+ + Introduced the xMiniListItem structure that does not include the
+ xListItem members that are not required by the xListEnd member of a list.
+ Again this was done to reduce RAM usage.
+
+ + Changed the volatile definitions of some structure members to clean up
+ the code where the list structures are used.
+
+Changes from V4.0.4
+
+ + Optimised vListInsert() in the case when the wake time is the maximum
+ tick count value.
+*/
+
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "list.h"
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+void vListInitialise( xList *pxList )
+{
+ /* The list structure contains a list item which is used to mark the
+ end of the list. To initialise the list the list end is inserted
+ as the only list entry. */
+ pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
+
+ /* The list end value is the highest possible value in the list to
+ ensure it remains at the end of the list. */
+ pxList->xListEnd.xItemValue = portMAX_DELAY;
+
+ /* The list end next and previous pointers point to itself so we know
+ when the list is empty. */
+ pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
+ pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
+
+ pxList->uxNumberOfItems = 0;
+}
+/*-----------------------------------------------------------*/
+
+void vListInitialiseItem( xListItem *pxItem )
+{
+ /* Make sure the list item is not recorded as being on a list. */
+ pxItem->pvContainer = NULL;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem * pxIndex;
+
+ /* Insert a new list item into pxList, but rather than sort the list,
+ makes the new list item the last item to be removed by a call to
+ pvListGetOwnerOfNextEntry. This means it has to be the item pointed to by
+ the pxIndex member. */
+ pxIndex = pxList->pxIndex;
+
+ pxNewListItem->pxNext = pxIndex->pxNext;
+ pxNewListItem->pxPrevious = pxList->pxIndex;
+ pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+ pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
+ pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;
+
+ /* Remember which list the item is in. */
+ pxNewListItem->pvContainer = ( void * ) pxList;
+
+ ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListInsert( xList *pxList, xListItem *pxNewListItem )
+{
+volatile xListItem *pxIterator;
+portTickType xValueOfInsertion;
+
+ /* Insert the new list item into the list, sorted in ulListItem order. */
+ xValueOfInsertion = pxNewListItem->xItemValue;
+
+ /* If the list already contains a list item with the same item value then
+ the new list item should be placed after it. This ensures that TCB's which
+ are stored in ready lists (all of which have the same ulListItem value)
+ get an equal share of the CPU. However, if the xItemValue is the same as
+ the back marker the iteration loop below will not end. This means we need
+ to guard against this by checking the value first and modifying the
+ algorithm slightly if necessary. */
+ if( xValueOfInsertion == portMAX_DELAY )
+ {
+ pxIterator = pxList->xListEnd.pxPrevious;
+ }
+ else
+ {
+ for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
+ {
+ /* There is nothing to do here, we are just iterating to the
+ wanted insertion position. */
+ }
+ }
+
+ pxNewListItem->pxNext = pxIterator->pxNext;
+ pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
+ pxNewListItem->pxPrevious = pxIterator;
+ pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;
+
+ /* Remember which list the item is in. This allows fast removal of the
+ item later. */
+ pxNewListItem->pvContainer = ( void * ) pxList;
+
+ ( pxList->uxNumberOfItems )++;
+}
+/*-----------------------------------------------------------*/
+
+void vListRemove( xListItem *pxItemToRemove )
+{
+xList * pxList;
+
+ pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
+ pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
+
+ /* The list item knows which list it is in. Obtain the list from the list
+ item. */
+ pxList = ( xList * ) pxItemToRemove->pvContainer;
+
+ /* Make sure the index is left pointing to a valid item. */
+ if( pxList->pxIndex == pxItemToRemove )
+ {
+ pxList->pxIndex = pxItemToRemove->pxPrevious;
+ }
+
+ pxItemToRemove->pvContainer = NULL;
+ ( pxList->uxNumberOfItems )--;
+}
+/*-----------------------------------------------------------*/
+
--- /dev/null
+SRC_FILES=port.c portISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Implementation of functions defined in portable.h for the ARM7 port.
+ *
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in this file. The ISR routines, which can only be compiled
+ * to ARM mode are contained in portISR.c.
+ *----------------------------------------------------------*/
+
+/*
+ Changes from V2.5.2
+
+ + ulCriticalNesting is now saved as part of the task context, as is
+ therefore added to the initial task stack during pxPortInitialiseStack.
+
+ Changes from V3.2.2
+
+ + Bug fix - The prescale value for the timer setup is now written to T0_PR
+ instead of T0_PC. This bug would have had no effect unless a prescale
+ value was actually used.
+*/
+
+
+/* Standard includes. */
+#include <stdlib.h>
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to setup the task context. */
+#define portINITIAL_SPSR ( ( portSTACK_TYPE ) 0x1f ) /* System mode, ARM mode, interrupts enabled. */
+#define portTHUMB_MODE_BIT ( ( portSTACK_TYPE ) 0x20 )
+#define portINSTRUCTION_SIZE ( ( portSTACK_TYPE ) 4 )
+#define portNO_CRITICAL_SECTION_NESTING ( ( portSTACK_TYPE ) 0 )
+
+/* Constants required to setup the tick ISR. */
+#define portENABLE_TIMER ( ( unsigned portCHAR ) 0x01 )
+#define portPRESCALE_VALUE 0x00
+#define portINTERRUPT_ON_MATCH ( ( unsigned portLONG ) 0x01 )
+#define portRESET_COUNT_ON_MATCH ( ( unsigned portLONG ) 0x02 )
+
+/*-----------------------------------------------------------*/
+
+/* Setup the timer to generate the tick interrupts. */
+static void prvSetupTimerInterrupt( void );
+
+/*
+ * The scheduler can only be started from ARM mode, so
+ * vPortISRStartFirstSTask() is defined in portISR.c.
+ */
+extern void vPortISRStartFirstTask( void );
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Initialise the stack of a task to look exactly as if a call to
+ * portSAVE_CONTEXT had been called.
+ *
+ * See header file for description.
+ */
+portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
+{
+portSTACK_TYPE *pxOriginalTOS;
+
+ pxOriginalTOS = pxTopOfStack;
+
+ /* Setup the initial stack of the task. The stack is set exactly as
+ expected by the portRESTORE_CONTEXT() macro. */
+
+ /* First on the stack is the return address - which in this case is the
+ start of the task. The offset is added to make the return address appear
+ as it would within an IRQ ISR. */
+ *pxTopOfStack = ( portSTACK_TYPE ) pxCode + portINSTRUCTION_SIZE;
+ pxTopOfStack--;
+
+ *pxTopOfStack = ( portSTACK_TYPE ) 0xaaaaaaaa; /* R14 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x12121212; /* R12 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x11111111; /* R11 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x10101010; /* R10 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x09090909; /* R9 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x08080808; /* R8 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x07070707; /* R7 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x06060606; /* R6 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x05050505; /* R5 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x04040404; /* R4 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x03030303; /* R3 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x02020202; /* R2 */
+ pxTopOfStack--;
+ *pxTopOfStack = ( portSTACK_TYPE ) 0x01010101; /* R1 */
+ pxTopOfStack--;
+
+ /* When the task starts is will expect to find the function parameter in
+ R0. */
+ *pxTopOfStack = ( portSTACK_TYPE ) pvParameters; /* R0 */
+ pxTopOfStack--;
+
+ /* The last thing onto the stack is the status register, which is set for
+ system mode, with interrupts enabled. */
+ *pxTopOfStack = ( portSTACK_TYPE ) portINITIAL_SPSR;
+
+ #ifdef THUMB_INTERWORK
+ {
+ /* We want the task to start in thumb mode. */
+ *pxTopOfStack |= portTHUMB_MODE_BIT;
+ }
+ #endif
+
+ pxTopOfStack--;
+
+ /* Some optimisation levels use the stack differently to others. This
+ means the interrupt flags cannot always be stored on the stack and will
+ instead be stored in a variable, which is then saved as part of the
+ tasks context. */
+ *pxTopOfStack = portNO_CRITICAL_SECTION_NESTING;
+
+ return pxTopOfStack;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xPortStartScheduler( void )
+{
+ /* Start the timer that generates the tick ISR. Interrupts are disabled
+ here already. */
+ prvSetupTimerInterrupt();
+
+ /* Start the first task. */
+ vPortISRStartFirstTask();
+
+ /* Should not get here! */
+ return 0;
+}
+/*-----------------------------------------------------------*/
+
+void vPortEndScheduler( void )
+{
+ /* It is unlikely that the ARM port will require this function as there
+ is nothing to return to. */
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Setup the timer 0 to generate the tick interrupts at the required frequency.
+ */
+static void prvSetupTimerInterrupt( void )
+{
+unsigned portLONG ulCompareMatch;
+
+ SCB_PCONP |= SCB_PCONP_PCTIM0;
+
+ /* A 1ms tick does not require the use of the timer prescale. This is
+ defaulted to zero but can be used if necessary. */
+ T0_PR = portPRESCALE_VALUE;
+
+ /* Calculate the match value required for our wanted tick rate. */
+ ulCompareMatch = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
+
+ /* Protect against divide by zero. Using an if() statement still results
+ in a warning - hence the #if. */
+ #if portPRESCALE_VALUE != 0
+ {
+ ulCompareMatch /= ( portPRESCALE_VALUE + 1 );
+ }
+ #endif
+ T0_MR0 = ulCompareMatch;
+
+ /* Generate tick with timer 0 compare match. */
+ T0_MCR = portRESET_COUNT_ON_MATCH | portINTERRUPT_ON_MATCH;
+
+ /* Setup the VIC for the timer. */
+ VIC_IntSelect &= ~VIC_IntSelect_Timer0;
+ VIC_IntEnable = VIC_IntEnable_Timer0;
+
+ /* The ISR installed depends on whether the preemptive or cooperative
+ scheduler is being used. */
+ #if configUSE_PREEMPTION == 1
+ {
+ extern void ( vPreemptiveTick )( void );
+ VIC_VectAddr0 = ( portLONG ) vPreemptiveTick;
+ }
+ #else
+ {
+ extern void ( vNonPreemptiveTick )( void );
+ VIC_VectAddr0 = ( portLONG ) vNonPreemptiveTick;
+ }
+ #endif
+
+ VIC_VectCntl0 = VIC_VectCntl_ENABLE | VIC_Channel_Timer0;
+
+ /* Start the timer - interrupts are disabled when this function is called
+ so it is okay to do this here. */
+ T0_TCR = portENABLE_TIMER;
+}
+/*-----------------------------------------------------------*/
+
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+
+/*-----------------------------------------------------------
+ * Components that can be compiled to either ARM or THUMB mode are
+ * contained in port.c The ISR routines, which can only be compiled
+ * to ARM mode, are contained in this file.
+ *----------------------------------------------------------*/
+
+/*
+ Changes from V2.5.2
+
+ + The critical section management functions have been changed. These no
+ longer modify the stack and are safe to use at all optimisation levels.
+ The functions are now also the same for both ARM and THUMB modes.
+
+ Changes from V2.6.0
+
+ + Removed the 'static' from the definition of vNonPreemptiveTick() to
+ allow the demo to link when using the cooperative scheduler.
+
+ Changes from V3.2.4
+
+ + The assembler statements are now included in a single asm block rather
+ than each line having its own asm block.
+*/
+
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Constants required to handle interrupts. */
+#define portTIMER_MATCH_ISR_BIT ( ( unsigned portCHAR ) 0x01 )
+#define portCLEAR_VIC_INTERRUPT ( ( unsigned portLONG ) 0 )
+
+/* Constants required to handle critical sections. */
+#define portNO_CRITICAL_NESTING ( ( unsigned portLONG ) 0 )
+volatile unsigned portLONG ulCriticalNesting = 9999UL;
+
+/*-----------------------------------------------------------*/
+
+/* ISR to handle manual context switches (from a call to taskYIELD()). */
+void vPortYieldProcessor( void ) __attribute__((interrupt("SWI"), naked));
+
+/*
+ * The scheduler can only be started from ARM mode, hence the inclusion of this
+ * function here.
+ */
+void vPortISRStartFirstTask( void );
+/*-----------------------------------------------------------*/
+
+void vPortISRStartFirstTask( void )
+{
+ /* Simply start the scheduler. This is included here as it can only be
+ called from ARM mode. */
+ portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Called by portYIELD() or taskYIELD() to manually force a context switch.
+ *
+ * When a context switch is performed from the task level the saved task
+ * context is made to look as if it occurred from within the tick ISR. This
+ * way the same restore context function can be used when restoring the context
+ * saved from the ISR or that saved from a call to vPortYieldProcessor.
+ */
+void vPortYieldProcessor( void )
+{
+ /* Within an IRQ ISR the link register has an offset from the true return
+ address, but an SWI ISR does not. Add the offset manually so the same
+ ISR return code can be used in both cases. */
+ asm volatile ( "ADD LR, LR, #4" );
+
+ /* Perform the context switch. First save the context of the current task. */
+ portSAVE_CONTEXT();
+
+ /* Find the highest priority task that is ready to run. */
+ vTaskSwitchContext();
+
+ /* Restore the context of the new task. */
+ portRESTORE_CONTEXT();
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * The ISR used for the scheduler tick depends on whether the cooperative or
+ * the preemptive scheduler is being used.
+ */
+
+#if configUSE_PREEMPTION == 0
+
+ /* The cooperative scheduler requires a normal IRQ service routine to
+ simply increment the system tick. */
+ void vNonPreemptiveTick( void ) __attribute__ ((interrupt ("IRQ")));
+ void vNonPreemptiveTick( void )
+ {
+ vTaskIncrementTick();
+ T0_IR = portTIMER_MATCH_ISR_BIT;
+ VICVectAddr = portCLEAR_VIC_INTERRUPT;
+ }
+
+#else
+
+ /* The preemptive scheduler is defined as "naked" as the full context is
+ saved on entry as part of the context switch. */
+ void vPreemptiveTick( void ) __attribute__((naked));
+ void vPreemptiveTick( void )
+ {
+ /* Save the context of the interrupted task. */
+ portSAVE_CONTEXT();
+
+ /* Increment the RTOS tick count, then look for the highest priority
+ task that is ready to run. */
+ vTaskIncrementTick();
+ vTaskSwitchContext();
+
+ /* Ready for the next interrupt. */
+ T0_IR = portTIMER_MATCH_ISR_BIT;
+ VIC_VectAddr = portCLEAR_VIC_INTERRUPT;
+
+ /* Restore the context of the new task. */
+ portRESTORE_CONTEXT();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+/*
+ * The interrupt management utilities can only be called from ARM mode. When
+ * THUMB_INTERWORK is defined the utilities are defined as functions here to
+ * ensure a switch to ARM mode. When THUMB_INTERWORK is not defined then
+ * the utilities are defined as macros in portmacro.h - as per other ports.
+ */
+#ifdef THUMB_INTERWORK
+
+ void vPortDisableInterruptsFromThumb( void ) __attribute__ ((naked));
+ void vPortEnableInterruptsFromThumb( void ) __attribute__ ((naked));
+
+ void vPortDisableInterruptsFromThumb( void )
+ {
+ asm volatile (
+ "STMDB SP!, {R0} \n\t" /* Push R0. */
+ "MRS R0, CPSR \n\t" /* Get CPSR. */
+ "ORR R0, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */
+ "LDMIA SP!, {R0} \n\t" /* Pop R0. */
+ "BX R14" ); /* Return back to thumb. */
+ }
+
+ void vPortEnableInterruptsFromThumb( void )
+ {
+ asm volatile (
+ "STMDB SP!, {R0} \n\t" /* Push R0. */
+ "MRS R0, CPSR \n\t" /* Get CPSR. */
+ "BIC R0, R0, #0xC0 \n\t" /* Enable IRQ, FIQ. */
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */
+ "LDMIA SP!, {R0} \n\t" /* Pop R0. */
+ "BX R14" ); /* Return back to thumb. */
+ }
+
+#endif /* THUMB_INTERWORK */
+
+/* The code generated by the GCC compiler uses the stack in different ways at
+different optimisation levels. The interrupt flags can therefore not always
+be saved to the stack. Instead the critical section nesting level is stored
+in a variable, which is then saved as part of the stack context. */
+void vPortEnterCritical( void )
+{
+ /* Disable interrupts as per portDISABLE_INTERRUPTS(); */
+ asm volatile (
+ "STMDB SP!, {R0} \n\t" /* Push R0. */
+ "MRS R0, CPSR \n\t" /* Get CPSR. */
+ "ORR R0, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */
+ "LDMIA SP!, {R0}" ); /* Pop R0. */
+
+ /* Now interrupts are disabled ulCriticalNesting can be accessed
+ directly. Increment ulCriticalNesting to keep a count of how many times
+ portENTER_CRITICAL() has been called. */
+ ulCriticalNesting++;
+}
+
+void vPortExitCritical( void )
+{
+ if( ulCriticalNesting > portNO_CRITICAL_NESTING )
+ {
+ /* Decrement the nesting count as we are leaving a critical section. */
+ ulCriticalNesting--;
+
+ /* If the nesting level has reached zero then interrupts should be
+ re-enabled. */
+ if( ulCriticalNesting == portNO_CRITICAL_NESTING )
+ {
+ /* Enable interrupts as per portEXIT_CRITICAL(). */
+ asm volatile (
+ "STMDB SP!, {R0} \n\t" /* Push R0. */
+ "MRS R0, CPSR \n\t" /* Get CPSR. */
+ "BIC R0, R0, #0xC0 \n\t" /* Enable IRQ, FIQ. */
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */
+ "LDMIA SP!, {R0}" ); /* Pop R0. */
+ }
+ }
+}
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+ Changes from V3.2.3
+
+ + Modified portENTER_SWITCHING_ISR() to allow use with GCC V4.0.1.
+
+ Changes from V3.2.4
+
+ + Removed the use of the %0 parameter within the assembler macros and
+ replaced them with hard coded registers. This will ensure the
+ assembler does not select the link register as the temp register as
+ was occasionally happening previously.
+
+ + The assembler statements are now included in a single asm block rather
+ than each line having its own asm block.
+*/
+
+#ifndef PORTMACRO_H
+#define PORTMACRO_H
+
+/*-----------------------------------------------------------
+ * Port specific definitions.
+ *
+ * The settings in this file configure FreeRTOS correctly for the
+ * given hardware and compiler.
+ *
+ * These settings should not be altered.
+ *-----------------------------------------------------------
+ */
+
+/* Type definitions. */
+#define portCHAR char
+#define portFLOAT float
+#define portDOUBLE double
+#define portLONG long
+#define portSHORT short
+#define portSTACK_TYPE unsigned portLONG
+#define portBASE_TYPE portLONG
+
+#if( configUSE_16_BIT_TICKS == 1 )
+ typedef unsigned portSHORT portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffff
+#else
+ typedef unsigned portLONG portTickType;
+ #define portMAX_DELAY ( portTickType ) 0xffffffff
+#endif
+/*-----------------------------------------------------------*/
+
+/* Architecture specifics. */
+#define portSTACK_GROWTH ( -1 )
+#define portTICK_RATE_MS ( ( portTickType ) 1000 / configTICK_RATE_HZ )
+#define portBYTE_ALIGNMENT 4
+#define portNOP() asm volatile ( "NOP" );
+/*-----------------------------------------------------------*/
+
+
+/* Scheduler utilities. */
+
+/*
+ * portRESTORE_CONTEXT, portRESTORE_CONTEXT, portENTER_SWITCHING_ISR
+ * and portEXIT_SWITCHING_ISR can only be called from ARM mode, but
+ * are included here for efficiency. An attempt to call one from
+ * THUMB mode code will result in a compile time error.
+ */
+
+#define portRESTORE_CONTEXT() \
+{ \
+extern volatile void * volatile pxCurrentTCB; \
+extern volatile unsigned portLONG ulCriticalNesting; \
+ \
+ /* Set the LR to the task stack. */ \
+ asm volatile ( \
+ "LDR R0, =pxCurrentTCB \n\t" \
+ "LDR R0, [R0] \n\t" \
+ "LDR LR, [R0] \n\t" \
+ \
+ /* The critical nesting depth is the first item on the stack. */ \
+ /* Load it into the ulCriticalNesting variable. */ \
+ "LDR R0, =ulCriticalNesting \n\t" \
+ "LDMFD LR!, {R1} \n\t" \
+ "STR R1, [R0] \n\t" \
+ \
+ /* Get the SPSR from the stack. */ \
+ "LDMFD LR!, {R0} \n\t" \
+ "MSR SPSR, R0 \n\t" \
+ \
+ /* Restore all system mode registers for the task. */ \
+ "LDMFD LR, {R0-R14}^ \n\t" \
+ "NOP \n\t" \
+ \
+ /* Restore the return address. */ \
+ "LDR LR, [LR, #+60] \n\t" \
+ \
+ /* And return - correcting the offset in the LR to obtain the */ \
+ /* correct address. */ \
+ "SUBS PC, LR, #4 \n\t" \
+ ); \
+ ( void ) ulCriticalNesting; \
+ ( void ) pxCurrentTCB; \
+}
+/*-----------------------------------------------------------*/
+
+#define portSAVE_CONTEXT() \
+{ \
+extern volatile void * volatile pxCurrentTCB; \
+extern volatile unsigned portLONG ulCriticalNesting; \
+ \
+ /* Push R0 as we are going to use the register. */ \
+ asm volatile ( \
+ "STMDB SP!, {R0} \n\t" \
+ \
+ /* Set R0 to point to the task stack pointer. */ \
+ "STMDB SP,{SP}^ \n\t" \
+ "NOP \n\t" \
+ "SUB SP, SP, #4 \n\t" \
+ "LDMIA SP!,{R0} \n\t" \
+ \
+ /* Push the return address onto the stack. */ \
+ "STMDB R0!, {LR} \n\t" \
+ \
+ /* Now we have saved LR we can use it instead of R0. */ \
+ "MOV LR, R0 \n\t" \
+ \
+ /* Pop R0 so we can save it onto the system mode stack. */ \
+ "LDMIA SP!, {R0} \n\t" \
+ \
+ /* Push all the system mode registers onto the task stack. */ \
+ "STMDB LR,{R0-LR}^ \n\t" \
+ "NOP \n\t" \
+ "SUB LR, LR, #60 \n\t" \
+ \
+ /* Push the SPSR onto the task stack. */ \
+ "MRS R0, SPSR \n\t" \
+ "STMDB LR!, {R0} \n\t" \
+ \
+ "LDR R0, =ulCriticalNesting \n\t" \
+ "LDR R0, [R0] \n\t" \
+ "STMDB LR!, {R0} \n\t" \
+ \
+ /* Store the new top of stack for the task. */ \
+ "LDR R0, =pxCurrentTCB \n\t" \
+ "LDR R0, [R0] \n\t" \
+ "STR LR, [R0] \n\t" \
+ ); \
+ ( void ) ulCriticalNesting; \
+ ( void ) pxCurrentTCB; \
+}
+
+
+/*-----------------------------------------------------------
+ * ISR entry and exit macros. These are only required if a task switch
+ * is required from the ISR.
+ *----------------------------------------------------------*/
+
+
+#define portENTER_SWITCHING_ISR() \
+ /* Save the context of the interrupted task. */ \
+ portSAVE_CONTEXT(); \
+ \
+ /* We don't know the stack requirements for the ISR, so the frame */\
+ /* pointer will be set to the top of the task stack, and the stack*/\
+ /* pointer left where it is. The IRQ stack will get used for any */\
+ /* functions calls made by this ISR. */ \
+ asm volatile ( "SUB R11, LR, #4" ); \
+ {
+
+#define portEXIT_SWITCHING_ISR( SwitchRequired ) \
+ /* If a switch is required then we just need to call */ \
+ /* vTaskSwitchContext() as the context has already been */ \
+ /* saved. */ \
+ if( SwitchRequired ) \
+ { \
+ vTaskSwitchContext(); \
+ } \
+ } \
+ /* Restore the context of which ever task is now the highest */ \
+ /* priority that is ready to run. */ \
+ portRESTORE_CONTEXT();
+
+#define portYIELD() asm volatile ( "SWI" );
+/*-----------------------------------------------------------*/
+
+
+/* Critical section management. */
+
+/*
+ * The interrupt management utilities can only be called from ARM mode. When
+ * THUMB_INTERWORK is defined the utilities are defined as functions in
+ * portISR.c to ensure a switch to ARM mode. When THUMB_INTERWORK is not
+ * defined then the utilities are defined as macros here - as per other ports.
+ */
+
+#ifdef THUMB_INTERWORK
+
+ extern void vPortDisableInterruptsFromThumb( void ) __attribute__ ((naked));
+ extern void vPortEnableInterruptsFromThumb( void ) __attribute__ ((naked));
+
+ #define portDISABLE_INTERRUPTS() vPortDisableInterruptsFromThumb()
+ #define portENABLE_INTERRUPTS() vPortEnableInterruptsFromThumb()
+
+#else
+
+ #define portDISABLE_INTERRUPTS() \
+ asm volatile ( \
+ "STMDB SP!, {R0} \n\t" /* Push R0. */ \
+ "MRS R0, CPSR \n\t" /* Get CPSR. */ \
+ "ORR R0, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */ \
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */ \
+ "LDMIA SP!, {R0} " ) /* Pop R0. */
+
+ #define portENABLE_INTERRUPTS() \
+ asm volatile ( \
+ "STMDB SP!, {R0} \n\t" /* Push R0. */ \
+ "MRS R0, CPSR \n\t" /* Get CPSR. */ \
+ "BIC R0, R0, #0xC0 \n\t" /* Enable IRQ, FIQ. */ \
+ "MSR CPSR, R0 \n\t" /* Write back modified value. */ \
+ "LDMIA SP!, {R0} " ) /* Pop R0. */
+
+#endif /* THUMB_INTERWORK */
+
+extern void vPortEnterCritical( void );
+extern void vPortExitCritical( void );
+
+#define portENTER_CRITICAL() vPortEnterCritical();
+#define portEXIT_CRITICAL() vPortExitCritical();
+/*-----------------------------------------------------------*/
+
+/* Task function macros as described on the FreeRTOS.org WEB site. */
+#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) __attribute__ ((naked))
+#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+
+#endif /* PORTMACRO_H */
+
--- /dev/null
+#
+# Define all object files.
+#
+SUBDIRS=ARM7_LPC2000
+
+.PHONY: all
+all:
+ @for i in $(SUBDIRS); do \
+ (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
--- /dev/null
+#
+# Define all object files.
+#
+SUBDIRS=GCC MemMang
+
+.PHONY: all
+all:
+ @for i in $(SUBDIRS); do \
+ (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
--- /dev/null
+SRC_FILES=heap_2.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+
+Changes between V2.5.1 and V2.5.1
+
+ + The memory pool has been defined within a struct to ensure correct memory
+ alignment on 32bit systems.
+
+Changes between V2.6.1 and V3.0.0
+
+ + An overflow check has been added to ensure the next free byte variable
+ does not wrap around.
+*/
+
+
+/*
+ * The simplest possible implementation of pvPortMalloc(). Note that this
+ * implementation does NOT allow allocated memory to be freed again.
+ *
+ * See heap_2.c and heap_3.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Setup the correct byte alignment mask for the defined byte alignment. */
+
+#if portBYTE_ALIGNMENT == 8
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
+#endif
+
+#ifndef heapBYTE_ALIGNMENT_MASK
+ #error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+/* Allocate the memory for the heap. The struct is used to force byte
+alignment without using any non-portable code. */
+static struct xRTOS_HEAP
+{
+ unsigned portLONG ulDummy;
+ unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
+} xHeap;
+
+static size_t xNextFreeByte = ( size_t ) 0;
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+void *pvReturn = NULL;
+
+ /* Ensure that blocks are always aligned to the required number of bytes. */
+ #if portBYTE_ALIGNMENT != 1
+ if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
+ {
+ /* Byte alignment required. */
+ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
+ }
+ #endif
+
+ vTaskSuspendAll();
+ {
+ /* Check there is enough room left for the allocation. */
+ if( ( ( xNextFreeByte + xWantedSize ) < configTOTAL_HEAP_SIZE ) &&
+ ( ( xNextFreeByte + xWantedSize ) > xNextFreeByte ) )/* Check for overflow. */
+ {
+ /* Return the next free byte then increment the index past this
+ block. */
+ pvReturn = &( xHeap.ucHeap[ xNextFreeByte ] );
+ xNextFreeByte += xWantedSize;
+ }
+ }
+ xTaskResumeAll();
+
+ return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+ /* Memory cannot be freed using this scheme. See heap_2.c and heap_3.c
+ for alternative implementations, and the memory management pages of
+ http://www.FreeRTOS.org for more information. */
+ ( void ) pv;
+}
+/*-----------------------------------------------------------*/
+
+void vPortInitialiseBlocks( void )
+{
+ /* Only required when static memory is not cleared. */
+ xNextFreeByte = ( size_t ) 0;
+}
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+ * A sample implementation of pvPortMalloc() and vPortFree() that permits
+ * allocated blocks to be freed, but does not combine adjacent free blocks
+ * into a single larger block.
+ *
+ * See heap_1.c and heap_3.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Setup the correct byte alignment mask for the defined byte alignment. */
+
+#if portBYTE_ALIGNMENT == 8
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0007 )
+#endif
+
+#if portBYTE_ALIGNMENT == 4
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0003 )
+#endif
+
+#if portBYTE_ALIGNMENT == 2
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0001 )
+#endif
+
+#if portBYTE_ALIGNMENT == 1
+ #define heapBYTE_ALIGNMENT_MASK ( ( size_t ) 0x0000 )
+#endif
+
+#ifndef heapBYTE_ALIGNMENT_MASK
+ #error "Invalid portBYTE_ALIGNMENT definition"
+#endif
+
+/* Allocate the memory for the heap. The struct is used to force byte
+alignment without using any non-portable code. */
+static struct xRTOS_HEAP
+{
+ unsigned portLONG ulDummy;
+ unsigned portCHAR ucHeap[ configTOTAL_HEAP_SIZE ];
+} xHeap;
+
+/* Define the linked list structure. This is used to link free blocks in order
+of their size. */
+typedef struct A_BLOCK_LINK
+{
+ struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
+ size_t xBlockSize; /*<< The size of the free block. */
+} xBlockLink;
+
+
+static const unsigned portSHORT heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
+#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
+
+/* Create a couple of list links to mark the start and end of the list. */
+static xBlockLink xStart, xEnd;
+
+/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
+
+/*
+ * Insert a block into the list of free blocks - which is ordered by size of
+ * the block. Small blocks at the start of the list and large blocks at the end
+ * of the list.
+ */
+#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
+{ \
+xBlockLink *pxIterator; \
+size_t xBlockSize; \
+ \
+ xBlockSize = pxBlockToInsert->xBlockSize; \
+ \
+ /* Iterate through the list until a block is found that has a larger size */ \
+ /* than the block we are inserting. */ \
+ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
+ { \
+ /* There is nothing to do here - just iterate to the correct position. */ \
+ } \
+ \
+ /* Update the list to include the block being inserted in the correct */ \
+ /* position. */ \
+ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
+ pxIterator->pxNextFreeBlock = pxBlockToInsert; \
+}
+/*-----------------------------------------------------------*/
+
+#define prvHeapInit() \
+{ \
+xBlockLink *pxFirstFreeBlock; \
+ \
+ /* xStart is used to hold a pointer to the first item in the list of free */ \
+ /* blocks. The void cast is used to prevent compiler warnings. */ \
+ xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap; \
+ xStart.xBlockSize = ( size_t ) 0; \
+ \
+ /* xEnd is used to mark the end of the list of free blocks. */ \
+ xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \
+ xEnd.pxNextFreeBlock = NULL; \
+ \
+ /* To start with there is a single free block that is sized to take up the \
+ entire heap space. */ \
+ pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \
+ pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \
+ pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \
+}
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vPortUsedMem == 1 )
+
+void vPortUsedMem(int *bytesFree, int *bytesUsed, int *blocksFree)
+{
+ xBlockLink *pxBlock = &xStart;
+
+ *bytesFree = 0;
+ *bytesUsed = 0;
+ *blocksFree = 0;
+
+ vTaskSuspendAll();
+
+ while ((pxBlock) && (pxBlock != &xEnd))
+ {
+ *bytesFree += pxBlock->xBlockSize;
+ pxBlock = pxBlock->pxNextFreeBlock;
+ ++*blocksFree;
+ }
+
+ xTaskResumeAll();
+
+ *bytesUsed = configTOTAL_HEAP_SIZE - *bytesFree;
+}
+
+#endif
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+ xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
+ static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
+ void *pvReturn = NULL;
+
+ vTaskSuspendAll();
+ {
+ /* If this is the first call to malloc then the heap will require
+ initialisation to setup the list of free blocks. */
+ if( xHeapHasBeenInitialised == pdFALSE )
+ {
+ prvHeapInit();
+ xHeapHasBeenInitialised = pdTRUE;
+ }
+
+ /* The wanted size is increased so it can contain a xBlockLink
+ structure in addition to the requested amount of bytes. */
+ if( xWantedSize > 0 )
+ {
+ xWantedSize += heapSTRUCT_SIZE;
+
+ /* Ensure that blocks are always aligned to the required number of bytes. */
+ if( xWantedSize & heapBYTE_ALIGNMENT_MASK )
+ {
+ /* Byte alignment required. */
+ xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & heapBYTE_ALIGNMENT_MASK ) );
+ }
+ }
+
+ if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
+ {
+ /* Blocks are stored in byte order - traverse the list from the start
+ (smallest) block until one of adequate size is found. */
+ pxPreviousBlock = &xStart;
+ pxBlock = xStart.pxNextFreeBlock;
+ while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
+ {
+ pxPreviousBlock = pxBlock;
+ pxBlock = pxBlock->pxNextFreeBlock;
+ }
+
+ /* If we found the end marker then a block of adequate size was not found. */
+ if( pxBlock != &xEnd )
+ {
+ /* Return the memory space - jumping over the xBlockLink structure
+ at its start. */
+ pvReturn = ( void * ) ( ( ( unsigned portCHAR * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
+
+ /* This block is being returned for use so must be taken our of the
+ list of free blocks. */
+ pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
+
+ /* If the block is larger than required it can be split into two. */
+ if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
+ {
+ /* This block is to be split into two. Create a new block
+ following the number of bytes requested. The void cast is
+ used to prevent byte alignment warnings from the compiler. */
+ pxNewBlockLink = ( void * ) ( ( ( unsigned portCHAR * ) pxBlock ) + xWantedSize );
+
+ /* Calculate the sizes of two blocks split from the single
+ block. */
+ pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
+ pxBlock->xBlockSize = xWantedSize;
+
+ /* Insert the new block into the list of free blocks. */
+ prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
+ }
+ }
+ }
+ }
+ xTaskResumeAll();
+
+ return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+unsigned portCHAR *puc = ( unsigned portCHAR * ) pv;
+xBlockLink *pxLink;
+
+ if( pv )
+ {
+ /* The memory being freed will have an xBlockLink structure immediately
+ before it. */
+ puc -= heapSTRUCT_SIZE;
+
+ /* This casting is to keep the compiler from issuing warnings. */
+ pxLink = ( void * ) puc;
+
+ vTaskSuspendAll();
+ {
+ /* Add this block to the list of free blocks. */
+ prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
+ }
+ xTaskResumeAll();
+ }
+}
+/*-----------------------------------------------------------*/
+
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+
+/*
+ * Implementation of pvPortMalloc() and vPortFree() that relies on the
+ * compilers own malloc() and free() implementations.
+ *
+ * This file can only be used if the linker is configured to to generate
+ * a heap memory area.
+ *
+ * See heap_2.c and heap_1.c for alternative implementations, and the memory
+ * management pages of http://www.FreeRTOS.org for more information.
+ */
+
+#include <stdlib.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/*-----------------------------------------------------------*/
+
+void *pvPortMalloc( size_t xWantedSize )
+{
+void *pvReturn;
+
+ vTaskSuspendAll();
+ {
+ pvReturn = malloc( xWantedSize );
+ }
+ xTaskResumeAll();
+
+ return pvReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vPortFree( void *pv )
+{
+ if( pv )
+ {
+ vTaskSuspendAll();
+ {
+ free( pv );
+ }
+ xTaskResumeAll();
+ }
+}
+
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+/*
+Changes from V1.01
+
+ + More use of 8bit data types.
+ + Function name prefixes changed where the data type returned has changed.
+
+Changed from V2.0.0
+
+ + Added the queue locking mechanism and make more use of the scheduler
+ suspension feature to minimise the time interrupts have to be disabled
+ when accessing a queue.
+
+Changed from V2.2.0
+
+ + Explicit use of 'signed' qualifier on portCHAR types added.
+
+Changes from V3.0.0
+
+ + API changes as described on the FreeRTOS.org WEB site.
+
+Changes from V3.2.3
+
+ + Added the queue functions that can be used from co-routines.
+
+Changes from V4.0.5
+
+ + Added a loop within xQueueSend() and xQueueReceive() to prevent the
+ functions exiting when a block time remains and the function has
+ not completed.
+
+Changes from V4.1.2:
+
+ + BUG FIX: Removed the call to prvIsQueueEmpty from within xQueueCRReceive
+ as it exited with interrupts enabled. Thanks Paul Katz.
+
+Changes from V4.1.3:
+
+ + Modified xQueueSend() and xQueueReceive() to handle the (very unlikely)
+ case whereby a task unblocking due to a temporal event can remove/send an
+ item from/to a queue when a higher priority task is still blocked on the
+ queue. This modification is a result of the SafeRTOS testing.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "croutine.h"
+
+/*-----------------------------------------------------------
+ * PUBLIC LIST API documented in list.h
+ *----------------------------------------------------------*/
+
+/* Constants used with the cRxLock and cTxLock structure members. */
+#define queueUNLOCKED ( ( signed portBASE_TYPE ) -1 )
+#define queueERRONEOUS_UNBLOCK ( -1 )
+
+/*
+ * Definition of the queue used by the scheduler.
+ * Items are queued by copy, not reference.
+ */
+typedef struct QueueDefinition
+{
+ signed portCHAR *pcHead; /*< Points to the beginning of the queue storage area. */
+ signed portCHAR *pcTail; /*< Points to the byte at the end of the queue storage area. Once more byte is allocated than necessary to store the queue items, this is used as a marker. */
+
+ signed portCHAR *pcWriteTo; /*< Points to the free next place in the storage area. */
+ signed portCHAR *pcReadFrom; /*< Points to the last place that a queued item was read from. */
+
+ xList xTasksWaitingToSend; /*< List of tasks that are blocked waiting to post onto this queue. Stored in priority order. */
+ xList xTasksWaitingToReceive; /*< List of tasks that are blocked waiting to read from this queue. Stored in priority order. */
+
+ unsigned portBASE_TYPE uxMessagesWaiting;/*< The number of items currently in the queue. */
+ unsigned portBASE_TYPE uxLength; /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
+ unsigned portBASE_TYPE uxItemSize; /*< The size of each items that the queue will hold. */
+
+ signed portBASE_TYPE xRxLock; /*< Stores the number of items received from the queue (removed from the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+ signed portBASE_TYPE xTxLock; /*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked. Set to queueUNLOCKED when the queue is not locked. */
+} xQUEUE;
+/*-----------------------------------------------------------*/
+
+/*
+ * Inside this file xQueueHandle is a pointer to a xQUEUE structure.
+ * To keep the definition private the API header file defines it as a
+ * pointer to void.
+ */
+typedef xQUEUE * xQueueHandle;
+
+/*
+ * Prototypes for public functions are included here so we don't have to
+ * include the API header file (as it defines xQueueHandle differently). These
+ * functions are documented in the API header file.
+ */
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize );
+signed portBASE_TYPE xQueueSend( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait );
+unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue );
+void vQueueDelete( xQueueHandle xQueue );
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken );
+signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+
+#if configUSE_CO_ROUTINES == 1
+ signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken );
+ signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken );
+ signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait );
+ signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait );
+#endif
+
+/*
+ * Unlocks a queue locked by a call to prvLockQueue. Locking a queue does not
+ * prevent an ISR from adding or removing items to the queue, but does prevent
+ * an ISR from removing tasks from the queue event lists. If an ISR finds a
+ * queue is locked it will instead increment the appropriate queue lock count
+ * to indicate that a task may require unblocking. When the queue in unlocked
+ * these lock counts are inspected, and the appropriate action taken.
+ */
+static void prvUnlockQueue( xQueueHandle pxQueue );
+
+/*
+ * Uses a critical section to determine if there is any data in a queue.
+ *
+ * @return pdTRUE if the queue contains no items, otherwise pdFALSE.
+ */
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue );
+
+/*
+ * Uses a critical section to determine if there is any space in a queue.
+ *
+ * @return pdTRUE if there is no space, otherwise pdFALSE;
+ */
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue );
+
+/*
+ * Macro that copies an item into the queue. This is done by copying the item
+ * byte for byte, not by reference. Updates the queue state to ensure it's
+ * integrity after the copy.
+ */
+#define prvCopyQueueData( pxQueue, pvItemToQueue ) \
+{ \
+ memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( unsigned ) pxQueue->uxItemSize ); \
+ ++( pxQueue->uxMessagesWaiting ); \
+ pxQueue->pcWriteTo += pxQueue->uxItemSize; \
+ if( pxQueue->pcWriteTo >= pxQueue->pcTail ) \
+ { \
+ pxQueue->pcWriteTo = pxQueue->pcHead; \
+ } \
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Macro to mark a queue as locked. Locking a queue prevents an ISR from
+ * accessing the queue event lists.
+ */
+#define prvLockQueue( pxQueue ) \
+{ \
+ taskENTER_CRITICAL(); \
+ ++( pxQueue->xRxLock ); \
+ ++( pxQueue->xTxLock ); \
+ taskEXIT_CRITICAL(); \
+}
+/*-----------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------
+ * PUBLIC QUEUE MANAGEMENT API documented in queue.h
+ *----------------------------------------------------------*/
+
+xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize )
+{
+xQUEUE *pxNewQueue;
+size_t xQueueSizeInBytes;
+
+ /* Allocate the new queue structure. */
+ if( uxQueueLength > ( unsigned portBASE_TYPE ) 0 )
+ {
+ pxNewQueue = ( xQUEUE * ) pvPortMalloc( sizeof( xQUEUE ) );
+ if( pxNewQueue != NULL )
+ {
+ /* Create the list of pointers to queue items. The queue is one byte
+ longer than asked for to make wrap checking easier/faster. */
+ xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ) + ( size_t ) 1;
+
+ pxNewQueue->pcHead = ( signed portCHAR * ) pvPortMalloc( xQueueSizeInBytes );
+ if( pxNewQueue->pcHead != NULL )
+ {
+ /* Initialise the queue members as described above where the
+ queue type is defined. */
+ pxNewQueue->pcTail = pxNewQueue->pcHead + ( uxQueueLength * uxItemSize );
+ pxNewQueue->uxMessagesWaiting = 0;
+ pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
+ pxNewQueue->pcReadFrom = pxNewQueue->pcHead + ( ( uxQueueLength - 1 ) * uxItemSize );
+ pxNewQueue->uxLength = uxQueueLength;
+ pxNewQueue->uxItemSize = uxItemSize;
+ pxNewQueue->xRxLock = queueUNLOCKED;
+ pxNewQueue->xTxLock = queueUNLOCKED;
+
+ /* Likewise ensure the event queues start with the correct state. */
+ vListInitialise( &( pxNewQueue->xTasksWaitingToSend ) );
+ vListInitialise( &( pxNewQueue->xTasksWaitingToReceive ) );
+
+ return pxNewQueue;
+ }
+ else
+ {
+ vPortFree( pxNewQueue );
+ }
+ }
+ }
+
+ /* Will only reach here if we could not allocate enough memory or no memory
+ was required. */
+ return NULL;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn = pdPASS;
+xTimeOutType xTimeOut;
+
+ /* Make sure other tasks do not access the queue. */
+ vTaskSuspendAll();
+
+ /* Capture the current time status for future reference. */
+ vTaskSetTimeOutState( &xTimeOut );
+
+ /* It is important that this is the only thread/ISR that modifies the
+ ready or delayed lists until xTaskResumeAll() is called. Places where
+ the ready/delayed lists are modified include:
+
+ + vTaskDelay() - Nothing can call vTaskDelay as the scheduler is
+ suspended, vTaskDelay() cannot be called from an ISR.
+ + vTaskPrioritySet() - Has a critical section around the access.
+ + vTaskSwitchContext() - This will not get executed while the scheduler
+ is suspended.
+ + prvCheckDelayedTasks() - This will not get executed while the
+ scheduler is suspended.
+ + xTaskCreate() - Has a critical section around the access.
+ + vTaskResume() - Has a critical section around the access.
+ + xTaskResumeAll() - Has a critical section around the access.
+ + xTaskRemoveFromEventList - Checks to see if the scheduler is
+ suspended. If so then the TCB being removed from the event is
+ removed from the event and added to the xPendingReadyList.
+ */
+
+ /* Make sure interrupts do not access the queue event list. */
+ prvLockQueue( pxQueue );
+
+ /* It is important that interrupts to not access the event list of the
+ queue being modified here. Places where the event list is modified
+ include:
+
+ + xQueueSendFromISR(). This checks the lock on the queue to see if
+ it has access. If the queue is locked then the Tx lock count is
+ incremented to signify that a task waiting for data can be made ready
+ once the queue lock is removed. If the queue is not locked then
+ a task can be moved from the event list, but will not be removed
+ from the delayed list or placed in the ready list until the scheduler
+ is unlocked.
+
+ + xQueueReceiveFromISR(). As per xQueueSendFromISR().
+ */
+
+ /* If the queue is already full we may have to block. */
+ do
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ /* The queue is full - do we want to block or just leave without
+ posting? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* We are going to place ourselves on the xTasksWaitingToSend event
+ list, and will get woken should the delay expire, or space become
+ available on the queue.
+
+ As detailed above we do not require mutual exclusion on the event
+ list as nothing else can modify it or the ready lists while we
+ have the scheduler suspended and queue locked.
+
+ It is possible that an ISR has removed data from the queue since we
+ checked if any was available. If this is the case then the data
+ will have been copied from the queue, and the queue variables
+ updated, but the event list will not yet have been checked to see if
+ anything is waiting as the queue is locked. */
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
+
+ /* Force a context switch now as we are blocked. We can do
+ this from within a critical section as the task we are
+ switching to has its own context. When we return here (i.e. we
+ unblock) we will leave the critical section as normal.
+
+ It is possible that an ISR has caused an event on an unrelated and
+ unlocked queue. If this was the case then the event list for that
+ queue will have been updated but the ready lists left unchanged -
+ instead the readied task will have been added to the pending ready
+ list. */
+ taskENTER_CRITICAL();
+ {
+ /* We can safely unlock the queue and scheduler here as
+ interrupts are disabled. We must not yield with anything
+ locked, but we can yield from within a critical section.
+
+ Tasks that have been placed on the pending ready list cannot
+ be tasks that are waiting for events on this queue. See
+ in comment xTaskRemoveFromEventList(). */
+ prvUnlockQueue( pxQueue );
+
+ /* Resuming the scheduler may cause a yield. If so then there
+ is no point yielding again here. */
+ if( !xTaskResumeAll() )
+ {
+ taskYIELD();
+ }
+
+ /* We want to check to see if the queue is still full
+ before leaving the critical section. This is to prevent
+ this task placing an item into the queue due to an
+ interrupt making space on the queue between critical
+ sections (when there might be a higher priority task
+ blocked on the queue that cannot run yet because the
+ scheduler gets suspended). */
+ if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
+ {
+ /* We unblocked but there is no space in the queue,
+ we probably timed out. */
+ xReturn = errQUEUE_FULL;
+ }
+
+ /* Before leaving the critical section we have to ensure
+ exclusive access again. */
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+ /* If xReturn is errQUEUE_FULL then we unblocked when the queue
+ was still full. Don't check it again now as it is possible that
+ an interrupt has removed an item from the queue since we left the
+ critical section and we don't want to write to the queue in case
+ there is a task of higher priority blocked waiting for space to
+ be available on the queue. If this is the case the higher priority
+ task will execute when the scheduler is unsupended. */
+ if( xReturn != errQUEUE_FULL )
+ {
+ /* When we are here it is possible that we unblocked as space became
+ available on the queue. It is also possible that an ISR posted to the
+ queue since we left the critical section, so it may be that again there
+ is no space. This would only happen if a task and ISR post onto the
+ same queue. */
+ taskENTER_CRITICAL();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ /* There is room in the queue, copy the data into the queue. */
+ prvCopyQueueData( pxQueue, pvItemToQueue );
+ xReturn = pdPASS;
+
+ /* Update the TxLock count so prvUnlockQueue knows to check for
+ tasks waiting for data to become available in the queue. */
+ ++( pxQueue->xTxLock );
+ }
+ else
+ {
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+
+ if( xReturn == errQUEUE_FULL )
+ {
+ if( xTicksToWait > 0 )
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ xReturn = queueERRONEOUS_UNBLOCK;
+ }
+ }
+ }
+ }
+ while( xReturn == queueERRONEOUS_UNBLOCK );
+
+ prvUnlockQueue( pxQueue );
+ xTaskResumeAll();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )
+{
+ /* Similar to xQueueSend, except we don't block if there is no room in the
+ queue. Also we don't directly wake a task that was blocked on a queue
+ read, instead we return a flag to say whether a context switch is required
+ or not (i.e. has a task with a higher priority than us been woken by this
+ post). */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ prvCopyQueueData( pxQueue, pvItemToQueue );
+
+ /* If the queue is locked we do not alter the event list. This will
+ be done when the queue is unlocked later. */
+ if( pxQueue->xTxLock == queueUNLOCKED )
+ {
+ /* We only want to wake one task per ISR, so check that a task has
+ not already been woken. */
+ if( !xTaskPreviouslyWoken )
+ {
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ return pdTRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was posted while it was locked. */
+ ++( pxQueue->xTxLock );
+ }
+ }
+
+ return xTaskPreviouslyWoken;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn = pdTRUE;
+xTimeOutType xTimeOut;
+
+ /* This function is very similar to xQueueSend(). See comments within
+ xQueueSend() for a more detailed explanation.
+
+ Make sure other tasks do not access the queue. */
+ vTaskSuspendAll();
+
+ /* Capture the current time status for future reference. */
+ vTaskSetTimeOutState( &xTimeOut );
+
+ /* Make sure interrupts do not access the queue. */
+ prvLockQueue( pxQueue );
+
+ do
+ {
+ /* If there are no messages in the queue we may have to block. */
+ if( prvIsQueueEmpty( pxQueue ) )
+ {
+ /* There are no messages in the queue, do we want to block or just
+ leave with nothing? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+ taskENTER_CRITICAL();
+ {
+ prvUnlockQueue( pxQueue );
+ if( !xTaskResumeAll() )
+ {
+ taskYIELD();
+ }
+
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* We unblocked but the queue is empty. We probably
+ timed out. */
+ xReturn = errQUEUE_EMPTY;
+ }
+
+ vTaskSuspendAll();
+ prvLockQueue( pxQueue );
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+ if( xReturn != errQUEUE_EMPTY )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ /* Increment the lock count so prvUnlockQueue knows to check for
+ tasks waiting for space to become available on the queue. */
+ ++( pxQueue->xRxLock );
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = errQUEUE_EMPTY;
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+
+ if( xReturn == errQUEUE_EMPTY )
+ {
+ if( xTicksToWait > 0 )
+ {
+ if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+ {
+ xReturn = queueERRONEOUS_UNBLOCK;
+ }
+ }
+ }
+ } while( xReturn == queueERRONEOUS_UNBLOCK );
+
+ /* We no longer require exclusive access to the queue. */
+ prvUnlockQueue( pxQueue );
+ xTaskResumeAll();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )
+{
+signed portBASE_TYPE xReturn;
+
+ /* We cannot block from an ISR, so check there is data available. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Copy the data from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ /* If the queue is locked we will not modify the event list. Instead
+ we update the lock count so the task that unlocks the queue will know
+ that an ISR has removed data while the queue was locked. */
+ if( pxQueue->xRxLock == queueUNLOCKED )
+ {
+ /* We only want to wake one task per ISR, so check that a task has
+ not already been woken. */
+ if( !( *pxTaskWoken ) )
+ {
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority than us so
+ force a context switch. */
+ *pxTaskWoken = pdTRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Increment the lock count so the task that unlocks the queue
+ knows that data was removed while it was locked. */
+ ++( pxQueue->xRxLock );
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )
+{
+unsigned portBASE_TYPE uxReturn;
+
+ taskENTER_CRITICAL();
+ uxReturn = pxQueue->uxMessagesWaiting;
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vQueueDelete( xQueueHandle pxQueue )
+{
+ vPortFree( pxQueue->pcHead );
+ vPortFree( pxQueue );
+}
+/*-----------------------------------------------------------*/
+
+static void prvUnlockQueue( xQueueHandle pxQueue )
+{
+ /* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
+
+ /* The lock counts contains the number of extra data items placed or
+ removed from the queue while the queue was locked. When a queue is
+ locked items can be added or removed, but the event lists cannot be
+ updated. */
+ taskENTER_CRITICAL();
+ {
+ --( pxQueue->xTxLock );
+
+ /* See if data was added to the queue while it was locked. */
+ if( pxQueue->xTxLock > queueUNLOCKED )
+ {
+ pxQueue->xTxLock = queueUNLOCKED;
+
+ /* Data was posted while the queue was locked. Are any tasks
+ blocked waiting for data to become available? */
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+ {
+ /* Tasks that are removed from the event list will get added to
+ the pending ready list as the scheduler is still suspended. */
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The task waiting has a higher priority so record that a
+ context switch is required. */
+ vTaskMissedYield();
+ }
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+
+ /* Do the same for the Rx lock. */
+ taskENTER_CRITICAL();
+ {
+ --( pxQueue->xRxLock );
+
+ if( pxQueue->xRxLock > queueUNLOCKED )
+ {
+ pxQueue->xRxLock = queueUNLOCKED;
+
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+ {
+ if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ vTaskMissedYield();
+ }
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
+{
+signed portBASE_TYPE xReturn;
+
+ taskENTER_CRITICAL();
+ xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
+ taskEXIT_CRITICAL();
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already full we may have to block. A critical section
+ is required to prevent an interrupt removing something from the queue
+ between the check to see if the queue is full and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( prvIsQueueFull( pxQueue ) )
+ {
+ /* The queue is full - do we want to block or just leave without
+ posting? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is called from a coroutine we cannot block directly, but
+ return indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ /* There is room in the queue, copy the data into the queue. */
+ prvCopyQueueData( pxQueue, pvItemToQueue );
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for data to become available? */
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechansim is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ /* The co-routine waiting has a higher priority so record
+ that a yield might be appropriate. */
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = errQUEUE_FULL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
+{
+signed portBASE_TYPE xReturn;
+
+ /* If the queue is already empty we may have to block. A critical section
+ is required to prevent an interrupt adding something to the queue
+ between the check to see if the queue is empty and blocking on the queue. */
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* There are no messages in the queue, do we want to block or just
+ leave with nothing? */
+ if( xTicksToWait > ( portTickType ) 0 )
+ {
+ /* As this is a co-routine we cannot block directly, but return
+ indicating that we need to block. */
+ vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
+ portENABLE_INTERRUPTS();
+ return errQUEUE_BLOCKED;
+ }
+ else
+ {
+ portENABLE_INTERRUPTS();
+ return errQUEUE_FULL;
+ }
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ portNOP();
+
+ portDISABLE_INTERRUPTS();
+ {
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Data is available from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ xReturn = pdPASS;
+
+ /* Were any co-routines waiting for space to become available? */
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+ {
+ /* In this instance the co-routine could be placed directly
+ into the ready list as we are within a critical section.
+ Instead the same pending ready list mechansim is used as if
+ the event were caused from within an interrupt. */
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ xReturn = errQUEUE_YIELD;
+ }
+ }
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+ }
+ portENABLE_INTERRUPTS();
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
+{
+ /* Cannot block within an ISR so if there is no space on the queue then
+ exit without doing anything. */
+ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ {
+ prvCopyQueueData( pxQueue, pvItemToQueue );
+
+ /* We only want to wake one co-routine per ISR, so check that a
+ co-routine has not already been woken. */
+ if( !xCoRoutinePreviouslyWoken )
+ {
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+ {
+ return pdTRUE;
+ }
+ }
+ }
+ }
+
+ return xCoRoutinePreviouslyWoken;
+}
+#endif
+/*-----------------------------------------------------------*/
+
+#if configUSE_CO_ROUTINES == 1
+signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
+{
+signed portBASE_TYPE xReturn;
+
+ /* We cannot block from an ISR, so check there is data available. If
+ not then just leave without doing anything. */
+ if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
+ {
+ /* Copy the data from the queue. */
+ pxQueue->pcReadFrom += pxQueue->uxItemSize;
+ if( pxQueue->pcReadFrom >= pxQueue->pcTail )
+ {
+ pxQueue->pcReadFrom = pxQueue->pcHead;
+ }
+ --( pxQueue->uxMessagesWaiting );
+ memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
+
+ if( !( *pxCoRoutineWoken ) )
+ {
+ if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
+ {
+ if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+ {
+ *pxCoRoutineWoken = pdTRUE;
+ }
+ }
+ }
+
+ xReturn = pdPASS;
+ }
+ else
+ {
+ xReturn = pdFAIL;
+ }
+
+ return xReturn;
+}
+#endif
+/*-----------------------------------------------------------*/
+
--- /dev/null
+/*
+ FreeRTOS.org V4.4.0 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version, along
+ with development and support options.
+ ***************************************************************************
+*/
+
+/*
+Changes from V1.00:
+
+ + Call to portRESTORE_CONTEXT has been removed. The first context
+ switch is now performed within sPortStartScheduler().
+
+Changes from V1.01:
+
+ + More use of 8bit data types.
+ + Function name prefixes changed where the data type returned has changed.
+ + configUSE_TRACE_FACILITY is no longer defined by default.
+
+Changes from V1.2.0
+
+ + Introduced ucTopReadyPriority. This tracks the highest priority ready
+ queue that contains a valid TCB and thus makes the context switch
+ slightly faster.
+
+ + prvAddTaskToReadyQueue() has been made a macro.
+
+Changes from V1.2.6
+
+ + Added conditional compilation directives.
+ + Extended API.
+ + Rearranged function order.
+ + Creating a task now causes a context switch if the task being created
+ has a higher priority than the calling task - assuming the kernel is
+ running.
+ + vTaskDelete() now only causes a context switch if the calling task is
+ the task being deleted.
+
+Changes from V2.0.0
+
+ + Allow the type of the tick count to be 16 or 32 bits.
+ + Introduce xPendingReadyList feature to allow the time interrupts have to
+ be disabled to be minimised.
+ + Remove the #if( INCLUDE_vTaskSuspendAll ) statements. vTaskSuspendAll()
+ is now always included as it is used by the scheduler itself.
+
+Changes from V2.1.0
+
+ + Bug fix - pxCurrentTCB is now initialised before the call to
+ prvInitializeTaskLists(). Previously pxCurrentTCB could be accessed
+ while null.
+
+Changed from V2.1.1
+
+ + Change to where lStackSize is declared within sTaskCreate() to prevent
+ compiler warnings with 8051 port.
+
+Changes from V2.2.0
+
+ + Explicit use of 'signed' qualifier on portCHAR types added.
+ + Changed odd calculation of initial pxTopOfStack value when
+ portSTACK_GROWTH < 0.
+ + Removed pcVersionNumber definition.
+
+Changes from V2.5.3
+
+ + cTaskResumeAll() modified to ensure it can be called prior to the task
+ lists being initialised.
+
+Changes from V2.5.5
+
+ + Added API function vTaskDelayUntil().
+ + Added INCLUDE_vTaskDelay conditional compilation.
+
+Changes from V2.6.0
+
+ + Updated the vWriteTraceToBuffer macro to always be 4 byte aligned so it
+ can be used on ARM architectures.
+ + tskMAX_TASK_NAME_LEN definition replaced with the port specific
+ configMAX_TASK_NAME_LEN definition.
+ + Removed the call to strcpy when copying across the task name into the
+ TCB.
+ + Added ucTasksDeleted variable to prevent vTaskSuspendAll() being called
+ too often in the idle task.
+
+Changes between V3.0.0 and V2.6.1
+
+ + When resuming the scheduler a yield is performed if either a tick has
+ been missed, or a task is moved from the pending ready list into a ready
+ list. Previously a yield was not performed on this second condition.
+ + Introduced the type portBASE_TYPE. This necessitates several API
+ changes.
+ + Removed the sUsingPreemption variable. The constant defined in
+ portmacro.h is now used directly.
+ + The idle task can now include an optional hook function - and no longer
+ completes its time slice if other tasks with equal priority to it are
+ ready to run.
+ + See the FreeRTOS.org documentation for more information on V2.x.x to
+ V3.x.x modifications.
+
+Changes from V3.1.1
+
+ + Modified vTaskPrioritySet() and vTaskResume() to allow these functions to
+ be called while the scheduler is suspended.
+ + Corrected the task ordering within event lists.
+
+Changes from V3.2.0
+
+ + Added function xTaskGetCurrentTaskHandle().
+
+Changes from V3.2.4
+
+ + Changed the volatile declarations on some variables to reflect the
+ changes to the list definitions.
+ + Changed the order of the TCB definition so there is commonality between
+ the task control block and a co-routine control block.
+ + Allow the scheduler to be started even if no tasks other than the idle
+ task has been created. This allows co-routines to run even when no tasks
+ have been created.
+ + The need for a context switch is now signalled if a task woken by an
+ event has a priority greater or equal to the currently running task.
+ Previously this was only greater than.
+
+Changes from V4.0.0
+
+ + Added the xMissedYield handling.
+
+Changes from V4.0.1
+
+ + The function vTaskList() now suspends the scheduler rather than disabling
+ interrupts during the creation of the task list.
+ + Allow a task to delete itself by passing in its own handle. Previously
+ this could only be done by passing in NULL.
+ + The tick hook function is now called only within a tick isr. Previously
+ it was also called when the tick function was called during the scheduler
+ unlocking process.
+
+Changes from V4.0.3
+
+ + Extra checks have been placed in vTaskPrioritySet() to avoid unnecessary
+ yields.
+
+Changed from V4.0.4
+
+ + Bug fix: The 'value' of the event list item is updated when the priority
+ of a task is changed. Previously only the priority of the TCB itself was
+ changed.
+ + When resuming a task a check is first made to see if the task is actually
+ suspended.
+ + vTaskPrioritySet() and vTaskResume() no longer use the event list item.
+ This has not been necessary since V4.0.1 when the xMissedYield handling
+ was added.
+ + Implement xTaskResumeFromISR().
+
+Changes from V4.0.5
+
+ + Added utility functions and xOverflowCount variable to facilitate the
+ queue.c changes.
+
+Changes from V4.1.2
+
+ + Tasks that block on events with a timeout of portMAX_DELAY are now
+ blocked indefinitely if configINCLUDE_vTaskSuspend is defined.
+ Previously portMAX_DELAY was just the longest block time possible.
+
+Changes from V4.1.3
+
+ + Very small change made to xTaskCheckForTimeout() as a result of the
+ SafeRTOS testing. This corrects the case where the function can return an
+ invalid value - but only in an extremely unlikely scenario.
+
+Changes since V4.3.1:
+
+ + Added xTaskGetSchedulerState() function.
+ + Added prvIsTaskSuspended() to take into account the Occurrence of
+ vTaskResume() or vTaskResumeFromISR() being called passing in the
+ handle of a task that appears in the Suspended list only because it
+ is blocked on an event without a timeout being specified.
+ + Updated xTaskCheckForTimeout() to take into account that tasks blocked
+ using the Suspended list should never time out.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+/*
+ * Macro to define the amount of stack available to the idle task.
+ */
+#define tskIDLE_STACK_SIZE configMINIMAL_STACK_SIZE
+
+
+/*
+ * Default a definitions for backwards compatibility with old
+ * portmacro.h files.
+ */
+#ifndef configMAX_TASK_NAME_LEN
+ #define configMAX_TASK_NAME_LEN 16
+#endif
+
+#ifndef INCLUDE_xTaskGetCurrentTaskHandle
+ #define INCLUDE_xTaskGetCurrentTaskHandle 0
+#endif
+
+#ifndef configIDLE_SHOULD_YIELD
+ #define configIDLE_SHOULD_YIELD 1
+#endif
+
+#if configMAX_TASK_NAME_LEN < 1
+ #undef configMAX_TASK_NAME_LEN
+ #define configMAX_TASK_NAME_LEN 1
+#endif
+
+#ifndef INCLUDE_xTaskResumeFromISR
+ #define INCLUDE_xTaskResumeFromISR 1
+#endif
+
+#ifndef INCLUDE_xTaskGetSchedulerState
+ #define INCLUDE_xTaskGetSchedulerState 0
+#endif
+
+/*
+ * Task control block. A task control block (TCB) is allocated to each task,
+ * and stores the context of the task.
+ */
+typedef struct tskTaskControlBlock
+{
+ volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
+ xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
+ xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
+ unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
+ portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
+ unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
+ signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
+ unsigned portSHORT usStackDepth; /*< Total depth of the stack (when empty). This is defined as the number of variables the stack can hold, not the number of bytes. */
+} tskTCB;
+
+/*lint -e956 */
+
+tskTCB * volatile pxCurrentTCB = NULL;
+
+/* Lists for ready and blocked tasks. --------------------*/
+
+static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; /*< Prioritised ready tasks. */
+static xList xDelayedTaskList1; /*< Delayed tasks. */
+static xList xDelayedTaskList2; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
+static xList * volatile pxDelayedTaskList; /*< Points to the delayed task list currently being used. */
+static xList * volatile pxOverflowDelayedTaskList; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
+static xList xPendingReadyList; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready queue when the scheduler is resumed. */
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ static volatile xList xTasksWaitingTermination; /*< Tasks that have been deleted - but the their memory not yet freed. */
+ static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0;
+
+#endif
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ static xList xSuspendedTaskList; /*< Tasks that are currently suspended. */
+
+#endif
+
+/* File private variables. --------------------------------*/
+static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks = ( unsigned portBASE_TYPE ) 0;
+static volatile portTickType xTickCount = ( portTickType ) 0;
+static unsigned portBASE_TYPE uxTopUsedPriority = tskIDLE_PRIORITY;
+static volatile unsigned portBASE_TYPE uxTopReadyPriority = tskIDLE_PRIORITY;
+static volatile signed portBASE_TYPE xSchedulerRunning = pdFALSE;
+static volatile unsigned portBASE_TYPE uxSchedulerSuspended = ( unsigned portBASE_TYPE ) pdFALSE;
+static volatile unsigned portBASE_TYPE uxMissedTicks = ( unsigned portBASE_TYPE ) 0;
+static volatile portBASE_TYPE xMissedYield = ( portBASE_TYPE ) pdFALSE;
+static volatile portBASE_TYPE xNumOfOverflows = ( portBASE_TYPE ) 0;
+/* Debugging and trace facilities private variables and macros. ------------*/
+
+/*
+ * The value used to fill the stack of a task when the task is created. This
+ * is used purely for checking the high water mark for tasks.
+ */
+#define tskSTACK_FILL_BYTE ( 0xa5 )
+
+/*
+ * Macros used by vListTask to indicate which state a task is in.
+ */
+#define tskBLOCKED_CHAR ( ( signed portCHAR ) 'B' )
+#define tskREADY_CHAR ( ( signed portCHAR ) 'R' )
+#define tskDELETED_CHAR ( ( signed portCHAR ) 'D' )
+#define tskSUSPENDED_CHAR ( ( signed portCHAR ) 'S' )
+
+/*
+ * Macros and private variables used by the trace facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define tskSIZE_OF_EACH_TRACE_LINE ( ( unsigned portLONG ) ( sizeof( unsigned portLONG ) + sizeof( unsigned portLONG ) ) )
+ static volatile signed portCHAR * volatile pcTraceBuffer;
+ static signed portCHAR *pcTraceBufferStart;
+ static signed portCHAR *pcTraceBufferEnd;
+ static signed portBASE_TYPE xTracing = pdFALSE;
+
+#endif
+
+/*
+ * Macro that writes a trace of scheduler activity to a buffer. This trace
+ * shows which task is running when and is very useful as a debugging tool.
+ * As this macro is called each context switch it is a good idea to undefine
+ * it if not using the facility.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ #define vWriteTraceToBuffer() \
+ { \
+ if( xTracing ) \
+ { \
+ static unsigned portBASE_TYPE uxPreviousTask = 255; \
+ \
+ if( uxPreviousTask != pxCurrentTCB->uxTCBNumber ) \
+ { \
+ if( ( pcTraceBuffer + tskSIZE_OF_EACH_TRACE_LINE ) < pcTraceBufferEnd ) \
+ { \
+ uxPreviousTask = pxCurrentTCB->uxTCBNumber; \
+ *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) xTickCount; \
+ pcTraceBuffer += sizeof( unsigned portLONG ); \
+ *( unsigned portLONG * ) pcTraceBuffer = ( unsigned portLONG ) uxPreviousTask; \
+ pcTraceBuffer += sizeof( unsigned portLONG ); \
+ } \
+ else \
+ { \
+ xTracing = pdFALSE; \
+ } \
+ } \
+ } \
+ }
+
+#else
+
+ #define vWriteTraceToBuffer()
+
+#endif
+
+
+/*
+ * Place the task represented by pxTCB into the appropriate ready queue for
+ * the task. It is inserted at the end of the list. One quirk of this is
+ * that if the task being inserted is at the same priority as the currently
+ * executing task, then it will only be rescheduled after the currently
+ * executing task has been rescheduled.
+ */
+#define prvAddTaskToReadyQueue( pxTCB ) \
+{ \
+ if( pxTCB->uxPriority > uxTopReadyPriority ) \
+ { \
+ uxTopReadyPriority = pxTCB->uxPriority; \
+ } \
+ vListInsertEnd( ( xList * ) &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xGenericListItem ) ); \
+}
+
+/*
+ * Macro that looks at the list of tasks that are currently delayed to see if
+ * any require waking.
+ *
+ * Tasks are stored in the queue in the order of their wake time - meaning
+ * once one tasks has been found whose timer has not expired we need not look
+ * any further down the list.
+ */
+#define prvCheckDelayedTasks() \
+{ \
+register tskTCB *pxTCB; \
+ \
+ while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ) ) != NULL ) \
+ { \
+ if( xTickCount < listGET_LIST_ITEM_VALUE( &( pxTCB->xGenericListItem ) ) ) \
+ { \
+ break; \
+ } \
+ vListRemove( &( pxTCB->xGenericListItem ) ); \
+ /* Is the task waiting on an event also? */ \
+ if( pxTCB->xEventListItem.pvContainer ) \
+ { \
+ vListRemove( &( pxTCB->xEventListItem ) ); \
+ } \
+ prvAddTaskToReadyQueue( pxTCB ); \
+ } \
+}
+
+/*
+ * Several functions take an xTaskHandle parameter that can optionally be NULL,
+ * where NULL is used to indicate that the handle of the currently executing
+ * task should be used in place of the parameter. This macro simply checks to
+ * see if the parameter is NULL and returns a pointer to the appropriate TCB.
+ */
+#define prvGetTCBFromHandle( pxHandle ) ( ( pxHandle == NULL ) ? ( tskTCB * ) pxCurrentTCB : ( tskTCB * ) pxHandle )
+
+
+/* File private functions. --------------------------------*/
+
+/*
+ * Utility to ready a TCB for a given task. Mainly just copies the parameters
+ * into the TCB structure.
+ */
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority );
+
+/*
+ * Utility to ready all the lists used by the scheduler. This is called
+ * automatically upon the creation of the first task.
+ */
+static void prvInitialiseTaskLists( void );
+
+/*
+ * The idle task, which as all tasks is implemented as a never ending loop.
+ * The idle task is automatically created and added to the ready lists upon
+ * creation of the first user task.
+ *
+ * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters );
+
+/*
+ * Utility to free all memory allocated by the scheduler to hold a TCB,
+ * including the stack pointed to by the TCB.
+ *
+ * This does not free memory allocated by the task itself (i.e. memory
+ * allocated by calls to pvPortMalloc from within the tasks application code).
+ */
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+ static void prvDeleteTCB( tskTCB *pxTCB );
+#endif
+
+/*
+ * Used only by the idle task. This checks to see if anything has been placed
+ * in the list of tasks waiting to be deleted. If so the task is cleaned up
+ * and its TCB deleted.
+ */
+static void prvCheckTasksWaitingTermination( void );
+
+/*
+ * Allocates memory from the heap for a TCB and associated stack. Checks the
+ * allocation was successful.
+ */
+static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth );
+
+/*
+ * Called from vTaskList. vListTasks details all the tasks currently under
+ * control of the scheduler. The tasks may be in one of a number of lists.
+ * prvListTaskWithinSingleList accepts a list and details the tasks from
+ * within just that list.
+ *
+ * THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY, AND SHOULD NOT BE CALLED FROM
+ * NORMAL APPLICATION CODE.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus );
+
+#endif
+
+/*
+ * When a task is created, the stack of the task is filled with a known value.
+ * This function determines the 'high water mark' of the task stack by
+ * determining how much of the stack remains at the original preset value.
+ */
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte );
+
+#endif
+
+/*
+ * Checks that a task being resumed (unsuspended) is actually in the Suspended
+ * state.
+ */
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ static portBASE_TYPE prvIsTaskSuspended( const tskTCB * const pxTCB );
+
+#endif
+
+/*lint +e956 */
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CREATION API documented in task.h
+ *----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskCreate( pdTASK_CODE pvTaskCode, const signed portCHAR * const pcName, unsigned portSHORT usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, xTaskHandle *pxCreatedTask )
+{
+signed portBASE_TYPE xReturn;
+tskTCB * pxNewTCB;
+static unsigned portBASE_TYPE uxTaskNumber = 0; /*lint !e956 Static is deliberate - this is guarded before use. */
+
+ /* Allocate the memory required by the TCB and stack for the new task.
+ checking that the allocation was successful. */
+ pxNewTCB = prvAllocateTCBAndStack( usStackDepth );
+
+ if( pxNewTCB != NULL )
+ {
+ portSTACK_TYPE *pxTopOfStack;
+
+ /* Setup the newly allocated TCB with the initial state of the task. */
+ prvInitialiseTCBVariables( pxNewTCB, usStackDepth, pcName, uxPriority );
+
+ /* Calculate the top of stack address. This depends on whether the
+ stack grows from high memory to low (as per the 80x86) or visa versa.
+ portSTACK_GROWTH is used to make the result positive or negative as
+ required by the port. */
+ #if portSTACK_GROWTH < 0
+ {
+ pxTopOfStack = pxNewTCB->pxStack + ( pxNewTCB->usStackDepth - 1 );
+ }
+ #else
+ {
+ pxTopOfStack = pxNewTCB->pxStack;
+ }
+ #endif
+
+ /* Initialize the TCB stack to look as if the task was already running,
+ but had been interrupted by the scheduler. The return address is set
+ to the start of the task function. Once the stack has been initialised
+ the top of stack variable is updated. */
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pvTaskCode, pvParameters );
+
+ /* We are going to manipulate the task queues to add this task to a
+ ready list, so must make sure no interrupts occur. */
+ portENTER_CRITICAL();
+ {
+ uxCurrentNumberOfTasks++;
+ if( uxCurrentNumberOfTasks == ( unsigned portBASE_TYPE ) 1 )
+ {
+ /* As this is the first task it must also be the current task. */
+ pxCurrentTCB = pxNewTCB;
+
+ /* This is the first task to be created so do the preliminary
+ initialisation required. We will not recover if this call
+ fails, but we will report the failure. */
+ prvInitialiseTaskLists();
+ }
+ else
+ {
+ /* If the scheduler is not already running, make this task the
+ current task if it is the highest priority task to be created
+ so far. */
+ if( xSchedulerRunning == pdFALSE )
+ {
+ if( pxCurrentTCB->uxPriority <= uxPriority )
+ {
+ pxCurrentTCB = pxNewTCB;
+ }
+ }
+ }
+
+ /* Remember the top priority to make context switching faster. Use
+ the priority in pxNewTCB as this has been capped to a valid value. */
+ if( pxNewTCB->uxPriority > uxTopUsedPriority )
+ {
+ uxTopUsedPriority = pxNewTCB->uxPriority;
+ }
+
+ /* Add a counter into the TCB for tracing only. */
+ pxNewTCB->uxTCBNumber = uxTaskNumber;
+ uxTaskNumber++;
+
+ prvAddTaskToReadyQueue( pxNewTCB );
+
+ xReturn = pdPASS;
+ }
+ portEXIT_CRITICAL();
+ }
+ else
+ {
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+ }
+
+ if( xReturn == pdPASS )
+ {
+ if( ( void * ) pxCreatedTask != NULL )
+ {
+ /* Pass the TCB out - in an anonymous way. The calling function/
+ task can use this as a handle to delete the task later if
+ required.*/
+ *pxCreatedTask = ( xTaskHandle ) pxNewTCB;
+ }
+
+ if( xSchedulerRunning != pdFALSE )
+ {
+ /* If the created task is of a higher priority than the current task
+ then it should run now. */
+ if( pxCurrentTCB->uxPriority < uxPriority )
+ {
+ taskYIELD();
+ }
+ }
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelete == 1 )
+
+ void vTaskDelete( xTaskHandle pxTaskToDelete )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ deleted. */
+ if( pxTaskToDelete == pxCurrentTCB )
+ {
+ pxTaskToDelete = NULL;
+ }
+
+ /* If null is passed in here then we are deleting ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
+
+ /* Remove task from the ready list and place in the termination list.
+ This will stop the task from be scheduled. The idle task will check
+ the termination list and free up any memory allocated by the
+ scheduler for the TCB and stack. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
+
+ /* Increment the ucTasksDeleted variable so the idle task knows
+ there is a task that has been deleted and that it should therefore
+ check the xTasksWaitingTermination list. */
+ ++uxTasksDeleted;
+ }
+ taskEXIT_CRITICAL();
+
+ /* Force a reschedule if we have just deleted the current task. */
+ if( xSchedulerRunning != pdFALSE )
+ {
+ if( ( void * ) pxTaskToDelete == NULL )
+ {
+ taskYIELD();
+ }
+ }
+ }
+
+#endif
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * TASK CONTROL API documented in task.h
+ *----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelayUntil == 1 )
+
+ void vTaskDelayUntil( portTickType *pxPreviousWakeTime, portTickType xTimeIncrement )
+ {
+ portTickType xTimeToWake;
+ portBASE_TYPE xAlreadyYielded, xShouldDelay = pdFALSE;
+
+ vTaskSuspendAll();
+ {
+ /* Generate the tick time at which the task wants to wake. */
+ xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
+
+ if( xTickCount < *pxPreviousWakeTime )
+ {
+ /* The tick count has overflowed since this function was
+ lasted called. In this case the only time we should ever
+ actually delay is if the wake time has also overflowed,
+ and the wake time is greater than the tick time. When this
+ is the case it is as if neither time had overflowed. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+ else
+ {
+ /* The tick time has not overflowed. In this case we will
+ delay if either the wake time has overflowed, and/or the
+ tick time is less than the wake time. */
+ if( ( xTimeToWake < *pxPreviousWakeTime ) || ( xTimeToWake > xTickCount ) )
+ {
+ xShouldDelay = pdTRUE;
+ }
+ }
+
+ /* Update the wake time ready for the next call. */
+ *pxPreviousWakeTime = xTimeToWake;
+
+ if( xShouldDelay )
+ {
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the
+ overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the
+ current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ }
+ }
+ xAlreadyYielded = xTaskResumeAll();
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ taskYIELD();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskDelay == 1 )
+
+ void vTaskDelay( portTickType xTicksToDelay )
+ {
+ portTickType xTimeToWake;
+ signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* A delay time of zero just forces a reschedule. */
+ if( xTicksToDelay > ( portTickType ) 0 )
+ {
+ vTaskSuspendAll();
+ {
+ /* A task that is removed from the event list while the
+ scheduler is suspended will not get placed in the ready
+ list or removed from the blocked list until the scheduler
+ is resumed.
+
+ This task cannot be in an event list as it is the currently
+ executing task. */
+
+ /* Calculate the time to wake - this may overflow but this is
+ not a problem. */
+ xTimeToWake = xTickCount + xTicksToDelay;
+
+ /* We must remove ourselves from the ready list before adding
+ ourselves to the blocked list as the same list item is used for
+ both lists. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+ /* The list item will be inserted in wake time order. */
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the
+ overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the
+ current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ }
+ xAlreadyYielded = xTaskResumeAll();
+ }
+
+ /* Force a reschedule if xTaskResumeAll has not already done so, we may
+ have put ourselves to sleep. */
+ if( !xAlreadyYielded )
+ {
+ taskYIELD();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_uxTaskPriorityGet == 1 )
+
+ unsigned portBASE_TYPE uxTaskPriorityGet( xTaskHandle pxTask )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxReturn;
+
+ taskENTER_CRITICAL();
+ {
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+ uxReturn = pxTCB->uxPriority;
+ }
+ taskEXIT_CRITICAL();
+
+ return uxReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskPrioritySet == 1 )
+
+ void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority )
+ {
+ tskTCB *pxTCB;
+ unsigned portBASE_TYPE uxCurrentPriority, xYieldRequired = pdFALSE;
+
+ /* Ensure the new priority is valid. */
+ if( uxNewPriority >= configMAX_PRIORITIES )
+ {
+ uxNewPriority = configMAX_PRIORITIES - 1;
+ }
+
+ taskENTER_CRITICAL();
+ {
+ /* If null is passed in here then we are changing the
+ priority of the calling function. */
+ pxTCB = prvGetTCBFromHandle( pxTask );
+ uxCurrentPriority = pxTCB->uxPriority;
+
+ if( uxCurrentPriority != uxNewPriority )
+ {
+ /* The priority change may have readied a task of higher
+ priority than the calling task. */
+ if( uxNewPriority > pxCurrentTCB->uxPriority )
+ {
+ if( pxTask != NULL )
+ {
+ /* The priority of another task is being raised. If we
+ were raising the priority of the currently running task
+ there would be no need to switch as it must have already
+ been the highest priority task. */
+ xYieldRequired = pdTRUE;
+ }
+ }
+ else if( pxTask == NULL )
+ {
+ /* Setting our own priority down means there may now be another
+ task of higher priority that is ready to execute. */
+ xYieldRequired = pdTRUE;
+ }
+
+ pxTCB->uxPriority = uxNewPriority;
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxNewPriority );
+
+ /* If the task is in the blocked or suspended list we need do
+ nothing more than change it's priority variable. However, if
+ the task is in a ready list it needs to be removed and placed
+ in the queue appropriate to its new priority. */
+ if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxCurrentPriority ] ), &( pxTCB->xGenericListItem ) ) )
+ {
+ /* The task is currently in its ready list - remove before adding
+ it to it's new ready list. As we are in a critical section we
+ can do this even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+
+ if( xYieldRequired == pdTRUE )
+ {
+ taskYIELD();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskSuspend( xTaskHandle pxTaskToSuspend )
+ {
+ tskTCB *pxTCB;
+
+ taskENTER_CRITICAL();
+ {
+ /* Ensure a yield is performed if the current task is being
+ suspended. */
+ if( pxTaskToSuspend == pxCurrentTCB )
+ {
+ pxTaskToSuspend = NULL;
+ }
+
+ /* If null is passed in here then we are suspending ourselves. */
+ pxTCB = prvGetTCBFromHandle( pxTaskToSuspend );
+
+ /* Remove task from the ready/delayed list and place in the suspended list. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+
+ /* Is the task waiting on an event also? */
+ if( pxTCB->xEventListItem.pvContainer )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ }
+
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, &( pxTCB->xGenericListItem ) );
+ }
+ taskEXIT_CRITICAL();
+
+ /* We may have just suspended the current task. */
+ if( ( void * ) pxTaskToSuspend == NULL )
+ {
+ taskYIELD();
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ static portBASE_TYPE prvIsTaskSuspended( const tskTCB * const pxTCB )
+ {
+ portBASE_TYPE xReturn = pdFALSE;
+
+ /* Is the task we are attempting to resume actually in the
+ suspended list? */
+ if( listIS_CONTAINED_WITHIN( &xSuspendedTaskList, &( pxTCB->xGenericListItem ) ) != pdFALSE )
+ {
+ /* Has the task already been resumed from within an ISR? */
+ if( listIS_CONTAINED_WITHIN( &xPendingReadyList, &( pxTCB->xEventListItem ) ) != pdTRUE )
+ {
+ /* Is it in the suspended list because it is in the
+ Suspended state? It is possible to be in the suspended
+ list because it is blocked on a task with no timeout
+ specified. */
+ if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) == pdTRUE )
+ {
+ xReturn = pdTRUE;
+ }
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_vTaskSuspend == 1 )
+
+ void vTaskResume( xTaskHandle pxTaskToResume )
+ {
+ tskTCB *pxTCB;
+
+ /* Remove the task from whichever list it is currently in, and place
+ it in the ready list. */
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ /* The parameter cannot be NULL as it is impossible to resume the
+ currently executing task. */
+ if( pxTCB != NULL )
+ {
+ taskENTER_CRITICAL();
+ {
+ if( prvIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ /* As we are in a critical section we can access the ready
+ lists even if the scheduler is suspended. */
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* We may have just resumed a higher priority task. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* This yield may not cause the task just resumed to run, but
+ will leave the lists in the correct state for the next yield. */
+ taskYIELD();
+ }
+ }
+ }
+ taskEXIT_CRITICAL();
+ }
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ portBASE_TYPE xTaskResumeFromISR( xTaskHandle pxTaskToResume )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+ tskTCB *pxTCB;
+
+ pxTCB = ( tskTCB * ) pxTaskToResume;
+
+ if( prvIsTaskSuspended( pxTCB ) == pdTRUE )
+ {
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xYieldRequired = ( pxTCB->uxPriority >= pxCurrentTCB->uxPriority );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed, at which point a
+ yield will be preformed if necessary. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
+ }
+ }
+
+ return xYieldRequired;
+ }
+
+#endif
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC SCHEDULER CONTROL documented in task.h
+ *----------------------------------------------------------*/
+
+
+void vTaskStartScheduler( void )
+{
+portBASE_TYPE xReturn;
+
+ /* Add the idle task at the lowest priority. */
+ xReturn = xTaskCreate( prvIdleTask, ( signed portCHAR * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
+
+ if( xReturn == pdPASS )
+ {
+ /* Interrupts are turned off here, to ensure a tick does not occur
+ before or during the call to xPortStartScheduler(). The stacks of
+ the created tasks contain a status word with interrupts switched on
+ so interrupts will automatically get re-enabled when the first task
+ starts to run.
+
+ STEPPING THROUGH HERE USING A DEBUGGER CAN CAUSE BIG PROBLEMS IF THE
+ DEBUGGER ALLOWS INTERRUPTS TO BE PROCESSED. */
+ portDISABLE_INTERRUPTS();
+
+ xSchedulerRunning = pdTRUE;
+ xTickCount = ( portTickType ) 0;
+
+ /* Setting up the timer tick is hardware specific and thus in the
+ portable interface. */
+ if( xPortStartScheduler() )
+ {
+ /* Should not reach here as if the scheduler is running the
+ function will not return. */
+ }
+ else
+ {
+ /* Should only reach here if a task calls xTaskEndScheduler(). */
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTaskEndScheduler( void )
+{
+ /* Stop the scheduler interrupts and call the portable scheduler end
+ routine so the original ISRs can be restored if necessary. The port
+ layer must ensure interrupts enable bit is left in the correct state. */
+ portDISABLE_INTERRUPTS();
+ xSchedulerRunning = pdFALSE;
+ vPortEndScheduler();
+}
+/*----------------------------------------------------------*/
+
+void vTaskSuspendAll( void )
+{
+ portENTER_CRITICAL();
+ ++uxSchedulerSuspended;
+ portEXIT_CRITICAL();
+}
+/*----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskResumeAll( void )
+{
+register tskTCB *pxTCB;
+signed portBASE_TYPE xAlreadyYielded = pdFALSE;
+
+ /* It is possible that an ISR caused a task to be removed from an event
+ list while the scheduler was suspended. If this was the case then the
+ removed task will have been added to the xPendingReadyList. Once the
+ scheduler has been resumed it is safe to move all the pending ready
+ tasks from this list into their appropriate ready list. */
+ portENTER_CRITICAL();
+ {
+ --uxSchedulerSuspended;
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ if( uxCurrentNumberOfTasks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ portBASE_TYPE xYieldRequired = pdFALSE;
+
+ /* Move any readied tasks from the pending list into the
+ appropriate ready list. */
+ while( ( pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xPendingReadyList ) ) ) != NULL )
+ {
+ vListRemove( &( pxTCB->xEventListItem ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxTCB );
+
+ /* If we have moved a task that has a priority higher than
+ the current task then we should yield. */
+ if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ xYieldRequired = pdTRUE;
+ }
+ }
+
+ /* If any ticks occurred while the scheduler was suspended then
+ they should be processed now. This ensures the tick count does not
+ slip, and that any delayed tasks are resumed at the correct time. */
+ if( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ while( uxMissedTicks > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskIncrementTick();
+ --uxMissedTicks;
+ }
+
+ /* As we have processed some ticks it is appropriate to yield
+ to ensure the highest priority task that is ready to run is
+ the task actually running. */
+ xYieldRequired = pdTRUE;
+ }
+
+ if( ( xYieldRequired == pdTRUE ) || ( xMissedYield == pdTRUE ) )
+ {
+ xAlreadyYielded = pdTRUE;
+ xMissedYield = pdFALSE;
+ taskYIELD();
+ }
+ }
+ }
+ }
+ portEXIT_CRITICAL();
+
+ return xAlreadyYielded;
+}
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * PUBLIC TASK UTILITIES documented in task.h
+ *----------------------------------------------------------*/
+
+
+
+portTickType xTaskGetTickCount( void )
+{
+portTickType xTicks;
+
+ /* Critical section required if running on a 16 bit processor. */
+ taskENTER_CRITICAL();
+ {
+ xTicks = xTickCount;
+ }
+ taskEXIT_CRITICAL();
+
+ return xTicks;
+}
+/*-----------------------------------------------------------*/
+
+unsigned portBASE_TYPE uxTaskGetNumberOfTasks( void )
+{
+unsigned portBASE_TYPE uxNumberOfTasks;
+
+ taskENTER_CRITICAL();
+ uxNumberOfTasks = uxCurrentNumberOfTasks;
+ taskEXIT_CRITICAL();
+
+ return uxNumberOfTasks;
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_vTaskDelete == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ void vTaskList( signed portCHAR *pcWriteBuffer )
+ {
+ unsigned portBASE_TYPE uxQueue;
+
+ /* This is a VERY costly function that should be used for debug only.
+ It leaves interrupts disabled for a LONG time. */
+
+ vTaskSuspendAll();
+ {
+ /* Run through all the lists that could potentially contain a TCB and
+ report the task name, state and stack high water mark. */
+
+ pcWriteBuffer[ 0 ] = ( signed portCHAR ) 0x00;
+ strcat( ( portCHAR * ) pcWriteBuffer, ( const portCHAR * ) "\r\n" );
+
+ uxQueue = uxTopUsedPriority + 1;
+
+ do
+ {
+ uxQueue--;
+
+ if( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxQueue ] ) ) )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &( pxReadyTasksLists[ uxQueue ] ), tskREADY_CHAR );
+ }
+ }while( uxQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
+
+ if( !listLIST_IS_EMPTY( pxDelayedTaskList ) )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ if( !listLIST_IS_EMPTY( pxOverflowDelayedTaskList ) )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) pxOverflowDelayedTaskList, tskBLOCKED_CHAR );
+ }
+
+ if( !listLIST_IS_EMPTY( &xTasksWaitingTermination ) )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xTasksWaitingTermination, tskDELETED_CHAR );
+ }
+
+ if( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
+ {
+ prvListTaskWithinSingleList( pcWriteBuffer, ( xList * ) &xSuspendedTaskList, tskSUSPENDED_CHAR );
+ }
+ }
+ xTaskResumeAll();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ void vTaskStartTrace( signed portCHAR * pcBuffer, unsigned portLONG ulBufferSize )
+ {
+ portENTER_CRITICAL();
+ {
+ pcTraceBuffer = ( volatile signed portCHAR * volatile )pcBuffer;
+ pcTraceBufferStart = pcBuffer;
+ pcTraceBufferEnd = pcBuffer + ( ulBufferSize - tskSIZE_OF_EACH_TRACE_LINE );
+ xTracing = pdTRUE;
+ }
+ portEXIT_CRITICAL();
+ }
+
+#endif
+/*----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ unsigned portLONG ulTaskEndTrace( void )
+ {
+ unsigned portLONG ulBufferLength;
+
+ portENTER_CRITICAL();
+ xTracing = pdFALSE;
+ portEXIT_CRITICAL();
+
+ ulBufferLength = ( unsigned portLONG ) ( pcTraceBuffer - pcTraceBufferStart );
+
+ return ulBufferLength;
+ }
+
+#endif
+
+
+
+/*-----------------------------------------------------------
+ * SCHEDULER INTERNALS AVAILABLE FOR PORTING PURPOSES
+ * documented in task.h
+ *----------------------------------------------------------*/
+
+
+inline void vTaskIncrementTick( void )
+{
+ /* Called by the portable layer each time a tick interrupt occurs.
+ Increments the tick then checks to see if the new tick value will cause any
+ tasks to be unblocked. */
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ ++xTickCount;
+ if( xTickCount == ( portTickType ) 0 )
+ {
+ xList *pxTemp;
+
+ /* Tick count has overflowed so we need to swap the delay lists.
+ If there are any items in pxDelayedTaskList here then there is
+ an error! */
+ pxTemp = pxDelayedTaskList;
+ pxDelayedTaskList = pxOverflowDelayedTaskList;
+ pxOverflowDelayedTaskList = pxTemp;
+ xNumOfOverflows++;
+ }
+
+ /* See if this tick has made a timeout expire. */
+ prvCheckDelayedTasks();
+ }
+ else
+ {
+ ++uxMissedTicks;
+
+ /* The tick hook gets called at regular intervals, even if the
+ scheduler is locked. */
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ extern void vApplicationTickHook( void );
+
+ vApplicationTickHook();
+ }
+ #endif
+ }
+
+ #if ( configUSE_TICK_HOOK == 1 )
+ {
+ extern void vApplicationTickHook( void );
+
+ /* Guard against the tick hook being called when the missed tick
+ count is being unwound (when the scheduler is being unlocked. */
+ if( uxMissedTicks == 0 )
+ {
+ vApplicationTickHook();
+ }
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+#if ( ( INCLUDE_vTaskCleanUpResources == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
+
+ void vTaskCleanUpResources( void )
+ {
+ unsigned portSHORT usQueue;
+ volatile tskTCB *pxTCB;
+
+ usQueue = ( unsigned portSHORT ) uxTopUsedPriority + ( unsigned portSHORT ) 1;
+
+ /* Remove any TCB's from the ready queues. */
+ do
+ {
+ usQueue--;
+
+ while( !listLIST_IS_EMPTY( &( pxReadyTasksLists[ usQueue ] ) ) )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &( pxReadyTasksLists[ usQueue ] ) );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }while( usQueue > ( unsigned portSHORT ) tskIDLE_PRIORITY );
+
+ /* Remove any TCB's from the delayed queue. */
+ while( !listLIST_IS_EMPTY( &xDelayedTaskList1 ) )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList1 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ /* Remove any TCB's from the overflow delayed queue. */
+ while( !listLIST_IS_EMPTY( &xDelayedTaskList2 ) )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xDelayedTaskList2 );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+
+ while( !listLIST_IS_EMPTY( &xSuspendedTaskList ) )
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxTCB, &xSuspendedTaskList );
+ vListRemove( ( xListItem * ) &( pxTCB->xGenericListItem ) );
+
+ prvDeleteTCB( ( tskTCB * ) pxTCB );
+ }
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+void vTaskSwitchContext( void )
+{
+ if( uxSchedulerSuspended != ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ /* The scheduler is currently suspended - do not allow a context
+ switch. */
+ xMissedYield = pdTRUE;
+ return;
+ }
+
+ /* Find the highest priority queue that contains ready tasks. */
+ while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopReadyPriority ] ) ) )
+ {
+ --uxTopReadyPriority;
+ }
+
+ /* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the tasks of the
+ same priority get an equal share of the processor time. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopReadyPriority ] ) );
+ vWriteTraceToBuffer();
+}
+/*-----------------------------------------------------------*/
+
+void vTaskPlaceOnEventList( xList *pxEventList, portTickType xTicksToWait )
+{
+portTickType xTimeToWake;
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. */
+
+ /* Place the event list item of the TCB in the appropriate event list.
+ This is placed in the list in priority order so the highest priority task
+ is the first to be woken by the event. */
+ vListInsert( ( xList * ) pxEventList, ( xListItem * ) &( pxCurrentTCB->xEventListItem ) );
+
+ /* We must remove ourselves from the ready list before adding ourselves
+ to the blocked list as the same list item is used for both lists. We have
+ exclusive access to the ready lists as the scheduler is locked. */
+ vListRemove( ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ if( xTicksToWait == portMAX_DELAY )
+ {
+ /* Add ourselves to the suspended task list instead of a delayed task
+ list to ensure we are not woken by a timing event. We will block
+ indefinitely. */
+ vListInsertEnd( ( xList * ) &xSuspendedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ }
+ }
+ #else
+ {
+ /* Calculate the time at which the task should be woken if the event does
+ not occur. This may overflow but this doesn't matter. */
+ xTimeToWake = xTickCount + xTicksToWait;
+
+ listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xGenericListItem ), xTimeToWake );
+
+ if( xTimeToWake < xTickCount )
+ {
+ /* Wake time has overflowed. Place this item in the overflow list. */
+ vListInsert( ( xList * ) pxOverflowDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ else
+ {
+ /* The wake time has not overflowed, so we can use the current block list. */
+ vListInsert( ( xList * ) pxDelayedTaskList, ( xListItem * ) &( pxCurrentTCB->xGenericListItem ) );
+ }
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+signed portBASE_TYPE xTaskRemoveFromEventList( const xList *pxEventList )
+{
+tskTCB *pxUnblockedTCB;
+portBASE_TYPE xReturn;
+
+ /* THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED OR THE
+ SCHEDULER SUSPENDED. It can also be called from within an ISR. */
+
+ /* The event list is sorted in priority order, so we can remove the
+ first in the list, remove the TCB from the delayed list, and add
+ it to the ready list.
+
+ If an event is for a queue that is locked then this function will never
+ get called - the lock count on the queue will get modified instead. This
+ means we can always expect exclusive access to the event list here. */
+ pxUnblockedTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
+ vListRemove( &( pxUnblockedTCB->xEventListItem ) );
+
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ vListRemove( &( pxUnblockedTCB->xGenericListItem ) );
+ prvAddTaskToReadyQueue( pxUnblockedTCB );
+ }
+ else
+ {
+ /* We cannot access the delayed or ready lists, so will hold this
+ task pending until the scheduler is resumed. */
+ vListInsertEnd( ( xList * ) &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
+ }
+
+ if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
+ {
+ /* Return true if the task removed from the event list has
+ a higher priority than the calling task. This allows
+ the calling task to know if it should force a context
+ switch now. */
+ xReturn = pdTRUE;
+ }
+ else
+ {
+ xReturn = pdFALSE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskSetTimeOutState( xTimeOutType *pxTimeOut )
+{
+ pxTimeOut->xOverflowCount = xNumOfOverflows;
+ pxTimeOut->xTimeOnEntering = xTickCount;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xTaskCheckForTimeOut( xTimeOutType *pxTimeOut, portTickType * const pxTicksToWait )
+{
+portBASE_TYPE xReturn;
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ /* If INCLUDE_vTaskSuspend is set to 1 and the block time specified is
+ the maximum block time then the task should block indefinitely, and
+ therefore never time out. */
+ if( *pxTicksToWait == portMAX_DELAY )
+ {
+ xReturn = pdFALSE;
+ }
+ else /* We are not blocking indefinitely, perform the checks below. */
+ #endif
+
+ if( ( xNumOfOverflows != pxTimeOut->xOverflowCount ) && ( xTickCount >= pxTimeOut->xTimeOnEntering ) )
+ {
+ /* The tick count is greater than the time at which vTaskSetTimeout()
+ was called, but has also overflowed since vTaskSetTimeOut() was called.
+ It must have wrapped all the way around and gone past us again. This
+ passed since vTaskSetTimeout() was called. */
+ xReturn = pdTRUE;
+ }
+ else if( ( xTickCount - pxTimeOut->xTimeOnEntering ) < *pxTicksToWait )
+ {
+ /* Not a genuine timeout. Adjust parameters for time remaining. */
+ *pxTicksToWait -= ( xTickCount - pxTimeOut->xTimeOnEntering );
+ vTaskSetTimeOutState( pxTimeOut );
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vTaskMissedYield( void )
+{
+ xMissedYield = pdTRUE;
+}
+
+/*
+ * -----------------------------------------------------------
+ * The Idle task.
+ * ----------------------------------------------------------
+ *
+ * The portTASK_FUNCTION() macro is used to allow port/compiler specific
+ * language extensions. The equivalent prototype for this function is:
+ *
+ * void prvIdleTask( void *pvParameters );
+ *
+ */
+static portTASK_FUNCTION( prvIdleTask, pvParameters )
+{
+ /* Stop warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* See if any tasks have been deleted. */
+ prvCheckTasksWaitingTermination();
+
+ #if ( configUSE_PREEMPTION == 0 )
+ {
+ /* If we are not using preemption we keep forcing a task switch to
+ see if any other task has become available. If we are using
+ preemption we don't need to do this as any task becoming available
+ will automatically get the processor anyway. */
+ taskYIELD();
+ }
+ #endif
+
+ #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
+ {
+ /* When using preemption tasks of equal priority will be
+ timesliced. If a task that is sharing the idle priority is ready
+ to run then the idle task should yield before the end of the
+ timeslice.
+
+ A critical region is not required here as we are just reading from
+ the list, and an occasional incorrect value will not matter. If
+ the ready list at the idle priority contains more than one task
+ then a task other than the idle task is ready to execute. */
+ if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( unsigned portBASE_TYPE ) 1 )
+ {
+ taskYIELD();
+ }
+ }
+ #endif
+
+ #if ( configUSE_IDLE_HOOK == 1 )
+ {
+ extern void vApplicationIdleHook( void );
+
+ /* Call the user defined function from within the idle task. This
+ allows the application designer to add background functionality
+ without the overhead of a separate task.
+ NOTE: vApplicationIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES,
+ CALL A FUNCTION THAT MIGHT BLOCK. */
+ vApplicationIdleHook();
+ }
+ #endif
+ }
+} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
+
+
+
+
+
+
+
+/*-----------------------------------------------------------
+ * File private functions documented at the top of the file.
+ *----------------------------------------------------------*/
+
+
+
+static void prvInitialiseTCBVariables( tskTCB *pxTCB, unsigned portSHORT usStackDepth, const signed portCHAR * const pcName, unsigned portBASE_TYPE uxPriority )
+{
+ pxTCB->usStackDepth = usStackDepth;
+
+ /* Store the function name in the TCB. */
+ strncpy( ( char * ) pxTCB->pcTaskName, ( const char * ) pcName, ( unsigned portSHORT ) configMAX_TASK_NAME_LEN );
+ pxTCB->pcTaskName[ ( unsigned portSHORT ) configMAX_TASK_NAME_LEN - ( unsigned portSHORT ) 1 ] = '\0';
+
+ /* This is used as an array index so must ensure it's not too large. */
+ if( uxPriority >= configMAX_PRIORITIES )
+ {
+ uxPriority = configMAX_PRIORITIES - 1;
+ }
+
+ pxTCB->uxPriority = uxPriority;
+
+ vListInitialiseItem( &( pxTCB->xGenericListItem ) );
+ vListInitialiseItem( &( pxTCB->xEventListItem ) );
+
+ /* Set the pxTCB as a link back from the xListItem. This is so we can get
+ back to the containing TCB from a generic item in a list. */
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xGenericListItem ), pxTCB );
+
+ /* Event lists are always in priority order. */
+ listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
+ listSET_LIST_ITEM_OWNER( &( pxTCB->xEventListItem ), pxTCB );
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseTaskLists( void )
+{
+unsigned portBASE_TYPE uxPriority;
+
+ for( uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++ )
+ {
+ vListInitialise( ( xList * ) &( pxReadyTasksLists[ uxPriority ] ) );
+ }
+
+ vListInitialise( ( xList * ) &xDelayedTaskList1 );
+ vListInitialise( ( xList * ) &xDelayedTaskList2 );
+ vListInitialise( ( xList * ) &xPendingReadyList );
+
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ vListInitialise( ( xList * ) &xTasksWaitingTermination );
+ }
+ #endif
+
+ #if ( INCLUDE_vTaskSuspend == 1 )
+ {
+ vListInitialise( ( xList * ) &xSuspendedTaskList );
+ }
+ #endif
+
+ /* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
+ using list2. */
+ pxDelayedTaskList = &xDelayedTaskList1;
+ pxOverflowDelayedTaskList = &xDelayedTaskList2;
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckTasksWaitingTermination( void )
+{
+ #if ( INCLUDE_vTaskDelete == 1 )
+ {
+ portBASE_TYPE xListIsEmpty;
+
+ /* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
+ too often in the idle task. */
+ if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
+ {
+ vTaskSuspendAll();
+ xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
+ xTaskResumeAll();
+
+ if( !xListIsEmpty )
+ {
+ tskTCB *pxTCB;
+
+ portENTER_CRITICAL();
+ {
+ pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
+ vListRemove( &( pxTCB->xGenericListItem ) );
+ --uxCurrentNumberOfTasks;
+ --uxTasksDeleted;
+ }
+ portEXIT_CRITICAL();
+
+ prvDeleteTCB( pxTCB );
+ }
+ }
+ }
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+static tskTCB *prvAllocateTCBAndStack( unsigned portSHORT usStackDepth )
+{
+tskTCB *pxNewTCB;
+
+ /* Allocate space for the TCB. Where the memory comes from depends on
+ the implementation of the port malloc function. */
+ pxNewTCB = ( tskTCB * ) pvPortMalloc( sizeof( tskTCB ) );
+
+ if( pxNewTCB != NULL )
+ {
+ /* Allocate space for the stack used by the task being created.
+ The base of the stack memory stored in the TCB so the task can
+ be deleted later if required. */
+ pxNewTCB->pxStack = ( portSTACK_TYPE * ) pvPortMalloc( ( ( size_t )usStackDepth ) * sizeof( portSTACK_TYPE ) );
+
+ if( pxNewTCB->pxStack == NULL )
+ {
+ /* Could not allocate the stack. Delete the allocated TCB. */
+ vPortFree( pxNewTCB );
+ pxNewTCB = NULL;
+ }
+ else
+ {
+ /* Just to help debugging. */
+ memset( pxNewTCB->pxStack, tskSTACK_FILL_BYTE, usStackDepth * sizeof( portSTACK_TYPE ) );
+ }
+ }
+
+ return pxNewTCB;
+}
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+
+ static void prvListTaskWithinSingleList( signed portCHAR *pcWriteBuffer, xList *pxList, signed portCHAR cStatus )
+ {
+ volatile tskTCB *pxNextTCB, *pxFirstTCB;
+ static portCHAR pcStatusString[ 50 ];
+ unsigned portSHORT usStackRemaining;
+
+ /* Write the details of all the TCB's in pxList into the buffer. */
+ listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
+ do
+ {
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+ usStackRemaining = usTaskCheckFreeStackSpace( ( unsigned portCHAR * ) pxNextTCB->pxStack );
+ sprintf( pcStatusString, ( portCHAR * ) "%s\t\t%c\t%u\t%u\t%u\r\n", pxNextTCB->pcTaskName, cStatus, ( unsigned int ) pxNextTCB->uxPriority, usStackRemaining, ( unsigned int ) pxNextTCB->uxTCBNumber );
+ strcat( ( portCHAR * ) pcWriteBuffer, ( portCHAR * ) pcStatusString );
+
+ } while( pxNextTCB != pxFirstTCB );
+ }
+
+#endif
+/*-----------------------------------------------------------*/
+
+#if ( configUSE_TRACE_FACILITY == 1 )
+ unsigned portSHORT usTaskCheckFreeStackSpace( const unsigned portCHAR *pucStackByte )
+ {
+ register unsigned portSHORT usCount = 0;
+
+ while( *pucStackByte == tskSTACK_FILL_BYTE )
+ {
+ pucStackByte -= portSTACK_GROWTH;
+ usCount++;
+ }
+
+ usCount /= sizeof( portSTACK_TYPE );
+
+ return usCount;
+ }
+#endif
+/*-----------------------------------------------------------*/
+
+
+
+#if ( ( INCLUDE_vTaskDelete == 1 ) || ( INCLUDE_vTaskCleanUpResources == 1 ) )
+
+ static void prvDeleteTCB( tskTCB *pxTCB )
+ {
+ /* Free up the memory allocated by the scheduler for the task. It is up to
+ the task to free any memory allocated at the application level. */
+ vPortFree( pxTCB->pxStack );
+ vPortFree( pxTCB );
+ }
+
+#endif
+
+
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 )
+
+ xTaskHandle xTaskGetCurrentTaskHandle( void )
+ {
+ xTaskHandle xReturn;
+
+ portENTER_CRITICAL();
+ {
+ xReturn = ( xTaskHandle ) pxCurrentTCB;
+ }
+ portEXIT_CRITICAL();
+
+ return xReturn;
+ }
+
+#endif
+
+/*-----------------------------------------------------------*/
+
+#if ( INCLUDE_xTaskGetSchedulerState == 1 )
+
+ portBASE_TYPE xTaskGetSchedulerState( void )
+ {
+ portBASE_TYPE xReturn;
+
+ if( xSchedulerRunning == pdFALSE )
+ {
+ xReturn = taskSCHEDULER_NOT_STARTED;
+ }
+ else
+ {
+ if( uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE )
+ {
+ xReturn = taskSCHEDULER_RUNNING;
+ }
+ else
+ {
+ xReturn = taskSCHEDULER_SUSPENDED;
+ }
+ }
+
+ return xReturn;
+ }
+
+#endif
+
+
--- /dev/null
+/*
+ FreeRTOS.org V4.3.1 - Copyright (C) 2003-2007 Richard Barry.
+
+ This file is part of the FreeRTOS.org distribution.
+
+ FreeRTOS.org is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ FreeRTOS.org 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.org; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ A special exception to the GPL can be applied should you wish to distribute
+ a combined work that includes FreeRTOS.org, without being obliged to provide
+ the source code for any proprietary components. See the licensing section
+ of http://www.FreeRTOS.org for full details of how and when the exception
+ can be applied.
+
+ ***************************************************************************
+ See http://www.FreeRTOS.org for documentation, latest information, license
+ and contact details. Please ensure to read the configuration and relevant
+ port sections of the online documentation.
+
+ Also see http://www.SafeRTOS.com for an IEC 61508 compliant version along
+ with commercial development and support options.
+ ***************************************************************************
+*/
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+#include <lpc210x.h>
+
+//
+// Application specific definitions.
+//
+#define configUSE_PREEMPTION 1
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configCPU_CLOCK_HZ ((unsigned portLONG) 48000000) // =12.0000MHz xtal multiplied by 4 using the PLL.
+#define configTICK_RATE_HZ ((portTickType) 100)
+#define configMAX_PRIORITIES ((unsigned portBASE_TYPE) 4)
+#define configMINIMAL_STACK_SIZE ((unsigned portSHORT) 128)
+#define configTOTAL_HEAP_SIZE ((size_t) (18 * 1024))
+#define configMAX_TASK_NAME_LEN (8)
+#define configUSE_TRACE_FACILITY 1
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+
+//
+// Co-routine definitions
+//
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES (2)
+
+//
+// Set the following definitions to 1 to include the API function, or zero
+// to exclude the API function.
+//
+#define INCLUDE_vTaskPrioritySet 1
+#define INCLUDE_uxTaskPriorityGet 1
+#define INCLUDE_vTaskDelete 1
+#define INCLUDE_vTaskCleanUpResources 0
+#define INCLUDE_vTaskSuspend 1
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_vPortUsedMem 1
+
+#endif /* FREERTOS_CONFIG_H */
--- /dev/null
+.SILENT:
+
+#
+# -D CFG_CONSOLE_USB for console on USB
+# -D CFG_CONSOLE_UART0 for console on UART0
+# -D CFG_CONSOLE_UART1 for console on UART1 instead of USB (disables GPS task, baud rate set to 115200)
+# -D CFG_USB_MSC to use SD/MMC as a mass storage class device over USB
+#
+export LPC2148DEMO_OPTS=-D CFG_CONSOLE_USB
+
+#
+# These shouldn't need to be changed
+#
+export CC=arm-elf-gcc
+export AR=arm-elf-ar
+export OBJCOPY=arm-elf-objcopy
+export OBJDUMP=arm-elf-objdump
+export CRT0=boot.s
+export WARNINGS=-Wall -Wextra -Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align -Wsign-compare -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wunused
+export CFLAGS=$(WARNINGS) -D RUN_MODE=RUN_FROM_ROM -D GCC_ARM7 $(INCLUDES) $(BASEINCLUDE) -mcpu=arm7tdmi -T$(LDSCRIPT) -g -O3 -fomit-frame-pointer $(LPC2148DEMO_OPTS)
+export LDSCRIPT=lpc2148-rom.ld
+export LINKER_FLAGS=$(COMMON)/common.a -Xlinker -olpc2148.elf -Xlinker -M -Xlinker -Map=lpc2148.map
+export ROOT=$(shell pwd)
+export BASEINCLUDE=-I$(ROOT) -I$(ROOT)/FreeRTOS/include
+export COMMON=$(ROOT)/common
+
+#
+# Project sub-directories
+#
+SUBDIRS=FreeRTOS adc cpu dac eints fatfs fiq gps i2c iap leds monitor newlib rtc sensors swi uart usb usbmass usbser
+
+SRC_FILES = main.c
+
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all :
+ @for i in $(SUBDIRS); do \
+ (cd $$i; $(MAKE) $(MFLAGS) $(MYMAKEFLAGS) all); done
+ make lpc2148.hex
+
+lpc2148.hex : .depend Makefile lpc2148.elf
+ $(OBJCOPY) lpc2148.elf -O ihex lpc2148.hex
+ @echo "Length is " `grep __"end_of_text__ = ." *.map | cut -b 17-35` "bytes"
+
+lpc2148.elf : .depend Makefile $(ARM_OBJ) $(COMMON)/common.a $(CRT0) $(LDSCRIPT)
+ $(CC) $(CFLAGS) $(ARM_OBJ) -nostartfiles $(CRT0) $(LINKER_FLAGS)
+ $(OBJDUMP) -d -S lpc2148.elf >lpc2148.lst
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+#
+# Utility targets
+#
+.PHONY: tags
+tags :
+ @rm -f ctags
+ find . -name \*.c -exec ctags -a {} \;
+ find . -name \*.h -exec ctags -a {} \;
+
+.PHONEY: clean
+clean :
+ find . -name \*.o -exec rm -f {} \;
+ find . -name .depend -exec rm -f {} \;
+ rm -f *.map *.lst *.elf *.hex .depend $(COMMON)/common.a
+
+#
+#
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+ J.C. Wren
+ 2007/07/22
+ jcwren@jcwren.com
+
+ The most recent version of this package may be found at http://jcwren.com/arm
+
+ I'm changing the format of how updates are documented. Rather than including
+ it in the body of the text, they will be appended to the front, with a date.
+
+ 2007/07/22, version 1.20:
+
+ Added interrupt driven I2C master transmit and receive code. I'm pretty
+ confident that all the cases are handled correctly, but I don't have any
+ way to introduce certain errors for testing. There are now two files in
+ the ./i2c directory, "i2cInt.c" and "i2cPolled.c". Edit the ./i2c/Makefile
+ to select interrupt drive or polled I2C handling. There is some support
+ for debugging I2C the interrupt drive routines. As interrupts occur, the
+ various state changes are recorded, and the 'i2c dump' command will display
+ them. This is disabled by default, but can be enabled by editing the
+ ./i2c/i2cInt.c file and defining I2C_DEBUG.
+
+ Added raw I2C support. The 'i2c' commands allow directly reading and
+ writing an I2C device (as opposed to using the LM75 wrapper for LM75's, or
+ the EEPROM wrapper for EEPROMs). See 'i2c help' for a list of commands.
+ Note that when reading from an I2C device via the raw commands, a maximum
+ of 16 bytes may be read or written. If you need more, change the buffer
+ sizes in the appropriate commands in ./monitor/monitor.c, and also the
+ maximum number of arguments in the command dispatch table (commandListI2C).
+
+ Added EEPROM support. The 'ee' subset of commands allow reading and
+ writing of a 24Cxxx series type EEPROM. The code is currently targeted at
+ an Atmel 24C1024 128x8 part (I had some laying around). It should be
+ pretty easy to rework them for any smaller part. See 'ee help' for a list
+ of supported commands.
+
+ Fixed the LM75 support to allow writing the config, TOS and THYST
+ registers. The previous versions allowed reading the registers, but I
+ forgot to write code to allow changing them. Oops.
+
+ Moved 'date' and 'setdate' commands into the 'rtc' sub-menu as 'get' and
+ 'set', respectively. Added 'alarm' command that allows setting an alarm
+ date/time, or disabling it. When an alarm fires, 'ALARM -- YYYY/MM/DD
+ HH:MM:SS' is printed to the console. Also added 'periodic', which when
+ enabled, prints 'PERIODIC -- YYYY/MM/DD HH:MM:SS' to the console at the top
+ of every minute. The RTC also demonstrates using the default vector
+ address functionality of the non-vectored IRQs in the VIC (alternatively,
+ by un-defining RTC_NONVECTOREDIRQ in the ./rtc/rtc.h file, a regular
+ vectored IRQ can be used).
+
+ Note on the RTC alarm and periodic output: It's really gross. Console
+ input is handled by a libc read() call. This is a blocking call,
+ implemented by doing a FreeRTOS xQueueReceive in the console device code
+ (UART 0, UART 1, or USB). So the only way to get the read() to return so
+ the CCI can output the message is to reserve the special characters 0xfe
+ and 0xff (something a user can usually never type). When the CCI getline
+ routine sees either of those characters, it immediately returns. These
+ characters are then checked for by the CCI command parser, and either an
+ alarm or periodic message output. If the user is in the process of typing
+ in a command, the input will be lost. Without totally rewriting the CCI
+ into a queue based message passing architecture, I couldn't find a more
+ elegant way to handle this. So basically, the RTC interrupt sends a 0xfe
+ or 0xff into the input buffer for the console device, which then returns
+ the character, which is then processed by the CCI code.
+
+ Changed the 'task' command to a 'mem' sub-command. Added the 'map'
+ command, which shows how memory is allocated. Overview: The .txt section
+ contains the program code, the initialization values for static data in RAM
+ (statements like 'static int i = 172;'), and the glue section (I believe
+ this is where ARM/THUMB inter-networking code is placed). The .data section
+ is the area of RAM that gets initialized from the constants in FLASH at
+ startup (so that i == 172). The .bss section is all static data that is
+ zero length (statements like 'static int foo [12]'). The 'map' command
+ prints out the starting and ending address of each area (size calulation is
+ left to the user). Also included is the starting and ending addresses for
+ the various stacks (undefined, abort, FIQ, IRQ, service), the start of heap,
+ and the current heap end. The scheduler executes in supervisor mode, tasks
+ execute in system mode.
+
+ Added FIQ demo. Timer 1 is set up to interrupt at 8hz (8 times a second,
+ or every 125 milliseconds), and is configured as a fast interrupt. The
+ interrupt handler does nothing more than increment a counter. The 'fiq on'
+ command will enable the timer, 'fiq off' will disable it, 'fiq count' will
+ print the counter value, and 'fiq clear' will reset the counter to 0. As
+ long as the FIQ is enabled, it should be merrily counting along. NOTE: the
+ actual FIQ vector is in ./boot.s. Also in this file is the FIQ stack size.
+ I've set it to 32 bytes (8 words). This was derived empirically by
+ examining the lpc2148.lst file, and seeing how many registers were pushed
+ by the fiqISR code. Only 3 registers are pushed, so 8 words was deemed
+ enough space. An interrupt that actually does anything substantial will
+ require more stack space, and the FIQ_STACK_SIZE should be adjusted
+ accordingly. The FIQ in the CPSR is enabled by FreeRTOS when it starts the
+ scheduler, just like the IRQ.
+
+ The stacks have been tuned down pretty small to allow a larger heap area.
+ Many boot.s files allocate 1K for the supervisor stack, and another 1K for
+ the IRQ stack. I've tried to exercise all the functions in the demo to get
+ a feel for stack usage, and both of those stacks have been tuned down to
+ 256 bytes each. There shouldn't be any issue with using a lot of stack in
+ any code prior to the call to vTaskStartScheduler(), since the supervisor
+ stack will overflow into system/user stack space. Once tasks are running,
+ they have their own private stack spaces inside the FreeRTOS allocated
+ memory. If the interrupt routines are modified to use more dynamic space,
+ then the interrupt stack may need to be increased. So far, I've seen less
+ than 50% utilization. The FIQ stack is very small, as it does nothing more
+ than increment a counter. More complex FIQ routines will need more space.
+
+ Fixed problem with CCI 'mv' command failing. Default compiliation options
+ for newlib for ARM don't define HAVE_RENAME, so the newlib rename() was
+ trying to do the link/unlink method of rename a file. FatFS (and FAT file
+ systems) don't support links, so this was always failing, since link()
+ returns -1. Provided our own rename() in newlib/syscalls.c to override the
+ newlib rename().
+
+ Added a data abort, prefetch abort and undefined instruction handler. The
+ abort handler works by saving the state of the CPU to a block of memory,
+ then enabling the watchdog to force a reset. This method was used instead
+ of printing directly to the serial port, as some people are using the USB
+ as the console port, and there's no gaurantee that the system is still
+ stable enough for USB to work. So instead, the state is saved, the reset
+ is forced, and the user can then use the 'abort' set of commands to examine
+ the system state. The 'regs' command will display the registers at the
+ time of the abort, and print the opcode of the instruction that failed
+ (except for prefetch abort). The 'clear' command sets the memory used by
+ the abort handler to 0's. The 'dirty' command sets the sigil used to
+ indicate if the abort memory contains valid data. 'dabort', 'pabort' and
+ 'undef' force each of the types of aborts. To try it, start the system,
+ type 'abort clear', then 'abort regs'. All registers should be 0. Now
+ type 'abort dabort'. This forces an access to location 0x40008000, which
+ does not exist. After the LPC2148 has reset, type 'abort regs'. Examine
+ the PC value, open the lpc2148.lst file in an editor, and search for that
+ address. You should find that the abort occurred in the monitorAbortDabort
+ code, at the 'ldrb' instruction. Note that if the PC is showing somewhere
+ in the boot.s code area, it's likely a double abort is occuring. Most
+ likely the stack pointer was already corrupted at the time of the abort,
+ and when the stack is being copied, it's reading from memory that will
+ cause a data abort. After an abort, you'll want to do a 'wdt clear' to
+ clear the WDMOD.WDTOF flag, otherwise you'll be unable to re-enter ISP mode
+ without a power cycle.
+
+ Added 'misc' menu, which right now consists of the 'sizeof' command. This
+ displays the size of the common C data types (just in case you weren't sure
+ a void * is 4 byes). I'll add others here later, like when FreeRTOS starts
+ exposing structure sizes in a future release.
+
+ Updated FreeRTOS to version 4.4.0
+
+ CURRENTLY BROKE, WAITING FOR JTAG DONGLE (feel free to submit a fix).
+ Added USB mass storage capability. If CFG_USB_MSC is defined in the
+ Makefile, USB serial support will be disabled, and mass storage enabled.
+ This allows the MMC/SD card to be mounted like a disk drive. DANGER! The
+ CCI commands for file management remain enabled. This means you can create
+ a file on the Windows (or Linux) mounted device, and see the changes from
+ the CCI. HOWEVER: The SPI routines that read/write the MMC/SD card are not
+ thread-safe, so a USB request to read/write the disk can interrupt a CCI
+ command. It's crazy dangerous to actually use the CCI file commands while
+ the MMC/SD card is mounted under Windows or Linux. What you can do is
+ mount the MMC/SD card, copy files to/from it, unmount it, then use the CCI
+ commands to see that things really changed. A later revision of the demo
+ package will likely at least protect the SPI I/O from being interrupted
+ (although this defeats the 'Real' in RTOS to do so).
+
+
+Overview:
+
+ This package demonstrates using LPCUSB and FatFS under FreeRTOS on the Olimex
+ LPC2148 board, using GCC and newlib. Examples include FreeRTOS queues and
+ semaphores, LPC2148 analog to digital converters (ADCs), external interrupts,
+ the real-time clock (RTC), general purpose IO (GPIO), serial ports (UARTs),
+ and USB. Also included is a newlib syscalls.c that almost completely
+ implements all syscalls.c functions.
+
+ The package (as built, .hex file included) presents the USB port as a virtual
+ comm port. The virtualized port is used to talk to the console command
+ interpeter (CCI), that allows various functions to be exercised.
+ Alternatively, the package can re-compiled to use UART0 as the console port.
+
+ If a GPS with NMEA output at 4800 baud is connected to UART1, one of the
+ tasks will parse the NMEA input stream, and display a position report. In
+ addition, the RTC may be set from the GPS time/date.
+
+ FatFS support is included, and the CCI has several Unix-y commands to
+ manipulate files (mkfs, df, ls, mkdir, rmdir, rm, mv, cp, chmod, and sync).
+ There is also a command that allows through-put testing on the MMC/SD card.
+
+ This package exists because I wanted to familiarize myself with the LPC2148,
+ FreeRTOS, FatFS and LPCUSB for a personal project, using GCC and newlib (who
+ can afford those commercial packages? Not I). By slightly modifying the
+ resulting framework, I was able to produce a package that others may possibly
+ find useful.
+
+
+Software tools:
+
+ The package compiles using the arm-elf GCC package. Gentoo users can
+ install this by emerging the 'crossdev' package, then 'crossdev -t arm-elf'.
+ Once the arm-elf verison of GCC is installed, the package can be rebuilt with
+ 'make'.
+
+ To program the board, the Philips LPC2000 Flash Utility v2.2.3 Windows tool
+ was used. There are Linux based tools for programming the LPC21xx parts, any
+ of which support the LPC2148 should be suitable. It may be normal, but I
+ couldn't get the board to program at speeds other than 19200 and 38400.
+
+ ProComm was used to talk to the console port on UART0, and HyperTerm to talk
+ to the console port when using USB (Don't get me started on how crappy
+ HyperTerm is. I *DESPISE* this abortion, and figure that Hilgraeve must have
+ pictures of Gates with a goat or something. We can argue about MS quality
+ all day long, but HT has all the "quality" of a 6 year olds first programming
+ project in QBASIC. The only reason it was used was because ProComm can't
+ talk to COM18, which is what the virtual serial port appears as).
+
+ If using the USB virtual comm port under Windows, the 'usbser.sys' and
+ 'usbser.inf' files may be needed. Often, these files are already on the
+ drive somewhere, and Start->Search->Files can be used to located them. If
+ not present, they are included in the ./Windows directory in the package.
+
+ Under Linux, 'minicom' should be able to talk to both the serial port and the
+ virtual comm port the USB port appears as. Bertrik's wiki, located at
+ "http://wiki.sikken.nl/index.php?title=LPCUSB", has a note about using LPCUSB
+ under Linux.
+
+ The default baud rate for UART0 is 115200. The baud rate selected for the
+ USB virtual comm port is irrelevant, and may be any speed.
+
+
+Rebuilding it:
+
+ Simply typing 'make' should build the entire package. The FreeRTOS modules
+ will emit several warnings about type punned references, which can (safely?)
+ be ignored.
+
+ If you wish to use UART0 for the console port, edit ./monitor/monitor.c, jump
+ to near line 938, and change the "#if 1' to '#if 0', then recompile.
+
+ If you wish to change the baud rates for UART0 or UART1, edit ./main.c, jump
+ to near line 62, and change the rates. Any standard baud rate should produce
+ usable results.
+
+ 'make clean' will clean the project, removing the ./*.hex, ./*.lst, ./*.map,
+ ./*.elf files, and ./common/common.a, along with all *.o and .depend files in
+ any sub-directories.
+
+ 'make tags' will rebuild the ctags file for 'vi' (and no doubt emacs, if
+ you're one of "them").
+
+
+Hardware (required and optional):
+
+ Olimex LPC-P2148 board (required)
+ USB cable (optional)
+ Serial cable (optional)
+ GPS with NMEA output and serial cable (optional)
+
+
+Using it (Windows):
+
+ For the purposes of these instructions, it will be assumed that COM1 is the
+ serial port on the host PC, a USB cable is connected to the LPC-P2148 board
+ and the PC, and that the Philips LPC2000 Flash Utility V2.2.3 will be used
+ for programming. Please note that Windows 2000 was used, and that dialogs
+ for Windows XP are probably slightly different. If you're using Vista, I'm
+ surprised it can stay up long enough for you to read this document...
+
+ Connect the RS232_0/ICSP DB-9 on the LPC-P2148 board to the comm port on the
+ PC, using a straight-thru serial cable. Set both the ICSP slide switches
+ (located near the RS232_0/ICSP DB-9 connector) to the 'on' position (towards
+ the DB-9 connector), then press the reset button (located next to the ICSP
+ switches).
+
+ Configure the Philips utility for COM1, 38400 baud. Click the 'Read Device
+ ID' button. LPC2148 should appear in the 'Device' text field. Note that the
+ device ID has to be read to set the value, as there's a nasty bug in the
+ utility that prevents selecting it from the drop down list.
+
+ Click the "..." button in the 'Flash Programming' block, then locate and
+ select the 'lpc2148.hex' file, followed by clicking the 'Upload to Flash'
+ button. At this point, the flash image should start being programmed.
+
+ When it completes, set the two ISCP slide switches to 'off', and press the
+ reset button. The 'LED1' LED should start flashing.
+
+ If Windows already does not already have the 'usbser.sys' driver installed, a
+ dialog will appear regarding the discovery of new hardware. (I don't
+ remember how the dialog goes, so you'll have to infer your way through this
+ process). When prompted for the driver, navigate to the ./Windows directory,
+ and select 'usbser.inf'. This should install the driver for the virtual comm
+ port that will support the USB port.
+
+ Right-click on the 'My Computer' icon on the Windows desktop, select
+ Properties, then the Hardware tab, followed by 'Device Manager'. Click the
+ '+' on the 'Ports (COM & LPT), and there should be an entry for "USB CDC
+ serial port emulation (COMxx)" (where 'xx' will be a number). Note the COM
+ port for use with HyperTerm (see previous rant).
+
+ Start HyperTerm (Start->Programs->Accessories->Communications->HyperTerm)
+ (see previous rant). When the dialog appears, type a name for the connection
+ (The COMxx name is a good choice). Click the drop-down box under 'Connect
+ using'. Select the COMxx port name from the drop-down list. Click 'OK',
+ followed by File->Save. Now click the third icon from the left, which looks
+ like a telephone with the handset on the hook.
+
+ If all went well, typing 'help<return>' should show a list of commands
+ supported by the CCI. If so, congratulations! You can now play with various
+ commands. If not, there's not much advice that can be offered at this point.
+
+ Baldur Gislason informed me that the Philips Flash Utility has been replaced
+ by by Flash Magic (http://www.flashmagictool.com). I gave this a try, and it
+ worked well enough. It's a nicer interface, but it seems a tad slower.
+ Rather than go into detail how to use it, I'll just say that I set the devce
+ to LPC2148, interface to 'None (ISP)', the oscillator frequency to 12.00000,
+ and checked the 'Erase blocks used by Hex File', and it just worked.
+
+
+Using it (Linux):
+
+ Eeek! This needs to be written.
+
+ (Richard T. Stofer says that Debian plays nicely with the LPCUSB code. with
+ the virtualized comm port appearing as ACM0. 'minicom' can talk to this
+ port).
+
+
+Hardware thingies:
+
+ The two pushy buttons on the LPC-P2148 board (B1 and B2) enable and disable
+ LED2. Pressing B1 should light LED2, pressing B2 should extinguish it.
+ These buttons are connected to the EINT2 and EINT0 lines, respectively. The
+ associated code demonstrates handling an external interrupt, and toggling an
+ I/O pin in the interrupt service routine (ISR).
+
+ The potentiometer, AN_TR, is connected to ADC0, channel 3. The 'sensors'
+ task checks the value every 100 milliseconds. The software divides the pot
+ into 4 zones, each covering about 1/4 of the range the pot may be rotated.
+ When the pot is fully counter-clockwise, LED1 will be on for 200 milliseconds
+ and off for 800. When the pot is moved to the 2nd zone, the on/off times
+ become 400ms/600ms. The 3rd zone has on/off times of 600ms/400ms, and fully
+ clockwise is 800ms on, 200ms off.
+
+ LED1 is controlled by the LED task. This is a lower priority task. Each
+ time a single on/off cycle has completed, it's message queue is checked to
+ see if the blink ratio times should be changed due to the AN_TR pot changing
+ zones.
+
+ LED2 is controlled by the B1 and B2 pushy buttons, as mentioned above.
+
+ The DAC output on the AOUT pin changes every 100 milliseconds by 1/64 of the
+ range of the DAC (0.0515625 volts). The generates a sine wave with a period
+ of 12.8 seconds, or 0.078125 Hertz. Hang a 'scope or DVM on the AOUT pin to
+ see the change.
+
+ The I2C routines are setup to talk to a LM75 temperature sensor. These can
+ often be found on old PC motherboards, or as samples from National. The I2C
+ demo code is a simple polled approach, and does not take advantage of either
+ interrupts or the I2C state machine. The 'lm75' CCI command allows reading
+ and writing of the configuration, THYST and TOS registers, and reading of the
+ temperature register. The 'lm75 mode' command determines if the registers
+ are read using an I2C repeated start sequence instead of an I2C stop then I2C
+ start. Repeated starts are faster, and allow for holding the I2C bus in a
+ multi-master environment. The default is repeated starts (mode 0). There is
+ one potential spot for the code to hang. If the I2C bus fails to release SCL
+ (if the I2C device is powered down, perhaps), it will hang waiting for the
+ status interrupt bit to change. Any hard while loops should be wrapped in a
+ counter or timer check.
+
+ Demo now includes watchdog timer example. 'wdt test' enables the watchdog.
+ If no command is typed for 10 seconds, the system will reset. 'wdt status'
+ can be used to examine the current watchdog state and the RSIR register
+ (which allows determination of why a reset occurred). Use 'wdt clear' to
+ clear the RSIR status.
+
+
+Sort of hardware thingies:
+
+ The SWI demo code is taken from several different projects, and culled down
+ into something I felt was more readable, and better for explanations. The
+ CCI 'swi' commands allow setting the state of, turning on, turning off and
+ toggling LED2. The commands starting with 'a' use the assembly interface
+ (assembly sequences are used to affect LED2), whereas the commands starting
+ with 'c' manage LED2 in C. Note that the pushy-buttons also toggle LED2, so
+ there can be some interaction.
+
+
+CCI commands:
+
+ If you're a Linux user, most of the file commands are fairly self
+ explanatory. If you're not a Linux user, you should be, because it's better
+ on our side of the fence. The file commands require that a MMC/SD card be
+ installed in the MMC/SD slot. BEFORE USING THE FILE COMMANDS, USE THE
+ 'mount' COMMAND TO MOUNT THE MMC/SD CARD. Note that the first partition on
+ the MMC/SD card will be mounted, and this is the only one supported. It must
+ be a FAT12, FAT16 or FAT32 partition.
+
+ If the MMC/SD card is not formatted with a FAT12/FAT16/FAT32 file system, you
+ can use the 'mkfs' command to create it. If anything already exists on the
+ card, 'mkfs' will wipe it out.
+
+ Note that while a fairly good success rate has been obtained with the cards
+ on hand, one Sandisk 64MB MMC card did not work. Not sure why, but the MMC
+ drivers are probably not handling something quite right.
+
+ 'cpcon <filename>' allows a text file to be created from the CCI. Enter text
+ until you're bored, then type ctrl-d save and exit. Note that whatever
+ characters are typed are saved into the file verbatim. This means that
+ characters like backspace are actually put into the file (feel free to
+ improve that code...)
+
+ Before creating any files, you may wish to set the system date, so that files
+ are date/time stamped properly. If a GPS with NMEA output is connected to
+ RS232_1, you can use the 'gps' command to verify the serial connection, that
+ NMEA data is being parsed, and that the GPS has acquired (required for the
+ date/time to be set). If you have no GPS attached, you may enter the date
+ and time as parameters. 'settime 2007/07/08 22:51:25' will set the date and
+ time to July 8th, 10:51pm and 25 seconds. No timezone info is applied, so
+ date/times acquired from the GPS are UTC. Date/times set manually may be set
+ to local time or UTC (or something completely random, if you're into that).
+
+ The 'thruput' command allows measuring MMC/SD read and write performance.
+ Eight file sizes are used: 1K, 8K, 16K, 64K, 128K, 512K, 1MB, and 2MB. A
+ temporary file is created on the MMC/SD card. Measurements can be done one
+ of four ways: 'noints' (fastest, but disables all tasking), 'normal' (CCI
+ task priority is not changed, no tasks are suspended), 'suspendall' (all
+ tasks are suspended, no context switches made, but 10ms interrupts still
+ runs), and 'high' (CCI task is elevated to highest priority for duration of
+ test). Oddly, writes are faster than reads when not using the 'noints' mode.
+ I have not yet researched why. Leaving interrupts enabled *seriously*
+ impacts the file system performance, nominally by a factor of 20.
+
+ Richard T. Stofer noticed that this slow down only appears when using the
+ 'usbser.sys' drivers under Windows. When using the Linux ACM drivers, or
+ when using UART0 as the console port with the USB cable disconnected, this
+ problem does not occur. We can only assume that the Windows driver sends
+ lots of (needless) packets (yet another reason to switch to Linux!)
+
+ The 'date' command will report the current date/time from the RTC. If you
+ have an external 3V battery plugged into the BAT connector, the RTC will
+ preserve it's values across power-downs. Regardless of the battery presence,
+ date/time will be preserved across resets (as long as power is not removed).
+
+ The 'sensors' commands reports very little useful information. The sensors
+ task executes every 100ms, and samples the ADC connected to the AN_TR
+ potentiometer. Every time the task runs, the sensors counter is increment by
+ one. If the AN_TR pot is adjusted far enough to change the zone, the ADC
+ changed value will increment. See the section above on the pot. The
+ associated code demonstrates running a high priority task with a constant
+ execution frequency, sampling an ADC, and sending a message to another task.
+
+ The 'mem' command displays the various tasks running, and the amount of
+ unused stack available to each task, along with the task priority and such.
+ The associated code demonstrates the 'vTaskList' RTOS call. Note that in a
+ 'real' system, leaving the task trace code enabled (configUSE_TRACE_FACILITY)
+ imposes a slight penalty on context switches, which may be undesirable.
+
+ The 'iap' commands allow experimenting with the In-Application Programming
+ (IAP) code. The demo code demonstrates preparing, erasing, writing, blank
+ checking, and retrieving processor ID and boot loader version numbers. IAP
+ deals with primarily with sectors. In the LPC2148 (which has 512K of flash),
+ there are 4K and 32K sectors. The CCI will not allow selecting sectors that
+ are used for code. The 'fss' command will find a safe sector to use with the
+ 'iap' commands. Once a safe sector is known, you can erase and fill this
+ sector. The blank checking will work on any valid sector (there are 27 in
+ the LPC2148). The IAP_COPYRAMTOFLASH (writing to flash) is demonstrated
+ by the fill command. Whatever size the sector selected is, the 'fill'
+ command will fill the entire contents with the supplied byte value. The 'md'
+ command can be used to dump the sector contents to see the effects of 'erase'
+ and 'fill'. The 'stoa' command is used to convert a sector number to an
+ address for 'md'. It is strongly recommended that you become familiar with
+ the section on IAP in the LPC2148 datasheet before using these commands. The
+ IAP prepare and compare functions are not CCI accessible. These are handled
+ internally by the erase and fill code.
+
+
+MMC/SD notes:
+
+ As mentioned above, I have a Sandisk 64MB MMC card that the MMC drivers can't
+ seem to recognize. I have 4 other cards that work fine, one of which is an
+ MMC, the other three which are SD. I'd like to resolve this issue.
+
+ During the 'thruput' test, when interrupts are left enabled, I have on rare
+ occasions seen a read or write error occur. I believe this is because a
+ context switch is taking place during some time critical code.
+
+ Ideally, interrupts would be disabled. However, disabling interrupts makes
+ an RTOS merely an OS. The 'real-time' part means predictable response to
+ interrupts, and the executing time-critical tasks on-time. In this code, the
+ MMC/SD code is non-reentrant (only one task may read/write the card), and not
+ time critical. If multiple tasks have to write to disk, this would
+ currently have to be handled by creating a task that communicates through
+ queues to other tasks, and manages the MMC/SD card.
+
+ Note that if a GPS is connected, a message that a NMEA checksum could not be
+ found may occasionally appear. While the actual test is being run, the GPS
+ task is not processing messages, and the serial buffer overruns. When the
+ task is allowed to run again (between tests), partial NMEA messages that
+ cannot be parsed may be present, resulting in the error message.
+
+
+GCC notes:
+
+ This code was compiled with -O3. This results in code that's about 16K
+ larger than -Os, but has a measurable impact on the MMC/SD card throughput
+ (not large, but it can be seen). I went with -O3 because with 512K of FLASH,
+ and 144K or so used, there's plenty of room.
+
+ I'm not sure what the compiliation options for newlib are. 'crossdev'
+ compiled those, and I suspect it was with -Os, since embedded systems
+ generally tend to consider size over speed.
+
+ GCC is an amazing package. I'm used to running into compiler issues with
+ many of the micros that I work with (SCCS, Microchips C18, etc). It's so
+ nice to have a compiler that produces code without problems, and doesn't have
+ idiot front-ends that can't even get the sign on an enum correct (at least
+ Microchip got it right for the dsPIC and PIC24 parts, which used GCC. C18...
+ Don't go there...)
+
+ There's a trick to writing Makefiles, and I don't have it. It's an arcane
+ art, and involves the slaughtering of goats, black candles, and full moons.
+ The Makefiles I did write are very basic, and use recursion ('Recursive make
+ considered harmful!'. Foo on that. Worked for me).
+
+ I tried a couple of approaches, and either everything built anyway, or
+ nothing built at all. To make the linking work, as files are compiled,
+ they're dumped in to ./common/common.a, and main.c is linked against that.
+ So far, the expected bite on the butt for doing it this way has not happened.
+
+ It would be really neat to have Makefiles done right. Alas, I don't know how
+ to do it right. So if the common.a approach looks really ugly to you, that
+ means you probably know how to write Makefiles that handle sub-directories
+ correctly, and you can tell me how it should be done :) (With examples!)
+
+
+Notes on newlib:
+
+ I wasn't happy with the newlib syscalls.c that was included in the original
+ LPC2148 port. I more or less completely rewrote this, with the exception of
+ _sbrk(). _open() can open the serial ports, USB port, and FatFS files. All
+ supporting functions except _fstat() work (see FatFS complaint at bottom).
+
+ Newlibs method of converting a file descriptor (as returned by _open()) to a
+ slot (which points to assorted info for that fd) uses a loop. As this is
+ done on EVERY read and write call, unnecessary overhead is added. I fixed
+ the find_slot() code to cache the last fd, and if it's the same on a
+ subsequent call, the search is skipped.
+
+ _open() is VERY suspect, in that remapping of FatFS f_open flags don't
+ correspond cleanly to Unix's open() call. I handle the four common cases
+ correctly, but lesser used ones may result in a EINVAL errno on open.
+
+ Opening FatFS files is expensive, RAM space-wise. Each open file uses a
+ FatFS FIL structure which contains a 512 byte buffer, plus some additional
+ space. With 32K on a LPC2148, and 20K being used for the FreeRTOS heap, that
+ leaves 12K that has to be used for the stack, heap, printf(), etc. Don't go
+ wild opening files, and be sure to close unused files to free the space. Use
+ open() instead of fopen() whenever possible, as the FILE structure has it's
+ own set of buffers.
+
+ There may be a way to figure out how much heap and stack have been used under
+ newlib. If there is, I haven't figured it out yet. I'd really like to be
+ able to make a newlib or system call that returns total space available, heap
+ used and stack used.
+
+ Since stdout and stderr point to same place, it's wise to close stderr and
+ set stderr to stdout. Only functions like assert() use stderr, so
+ intermixing stderr and stdout shouldn't be a problem. Especially since
+ there's no redirection of I/O...
+
+
+Header file for LPC2148 (lpc210x.h):
+
+ The original LPC2148 header file was very lacking. Not only were individual
+ bit fields generally not defined, major peripherials weren't defined. As a
+ result, FreeRTOS, LPCUSB, FatFS and newlib all used local defines. Worse,
+ some of these were simply "SOMEREG = (1<<31)". Great. What does bit 31 do?
+
+ Personally, I feel the best way is to define structures AND #defines. It's
+ good that a structure has an element called 'CLK', but setting CLK to 0
+ doesn't give a hint as to what clock mode is being set. A #define for
+ XXX_YYY_CLK_BIPHASE, then saying XXX_YYY_bits.ClkMode=XXX_YYY_CLK_BIPHASE is
+ a lot clearer.
+
+ I defined a mess of #defines, with the majority matching the names in the
+ datasheet. There were few that become triplely redundant, such as
+ WD_WDFEED_WDFEED1. This was reduced to WD_FEED_FEED1. The characters prior
+ to the first underscore define the module, with the next set the defining the
+ register name. Subsequent fields define the bit field name, and then
+ possible variations.
+
+ What I don't like about using #defines to define the registers is that the
+ programmer needs to know if the bits being affected need to be AND'ed or
+ OR'ed. Structures neatly solve this problem, but defining all the structures
+ takes a lot of work (yea, IAR has already done that, but it's not legal to
+ just swipe their nice headers).
+
+ With one exception I'm aware of (in the TODO section), I rewrote all the code
+ that sets registers to use the values in the lpc210x.h file.
+
+ While I doubt it makes the code more portable (will NXP change block
+ addresses, but leave bits the same? Probably not), it does make it more
+ readable.
+
+ One of the last major areas to be completed is to pull the USB protocol
+ engine #defines into lpc210x.h. These are currently defined in one of the
+ USB header files, and have poor name scoping (does "ACK_STAT" tell you what
+ module or register it applies to? No.)
+
+
+Software notes:
+
+ All copyrights are by their respective authors. FreeRTOS is by Richard
+ Barry. LPCUSB is by Bertrik Sikken. FatFS is by ChaN, with sections by Joel
+ Winarske. Other sections of code may have come from the intarweb, and have
+ respective copyrights, indicated or not. Any code that I personally authored
+ is free for public consumption, unemcumbered by any copyrights, etc (that
+ crap is just too confusing. BSD? LPGL? GPL3? Who the hell knows...)
+
+ I've re-formatted a good deal of code in LPCUSB and FatFS. Some portions
+ were re-written, others simply re-formatted to my coding style (which I
+ jokingly refer to as JC1). I have occasionally whacked comment blocks that I
+ didn't really think indicated what the code did, or was redundant. I
+ probably whacked some text with copyrights in the process. This in no way
+ reflects an attempt to claim the work as my own, or to otherwise dishonor the
+ original authors. As Isaac Newton (more or less) said, "If I have seen a
+ little further it is by standing on the shoulders of Giants." Without the
+ work of these most excellent people, this code would not exist.
+
+ Most of the reason for my re-formatting is my way of understanding the code,
+ going through it section by section. It's good because I have a better
+ understanding of it, worse because it makes drop-in replacement with updates
+ from the authors more difficult.
+
+ The most affected area is the SPI handling in the FatFS code. Originally
+ named 'mm_llc_spi1.c', I felt this was not cleanly integrated, so I rewrote
+ it. Maybe it's not better, but it is different :)
+
+ The FreeRTOS code is almost completely untouched, except for moving an #if
+ around that allowed compiling the trace code (configUSE_TRACE_FACILITY)
+ without requiring the task suspend code (INCLUDE_vTaskSuspend). In the end,
+ this was probably irrelevant, since I compiled the task suspend code in
+ anyway.
+
+
+Things I wish were different:
+
+ A collection of random little thoughts of things I wish were different.
+ These are just MY opinions, based on the way I do things. It's not to say
+ the original authors were wrong. It's just the way I'd make things, if I
+ were smart enough to write this stuff from scratch. Most people probably
+ shouldn't even read the following list...
+
+ While FreeRTOS attempts to isolate the user from system data structures, it's
+ a little *too* aggressive. These typedef'ed structures should be in a header
+ file, so applications can at least use sizeof() to help determine memory
+ allocation. Everything is done through recasted void* pointers.
+
+ It would be neat if FreeRTOS had a xDelayTaskUntil() that also took one or
+ more queues as a blocking item. I want to run a task every 'n' milliseconds,
+ but if something shows up in a queue, process it early. Perhaps this could
+ work like Unix's select(). Or perhaps a variadic function that takes
+ xQueueHandles as parameters.
+
+ I dont' care for FreeRTOS's use of portBLAH typedefs for portable types. The
+ world is pretty used to U8, U16, N32, and BOOL for unsigned char, unsigned
+ short, signed int, etc. FreeRTOS also seems to require declaring too many
+ things as 'signed', which should be a default. I'm sure this is done for
+ portability, but I find the types are not as intuitive as they could be.
+
+ Another minor itch is that all function names and types start with 'x'. I
+ would have preferred 'freertos', or better, a user-definable one, via a
+ #define macro. I think programmers forget that their package may be
+ integrated into a larger system, and while their naming convention works well
+ for their purpose, it may not scale well. FatFS and LPCUSB are guilty of
+ this as well.
+
+ FreeRTOS has a couple errors in several of the modules regarding type
+ punning. I understand what type punning is, but I don't know how to fix it
+ safely. Perhaps RB will fix those up in the next release.
+
+ FatFS changes return types too often, particularly for errors. There's the
+ errors from the SPI routines, the MMC routines, the disk routines, and the
+ top layer FatFS code. There should be unified errors for everything, so that
+ errors can be cleanly communicated up the stack.
+
+ FatFS can't go from file descriptor to filename. I haven't figured out a
+ clean and reliable way to map a fd back to a filename (FatFS f_stat() needs a
+ file name). I thought about malloc()'ing space in the openFiles_t structure
+ and copying the filename when the file is opened. However, paths can get up
+ to 128 characters, and only _fstat() needs that information. This seems very
+ wasteful.
+
+ FatFS wants the user to provid the get_fattime() function. FatFS should
+ really have a file for locally provided functions. It's already specific to
+ the SPI or IDE port implementation. As such, it should be stubbed out to
+ return 0 if the function isn't provided, or allow the user to implement in
+ the platform specific file (basically, an equivalent of syscalls.c, but
+ internal to FatFS).
+
+ FatFS has naming conventions that I don't like. It exposes too many internal
+ function names that should be declared static. Structure names like 'FIL'
+ are ambiguous, and too likely to collide with other libraries. Functions
+ should be preceed by the supporting module or library. All FatFS functions
+ should be in the form of fatfsOpen, fatfsClose, etc.
+
+ LPCUSB is not organized quite the way I'd do it. The USB protocol engine
+ defines need to have their names modified and moved into the lpc210x.h.
+
+ Newlib lacks certain calls on the ARM7 platform. sync() and chmod() do not
+ exist, while mkdir() does, but wit no corresponding _mkdir() support in
+ syscalls.c. Returning ENOSYS is easy enough, and doesn't take but a few
+ instructions. Providing support for a wider range of calls would be good,
+ taking into mind things like FatFS that provide file system support, etc.
+
+ The Olimex board COMPLETELY lacks documentation (at least, that I've been
+ able to find). It's up to the user to guess what the slide switches are for,
+ etc. It's probably pretty obvious to someone who's used the LPC2000 parts
+ before, but if you're buying a board to get started, you have to waste time
+ figuring out how to use it. Even a simple Xerox'ed sheet would have been
+ sufficient.
+
+ The Olimex board also lacks the ability to control the BSL line from the
+ serial port. Reset works, but without being able to flip the BSL switch,
+ it has little value.
+
+ The buzzer on the Olimex board is useless. Had it been connected to one of
+ the PWM outputs, some simple sound synthesis would have been possible. At
+ best, it demostrates you can toggle I/O pins fast enough to make noise.
+ However, unless you want clicks in the output, you have to disable
+ interrupts. And why *two* port pins? One would have been sufficient. I
+ would have preferred to have two more LEDs, rather than the buzzer.
+
+
+TODO:
+
+ ./FreeRTOS/portable/GCC/ARM7_LPC2000/port.c uses local defines for timer control
+ Finish rest of syscalls.c functions (fstat ())
+ Some modules (USB) still have local #defines for hardware (protocol engine)
+ Add VIC software interrupt demo (?)
+ Add data abort demo
+ Frequency measurement?
+ Add fast GPIO (beep speaker)
+ Fix SPI code to be thread safe
+ Fix I2C using polled mode for EEPROM
+ Add firmware update from file system
--- /dev/null
+[Version]
+Signature="$Windows NT$"
+Class=Ports
+ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
+Provider=%LINUX%
+DriverVer=08/17/2004,0.0.2.0
+; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com)
+; released under GNU General Public License
+
+[Manufacturer]
+%LINUX%=GSerialDeviceList
+
+[GSerialDeviceList]
+%GSERIAL%=GSerialInstall, USB\VID_FFFF&PID_0005
+
+[DestinationDirs]
+DefaultDestDir=10,System32\Drivers
+
+[GSerialInstall]
+CopyFiles=GSerialCopyFiles
+AddReg=GSerialAddReg
+
+[GSerialCopyFiles]
+usbser.sys
+
+[GSerialAddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,usbser.sys
+HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
+
+[GSerialInstall.Services]
+AddService = usbser,0x0002,GSerialService
+
+[GSerialService]
+DisplayName = %GSERIAL_DISPLAY_NAME%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\System32\Drivers\usbser.sys
+LoadOrderGroup = Base
+
+[Strings]
+LINUX = "Linux"
+GSERIAL = "USB CDC serial port emulation"
+GSERIAL_DISPLAY_NAME = "USB CDC serial port emulation"
\ No newline at end of file
--- /dev/null
+SRC_FILES=adc.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include "adc.h"
+
+//
+//
+//
+int adcRead0_3 (void)
+{
+ AD0_CR |= AD_CR_START_NOW;
+
+ while (!(AD0_DR3 & AD_DR_DONE))
+ ;
+
+ return ((AD0_DR3 & AD_DR_RESULTMASK) >> AD_DR_RESULTSHIFT);
+}
+
+//
+// Assumes PCLK == 48Mhz
+//
+void adcInit (void)
+{
+ SCB_PCONP |= SCB_PCONP_PCAD0;
+
+ PCB_PINSEL1 |= PCB_PINSEL1_P030_AD03;
+
+ AD0_CR = AD_CR_CLKS10 | AD_CR_PDN | ((11 - 1) << AD_CR_CLKDIVSHIFT) | AD_CR_SEL3;
+}
--- /dev/null
+#ifndef _ADC_H_
+#define _ADC_H_
+
+int adcRead0_3 (void);
+void adcInit (void);
+
+#endif
--- /dev/null
+@
+@ Sample initialization file
+@
+ .extern main
+ .extern exit
+
+ .text
+ .code 32
+
+ .align 0
+
+ .extern __bss_beg__
+ .extern __bss_end__
+ .extern __stack_end__
+ .extern __data_beg__
+ .extern __data_end__
+ .extern __data+beg_src__
+
+ .global start
+ .global endless_loop
+
+@
+@ Stack sizes. These have been determined empirically. If your interrupt
+@ routines become more complex or use a lot of dynamically allocated space,
+@ the IRQ and/or FIQ stacks may been be grown. The supervisor stack may
+@ overflow into the system/user stack as the system is going any initialization,
+@ before starting the FreeRTOS scheduler. The scheduler itself needs a small
+@ amount of supervisor stack space, once it's running.
+@
+ .set UND_STACK_SIZE, 0x00000004
+ .set ABT_STACK_SIZE, 0x00000004
+ .set FIQ_STACK_SIZE, 0x00000020
+ .set IRQ_STACK_SIZE, 0X00000100
+ .set SVC_STACK_SIZE, 0x00000100
+
+@
+@ Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
+@
+ .set MODE_USR, 0x10 @ User Mode
+ .set MODE_FIQ, 0x11 @ FIQ Mode
+ .set MODE_IRQ, 0x12 @ IRQ Mode
+ .set MODE_SVC, 0x13 @ Supervisor Mode
+ .set MODE_ABT, 0x17 @ Abort Mode
+ .set MODE_UND, 0x1B @ Undefined Mode
+ .set MODE_SYS, 0x1F @ System Mode
+
+ .equ I_BIT, 0x80 @ when I bit is set, IRQ is disabled
+ .equ F_BIT, 0x40 @ when F bit is set, FIQ is disabled
+ .equ T_BIT, 0x20 @ when T bit is set, THUMB mode is active
+
+start:
+_start:
+_mainCRTStartup:
+@
+@ Clear all of memory to 0xe5e5e5e5. We use this value later to determine
+@ stack highwater usage.
+@
+ ldr r1, .LC3 @ __data_beg__ is start of RAM
+ ldr r3, .LC6 @ __stack_end__ is end of RAM
+ sub r3, r3, r1 @ Length of RAM to set
+ ldr r2, =0xe5e5e5e5 @ Fill value
+
+.init_loop:
+ str r2, [r1], #4 @ Store fill value, r1 += 4
+ subs r3, r3, #4 @ Length -= 4
+ bgt .init_loop @ >= 0, go again
+
+.end_init_loop:
+
+@
+@ Clear BSS.
+@
+ ldr r1, .LC1 @ Start of memory block
+ ldr r3, .LC2 @ End of memory block
+ subs r3, r3, r1 @ Calculate length of block
+ beq .end_clear_loop @ If 0, nothing to do
+ mov r2, #0 @ Fill value
+
+.clear_loop:
+ strb r2, [r1], #1 @ Store byte, r1++
+ subs r3, r3, #1 @ Decrement counter
+ bgt .clear_loop @ >= 0, go again
+
+.end_clear_loop:
+
+@
+@ Initialize data.
+@
+ ldr r1, .LC3 @ Destination (.data in RAM)
+ ldr r2, .LC4 @ Source (.data in FLASH)
+ ldr r3, .LC5 @ End of .data in RAM
+ subs r3, r3, r1 @ Calculate length of block
+ beq .end_set_loop @ If 0, nothing to do
+
+.set_loop:
+ ldrb r4, [r2], #1 @ Get byte from source, r2++
+ strb r4, [r1], #1 @ Store byte to destination, r1++
+ subs r3, r3, #1 @ Decrement loop counter
+ bgt .set_loop @ >= 0, go again
+
+.end_set_loop:
+
+@
+@ Setup a stack for each mode - note that this only sets up a usable stack
+@ for system/user, SWI and IRQ modes. Also each mode is setup with
+@ interrupts initially disabled.
+@
+ ldr r1, .LC7 @ Pointer to various values we update
+ ldr r0, .LC6 @ Get top of stack space
+ msr CPSR_c, #MODE_UND|I_BIT|F_BIT @ Undefined Instruction Mode
+ mov sp, r0 @ Set undef mode SP
+ str r0, [r1, #0] @ Store this so 'mem map' knows
+
+ sub r0, r0, #UND_STACK_SIZE @ Subtract undef stack size for abort stack start
+ msr CPSR_c, #MODE_ABT|I_BIT|F_BIT @ Abort Mode
+ mov sp, r0 @ Set abort mode SP
+ str r0, [r1, #4] @ Store this so 'mem map' knows
+ str r0, [r1, #8] @ Store this so 'mem map' knows
+
+ sub r0, r0, #ABT_STACK_SIZE @ Subtract abort stack size for FIQ stack start
+ msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT @ FIQ Mode
+ mov sp, r0 @ Set FIQ mode SP
+ str r0, [r1, #12] @ Store this so 'mem map' knows
+ str r0, [r1, #16] @ Store this so 'mem map' knows
+
+ sub r0, r0, #FIQ_STACK_SIZE @ Subtract FIQ stack size for IRQ stack start
+ msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT @ IRQ Mode
+ mov sp, r0 @ Set IRQ mode SP
+ str r0, [r1, #20] @ Store this so 'mem map' knows
+ str r0, [r1, #24] @ Store this so 'mem map' knows
+
+ sub r0, r0, #IRQ_STACK_SIZE @ Subtract IRQ stack size for SVC stack start
+ msr CPSR_c, #MODE_SVC|I_BIT|F_BIT @ Supervisor Mode
+ mov sp, r0 @ Set supervisor mode SP
+ str r0, [r1, #28] @ Store this so 'mem map' knows
+ str r0, [r1, #32] @ Store this so 'mem map' knows
+ sub r2, r0, #256 @ MAGIC! FreeRTOS only uses a few bytes of supervisor stack...
+ str r2, [r1, #48] @ ...so tell _sbrk() where heap ends when FreeRTOS running
+
+ sub r0, r0, #SVC_STACK_SIZE @ Subtract supervisor stack size for system/user stack start
+ msr CPSR_c, #MODE_SYS|I_BIT|F_BIT @ System Mode
+ mov sp, r0 @ Set system/user mode SP
+ str r0, [r1, #36] @ Store this so 'mem map' knows
+ str r0, [r1, #40] @ Store this so 'mem map' knows
+
+@
+@ We want to start in supervisor mode (probably always, but FreeRTOS demands it)
+@
+ msr CPSR_c, #MODE_SVC|I_BIT|F_BIT
+
+@
+@ Set argc & argv, initialize newlib, and jump to main
+@
+ mov r0, #0 @ No arguments
+ mov r1, #0 @ No argv either
+
+ bl syscallsInit @ Initialize ./newlib/syscalls.c
+ bl main @ And call good ol' main()
+ b . @ In case main() ever returns
+
+@
+@ Indirect words
+@
+ .align 0
+.LC1: .word __bss_beg__
+.LC2: .word __bss_end__
+.LC3: .word __data_beg__
+.LC4: .word __data_beg_src__
+.LC5: .word __data_end__
+.LC6: .word __stack_end__
+.LC7: .word __stack_beg_und
+
+@
+@ Setup vector table.
+@
+.section .startup,"ax"
+ .code 32
+ .align 0
+
+ b _start @ reset - _start
+ ldr pc, _undf @ undefined - _undf
+ ldr pc, _swi @ SWI - _swi
+ ldr pc, _pabt @ program abort - _pabt
+ ldr pc, _dabt @ data abort - _dabt
+ nop @ reserved
+ ldr pc, [pc, #-0xff0] @ IRQ - read the VIC
+ ldr pc, _fiq @ FIQ - _fiq
+
+_undf: .word __undf @ undefined
+_swi: .word swiDispatch @ SWI
+_pabt: .word __pabt @ program abort
+_dabt: .word __dabt @ data abort
+_fiq: .word fiqISR @ FIQ
+
+@
+@ Handlers for undef, program abort and data abort. They all update
+@ their respective registers, then reset the system by timing out
+@ the watchdog (only apparent way to force a hardware reset)
+@
+__undf:
+ ldr sp, =(__abort_mem+5*4) @ Set sp_abt to data array with offset (restore later)
+ stmia sp, {r0-r12} @ Save first dataset in r0-r12 to array
+ sub r0, lr, #4 @ Calculate PC value of undef instruction
+ mov r1, #0 @ Abort type
+ b .abtstore @ Save info, reset system
+
+__pabt:
+ ldr sp, =(__abort_mem+5*4) @ Set sp_abt to data array with offset (restore later)
+ stmia sp, {r0-r12} @ Save first dataset in r0-r12 to array
+ sub r0, lr, #4 @ Calculate PC value of undef instruction
+ mov r1, #1 @ Abort type
+ b .abtstore @ Save info, reset system
+
+__dabt:
+ ldr sp, =(__abort_mem+5*4) @ Set sp_abt to data array with offset (restore later)
+ stmia sp, {r0-r12} @ Save first dataset in r0-r12 to array
+ sub r0, lr, #8 @ Calculate PC value of undef instruction
+ mov r1, #2 @ Abort type
+ b .abtstore @ Save info, reset system
+
+@
+@ Store the abort type. Then see if the sigil value is set, and if not,
+@ reset the abort counter to 0.
+@
+.abtstore:
+ ldr r2, =__abort_typ @ Abort type
+ str r1, [r2] @ Store it
+
+ ldr r2, =__abort_sig @ Get the sigil address
+ ldr r4, =ABORT_SIGIL @ Load sigil value
+ ldr r3, [r2] @ Get sigil contents
+ cmp r3, r4 @ Sigil set?
+
+ strne r4, [r2] @ No, store sigil value
+ ldrne r2, =__abort_cnt @ No, load address of abort counter
+ movne r4, #0 @ No, Zero for store
+ strne r4, [r2] @ No, Clear counter
+
+@
+@ Now build up structure of registers and stack (r0 = abort address, r1 =
+@ abort type). This code is based heavily on the work of Roger Lynx, from
+@ http://www.embedded.com/shared/printableArticle.jhtml?articleID=192202641
+@
+ mrs r5, cpsr @ Save current mode to R5 for mode switching
+ mrs r6, spsr @ spsr_abt = CPSR of dabt originating mode, save to r6 for mode switching
+ mov r2, r6 @ Building second dataset: r2 = CPSR of exception
+ tst r6, #0x0f @ Test mode of the raised exception
+ orreq r6, r6, #0x0f @ If 0, elevate from user mode to system mode
+ msr cpsr_c, r6 @ Switch out from mode 0x17 (abort) to ...
+ mov r3, lr @ ... dabt generating mode and state
+ mov r4, sp @ ... Get lr (=r3) and sp (=r4)
+ msr cpsr_c, r5 @ Switch back to mode 0x17 (abort)
+ cmp r1, #1 @ Test for prefetch abort
+ moveq r1, #0 @ Can't fetch instruction at the abort address
+ ldrne r1, [r0] @ r1 = [pc] (dabt)
+ ldr sp, =__abort_mem @ Reset sp to arrays starting address
+ stmia sp, {r0-r4} @ Save second dataset from r0 to r4
+
+ ldr r1, =__abort_stk @ Space where we'll store abort stack
+ mov r2,#8 @ Copy 8 stack entries
+.abtcopy:
+ ldr r0, [r4], #4 @ Get byte from source, r4 += 4
+ str r0, [r1], #4 @ Store byte to destination, r1 += 4
+ subs r2, r2, #1 @ Decrement loop counter
+ bgt .abtcopy @ >= 0, go again
+
+ b .sysreset @ And reset
+
+@
+@ Force a system reset with ye olde watch dogge
+@
+ .set SCB_RSIR_MASK, 0x0000000f
+ .set SCB_RSIR, 0xe01fc180
+ .set WD_MOD, 0xe0000000
+ .set WD_TC, 0xe0000004
+ .set WD_FEED, 0xe0000008
+ .set WD_MOD_WDEN, 0x00000001
+ .set WD_MOD_RESET, 0x00000002
+ .set WD_MOD_TOF, 0x00000004
+ .set WD_MOD_INT, 0x00000008
+ .set WD_MOD_MASK, 0x0000000f
+ .set WD_FEED_FEED1, 0x000000aa
+ .set WD_FEED_FEED2, 0x00000055
+ .set ABORT_SIGIL, 0xdeadc0de
+
+.sysreset:
+ ldr r1, =__abort_cnt @ Get the abort counter address
+ ldr r0, [r1] @ Load it
+ add r0, r0, #1 @ Add 1
+ str r0, [r1] @ Store it back
+
+@
+@ Now enable the watch dog, and go into a loop waiting for a timeout
+@
+ ldr r0, =SCB_RSIR_MASK
+ ldr r1, =SCB_RSIR
+ str r0, [r1]
+ ldr r0, =WD_MOD_WDEN | WD_MOD_RESET
+ ldr r1, =WD_MOD
+ str r0, [r1]
+ ldr r0, =120000
+ ldr r1, =WD_TC
+ str r0, [r1]
+ ldr r0, =WD_FEED_FEED1
+ ldr r1, =WD_FEED
+ str r0, [r1]
+ ldr r0, =WD_FEED_FEED2
+ ldr r1, =WD_FEED
+ str r0, [r1]
+ b .
+
+@
+@ These are in the .protected space in RAM to make sure that initialization
+@ code doesn't overwrite them. When a data abort or an undefined instruction
+@ exception occurs, the handlers update the respective locations below. ORDER
+@ IS IMPORTANT, THESE ARE MAPPED INTO THE C STRUCTURE abortDat_t in monitor.c
+@
+ .global __abort_dat
+ .section .protected
+ .align 0
+
+__abort_dat: .word 0 @ Dummy, not used
+__abort_sig: .word 0 @ Sigil to indicate data validity
+__abort_cnt: .word 0 @ Number of times we've aborted
+__abort_typ: .word 0 @ Type of abort (0=undef,1=pabort,2=dabort)
+__abort_mem: .space (18 * 4), 0 @ Registers from abort state
+__abort_stk: .space (8 * 4), 0 @ 8 stack entries from abort state
+
+@
+@ Define globals so application can figure out what stacks are where.
+@ Keep these in order! The stack setup code expects it.
+@
+ .global __stack_beg_und
+ .global __stack_end_und
+ .global __stack_beg_abt
+ .global __stack_end_abt
+ .global __stack_beg_fiq
+ .global __stack_end_fiq
+ .global __stack_beg_irq
+ .global __stack_end_irq
+ .global __stack_beg_svc
+ .global __stack_end_svc
+ .global __stack_beg_sys
+ .global __stack_end_sys
+ .global __heap_max
+ .global __heap_beg
+ .global __heap_end
+ .data
+ .align 0
+
+__stack_beg_und: .word 0 @ 0
+__stack_end_und: .word 0 @ 4
+__stack_beg_abt: .word 0 @ 8
+__stack_end_abt: .word 0 @ 12
+__stack_beg_fiq: .word 0 @ 16
+__stack_end_fiq: .word 0 @ 20
+__stack_beg_irq: .word 0 @ 24
+__stack_end_irq: .word 0 @ 28
+__stack_beg_svc: .word 0 @ 32
+__stack_end_svc: .word 0 @ 36
+__stack_beg_sys: .word 0 @ 40
+__stack_end_sys: .word 0 @ 44
+__heap_max: .word 0 @ 48
+__heap_beg: .word __heap_beg__
+__heap_end: .word __heap_end__
+
+ .end
--- /dev/null
+SRC_FILES=cpu.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+#include "cpu/cpu.h"
+
+//
+// Olimex board specific. LEDs are on P0.10, P0.11
+//
+#define partstFIRST_IO ((unsigned portLONG) 0x400)
+#define partstNUM_LEDS (2)
+#define partstALL_OUTPUTS_OFF ((unsigned portLONG) 0xffffffff)
+
+//
+//
+//
+void cpuSetupHardware (void)
+{
+#ifdef RUN_FROM_RAM
+ //
+ // Remap the interrupt vectors to RAM if we are are running from RAM
+ //
+ SCB_MEMMAP = SCB_MEMMAP_URM;
+#endif
+
+ //
+ // Configure the RS2332 pins. All other pins remain at their default of 0
+ //
+ PCB_PINSEL0 |= (PCB_PINSEL0_P00_TXD0 | PCB_PINSEL0_P01_RXD0 | PCB_PINSEL0_P08_TXD1 | PCB_PINSEL0_P09_RXD1);
+
+ //
+ // Set all GPIO to output other than the P0.14 (BSL), and the JTAG pins.
+ // The JTAG pins are left as input as I'm not sure what will happen if the
+ // Wiggler is connected after powerup - not that it would be a good idea to
+ // do that anyway.
+ //
+ GPIO0_IODIR = ~(GPIO_IO_P14 | GPIO_IO_P15 | GPIO_IO_P15);
+ GPIO1_IODIR = ~GPIO_IO_JTAG;
+
+ //
+ // Setup the PLL to multiply the 12Mhz XTAL input by 4, divide by 1
+ //
+ SCB_PLLCFG = (SCB_PLLCFG_MUL4 | SCB_PLLCFG_DIV1);
+
+ //
+ // Activate the PLL by turning it on then feeding the correct sequence of bytes
+ //
+ SCB_PLLCON = SCB_PLLCON_PLLE;
+ SCB_PLLFEED = SCB_PLLFEED_FEED1;
+ SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+ //
+ // Wait for the PLL to lock...
+ //
+ while (!(SCB_PLLSTAT & SCB_PLLSTAT_PLOCK))
+ ;
+
+ //
+ // ...before connecting it using the feed sequence again
+ //
+ SCB_PLLCON = SCB_PLLCON_PLLC | SCB_PLLCON_PLLE;
+ SCB_PLLFEED = SCB_PLLFEED_FEED1;
+ SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+ //
+ // Setup and turn on the MAM. Three cycle access is used due to the fast
+ // PLL used. It is possible faster overall performance could be obtained by
+ // tuning the MAM and PLL settings.
+ //
+ MAM_TIM = MAM_TIM_3;
+ MAM_CR = MAM_CR_FULL;
+
+ //
+ // Setup the peripheral bus to be the same as the PLL output (48Mhz)
+ //
+ SCB_VPBDIV = SCB_VPBDIV_100;
+
+ //
+ // Disable power to all modules
+ //
+ SCB_PCONP = 0x0000;
+
+ //
+ //
+ //
+ cpuGPIOInitialize ();
+}
+
+//
+//
+//
+void cpuPLLDisable (void)
+{
+ SCB_PLLCON = 0;
+ SCB_PLLFEED = SCB_PLLFEED_FEED1;
+ SCB_PLLFEED = SCB_PLLFEED_FEED2;
+ SCB_PLLCFG = 0;
+}
+
+//
+//
+//
+void cpuT1Disable (void)
+{
+ T1_TCR = 0;
+ T1_PR = 0;
+ T1_MCR = 0;
+ T1_CCR = 0;
+ T1_EMR = 0;
+ T1_CTCR = 0;
+ T1_IR = 0;
+}
+
+//
+//
+//
+void cpuGPIOInitialize (void)
+{
+ GPIO0_IOSET = partstALL_OUTPUTS_OFF;
+}
+
+void cpuToggleLED (unsigned portBASE_TYPE uxLED)
+{
+ unsigned portLONG ulLED = partstFIRST_IO;
+
+ if (uxLED < partstNUM_LEDS)
+ {
+ ulLED <<= (unsigned portLONG) uxLED;
+
+ if (GPIO0_IOPIN & ulLED)
+ GPIO0_IOCLR = ulLED;
+ else
+ GPIO0_IOSET = ulLED;
+ }
+}
--- /dev/null
+#ifndef _CPU_H_
+#define _CPU_H_
+
+void cpuSetupHardware (void);
+void cpuPLLDisable (void);
+void cpuT1Disable (void);
+void cpuGPIOInitialize (void);
+void cpuToggleLED (unsigned portBASE_TYPE uxLED);
+
+#endif
--- /dev/null
+SRC_FILES=dac.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include "dac.h"
+
+//
+//
+//
+void dacInit (void)
+{
+ PCB_PINSEL1 |= PCB_PINSEL1_P025_AOUT;
+
+ DAC_CR = 0;
+}
+
+unsigned int dacSet (unsigned int newValue)
+{
+ unsigned int dacCR;
+ unsigned int dacCurrentValue;
+
+ dacCR = DAC_CR;
+ dacCurrentValue = (dacCR & DAC_CR_VALUEMASK) >> DAC_CR_VALUESHIFT;
+ dacCR = (dacCR & ~DAC_CR_VALUEMASK) | ((newValue << DAC_CR_VALUESHIFT) & DAC_CR_VALUEMASK);
+ DAC_CR = dacCR;
+
+ return dacCurrentValue;
+}
--- /dev/null
+#ifndef _DAC_H_
+#define _DAC_H_
+
+void dacInit (void);
+unsigned int dacSet (unsigned int newValue);
+
+#endif
--- /dev/null
+SRC_FILES=eints.c eintsISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "eints.h"
+#include "eintsISR.h"
+
+//
+//
+//
+void eintsInit (void)
+{
+ portENTER_CRITICAL ();
+
+ PCB_PINSEL1 |= PCB_PINSEL1_P016_EINT0;
+ PCB_PINSEL0 |= PCB_PINSEL0_P015_EINT2;
+
+ SCB_EXTPOLAR &= ~(SCB_EXTPOLAR_EINT0 | SCB_EXTPOLAR_EINT2);
+ SCB_EXTMODE |= (SCB_EXTMODE_EINT0 | SCB_EXTMODE_EINT2);
+ SCB_EXTINT |= (SCB_EXTINT_EINT0 | SCB_EXTINT_EINT2);
+
+ VIC_IntSelect &= ~(VIC_IntSelect_EINT0 | VIC_IntSelect_EINT2);
+ VIC_VectAddr4 = (portLONG) eintsISR_EINT0;
+ VIC_VectCntl4 = VIC_VectCntl_ENABLE | VIC_Channel_EINT0;
+ VIC_VectAddr5 = (portLONG) eintsISR_EINT2;
+ VIC_VectCntl5 = VIC_VectCntl_ENABLE | VIC_Channel_EINT2;
+ VIC_IntEnable = VIC_IntEnable_EINT0 | VIC_IntEnable_EINT2;
+
+ portEXIT_CRITICAL ();
+}
--- /dev/null
+#ifndef _EINTS_H_
+#define _EINTS_H_
+
+void eintsInit (void);
+
+#endif
--- /dev/null
+//
+//
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "eintsISR.h"
+
+//
+//
+//
+void eintsISR_EINT0 (void) __attribute__ ((naked));
+void eintsISR_EINT2 (void) __attribute__ ((naked));
+
+//
+//
+//
+void eintsISR_EINT0 (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ SCB_EXTINT |= SCB_EXTINT_EINT0;
+
+ GPIO0_IOSET = GPIO_IO_P11;
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ portEXIT_SWITCHING_ISR (0);
+}
+
+void eintsISR_EINT2 (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ SCB_EXTINT |= SCB_EXTINT_EINT1;
+
+ GPIO0_IOCLR = GPIO_IO_P11;
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ portEXIT_SWITCHING_ISR (0);
+}
--- /dev/null
+#ifndef _EINTSISR_H_
+#define _EINTSISR_H_
+
+void eintsISR_EINT0 (void);
+void eintsISR_EINT2 (void);
+
+#endif
--- /dev/null
+SRC_FILES=ff.c mmc.c spi.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*************************************************************************
+ *
+ * Used with ICCARM and AARM.
+ *
+ * (c) Copyright IAR Systems 2005
+ *
+ * File name : disk.h
+ * Description : Disk common definitions module
+ *
+ * History :
+ * 1. Data : November 15, 2005
+ * Author : Stanimir Bonev
+ * Description : Create
+ *
+ * $Revision: 1.4 $
+**************************************************************************/
+#ifndef _DISK_H_
+#define _DISK_H_
+
+#include "sysdefs.h"
+
+typedef enum
+{
+ DiskCommandPass = 0,
+ DiskNotReady,
+ DiskNotPresent,
+ DiskParametersError,
+ DiskMiscompareError,
+ DiskChanged,
+ DiskUknowError,
+}
+DiskStatusCode_t;
+
+typedef enum
+{
+ DiskWrite = 0,
+ DiskRead,
+ DiskVerify,
+}
+DiskIoRequest_t;
+
+typedef enum
+{
+ DiskInquiry = 0,
+ DiskFormatCapacity,
+}
+DiskInfoType_t;
+
+typedef enum
+{
+ DiskMMC,
+ DiskSD,
+ DiskUnknow,
+}
+DiskType_t;
+
+typedef struct
+{
+ U32 BlockNumb;
+ U32 BlockSize;
+ DiskStatusCode_t DiskStatus;
+ DiskType_t DiskType;
+ BOOL WriteProtect;
+ BOOL MediaChanged;
+}
+/* __attribute__ ((packed)) */ DiskStatus_t, *pDiskStatus_t;
+
+typedef void (* DiskInitFpnt_t) (void);
+typedef U32 (* DiskInfoFpnt_t) (U8 *, DiskInfoType_t);
+typedef pDiskStatus_t (* DiskStatusFpnt_t) (void);
+typedef DiskStatusCode_t (* DiskIoFpnt_t) (U8 *, U32, U32, DiskIoRequest_t);
+
+#endif
--- /dev/null
+/*-----------------------------------------------------------------------
+/ Low level disk interface modlue include file R0.04a (C)ChaN, 2007
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO_H_
+#define _DISKIO_H_
+
+//
+// Status of Disk Functions
+//
+typedef U8 DSTATUS;
+
+//
+// Results of Disk Functions
+//
+typedef enum
+{
+ RES_OK = 0, /* 0: Successful */
+ RES_ERROR, /* 1: R/W Error */
+ RES_WRPRT, /* 2: Write Protected */
+ RES_NOTRDY, /* 3: Not Ready */
+ RES_PARERR /* 4: Invalid Parameter */
+}
+DRESULT;
+
+//
+// Disk Status Bits (DSTATUS)
+//
+#define STA_NOINIT 0x01 /* Drive not initialized */
+#define STA_NODISK 0x02 /* No medium in the drive */
+#define STA_PROTECT 0x04 /* Write protected */
+
+//
+// Command code for disk_ioctl()
+//
+#define GET_SECTOR_COUNT 1
+#define GET_SECTOR_SIZE 2
+#define CTRL_SYNC 3
+#define CTRL_POWER 4
+#define CTRL_LOCK 5
+#define CTRL_EJECT 6
+#define MMC_GET_CSD 10
+#define MMC_GET_CID 11
+#define MMC_GET_OCR 12
+#define ATA_GET_REV 20
+#define ATA_GET_MODEL 21
+#define ATA_GET_SN 22
+
+//
+//
+//
+DSTATUS diskInitialize (U8);
+DSTATUS diskShutdown (void);
+DSTATUS diskStatus (U8);
+DRESULT diskRead (U8, U8 *, U32, U8);
+#if _FS_READONLY == 0
+DRESULT diskWrite (U8, const U8 *, U32, U8);
+#endif
+DRESULT diskIoctl (U8, U8, void *);
+
+#endif
--- /dev/null
+/*--------------------------------------------------------------------------/
+ / FatFs - FAT file system module R0.04b (C)ChaN, 2007
+ /---------------------------------------------------------------------------/
+ / The FatFs module is an experimenal project to implement FAT file system to
+ / cheap microcontrollers. This is a free software and is opened for education,
+ / research and development under license policy of following trems.
+ /
+ / Copyright (C) 2007, ChaN, all right reserved.
+ /
+ / * The FatFs module is a free software and there is no warranty.
+ / * You can use, modify and/or redistribute it for personal, non-profit or
+ / profit use without any restriction under your responsibility.
+ / * Redistributions of source code must retain the above copyright notice.
+ /
+ /---------------------------------------------------------------------------/
+ / Feb 26, 2006 R0.00 Prototype.
+ / Apr 29, 2006 R0.01 First stable version.
+ / Jun 01, 2006 R0.02 Added FAT12 support.
+ / Removed unbuffered mode.
+ / Fixed a problem on small (<32M) patition.
+ / Jun 10, 2006 R0.02a Added a configuration option (_FS_MINIMUM).
+ / Sep 22, 2006 R0.03 Added f_rename().
+ / Changed option _FS_MINIMUM to _FS_MINIMIZE.
+ / Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast.
+ / Fixed f_mkdir() creates incorrect directory on FAT32.
+ / Feb 04, 2007 R0.04 Supported multiple drive system.
+ / Changed some interfaces for multiple drive system.
+ / Changed f_mountdrv() to f_mount().
+ / Added f_mkfs().
+ / Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive.
+ / Added a capability of extending file size to f_lseek().
+ / Added minimization level 3.
+ / Fixed an endian sensitive code in f_mkfs().
+ / May 05, 2007 R0.04b Added a configuration option _USE_NTFLAG.
+ / Added FSInfo support.
+ / Fixed DBCS name can result FR_INVALID_NAME.
+ / Fixed short seek (<= csize) collapses the file object.
+ /---------------------------------------------------------------------------*/
+#include <stdio.h> // ###
+#include <string.h>
+#include "ff.h" /* FatFs declarations */
+#include "diskio.h" /* Include file for user provided disk functions */
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+ ---------------------------------------------------------------------------*/
+
+static FATFS *FatFs[_DRIVES]; /* Pointer to the file system objects (logical drives) */
+static U16 fsid; /* File system mount ID */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change window offset */
+/*-----------------------------------------------------------------------*/
+
+static
+BOOL move_window ( /* TRUE: successful, FALSE: failed */
+ FATFS *fs, /* File system object */
+ U32 sector /* Sector number to make apperance in the fs->win[] */
+ ) /* Move to zero only writes back dirty window */
+{
+ U32 wsect;
+
+
+ wsect = fs->winsect;
+ if (wsect != sector) { /* Changed current window */
+#if _FS_READONLY == 0
+ U8 n;
+ if (fs->winflag) { /* Write back dirty window if needed */
+ if (diskWrite(fs->drive, fs->win, wsect, 1) != RES_OK)
+ return FALSE;
+ fs->winflag = 0;
+ if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */
+ for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to FAT copy */
+ wsect += fs->sects_fat;
+ diskWrite(fs->drive, fs->win, wsect, 1);
+ }
+ }
+ }
+#endif
+ if (sector) {
+ if (diskRead(fs->drive, fs->win, sector, 1) != RES_OK)
+ return FALSE;
+ fs->winsect = sector;
+ }
+ }
+ return TRUE;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Clean-up cached data */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+FRESULT sync ( /* FR_OK: successful, FR_RW_ERROR: failed */
+ FATFS *fs /* File system object */
+ )
+{
+ fs->winflag = 1;
+ if (!move_window(fs, 0)) return FR_RW_ERROR;
+#if _USE_FSINFO
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { /* Update FSInfo sector if needed */
+ fs->winsect = 0;
+ memset(fs->win, 0, 512);
+ ST_U16(&fs->win[BS_55AA], 0xAA55);
+ ST_U32(&fs->win[FSI_LeadSig], 0x41615252);
+ ST_U32(&fs->win[FSI_StrucSig], 0x61417272);
+ ST_U32(&fs->win[FSI_Free_Count], fs->free_clust);
+ ST_U32(&fs->win[FSI_Nxt_Free], fs->last_clust);
+ diskWrite(0, fs->win, fs->fsi_sector, 1);
+ fs->fsi_flag = 0;
+ }
+#endif
+ if (diskIoctl(fs->drive, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR;
+ return FR_OK;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get a cluster status */
+/*-----------------------------------------------------------------------*/
+
+static
+U32 get_cluster ( /* 0,>=2: successful, 1: failed */
+ FATFS *fs, /* File system object */
+ U32 clust /* Cluster# to get the link information */
+ )
+{
+ U16 wc, bc;
+ U32 fatsect;
+
+
+ if (clust >= 2 && clust < fs->max_clust) { /* Valid cluster# */
+ fatsect = fs->fatbase;
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (U16)clust * 3 / 2;
+ if (!move_window(fs, fatsect + (bc / S_SIZ))) break;
+ wc = fs->win[bc & (S_SIZ - 1)]; bc++;
+ if (!move_window(fs, fatsect + (bc / S_SIZ))) break;
+ wc |= (U16)fs->win[bc & (S_SIZ - 1)] << 8;
+ return (clust & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+ case FS_FAT16 :
+ if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) break;
+ return LD_U16(&fs->win[((U16)clust * 2) & (S_SIZ - 1)]);
+
+ case FS_FAT32 :
+ if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) break;
+ return LD_U32(&fs->win[((U16)clust * 4) & (S_SIZ - 1)]) & 0x0FFFFFFF;
+ }
+ }
+
+ return 1; /* There is no cluster information, or an error occured */
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change a cluster status */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+BOOL put_cluster ( /* TRUE: successful, FALSE: failed */
+ FATFS *fs, /* File system object */
+ U32 clust, /* Cluster# to change */
+ U32 val /* New value to mark the cluster */
+ )
+{
+ U16 bc;
+ U8 *p;
+ U32 fatsect;
+
+
+ fatsect = fs->fatbase;
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (U16)clust * 3 / 2;
+ if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE;
+ p = &fs->win[bc & (S_SIZ - 1)];
+ *p = (clust & 1) ? ((*p & 0x0F) | ((U8)val << 4)) : (U8)val;
+ bc++;
+ fs->winflag = 1;
+ if (!move_window(fs, fatsect + (bc / S_SIZ))) return FALSE;
+ p = &fs->win[bc & (S_SIZ - 1)];
+ *p = (clust & 1) ? (U8)(val >> 4) : ((*p & 0xF0) | ((U8)(val >> 8) & 0x0F));
+ break;
+
+ case FS_FAT16 :
+ if (!move_window(fs, fatsect + (clust / (S_SIZ / 2)))) return FALSE;
+ ST_U16(&fs->win[((U16)clust * 2) & (S_SIZ - 1)], (U16)val);
+ break;
+
+ case FS_FAT32 :
+ if (!move_window(fs, fatsect + (clust / (S_SIZ / 4)))) return FALSE;
+ ST_U32(&fs->win[((U16)clust * 4) & (S_SIZ - 1)], val);
+ break;
+
+ default :
+ return FALSE;
+ }
+ fs->winflag = 1;
+ return TRUE;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Remove a cluster chain */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+BOOL remove_chain ( /* TRUE: successful, FALSE: failed */
+ FATFS *fs, /* File system object */
+ U32 clust /* Cluster# to remove chain from */
+ )
+{
+ U32 nxt;
+
+
+ while (clust >= 2 && clust < fs->max_clust) {
+ nxt = get_cluster(fs, clust);
+ if (nxt == 1) return FALSE;
+ if (!put_cluster(fs, clust, 0)) return FALSE;
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust++;
+#if _USE_FSINFO
+ fs->fsi_flag = 1;
+#endif
+ }
+ clust = nxt;
+ }
+ return TRUE;
+}
+#endif
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Stretch or create a cluster chain */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_READONLY == 0
+static
+U32 create_chain ( /* 0: no free cluster, 1: error, >=2: new cluster number */
+ FATFS *fs, /* File system object */
+ U32 clust /* Cluster# to stretch, 0 means create new */
+ )
+{
+ U32 cstat, ncl, scl, mcl = fs->max_clust;
+
+
+ if (clust == 0) { /* Create new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (scl == 0 || scl >= mcl) scl = 1;
+ }
+ else { /* Stretch existing chain */
+ cstat = get_cluster(fs, clust); /* Check the cluster status */
+ if (cstat < 2) return 1; /* It is an invalid cluster */
+ if (cstat < mcl) return cstat; /* It is already followed by next cluster */
+ scl = clust;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= mcl) { /* Wrap around */
+ ncl = 2;
+ if (ncl > scl) return 0; /* No free custer */
+ }
+ cstat = get_cluster(fs, ncl); /* Get the cluster status */
+ if (cstat == 0) break; /* Found a free cluster */
+ if (cstat == 1) return 1; /* Any error occured */
+ if (ncl == scl) return 0; /* No free custer */
+ }
+
+ if (!put_cluster(fs, ncl, 0x0FFFFFFF)) return 1; /* Mark the new cluster "in use" */
+ if (clust && !put_cluster(fs, clust, ncl)) return 1; /* Link it to previous one if needed */
+
+ fs->last_clust = ncl; /* Update fsinfo */
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+#if _USE_FSINFO
+ fs->fsi_flag = 1;
+#endif
+ }
+
+ return ncl; /* Return new cluster number */
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get sector# from cluster# */
+/*-----------------------------------------------------------------------*/
+
+static
+U32 clust2sect ( /* !=0: sector number, 0: failed - invalid cluster# */
+ FATFS *fs, /* File system object */
+ U32 clust /* Cluster# to be converted */
+ )
+{
+ clust -= 2;
+ if (clust >= (fs->max_clust - 2)) return 0; /* Invalid cluster# */
+ return clust * fs->sects_clust + fs->database;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Move directory pointer to next */
+/*-----------------------------------------------------------------------*/
+
+static
+BOOL next_dir_entry ( /* TRUE: successful, FALSE: could not move next */
+ DIR *dirobj /* Pointer to directory object */
+ )
+{
+ U32 clust;
+ U16 idx;
+ FATFS *fs = dirobj->fs;
+
+
+ idx = dirobj->index + 1;
+ if ((idx & ((S_SIZ - 1) / 32)) == 0) { /* Table sector changed? */
+ dirobj->sect++; /* Next sector */
+ if (!dirobj->clust) { /* In static table */
+ if (idx >= fs->n_rootdir) return FALSE; /* Reached to end of table */
+ } else { /* In dynamic table */
+ if (((idx / (S_SIZ / 32)) & (fs->sects_clust - 1)) == 0) { /* Cluster changed? */
+ clust = get_cluster(fs, dirobj->clust); /* Get next cluster */
+ if (clust < 2 || clust >= fs->max_clust) /* Reached to end of table */
+ return FALSE;
+ dirobj->clust = clust; /* Initialize for new cluster */
+ dirobj->sect = clust2sect(fs, clust);
+ }
+ }
+ }
+ dirobj->index = idx; /* Lower 4 bit of dirobj->index indicates offset in dirobj->sect */
+ return TRUE;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Get file status from directory entry */
+/*-----------------------------------------------------------------------*/
+
+#if _FS_MINIMIZE <= 1
+static
+void get_fileinfo ( /* No return code */
+ FILINFO *finfo, /* Ptr to store the file information */
+ const U8 *dir /* Ptr to the directory entry */
+ )
+{
+ U8 n, c, a;
+ char *p;
+
+
+ p = &finfo->fname[0];
+ a = _USE_NTFLAG ? dir[DIR_NTres] : 0; /* NT flag */
+ for (n = 0; n < 8; n++) { /* Convert file name (body) */
+ c = dir[n];
+ if (c == ' ') break;
+ if (c == 0x05) c = 0xE5;
+ if (a & 0x08 && c >= 'A' && c <= 'Z') c += 0x20;
+ *p++ = c;
+ }
+ if (dir[8] != ' ') { /* Convert file name (extension) */
+ *p++ = '.';
+ for (n = 8; n < 11; n++) {
+ c = dir[n];
+ if (c == ' ') break;
+ if (a & 0x10 && c >= 'A' && c <= 'Z') c += 0x20;
+ *p++ = c;
+ }
+ }
+ *p = '\0';
+
+ finfo->fattrib = dir[DIR_Attr]; /* Attribute */
+ finfo->fsize = LD_U32(&dir[DIR_FileSize]); /* Size */
+ finfo->fdate = LD_U16(&dir[DIR_WrtDate]); /* Date */
+ finfo->ftime = LD_U16(&dir[DIR_WrtTime]); /* Time */
+}
+#endif /* _FS_MINIMIZE <= 1 */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Pick a paragraph and create the name in format of directory entry */
+/*-----------------------------------------------------------------------*/
+
+static
+char make_dirfile ( /* 1: error - detected an invalid format, '\0'or'/': next character */
+ const char **path, /* Pointer to the file path pointer */
+ char *dirname /* Pointer to directory name buffer {Name(8), Ext(3), NT flag(1)} */
+ )
+{
+ U8 n, t, c, a, b;
+
+ memset(dirname, ' ', 8+3); /* Fill buffer with spaces */
+ a = 0; b = 0x18; /* NT flag */
+ n = 0; t = 8;
+
+ for (;;) {
+
+ c = *(*path)++;
+
+ if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */
+ if (n == 0) break;
+ dirname[11] = _USE_NTFLAG ? (a & b) : 0;
+ return c;
+ }
+ if (c <= ' ' || c == 0x7F) break; /* Reject invisible chars */
+ if (c == '.') {
+ if (!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */
+ n = 8; t = 11; continue;
+ }
+ break;
+ }
+ if (_USE_SJIS &&
+ ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */
+ (c >= 0xE0 && c <= 0xFC))) {
+ if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */
+ c = 0x05;
+ a ^= 1; goto md_l2;
+ }
+ if (c == '"') break; /* Reject " */
+ if (c <= ')') goto md_l1; /* Accept ! # $ % & ' ( ) */
+ if (c <= ',') break; /* Reject * + , */
+ if (c <= '9') goto md_l1; /* Accept - 0-9 */
+ if (c <= '?') break; /* Reject : ; < = > ? */
+ if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */
+ if (c == '|') break; /* Reject | */
+ if (c >= '[' && c <= ']') break;/* Reject [ \ ] */
+ if (_USE_NTFLAG && c >= 'A' && c <= 'Z')
+ (t == 8) ? (b &= ~0x08) : (b &= ~0x10);
+ if (c >= 'a' && c <= 'z') { /* Convert to upper case */
+ c -= 0x20;
+ if (_USE_NTFLAG) (t == 8) ? (a |= 0x08) : (a |= 0x10);
+ }
+ }
+md_l1:
+ a &= ~1;
+md_l2:
+ if (n >= t) break;
+ dirname[n++] = c;
+ }
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Trace a file path */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT trace_path ( /* FR_OK(0): successful, !=0: error code */
+ DIR *dirobj, /* Pointer to directory object to return last directory */
+ char *fn, /* Pointer to last segment name to return {file(8),ext(3),attr(1)} */
+ const char *path, /* Full-path string to trace a file or directory */
+ U8 **dir /* Directory pointer in Win[] to retutn */
+ )
+{
+ U32 clust;
+ char ds;
+ U8 *dptr = NULL;
+ FATFS *fs = dirobj->fs; /* Get logical drive from the given DIR structure */
+
+
+ /* Initialize directory object */
+ clust = fs->dirbase;
+ if (fs->fs_type == FS_FAT32) {
+ dirobj->clust = dirobj->sclust = clust;
+ dirobj->sect = clust2sect(fs, clust);
+ } else {
+ dirobj->clust = dirobj->sclust = 0;
+ dirobj->sect = clust;
+ }
+ dirobj->index = 0;
+
+ if (*path == '\0') { /* Null path means the root directory */
+ *dir = NULL; return FR_OK;
+ }
+
+ for (;;) {
+ ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */
+ if (ds == 1) return FR_INVALID_NAME;
+ for (;;) {
+ if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR;
+ dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32]; /* Pointer to the directory entry */
+ if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */
+ return !ds ? FR_NO_FILE : FR_NO_PATH;
+ if (dptr[DIR_Name] != 0xE5 /* Matched? */
+ && !(dptr[DIR_Attr] & AM_VOL)
+ && !memcmp(&dptr[DIR_Name], fn, 8+3) ) break;
+ if (!next_dir_entry(dirobj)) /* Next directory pointer */
+ return !ds ? FR_NO_FILE : FR_NO_PATH;
+ }
+ if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */
+ if (!(dptr[DIR_Attr] & AM_DIR)) return FR_NO_PATH; /* Cannot trace because it is a file */
+ clust = ((U32)LD_U16(&dptr[DIR_FstClusHI]) << 16) | LD_U16(&dptr[DIR_FstClusLO]); /* Get cluster# of the directory */
+ dirobj->clust = dirobj->sclust = clust; /* Restart scanning at the new directory */
+ dirobj->sect = clust2sect(fs, clust);
+ dirobj->index = 2;
+ }
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Reserve a directory entry */
+/*-----------------------------------------------------------------------*/
+
+#if !_FS_READONLY
+static
+FRESULT reserve_direntry ( /* FR_OK: successful, FR_DENIED: no free entry, FR_RW_ERROR: a disk error occured */
+ DIR *dirobj, /* Target directory to create new entry */
+ U8 **dir /* Pointer to pointer to created entry to retutn */
+ )
+{
+ U32 clust, sector;
+ U8 c, n, *dptr;
+ FATFS *fs = dirobj->fs;
+
+
+ /* Re-initialize directory object */
+ clust = dirobj->sclust;
+ if (clust) { /* Dyanmic directory table */
+ dirobj->clust = clust;
+ dirobj->sect = clust2sect(fs, clust);
+ } else { /* Static directory table */
+ dirobj->sect = fs->dirbase;
+ }
+ dirobj->index = 0;
+
+ do {
+ if (!move_window(fs, dirobj->sect)) return FR_RW_ERROR;
+ dptr = &fs->win[(dirobj->index & ((S_SIZ - 1) / 32)) * 32]; /* Pointer to the directory entry */
+ c = dptr[DIR_Name];
+ if (c == 0 || c == 0xE5) { /* Found an empty entry! */
+ *dir = dptr; return FR_OK;
+ }
+ } while (next_dir_entry(dirobj)); /* Next directory pointer */
+ /* Reached to end of the directory table */
+
+ /* Abort when static table or could not stretch dynamic table */
+ if (!clust || !(clust = create_chain(fs, dirobj->clust))) return FR_DENIED;
+ if (clust == 1 || !move_window(fs, 0)) return FR_RW_ERROR;
+
+ fs->winsect = sector = clust2sect(fs, clust); /* Cleanup the expanded table */
+ memset(fs->win, 0, S_SIZ);
+ for (n = fs->sects_clust; n; n--) {
+ if (diskWrite(fs->drive, fs->win, sector, 1) != RES_OK)
+ return FR_RW_ERROR;
+ sector++;
+ }
+ fs->winflag = 1;
+ *dir = fs->win;
+ return FR_OK;
+}
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Load boot record and check if it is a FAT boot record */
+/*-----------------------------------------------------------------------*/
+
+static
+U8 check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record or error */
+ FATFS *fs, /* File system object */
+ U32 sect /* Sector# (lba) to check if it is a FAT boot record or not */
+ )
+{
+ if (diskRead(fs->drive, fs->win, sect, 1) != RES_OK) /* Load boot record */
+ return 2;
+ if (LD_U16(&fs->win[BS_55AA]) != 0xAA55) /* Check record signature (always offset 510) */
+ return 2;
+
+ if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) /* Check FAT signature */
+ return 0;
+ if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80))
+ return 0;
+
+ return 1;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Make sure that the file system is valid */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT auto_mount ( /* FR_OK(0): successful, !=0: any error occured */
+ const char **path, /* Pointer to pointer to the path name (drive number) */
+ FATFS **rfs, /* Pointer to pointer to the found file system object */
+ U8 chk_wp /* !=0: Check media write protection for wrinting fuctions */
+ )
+{
+ U8 drv, fmt, *tbl;
+ DSTATUS stat;
+ U32 bootsect, fatsize, totalsect, maxclust;
+ const char *p = *path;
+ FATFS *fs;
+
+
+ /* Get drive number from the path name */
+ while (*p == ' ') p++; /* Strip leading spaces */
+ drv = p[0] - '0'; /* Is there a drive number? */
+ if (drv <= 9 && p[1] == ':')
+ p += 2; /* Found a drive number, get and strip it */
+ else
+ drv = 0; /* No drive number is given, select drive 0 in default */
+ if (*p == '/') p++; /* Strip heading slash */
+ *path = p; /* Return pointer to the path name */
+
+ /* Check if the drive number is valid or not */
+ if (drv >= _DRIVES) return FR_INVALID_DRIVE; /* Is the drive number valid? */
+ if (!(fs = FatFs[drv])) return FR_NOT_ENABLED; /* Is the file system object registered? */
+ *rfs = fs; /* Returen pointer to the corresponding file system object */
+
+ /* Check if the logical drive has been mounted or not */
+ if (fs->fs_type) {
+ stat = diskStatus(fs->drive);
+ if (!(stat & STA_NOINIT)) { /* If the physical drive is kept initialized */
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ return FR_OK; /* The file system object is valid */
+ }
+ }
+
+ /* The logical drive has not been mounted, following code attempts to mount the logical drive */
+
+ memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */
+ fs->drive = LD2PD(drv); /* Bind the logical drive and a physical drive */
+ stat = diskInitialize (fs->drive); /* Initialize low level disk I/O layer */
+ if (stat & STA_NOINIT) /* Check if the drive is ready */
+ return FR_NOT_READY;
+#if S_MAX_SIZ > 512 /* Check disk sector size */
+ if (diskIoctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK || S_SIZ > S_MAX_SIZ)
+ return FR_NO_FILESYSTEM;
+#endif
+#if !_FS_READONLY
+ if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */
+ return FR_WRITE_PROTECTED;
+#endif
+ /* Search FAT partition on the drive */
+ fmt = check_fs(fs, bootsect = 0); /* Check sector 0 as an SFD format */
+ if (fmt == 1) { /* Not a FAT boot record, it may be patitioned */
+ /* Check a partition listed in top of the partition table */
+ tbl = &fs->win[MBR_Table + LD2PT(drv) * 16]; /* Partition table */
+ if (tbl[4]) { /* Is the partition existing? */
+ bootsect = LD_U32(&tbl[8]); /* Partition offset in LBA */
+ fmt = check_fs(fs, bootsect); /* Check the partition */
+ }
+ }
+ if (fmt || LD_U16(&fs->win[BPB_BytsPerSec]) != S_SIZ) /* No valid FAT patition is found */
+ return FR_NO_FILESYSTEM;
+
+ /* Initialize the file system object */
+ fatsize = LD_U16(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */
+ if (!fatsize) fatsize = LD_U32(&fs->win[BPB_FATSz32]);
+ fs->sects_fat = fatsize;
+ fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FAT copies */
+ fatsize *= fs->n_fats; /* (Number of sectors in FAT area) */
+ fs->fatbase = bootsect + LD_U16(&fs->win[BPB_RsvdSecCnt]); /* FAT start sector (lba) */
+ fs->sects_clust = fs->win[BPB_SecPerClus]; /* Number of sectors per cluster */
+ fs->n_rootdir = LD_U16(&fs->win[BPB_RootEntCnt]); /* Nmuber of root directory entries */
+ totalsect = LD_U16(&fs->win[BPB_TotSec16]); /* Number of sectors on the file system */
+ if (!totalsect) totalsect = LD_U32(&fs->win[BPB_TotSec32]);
+ fs->max_clust = maxclust = (totalsect /* Last cluster# + 1 */
+ - LD_U16(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (S_SIZ/32)
+ ) / fs->sects_clust + 2;
+
+ fmt = FS_FAT12; /* Determine the FAT sub type */
+ if (maxclust > 0xFF7) fmt = FS_FAT16;
+ if (maxclust > 0xFFF7) fmt = FS_FAT32;
+ fs->fs_type = fmt;
+
+ if (fmt == FS_FAT32)
+ fs->dirbase = LD_U32(&fs->win[BPB_RootClus]); /* Root directory start cluster */
+ else
+ fs->dirbase = fs->fatbase + fatsize; /* Root directory start sector (lba) */
+ fs->database = fs->fatbase + fatsize + fs->n_rootdir / (S_SIZ/32); /* Data start sector (lba) */
+
+#if !_FS_READONLY
+ fs->free_clust = 0xFFFFFFFF;
+#if _USE_FSINFO
+ /* Load fsinfo sector if needed */
+ if (fmt == FS_FAT32) {
+ fs->fsi_sector = bootsect + LD_U16(&fs->win[BPB_FSInfo]);
+ if (diskRead(0, fs->win, fs->fsi_sector, 1) == RES_OK &&
+ LD_U16(&fs->win[BS_55AA]) == 0xAA55 &&
+ LD_U32(&fs->win[FSI_LeadSig]) == 0x41615252 &&
+ LD_U32(&fs->win[FSI_StrucSig]) == 0x61417272) {
+ fs->last_clust = LD_U32(&fs->win[FSI_Nxt_Free]);
+ fs->free_clust = LD_U32(&fs->win[FSI_Free_Count]);
+ }
+ }
+#endif
+#endif
+ fs->id = ++fsid; /* File system mount ID */
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Check if the file/dir object is valid or not */
+/*-----------------------------------------------------------------------*/
+
+static
+FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Not valid */
+ const FATFS *fs, /* Pointer to the file system object */
+ U16 id /* id member of the target object to be checked */
+ )
+{
+ if (!fs || fs->id != id)
+ return FR_INVALID_OBJECT;
+ if (diskStatus(fs->drive) & STA_NOINIT)
+ return FR_NOT_READY;
+
+ return FR_OK;
+}
+
+
+
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+ --------------------------------------------------------------------------*/
+
+
+void f_printerror (FRESULT f)
+{
+ unsigned int i;
+
+ typedef struct errorStrings_s
+ {
+ FRESULT fresult;
+ const char *string;
+ }
+ errorStrings_t;
+
+ static errorStrings_t errorStrings [] =
+ {
+ { FR_OK, "OK" },
+ { FR_NOT_READY, "NOT_READY" },
+ { FR_NO_FILE, "NO_FILE" },
+ { FR_NO_PATH, "NO_PATH" },
+ { FR_INVALID_NAME, "INVALID_NAME" },
+ { FR_INVALID_DRIVE, "INVALID_DRIVE" },
+ { FR_DENIED, "DENIED" },
+ { FR_EXIST, "EXIST" },
+ { FR_RW_ERROR, "RW_ERROR" },
+ { FR_WRITE_PROTECTED, "WRITE_PROTECTED" },
+ { FR_NOT_ENABLED, "NOT_ENABLED" },
+ { FR_NO_FILESYSTEM, "NO_FILESYSTEM" },
+ { FR_INVALID_OBJECT, "INVALID_OBJECT" },
+ { FR_MKFS_ABORTED, "MKFS_ABORTED" },
+ };
+
+ for (i = 0; i < arrsizeof (errorStrings); i++)
+ {
+ if (errorStrings [i].fresult == f)
+ {
+ printf ("rrc=%u FR_%s\n", f, errorStrings [f].string);
+ return;
+ }
+ }
+
+ printf ("rrc=%u (no text equivalent)\n", f);
+}
+
+
+/*-----------------------------------------------------------------------*/
+/* Mount/Unmount a Locical Drive */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mount (U8 drv, FATFS *fs)
+{
+ FATFS *fsobj;
+
+ if (drv >= _DRIVES)
+ return FR_INVALID_DRIVE;
+
+ fsobj = FatFs [drv];
+ FatFs [drv] = fs;
+
+ if (fsobj)
+ memset (fsobj, 0, sizeof (FATFS));
+ if (fs)
+ memset (fs, 0, sizeof (FATFS));
+
+ return FR_OK;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Open or Create a File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_open (
+ FIL *fp, /* Pointer to the blank file object */
+ const char *path, /* Pointer to the file name */
+ U8 mode /* Access mode and file open mode flags */
+ )
+{
+ FRESULT res;
+ U8 *dir;
+ DIR dirobj;
+ char fn[8+3+1];
+ FATFS *fs;
+
+
+ fp->fs = NULL;
+#if !_FS_READONLY
+ mode &= (FA_READ|FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW);
+ res = auto_mount(&path, &fs, (U8)(mode & (FA_WRITE|FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)));
+#else
+ mode &= FA_READ;
+ res = auto_mount(&path, &fs, 0);
+#endif
+ if (res != FR_OK) return res;
+ dirobj.fs = fs;
+
+ /* Trace the file path */
+ res = trace_path(&dirobj, fn, path, &dir);
+#if !_FS_READONLY
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS|FA_OPEN_ALWAYS|FA_CREATE_NEW)) {
+ U32 ps, rs;
+ if (res != FR_OK) { /* No file, create new */
+ if (res != FR_NO_FILE) return res;
+ res = reserve_direntry(&dirobj, &dir);
+ if (res != FR_OK) return res;
+ memset(dir, 0, 32); /* Initialize the new entry with open name */
+ memcpy(&dir[DIR_Name], fn, 8+3);
+ dir[DIR_NTres] = fn[11];
+ mode |= FA_CREATE_ALWAYS;
+ }
+ else { /* Any object is already existing */
+ if (mode & FA_CREATE_NEW) /* Cannot create new */
+ return FR_EXIST;
+ if (dir == NULL || (dir[DIR_Attr] & (AM_RDO|AM_DIR))) /* Cannot overwrite it (R/O or DIR) */
+ return FR_DENIED;
+ if (mode & FA_CREATE_ALWAYS) { /* Resize it to zero if needed */
+ rs = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]); /* Get start cluster */
+ ST_U16(&dir[DIR_FstClusHI], 0); /* cluster = 0 */
+ ST_U16(&dir[DIR_FstClusLO], 0);
+ ST_U32(&dir[DIR_FileSize], 0); /* size = 0 */
+ fs->winflag = 1;
+ ps = fs->winsect; /* Remove the cluster chain */
+ if (!remove_chain(fs, rs) || !move_window(fs, ps))
+ return FR_RW_ERROR;
+ fs->last_clust = rs - 1; /* Reuse the cluster hole */
+ }
+ }
+ if (mode & FA_CREATE_ALWAYS) {
+ dir[DIR_Attr] = AM_ARC; /* New attribute */
+ ps = get_fattime();
+ ST_U32(&dir[DIR_WrtTime], ps); /* Updated time */
+ ST_U32(&dir[DIR_CrtTime], ps); /* Created time */
+ fs->winflag = 1;
+ }
+ }
+ /* Open an existing file */
+ else {
+#endif /* !_FS_READONLY */
+ if (res != FR_OK) return res; /* Trace failed */
+ if (dir == NULL || (dir[DIR_Attr] & AM_DIR)) /* It is a directory */
+ return FR_NO_FILE;
+#if !_FS_READONLY
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ return FR_DENIED;
+ }
+
+ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dir;
+#endif
+ fp->flag = mode; /* File access mode */
+ fp->org_clust = /* File start cluster */
+ ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+ fp->fsize = LD_U32(&dir[DIR_FileSize]); /* File size */
+ fp->fptr = 0; /* File ptr */
+ fp->sect_clust = 1; /* Sector counter */
+ fp->fs = fs; fp->id = fs->id; /* Owner file system object of the file */
+
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_read (
+ FIL *fp, /* Pointer to the file object */
+ void *buff, /* Pointer to data buffer */
+ U16 btr, /* Number of bytes to read */
+ U16 *br /* Pointer to number of bytes read */
+ )
+{
+ U32 clust, sect, remain;
+ U16 rcnt;
+ U8 cc, *rbuff = buff;
+ FRESULT res;
+ FATFS *fs = fp->fs;
+
+
+ *br = 0;
+ res = validate(fs, fp->id); /* Check validity of the object */
+ if (res) return res;
+ if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */
+ if (!(fp->flag & FA_READ)) return FR_DENIED; /* Check access mode */
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain) btr = (U16)remain; /* Truncate read count by number of bytes left */
+
+ for ( ; btr; /* Repeat until all data transferred */
+ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr & (S_SIZ - 1)) == 0) { /* On the sector boundary */
+ if (--fp->sect_clust) { /* Decrement left sector counter */
+ sect = fp->curr_sect + 1; /* Get current sector */
+ } else { /* On the cluster boundary, get next cluster */
+ clust = (fp->fptr == 0) ?
+ fp->org_clust : get_cluster(fs, fp->curr_clust);
+ if (clust < 2 || clust >= fs->max_clust)
+ goto fr_error;
+ fp->curr_clust = clust; /* Current cluster */
+ sect = clust2sect(fs, clust); /* Get current sector */
+ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */
+ }
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */
+ if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+ goto fr_error;
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ fp->curr_sect = sect; /* Update current sector */
+ cc = btr / S_SIZ; /* When left bytes >= S_SIZ, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (cc > fp->sect_clust) cc = fp->sect_clust;
+ if (diskRead(fs->drive, rbuff, sect, cc) != RES_OK)
+ goto fr_error;
+ fp->sect_clust -= cc - 1;
+ fp->curr_sect += cc - 1;
+ rcnt = cc * S_SIZ; continue;
+ }
+ if (diskRead(fs->drive, fp->buffer, sect, 1) != RES_OK) /* Load the sector into file I/O buffer */
+ goto fr_error;
+ }
+ rcnt = S_SIZ - ((U16)fp->fptr & (S_SIZ - 1)); /* Copy fractional bytes from file I/O buffer */
+ if (rcnt > btr) rcnt = btr;
+ memcpy(rbuff, &fp->buffer[fp->fptr & (S_SIZ - 1)], rcnt);
+ }
+
+ return FR_OK;
+
+fr_error: /* Abort this file due to an unrecoverable error */
+ fp->flag |= FA__ERROR;
+ return FR_RW_ERROR;
+}
+
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Write File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_write (
+ FIL *fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ U16 btw, /* Number of bytes to write */
+ U16 *bw /* Pointer to number of bytes written */
+ )
+{
+ U32 clust, sect;
+ U16 wcnt;
+ U8 cc;
+ FRESULT res;
+ const U8 *wbuff = buff;
+ FATFS *fs = fp->fs;
+
+
+ *bw = 0;
+ res = validate(fs, fp->id); /* Check validity of the object */
+ if (res) return res;
+ if (fp->flag & FA__ERROR) return FR_RW_ERROR; /* Check error flag */
+ if (!(fp->flag & FA_WRITE)) return FR_DENIED; /* Check access mode */
+ if (fp->fsize + btw < fp->fsize) return FR_OK; /* File size cannot reach 4GB */
+
+ for ( ; btw; /* Repeat until all data transferred */
+ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ if ((fp->fptr & (S_SIZ - 1)) == 0) { /* On the sector boundary */
+ if (--fp->sect_clust) { /* Decrement left sector counter */
+ sect = fp->curr_sect + 1; /* Get current sector */
+ } else { /* On the cluster boundary, get next cluster */
+ if (fp->fptr == 0) { /* Is top of the file */
+ clust = fp->org_clust;
+ if (clust == 0) /* No cluster is created yet */
+ fp->org_clust = clust = create_chain(fs, 0); /* Create a new cluster chain */
+ } else { /* Middle or end of file */
+ clust = create_chain(fs, fp->curr_clust); /* Trace or streach cluster chain */
+ }
+ if (clust == 0) break; /* Disk full */
+ if (clust == 1 || clust >= fs->max_clust) goto fw_error;
+ fp->curr_clust = clust; /* Current cluster */
+ sect = clust2sect(fs, clust); /* Get current sector */
+ fp->sect_clust = fs->sects_clust; /* Re-initialize the left sector counter */
+ }
+ if (fp->flag & FA__DIRTY) { /* Flush file I/O buffer if needed */
+ if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+ goto fw_error;
+ fp->flag &= ~FA__DIRTY;
+ }
+ fp->curr_sect = sect; /* Update current sector */
+ cc = btw / S_SIZ; /* When left bytes >= S_SIZ, */
+ if (cc) { /* Write maximum contiguous sectors directly */
+ if (cc > fp->sect_clust) cc = fp->sect_clust;
+ if (diskWrite(fs->drive, wbuff, sect, cc) != RES_OK)
+ goto fw_error;
+ fp->sect_clust -= cc - 1;
+ fp->curr_sect += cc - 1;
+ wcnt = cc * S_SIZ; continue;
+ }
+ if (fp->fptr < fp->fsize && /* Fill sector buffer with file data if needed */
+ diskRead(fs->drive, fp->buffer, sect, 1) != RES_OK)
+ goto fw_error;
+ }
+ wcnt = S_SIZ - ((U16)fp->fptr & (S_SIZ - 1)); /* Copy fractional bytes to file I/O buffer */
+ if (wcnt > btw) wcnt = btw;
+ memcpy(&fp->buffer[fp->fptr & (S_SIZ - 1)], wbuff, wcnt);
+ fp->flag |= FA__DIRTY;
+ }
+
+ if (fp->fptr > fp->fsize) fp->fsize = fp->fptr; /* Update file size if needed */
+ fp->flag |= FA__WRITTEN; /* Set file changed flag */
+ return FR_OK;
+
+fw_error: /* Abort this file due to an unrecoverable error */
+ fp->flag |= FA__ERROR;
+ return FR_RW_ERROR;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Synchronize between File and Disk */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_sync (
+ FIL *fp /* Pointer to the file object */
+ )
+{
+ U32 tim;
+ U8 *dir;
+ FRESULT res;
+ FATFS *fs = fp->fs;
+
+
+ res = validate(fs, fp->id); /* Check validity of the object */
+ if (res == FR_OK) {
+ if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
+ /* Write back data buffer if needed */
+ if (fp->flag & FA__DIRTY) {
+ if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+ return FR_RW_ERROR;
+ fp->flag &= ~FA__DIRTY;
+ }
+ /* Update the directory entry */
+ if (!move_window(fs, fp->dir_sect))
+ return FR_RW_ERROR;
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_U32(&dir[DIR_FileSize], fp->fsize); /* Update file size */
+ ST_U16(&dir[DIR_FstClusLO], fp->org_clust); /* Update start cluster */
+ ST_U16(&dir[DIR_FstClusHI], fp->org_clust >> 16);
+ tim = get_fattime(); /* Updated time */
+ ST_U32(&dir[DIR_WrtTime], tim);
+ fp->flag &= ~FA__WRITTEN;
+ res = sync(fs);
+ }
+ }
+ return res;
+}
+
+#endif /* !_FS_READONLY */
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Close File */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_close (
+ FIL *fp /* Pointer to the file object to be closed */
+ )
+{
+ FRESULT res;
+
+
+#if !_FS_READONLY
+ res = f_sync(fp);
+#else
+ res = validate(fp->fs, fp->id);
+#endif
+ if (res == FR_OK)
+ fp->fs = NULL;
+ return res;
+}
+
+
+
+
+#if _FS_MINIMIZE <= 2
+/*-----------------------------------------------------------------------*/
+/* Seek File R/W Pointer */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_lseek (
+ FIL *fp, /* Pointer to the file object */
+ U32 ofs /* File pointer from top of file */
+ )
+{
+ U32 clust, csize;
+ U8 csect;
+ FRESULT res;
+ FATFS *fs = fp->fs;
+
+
+ res = validate(fs, fp->id); /* Check validity of the object */
+ if (res) return res;
+ if (fp->flag & FA__ERROR) return FR_RW_ERROR;
+#if !_FS_READONLY
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty buffer if needed */
+ if (diskWrite(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+ goto fk_error;
+ fp->flag &= ~FA__DIRTY;
+ }
+ if (ofs > fp->fsize && !(fp->flag & FA_WRITE))
+#else
+ if (ofs > fp->fsize)
+#endif
+ ofs = fp->fsize;
+ fp->fptr = 0; fp->sect_clust = 1; /* Set file R/W pointer to top of the file */
+
+ /* Move file R/W pointer if needed */
+ if (ofs) {
+ clust = fp->org_clust; /* Get start cluster */
+#if !_FS_READONLY
+ if (!clust) { /* If the file does not have a cluster chain, create new cluster chain */
+ clust = create_chain(fs, 0);
+ if (clust == 1) goto fk_error;
+ fp->org_clust = clust;
+ }
+#endif
+ if (clust) { /* If the file has a cluster chain, it can be followed */
+ csize = (U32)fs->sects_clust * S_SIZ; /* Cluster size in unit of byte */
+ for (;;) { /* Loop to skip leading clusters */
+ fp->curr_clust = clust; /* Update current cluster */
+ if (ofs <= csize) break;
+#if !_FS_READONLY
+ if (fp->flag & FA_WRITE) /* Check if in write mode or not */
+ clust = create_chain(fs, clust); /* Force streached if in write mode */
+ else
+#endif
+ clust = get_cluster(fs, clust); /* Only follow cluster chain if not in write mode */
+ if (clust == 0) { /* Stop if could not follow the cluster chain */
+ ofs = csize; break;
+ }
+ if (clust == 1 || clust >= fs->max_clust) goto fk_error;
+ fp->fptr += csize; /* Update R/W pointer */
+ ofs -= csize;
+ }
+ csect = (U8)((ofs - 1) / S_SIZ); /* Sector offset in the cluster */
+ fp->curr_sect = clust2sect(fs, clust) + csect; /* Current sector */
+ if ((ofs & (S_SIZ - 1)) && /* Load current sector if needed */
+ diskRead(fs->drive, fp->buffer, fp->curr_sect, 1) != RES_OK)
+ goto fk_error;
+ fp->sect_clust = fs->sects_clust - csect; /* Left sector counter in the cluster */
+ fp->fptr += ofs; /* Update file R/W pointer */
+ }
+ }
+#if !_FS_READONLY
+ if ((fp->flag & FA_WRITE) && fp->fptr > fp->fsize) { /* Set updated flag if in write mode */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+
+ return FR_OK;
+
+fk_error: /* Abort this file due to an unrecoverable error */
+ fp->flag |= FA__ERROR;
+ return FR_RW_ERROR;
+}
+
+
+
+
+#if _FS_MINIMIZE <= 1
+/*-----------------------------------------------------------------------*/
+/* Create a directroy object */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_opendir (
+ DIR *dirobj, /* Pointer to directory object to create */
+ const char *path /* Pointer to the directory path */
+ )
+{
+ U8 *dir;
+ char fn[8+3+1];
+ FRESULT res;
+ FATFS *fs;
+
+
+ res = auto_mount(&path, &fs, 0);
+ if (res != FR_OK) return res;
+ dirobj->fs = fs;
+
+ res = trace_path(dirobj, fn, path, &dir); /* Trace the directory path */
+ if (res == FR_OK) { /* Trace completed */
+ if (dir != NULL) { /* It is not the root dir */
+ if (dir[DIR_Attr] & AM_DIR) { /* The entry is a directory */
+ dirobj->clust = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+ dirobj->sect = clust2sect(fs, dirobj->clust);
+ dirobj->index = 2;
+ } else { /* The entry is not a directory */
+ res = FR_NO_FILE;
+ }
+ }
+ dirobj->id = fs->id;
+ }
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Directory Entry in Sequense */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_readdir (
+ DIR *dirobj, /* Pointer to the directory object */
+ FILINFO *finfo /* Pointer to file information to return */
+ )
+{
+ U8 *dir, c, res;
+ FATFS *fs = dirobj->fs;
+
+
+ res = validate(fs, dirobj->id); /* Check validity of the object */
+ if (res) return (FRESULT) res;
+
+ finfo->fname[0] = 0;
+ while (dirobj->sect) {
+ if (!move_window(fs, dirobj->sect))
+ return FR_RW_ERROR;
+ dir = &fs->win[(dirobj->index & ((S_SIZ - 1) >> 5)) * 32]; /* pointer to the directory entry */
+ c = *dir;
+ if (c == 0) break; /* Has it reached to end of dir? */
+ if (c != 0xE5 && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
+ get_fileinfo(finfo, dir);
+ if (!next_dir_entry(dirobj)) dirobj->sect = 0; /* Next entry */
+ if (finfo->fname[0]) break; /* Found valid entry */
+ }
+
+ return FR_OK;
+}
+
+
+
+
+#if _FS_MINIMIZE == 0
+/*-----------------------------------------------------------------------*/
+/* Get File Status */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_stat (
+ const char *path, /* Pointer to the file path */
+ FILINFO *finfo /* Pointer to file information to return */
+ )
+{
+ U8 *dir;
+ char fn[8+3+1];
+ FRESULT res;
+ DIR dirobj;
+ FATFS *fs;
+
+
+ res = auto_mount(&path, &fs, 0);
+ if (res != FR_OK) return res;
+ dirobj.fs = fs;
+
+ res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
+ if (res == FR_OK) { /* Trace completed */
+ if (dir) /* Found an object */
+ get_fileinfo(finfo, dir);
+ else /* It is root dir */
+ res = FR_INVALID_NAME;
+ }
+
+ return res;
+}
+
+
+
+#if !_FS_READONLY
+/*-----------------------------------------------------------------------*/
+/* Get Number of Free Clusters */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_getfree (
+ const char *drv, /* Logical drive number */
+ U32 *nclust, /* Pointer to the double word to return number of free clusters */
+ FATFS **fatfs /* Pointer to pointer to the file system object to return */
+ )
+{
+ U32 n, clust, sect;
+ U8 fat, f, *p;
+ FRESULT res;
+ FATFS *fs;
+
+
+ /* Get drive number */
+ res = auto_mount(&drv, &fs, 0);
+ if (res != FR_OK) return res;
+ *fatfs = fs;
+
+ /* If number of free cluster is valid, return it without cluster scan. */
+ if (fs->free_clust <= fs->max_clust - 2) {
+ *nclust = fs->free_clust;
+ return FR_OK;
+ }
+
+ /* Count number of free clusters */
+ fat = fs->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clust = 2;
+ do {
+ if ((U16)get_cluster(fs, clust) == 0) n++;
+ } while (++clust < fs->max_clust);
+ } else {
+ clust = fs->max_clust;
+ sect = fs->fatbase;
+ f = 0; p = 0;
+ do {
+ if (!f) {
+ if (!move_window(fs, sect++)) return FR_RW_ERROR;
+ p = fs->win;
+ }
+ if (fat == FS_FAT16) {
+ if (LD_U16(p) == 0) n++;
+ p += 2; f += 1;
+ } else {
+ if (LD_U32(p) == 0) n++;
+ p += 4; f += 2;
+ }
+ } while (--clust);
+ }
+ fs->free_clust = n;
+#if _USE_FSINFO
+ if (fat == FS_FAT32) fs->fsi_flag = 1;
+#endif
+
+ *nclust = n;
+ return FR_OK;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Delete a File or a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_unlink (
+ const char *path /* Pointer to the file or directory path */
+ )
+{
+ U8 *dir, *sdir;
+ U32 dclust, dsect;
+ char fn[8+3+1];
+ FRESULT res;
+ DIR dirobj;
+ FATFS *fs;
+
+
+ res = auto_mount(&path, &fs, 1);
+ if (res != FR_OK) return res;
+ dirobj.fs = fs;
+
+ res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
+ if (res != FR_OK) return res; /* Trace failed */
+ if (dir == NULL) return FR_INVALID_NAME; /* It is the root directory */
+ if (dir[DIR_Attr] & AM_RDO) return FR_DENIED; /* It is a R/O object */
+ dsect = fs->winsect;
+ dclust = ((U32)LD_U16(&dir[DIR_FstClusHI]) << 16) | LD_U16(&dir[DIR_FstClusLO]);
+
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a sub-directory */
+ dirobj.clust = dclust; /* Check if the sub-dir is empty or not */
+ dirobj.sect = clust2sect(fs, dclust);
+ dirobj.index = 2;
+ do {
+ if (!move_window(fs, dirobj.sect)) return FR_RW_ERROR;
+ sdir = &fs->win[(dirobj.index & ((S_SIZ - 1) >> 5)) * 32];
+ if (sdir[DIR_Name] == 0) break;
+ if (sdir[DIR_Name] != 0xE5 && !(sdir[DIR_Attr] & AM_VOL))
+ return FR_DENIED; /* The directory is not empty */
+ } while (next_dir_entry(&dirobj));
+ }
+
+ if (!move_window(fs, dsect)) return FR_RW_ERROR; /* Mark the directory entry 'deleted' */
+ dir[DIR_Name] = 0xE5;
+ fs->winflag = 1;
+ if (!remove_chain(fs, dclust)) return FR_RW_ERROR; /* Remove the cluster chain */
+
+ return sync(fs);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Create a Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_mkdir (
+ const char *path /* Pointer to the directory path */
+ )
+{
+ U8 *dir, *fw, n;
+ char fn[8+3+1];
+ U32 sect, dsect, dclust, pclust, tim;
+ FRESULT res;
+ DIR dirobj;
+ FATFS *fs;
+
+ res = auto_mount(&path, &fs, 1);
+ if (res != FR_OK) return res;
+ dirobj.fs = fs;
+
+ res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
+ if (res == FR_OK) return FR_EXIST; /* Any file or directory is already existing */
+ if (res != FR_NO_FILE) return res;
+
+ res = reserve_direntry(&dirobj, &dir); /* Reserve a directory entry */
+ if (res != FR_OK) return res;
+ sect = fs->winsect;
+
+ dclust = create_chain(fs, 0); /* Allocate a cluster for new directory table */
+ if (dclust == 1) return FR_RW_ERROR;
+
+ dsect = clust2sect(fs, dclust);
+ if (!dsect) return FR_DENIED;
+
+ if (!move_window(fs, dsect)) return FR_RW_ERROR;
+
+ fw = fs->win;
+ memset(fw, 0, S_SIZ); /* Clear the new directory table */
+ for (n = 1; n < fs->sects_clust; n++) {
+ if (diskWrite(fs->drive, fw, ++dsect, 1) != RES_OK)
+ return FR_RW_ERROR;
+ }
+ memset(&fw[DIR_Name], ' ', 8+3); /* Create "." entry */
+ fw[DIR_Name] = '.';
+ fw[DIR_Attr] = AM_DIR;
+ tim = get_fattime();
+ ST_U32(&fw[DIR_WrtTime], tim);
+ memcpy(&fw[32], &fw[0], 32); fw[33] = '.'; /* Create ".." entry */
+ pclust = dirobj.sclust;
+#if _FAT32
+ ST_U16(&fw[ DIR_FstClusHI], dclust >> 16);
+ if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) pclust = 0;
+ ST_U16(&fw[32+DIR_FstClusHI], pclust >> 16);
+#endif
+ ST_U16(&fw[ DIR_FstClusLO], dclust);
+ ST_U16(&fw[32+DIR_FstClusLO], pclust);
+ fs->winflag = 1;
+
+ if (!move_window(fs, sect)) return FR_RW_ERROR;
+ memset(&dir[0], 0, 32); /* Initialize the new entry */
+ memcpy(&dir[DIR_Name], fn, 8+3); /* Name */
+ dir[DIR_NTres] = fn[11];
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_U32(&dir[DIR_WrtTime], tim); /* Crated time */
+ ST_U16(&dir[DIR_FstClusLO], dclust); /* Table start cluster */
+ ST_U16(&dir[DIR_FstClusHI], dclust >> 16);
+
+ return sync(fs);
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Change File Attribute */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_chmod (
+ const char *path, /* Pointer to the file path */
+ U8 value, /* Attribute bits */
+ U8 mask /* Attribute mask to change */
+ )
+{
+ FRESULT res;
+ U8 *dir;
+ DIR dirobj;
+ char fn[8+3+1];
+ FATFS *fs;
+
+
+ res = auto_mount(&path, &fs, 1);
+ if (res == FR_OK) {
+ dirobj.fs = fs;
+ res = trace_path(&dirobj, fn, path, &dir); /* Trace the file path */
+ if (res == FR_OK) { /* Trace completed */
+ if (dir == NULL) {
+ res = FR_INVALID_NAME;
+ } else {
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (U8)~mask); /* Apply attribute change */
+ res = sync(fs);
+ }
+ }
+ }
+ return res;
+}
+
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Rename File/Directory */
+/*-----------------------------------------------------------------------*/
+
+FRESULT f_rename (
+ const char *path_old, /* Pointer to the old name */
+ const char *path_new /* Pointer to the new name */
+ )
+{
+ FRESULT res;
+ U32 sect_old;
+ U8 *dir_old, *dir_new, direntry[32-11];
+ DIR dirobj;
+ char fn[8+3+1];
+ FATFS *fs;
+
+
+ res = auto_mount(&path_old, &fs, 1);
+ if (res != FR_OK) return res;
+ dirobj.fs = fs;
+
+ res = trace_path(&dirobj, fn, path_old, &dir_old); /* Check old object */
+ if (res != FR_OK) return res; /* The old object is not found */
+ if (!dir_old) return FR_NO_FILE;
+ sect_old = fs->winsect; /* Save the object information */
+ memcpy(direntry, &dir_old[DIR_Attr], 32-11);
+
+ res = trace_path(&dirobj, fn, path_new, &dir_new); /* Check new object */
+ if (res == FR_OK) return FR_EXIST; /* The new object name is already existing */
+ if (res != FR_NO_FILE) return res; /* Is there no old name? */
+ res = reserve_direntry(&dirobj, &dir_new); /* Reserve a directory entry */
+ if (res != FR_OK) return res;
+
+ memcpy(&dir_new[DIR_Attr], direntry, 32-11); /* Create new entry */
+ memcpy(&dir_new[DIR_Name], fn, 8+3);
+ dir_new[DIR_NTres] = fn[11];
+ fs->winflag = 1;
+
+ if (!move_window(fs, sect_old)) return FR_RW_ERROR; /* Remove old entry */
+ dir_old[DIR_Name] = 0xE5;
+
+ return sync(fs);
+}
+
+
+
+#if _USE_MKFS
+/*-----------------------------------------------------------------------*/
+/* Create File System on the Drive */
+/*-----------------------------------------------------------------------*/
+
+#define N_ROOTDIR 512
+#define N_FATS 1
+#define MAX_SECTOR 64000000UL
+#define MIN_SECTOR 2000UL
+#define ERASE_BLK 32
+
+
+FRESULT f_mkfs (
+ U8 drv, /* Logical drive number */
+ U8 partition, /* Partitioning rule 0:FDISK, 1:SFD */
+ U8 allocsize /* Allocation unit size [sectors] */
+ )
+{
+ U8 fmt, m, *tbl;
+ U32 b_part, b_fat, b_dir, b_data; /* Area offset (LBA) */
+ U32 n_part, n_rsv, n_fat, n_dir; /* Area size */
+ U32 n_clust, n;
+ FATFS *fs;
+ DSTATUS stat;
+
+
+ /* Check and mounted drive and clear work area */
+ if (drv >= _DRIVES)
+ return FR_INVALID_DRIVE;
+
+ if (!(fs = FatFs [drv]))
+ return FR_NOT_ENABLED;
+
+ memset (fs, 0, sizeof(FATFS));
+ drv = LD2PD(drv);
+
+ /* Check validity of the parameters */
+ for (n = 1; n <= 64 && allocsize != n; n <<= 1)
+ ;
+ if (n > 64 || partition >= 2)
+ { // ###
+ // printf ("line %d: n > 64 || partition >= 2. n=%d, partition=%d\n", __LINE__, n, partition); // ###
+ return FR_MKFS_ABORTED;
+ } // ###
+
+ /* Get disk statics */
+ stat = diskInitialize (drv);
+
+ if (stat & STA_NOINIT)
+ return FR_NOT_READY;
+ if (stat & STA_PROTECT)
+ return FR_WRITE_PROTECTED;
+ { // ###
+ DRESULT dres; // ###
+ if ((dres = diskIoctl (drv, GET_SECTOR_COUNT, &n_part)) != RES_OK || n_part < MIN_SECTOR)
+ { // ###
+ // printf ("line %d: ioctl returned %d. n_part=%d, MIN_SECTOR=%d\n", __LINE__, dres, n_part, MIN_SECTOR); // ###
+ return FR_MKFS_ABORTED;
+ } // ###
+ } // ###
+
+ if (n_part > MAX_SECTOR)
+ n_part = MAX_SECTOR;
+
+ b_part = (!partition) ? 63 : 0;
+ n_part -= b_part;
+#if S_MAX_SIZ > 512 /* Check disk sector size */
+ if (diskIoctl(drv, GET_SECTOR_SIZE, &S_SIZ) != RES_OK
+ || S_SIZ > S_MAX_SIZ
+ || (U32)S_SIZ * allocsize > 32768U)
+ return FR_MKFS_ABORTED;
+#endif
+
+ /* Pre-compute number of clusters and FAT type */
+ n_clust = n_part / allocsize;
+ fmt = FS_FAT12;
+ if (n_clust >= 0xFF7) fmt = FS_FAT16;
+ if (n_clust >= 0xFFF7) fmt = FS_FAT32;
+ switch (fmt) {
+ case FS_FAT12:
+ n_fat = ((n_clust * 3 + 1) / 2 + 3 + S_SIZ - 1) / S_SIZ;
+ n_rsv = 1 + partition;
+ n_dir = N_ROOTDIR * 32 / S_SIZ;
+ break;
+ case FS_FAT16:
+ n_fat = ((n_clust * 2) + 4 + S_SIZ - 1) / S_SIZ;
+ n_rsv = 1 + partition;
+ n_dir = N_ROOTDIR * 32 / S_SIZ;
+ break;
+ default:
+ n_fat = ((n_clust * 4) + 8 + S_SIZ - 1) / S_SIZ;
+ n_rsv = 33 - partition;
+ n_dir = 0;
+ }
+ b_fat = b_part + n_rsv; /* FATs start sector */
+ b_dir = b_fat + n_fat * N_FATS; /* Directory start sector */
+ b_data = b_dir + n_dir; /* Data start sector */
+
+#ifdef ERASE_BLK
+ /* Round up data start sector to erase block boundary */
+ n = (b_data + ERASE_BLK - 1) & ~(ERASE_BLK - 1);
+ b_dir += n - b_data;
+ n_fat += (n - b_data) / N_FATS;
+#endif
+ /* Determine number of cluster and final check of validity of the FAT type */
+ n_clust = (n_part - n_rsv - n_fat * 2 - n_dir) / allocsize;
+ if ( (fmt == FS_FAT16 && n_clust < 0xFF7)
+ || (fmt == FS_FAT32 && n_clust < 0xFFF7))
+ { // ###
+ // printf ("line %d: fmt=%d, FS_FAT16=%d, FS_FAT32=%d, n_clust=0x%x\n", __LINE__, fmt, FS_FAT16, FS_FAT32, n_clust); // ###
+ return FR_MKFS_ABORTED;
+ } // ###
+
+ /* Create partition table if needed */
+ if (!partition) {
+ U32 n_disk = b_part + n_part;
+
+ tbl = &fs->win[MBR_Table];
+ ST_U32(&tbl[0], 0x00010180); /* Partition start in CHS */
+ if (n_disk < 63UL * 255 * 1024) { /* Partition end in CHS */
+ n_disk = n_disk / 63 / 255;
+ tbl[7] = (U8)n_disk;
+ tbl[6] = (U8)((n_disk >> 2) | 63);
+ } else {
+ ST_U16(&tbl[6], 0xFFFF);
+ }
+ tbl[5] = 254;
+ if (fmt != FS_FAT32) /* System ID */
+ tbl[4] = (n_part < 0x10000) ? 0x04 : 0x06;
+ else
+ tbl[4] = 0x0c;
+ ST_U32(&tbl[8], 63); /* Partition start in LBA */
+ ST_U32(&tbl[12], n_part); /* Partition size in LBA */
+ ST_U16(&tbl[64], 0xAA55); /* Signature */
+ if (diskWrite(drv, fs->win, 0, 1) != RES_OK)
+ return FR_RW_ERROR;
+ }
+
+ /* Create boot record */
+ memset(tbl = fs->win, 0, S_SIZ);
+ ST_U32(&tbl[BS_jmpBoot], 0x90FEEB); /* Boot code (jmp $, nop) */
+ ST_U16(&tbl[BPB_BytsPerSec], S_SIZ); /* Sector size */
+ tbl[BPB_SecPerClus] = (U8)allocsize; /* Sectors per cluster */
+ ST_U16(&tbl[BPB_RsvdSecCnt], n_rsv); /* Reserved sectors */
+ tbl[BPB_NumFATs] = N_FATS; /* Number of FATs */
+ ST_U16(&tbl[BPB_RootEntCnt], S_SIZ / 32 * n_dir); /* Number of rootdir entries */
+ if (n_part < 0x10000) { /* Number of total sectors */
+ ST_U16(&tbl[BPB_TotSec16], n_part);
+ } else {
+ ST_U32(&tbl[BPB_TotSec32], n_part);
+ }
+ tbl[BPB_Media] = 0xF8; /* Media descripter */
+ ST_U16(&tbl[BPB_SecPerTrk], 63); /* Number of sectors per track */
+ ST_U16(&tbl[BPB_NumHeads], 255); /* Number of heads */
+ ST_U32(&tbl[BPB_HiddSec], b_part); /* Hidden sectors */
+ if (fmt != FS_FAT32) {
+ ST_U16(&tbl[BPB_FATSz16], n_fat); /* Number of secters per FAT */
+ tbl[BS_DrvNum] = 0x80; /* Drive number */
+ tbl[BS_BootSig] = 0x29; /* Extended boot signature */
+ memcpy(&tbl[BS_VolLab], "NO NAME FAT ", 19); /* Volume lavel, FAT signature */
+ } else {
+ ST_U32(&tbl[BPB_FATSz32], n_fat); /* Number of secters per FAT */
+ ST_U32(&tbl[BPB_RootClus], 2); /* Root directory cluster (2) */
+ ST_U16(&tbl[BPB_FSInfo], 1); /* FSInfo record (bs+1) */
+ ST_U16(&tbl[BPB_BkBootSec], 6); /* Backup boot record (bs+6) */
+ tbl[BS_DrvNum32] = 0x80; /* Drive number */
+ tbl[BS_BootSig32] = 0x29; /* Extended boot signature */
+ memcpy(&tbl[BS_VolLab32], "NO NAME FAT32 ", 19); /* Volume lavel, FAT signature */
+ }
+ ST_U16(&tbl[BS_55AA], 0xAA55); /* Signature */
+ if (diskWrite(drv, tbl, b_part+0, 1) != RES_OK)
+ return FR_RW_ERROR;
+ if (fmt == FS_FAT32)
+ diskWrite(drv, tbl, b_part+6, 1);
+
+ /* Initialize FAT area */
+ for (m = 0; m < N_FATS; m++) {
+ memset(tbl, 0, S_SIZ); /* 1st sector of the FAT */
+ if (fmt != FS_FAT32) {
+ n = (fmt == FS_FAT12) ? 0x00FFFFF8 : 0xFFFFFFF8;
+ ST_U32(&tbl[0], n); /* Reserve cluster #0-1 (FAT12/16) */
+ } else {
+ ST_U32(&tbl[0], 0xFFFFFFF8); /* Reserve cluster #0-1 (FAT32) */
+ ST_U32(&tbl[4], 0xFFFFFFFF);
+ ST_U32(&tbl[8], 0x0FFFFFFF); /* Reserve cluster #2 for root dir */
+ }
+ if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_RW_ERROR;
+ memset(tbl, 0, S_SIZ); /* Following FAT entries are filled by zero */
+ for (n = 1; n < n_fat; n++) {
+ if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_RW_ERROR;
+ }
+ }
+
+ /* Initialize Root directory */
+ for (m = 0; m < 64; m++) {
+ if (diskWrite(drv, tbl, b_fat++, 1) != RES_OK)
+ return FR_RW_ERROR;
+ }
+
+ /* Create FSInfo record if needed */
+ if (fmt == FS_FAT32) {
+ ST_U16(&tbl[BS_55AA], 0xAA55);
+ ST_U32(&tbl[FSI_LeadSig], 0x41615252);
+ ST_U32(&tbl[FSI_StrucSig], 0x61417272);
+ ST_U32(&tbl[FSI_Free_Count], n_clust - 1);
+ ST_U32(&tbl[FSI_Nxt_Free], 0xFFFFFFFF);
+ diskWrite(drv, tbl, b_part+1, 1);
+ diskWrite(drv, tbl, b_part+7, 1);
+ }
+
+ return (diskIoctl(drv, CTRL_SYNC, NULL) == RES_OK) ? FR_OK : FR_RW_ERROR;
+}
+
+#endif /* _USE_MKFS */
+#endif /* !_FS_READONLY */
+#endif /* _FS_MINIMIZE == 0 */
+#endif /* _FS_MINIMIZE <= 1 */
+#endif /* _FS_MINIMIZE <= 2 */
+
--- /dev/null
+/*--------------------------------------------------------------------------/
+/ FatFs - FAT file system module include file R0.04b (C)ChaN, 2007
+/---------------------------------------------------------------------------/
+/ FatFs module is an experimenal project to implement FAT file system to
+/ cheap microcontrollers. This is a free software and is opened for education,
+/ research and development under license policy of following trems.
+/
+/ Copyright (C) 2007, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is no warranty.
+/ * You can use, modify and/or redistribute it for personal, non-profit or
+/ profit use without any restriction under your responsibility.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/---------------------------------------------------------------------------*/
+
+#ifndef _FATFS_H_
+#define _FATFS_H_
+
+#define _MCU_ENDIAN 2
+/* The _MCU_ENDIAN defines which access method is used to the FAT structure.
+/ 1: Enable word access.
+/ 2: Disable word access and use byte-by-byte access instead.
+/ When the architectural byte order of the MCU is big-endian and/or address
+/ miss-aligned access is prohibited, the _MCU_ENDIAN must be set to 2.
+/ If it is not the case, it can be set to 1 for good code efficiency. */
+
+#define _FS_READONLY 0
+/* Setting _FS_READONLY to 1 defines read only configuration. This removes
+/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename
+/ and useless f_getfree. */
+
+#define _FS_MINIMIZE 0
+/* The _FS_MINIMIZE option defines minimization level to remove some functions.
+/ 0: Full function.
+/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod and f_rename are removed.
+/ 2: f_opendir and f_readdir are removed in addition to level 1.
+/ 3: f_lseek is removed in addition to level 2. */
+
+#define _DRIVES 1
+/* Number of logical drives to be used. This affects the size of internal table. */
+
+#define _USE_MKFS 1
+/* When _USE_MKFS is set to 1 and _FS_READONLY is set to 0, f_mkfs function is
+/ enabled. */
+
+#define _MULTI_PARTITION 0
+/* When _MULTI_PARTITION is set to 0, each logical drive is bound to same
+/ physical drive number and can mount only 1st primaly partition. When it is
+/ set to 1, each logical drive can mount a partition listed in Drives[]. */
+
+#define _USE_FSINFO 1
+/* To enable FSInfo support on FAT32 volume, set _USE_FSINFO to 1. */
+
+#define _USE_SJIS 1
+/* When _USE_SJIS is set to 1, Shift-JIS code transparency is enabled, otherwise
+/ only US-ASCII(7bit) code can be accepted as file/directory name. */
+
+#define _USE_NTFLAG 1
+/* When _USE_NTFLAG is set to 1, upper/lower case of the file name is preserved.
+/ Note that the files are always accessed in case insensitive. */
+
+#include "sysdefs.h"
+
+//
+// Definitions corresponds to multiple sector size (not tested)
+//
+#define S_MAX_SIZ 512 /* Do not change */
+#if S_MAX_SIZ > 512
+#define S_SIZ (fs->s_size)
+#else
+#define S_SIZ 512
+#endif
+
+//
+// File system object structure
+//
+typedef struct _FATFS
+{
+ U16 id; /* File system mount ID */
+ U16 n_rootdir; /* Number of root directory entries */
+ U32 winsect; /* Current sector appearing in the win[] */
+ U32 sects_fat; /* Sectors per fat */
+ U32 max_clust; /* Maximum cluster# + 1 */
+ U32 fatbase; /* FAT start sector */
+ U32 dirbase; /* Root directory start sector (cluster# for FAT32) */
+ U32 database; /* Data start sector */
+#if _FS_READONLY == 0
+ U32 last_clust; /* Last allocated cluster */
+ U32 free_clust; /* Number of free clusters */
+#if _USE_FSINFO
+ U32 fsi_sector; /* fsinfo sector */
+ U8 fsi_flag; /* fsinfo dirty flag (1:must be written back) */
+ U8 pad2;
+#endif
+#endif
+ U8 fs_type; /* FAT sub type */
+ U8 sects_clust; /* Sectors per cluster */
+#if S_MAX_SIZ > 512
+ U16 s_size; /* Sector size */
+#endif
+ U8 n_fats; /* Number of FAT copies */
+ U8 drive; /* Physical drive number */
+ U8 winflag; /* win[] dirty flag (1:must be written back) */
+ U8 pad1;
+ U8 win[S_MAX_SIZ]; /* Disk access window for Directory/FAT */
+}
+/* __attribute__ ((packed)) */ FATFS;
+
+//
+// Directory object structure
+//
+typedef struct _DIR
+{
+ U16 id; /* Owner file system mount ID */
+ U16 index; /* Current index */
+ FATFS* fs; /* Pointer to the owner file system object */
+ U32 sclust; /* Start cluster */
+ U32 clust; /* Current cluster */
+ U32 sect; /* Current sector */
+}
+/* __attribute__ ((packed)) */ DIR;
+
+//
+// File object structure
+//
+typedef struct _FIL
+{
+ U16 id; /* Owner file system mount ID */
+ U8 flag; /* File status flags */
+ U8 sect_clust; /* Left sectors in cluster */
+ FATFS* fs; /* Pointer to the owner file system object */
+ U32 fptr; /* File R/W pointer */
+ U32 fsize; /* File size */
+ U32 org_clust; /* File start cluster */
+ U32 curr_clust; /* Current cluster */
+ U32 curr_sect; /* Current sector */
+#if _FS_READONLY == 0
+ U32 dir_sect; /* Sector containing the directory entry */
+ U8* dir_ptr; /* Ponter to the directory entry in the window */
+#endif
+ U8 buffer [S_MAX_SIZ]; /* File R/W buffer */
+}
+/* __attribute__ ((packed)) */ FIL;
+
+//
+// File status structure
+//
+typedef struct _FILINFO
+{
+ U32 fsize; /* Size */
+ U16 fdate; /* Date */
+ U16 ftime; /* Time */
+ U8 fattrib; /* Attribute */
+ char fname [8+1+3+1]; /* Name (8.3 format) */
+}
+/* __attribute__ ((packed)) */ FILINFO;
+
+//
+// Definitions corresponds to multi partition
+//
+#if _MULTI_PARTITION != 0 /* Multiple partition cfg */
+
+typedef struct _PARTITION
+{
+ U8 pd; /* Physical drive # (0-255) */
+ U8 pt; /* Partition # (0-3) */
+}
+/* __attribute__ ((packed)) */ PARTITION;
+
+extern const PARTITION Drives []; /* Logical drive# to physical location conversion table */
+#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
+#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
+
+#else /* Single partition cfg */
+
+#define LD2PD(drv) (drv) /* Physical drive# is equal to logical drive# */
+#define LD2PT(drv) 0 /* Always mounts the 1st partition */
+
+#endif
+
+//
+// File function return code (FRESULT)
+//
+typedef enum
+{
+ FR_OK = 0, /* 0 */
+ FR_NOT_READY, /* 1 */
+ FR_NO_FILE, /* 2 */
+ FR_NO_PATH, /* 3 */
+ FR_INVALID_NAME, /* 4 */
+ FR_INVALID_DRIVE, /* 5 */
+ FR_DENIED, /* 6 */
+ FR_EXIST, /* 7 */
+ FR_RW_ERROR, /* 8 */
+ FR_WRITE_PROTECTED, /* 9 */
+ FR_NOT_ENABLED, /* 10 */
+ FR_NO_FILESYSTEM, /* 11 */
+ FR_INVALID_OBJECT, /* 12 */
+ FR_MKFS_ABORTED /* 13 */
+}
+FRESULT;
+
+//
+// FatFs module application interface
+//
+void f_printerror (FRESULT f); /* Print error code */
+FRESULT f_mount (U8, FATFS*); /* Mount/Unmount a logical drive */
+FRESULT f_open (FIL*, const char*, U8); /* Open or create a file */
+FRESULT f_read (FIL*, void*, U16, U16*); /* Read data from a file */
+FRESULT f_write (FIL*, const void*, U16, U16*); /* Write data to a file */
+FRESULT f_lseek (FIL*, U32); /* Move file pointer of a file object */
+FRESULT f_close (FIL*); /* Close an open file object */
+FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */
+FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
+FRESULT f_stat (const char*, FILINFO*); /* Get file status */
+FRESULT f_getfree (const char*, U32*, FATFS**); /* Get number of free clusters on the drive */
+FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
+FRESULT f_unlink (const char*); /* Delete an existing file or directory */
+FRESULT f_mkdir (const char*); /* Create a new directory */
+FRESULT f_chmod (const char*, U8, U8); /* Change file/dir attriburte */
+FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */
+FRESULT f_mkfs (U8, U8, U8); /* Create a file system on the drive */
+
+//
+// User defined function to give a current time to fatfs module
+//
+U32 get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
+ /* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
+
+//
+// File access control and file status flags (FIL.flag)
+//
+#define FA_OPEN_EXISTING 0x00
+#define FA_READ 0x01
+#if _FS_READONLY == 0
+#define FA_WRITE 0x02
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA__WRITTEN 0x20
+#define FA__DIRTY 0x40
+#endif
+#define FA__ERROR 0x80
+
+//
+// FAT sub type (FATFS.fs_type)
+//
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+
+//
+// File attribute bits for directory entry
+//
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+
+//
+// Offset of FAT structure members
+//
+#define BS_jmpBoot 0
+#define BS_OEMName 3
+#define BPB_BytsPerSec 11
+#define BPB_SecPerClus 13
+#define BPB_RsvdSecCnt 14
+#define BPB_NumFATs 16
+#define BPB_RootEntCnt 17
+#define BPB_TotSec16 19
+#define BPB_Media 21
+#define BPB_FATSz16 22
+#define BPB_SecPerTrk 24
+#define BPB_NumHeads 26
+#define BPB_HiddSec 28
+#define BPB_TotSec32 32
+#define BS_55AA 510
+
+#define BS_DrvNum 36
+#define BS_BootSig 38
+#define BS_VolID 39
+#define BS_VolLab 43
+#define BS_FilSysType 54
+
+#define BPB_FATSz32 36
+#define BPB_ExtFlags 40
+#define BPB_FSVer 42
+#define BPB_RootClus 44
+#define BPB_FSInfo 48
+#define BPB_BkBootSec 50
+#define BS_DrvNum32 64
+#define BS_BootSig32 66
+#define BS_VolID32 67
+#define BS_VolLab32 71
+#define BS_FilSysType32 82
+
+#define FSI_LeadSig 0
+#define FSI_StrucSig 484
+#define FSI_Free_Count 488
+#define FSI_Nxt_Free 492
+
+#define MBR_Table 446
+
+#define DIR_Name 0
+#define DIR_Attr 11
+#define DIR_NTres 12
+#define DIR_CrtTime 14
+#define DIR_CrtDate 16
+#define DIR_FstClusHI 20
+#define DIR_WrtTime 22
+#define DIR_WrtDate 24
+#define DIR_FstClusLO 26
+#define DIR_FileSize 28
+
+//
+// Multi-byte word access macros
+//
+#if _MCU_ENDIAN == 1 /* Use word access */
+#define LD_U16(ptr) (U16)(*(U16*)(U8*)(ptr))
+#define LD_U32(ptr) (U32)(*(U32*)(U8*)(ptr))
+#define ST_U16(ptr,val) *(U16*)(U8*)(ptr)=(U16)(val)
+#define ST_U32(ptr,val) *(U32*)(U8*)(ptr)=(U32)(val)
+#else
+#if _MCU_ENDIAN == 2 /* Use byte-by-byte access */
+#define LD_U16(ptr) (U16)(((U16)*(U8*)((ptr)+1)<<8)|(U16)*(U8*)(ptr))
+#define LD_U32(ptr) (U32)(((U32)*(U8*)((ptr)+3)<<24)|((U32)*(U8*)((ptr)+2)<<16)|((U16)*(U8*)((ptr)+1)<<8)|*(U8*)(ptr))
+#define ST_U16(ptr,val) *(U8*)(ptr)=(U8)(val); *(U8*)((ptr)+1)=(U8)((U16)(val)>>8)
+#define ST_U32(ptr,val) *(U8*)(ptr)=(U8)(val); *(U8*)((ptr)+1)=(U8)((U16)(val)>>8); *(U8*)((ptr)+2)=(U8)((U32)(val)>>16); *(U8*)((ptr)+3)=(U8)((U32)(val)>>24)
+#else
+#error Do not forget to set _MCU_ENDIAN properly!
+#endif
+#endif
+
+#endif
--- /dev/null
+/*************************************************************************
+ *
+ * Used with ICCARM and AARM.
+ *
+ * (c) Copyright IAR Systems 2005
+ *
+ * File name : mmc.c
+ * Description : MMC
+ *
+ * History :
+ * 1. Data : July 1, 2005
+ * Author : Stanimir Bonev
+ * Description : Create
+ *
+ * $Revision: 1.4 $
+ *
+ * (C) Joel Winarske, 2006,2007
+**************************************************************************/
+#include <stdio.h> // ###
+#include "disk.h"
+#include "diskio.h"
+#include "mmc.h"
+#include "spi.h"
+
+#define MMC_RET_ERROR(Res) do { mmcLastError = Res; return (MmcCardError); } while (0)
+#define MMC_RET_DATA_ERR(Res) do { mmcLastError = Res; return (MmcDataError); } while (0)
+
+#define CSD_GET_TRAN_SPEED_EXP() (mmcSdCsd [ 3] & 0x07)
+#define CSD_GET_TRAN_SPEED_MANT() ((mmcSdCsd [ 3] & 0xF8) >> 3)
+#define CSD_GET_NSAC() (mmcSdCsd [ 2])
+#define CSD_GET_TAAC_EXP() (mmcSdCsd [ 1] & 0x7)
+#define CSD_GET_TAAC_MANT() ((mmcSdCsd [ 1] & 0xF8) >> 3)
+#define CSD_GET_R2W_FACTOR() ((mmcSdCsd [12] & 0x1C) >> 2)
+#define CSD_GET_READ_BL_LEN() (mmcSdCsd [ 5] & 0x0F)
+#define CSD_GET_C_SIZE() (((mmcSdCsd [ 6] & 0x03) << 10) + (mmcSdCsd [7] << 2) + ((mmcSdCsd [8] & 0xc0) >> 6))
+#define CSD_GET_C_SIZE_MULT() (((mmcSdCsd [ 9] & 0x03) << 1) + ((mmcSdCsd [10] & 0x80) >> 7))
+#define CSD_GET_PERM_WRITE_PROTECT() ((mmcSdCsd [14] & 0x20) >> 5)
+#define CSD_GET_TMP_WRITE_PROTECT() ((mmcSdCsd [14] & 0x10) >> 4)
+
+static const U32 mmcTransfExp [] =
+{
+ 10000UL,
+ 100000UL,
+ 1000000UL,
+ 10000000UL,
+ 0UL,
+ 0UL,
+ 0UL,
+ 0UL,
+};
+
+static const U32 mmmcAccessTime [] =
+{
+ 10000000UL,
+ 1000000UL,
+ 100000UL,
+ 10000UL,
+ 1000UL,
+ 100UL,
+ 10UL,
+ 1UL,
+};
+
+static const U32 mmcCsdMant [] =
+{
+ 0UL,10UL,12UL,13UL,15UL,
+ 20UL,25UL,
+ 30UL,35UL,
+ 40UL,45UL,
+ 50UL,55UL,
+ 60UL,
+ 70UL,
+ 80UL,
+};
+
+static const U32 mmcAccessTimeMant [] =
+{
+ 0UL,100UL,83UL,77UL,67UL,
+ 50UL,40UL,
+ 33UL,29UL,
+ 25UL,22UL,
+ 20UL,18UL,
+ 17UL,
+ 14UL,
+ 13UL,
+};
+
+static const mmcCommads_t mmcCmd [CMD_END] =
+{
+ { 0x40, MmcNoArg, MmcR1 }, // CMD0
+ { 0x41, MmcNoArg, MmcR1 }, // CMD1
+ { 0x49, MmcNoArg, MmcR1 }, // CMD9
+ { 0x4A, MmcNoArg, MmcR1 }, // CMD10
+ { 0x4C, MmcNoArg, MmcR1 }, // CMD12
+ { 0x4D, MmcNoArg, MmcR2 }, // CMD13
+ { 0x50, MmcBlockLen, MmcR1 }, // CMD16
+ { 0x51, MmcDataAdd, MmcR1 }, // CMD17
+ { 0x52, MmcDataAdd, MmcR1 }, // CMD18
+ { 0x58, MmcDataAdd, MmcR1 }, // CMD24
+ { 0x59, MmcDataAdd, MmcR1 }, // CMD25
+ { 0x5B, MmcNoArg, MmcR1 }, // CMD27
+ { 0x5C, MmcDataAdd, MmcR1b}, // CMD28
+ { 0x5D, MmcDataAdd, MmcR1b}, // CMD29
+ { 0x5E, MmcDataAdd, MmcR1 }, // CMD30
+ { 0x60, MmcDataAdd, MmcR1 }, // CMD32
+ { 0x61, MmcDataAdd, MmcR1 }, // CMD33
+ { 0x62, MmcDataAdd, MmcR1 }, // CMD34
+ { 0x63, MmcDataAdd, MmcR1 }, // CMD35
+ { 0x64, MmcDataAdd, MmcR1 }, // CMD36
+ { 0x65, MmcDataAdd, MmcR1 }, // CMD37
+ { 0x66, MmcDummyWord, MmcR1b}, // CMD38
+ { 0x6A, MmcDummyWord, MmcR1b}, // CMD42
+ { 0x77, MmcNoArg, MmcR1 }, // CMD55
+ { 0x78, MmcNoArg, MmcR1 }, // CMD56
+ { 0x7A, MmcNoArg, MmcR3 }, // CMD58
+ { 0x7B, MmcDummyWord, MmcR1 }, // CMD59
+ { 0x69, MmcNoArg, MmcR1 } // ACMD41
+};
+
+static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
+static DiskStatus_t mmcDskStatus;
+static U32 mmcLastError;
+static U32 Tnac;
+static U32 Twr;
+static U8 mmcSdCsd [16];
+
+//
+//
+//
+static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg);
+static U32 mmcSetBlockLen (U32 length);
+static void mmcCSDImplement (void);
+static mmcState_t mmcInitMedia (void);
+static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command);
+static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length);
+static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length);
+static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length);
+
+/*************************************************************************
+ * Function Name: mmcSendCmd
+ * Parameters: MmcSpiCmdInd_t ComdInd,U32 Arg
+ *
+ * Return: U32
+ *
+ * Description: MMC commands implemet
+ *
+ *************************************************************************/
+static U32 mmcSendCmd (mmcSpiCmdInd_t ComdInd, U32 Arg)
+{
+ U32 ch = 0xff;
+ U32 i;
+
+ //
+ // Chip Select
+ //
+ spiChipSelect (1);
+
+ //
+ // Send command code
+ //
+ spiTransferByte (mmcCmd [ComdInd].TxData);
+
+ //
+ // Send command's arguments
+ //
+ if (mmcCmd [ComdInd].Arg == MmcNoArg)
+ {
+ spiTransferByte (0x00);
+ spiTransferByte (0x00);
+ spiTransferByte (0x00);
+ spiTransferByte (0x00);
+ }
+ else
+ {
+ spiTransferByte (Arg >> 24);
+ spiTransferByte (Arg >> 16);
+ spiTransferByte (Arg >> 8);
+ spiTransferByte (Arg);
+ }
+
+ //
+ // Send CRC
+ //
+ if (ComdInd == CMD0)
+ spiTransferByte (0x95);
+ else
+ spiTransferByte (0xff);
+
+ for (i = 9; i && (ch == 0xff); --i)
+ ch = spiTransferByte (0xff);
+
+ if (i == 0)
+ {
+ spiChipSelect (0);
+ return ((U32) -1);
+ }
+
+ switch (mmcCmd [ComdInd].Resp)
+ {
+ case MmcR1b :
+ {
+ U32 busy;
+
+ for (busy = 0, i = Twr; i && (busy != 0xff); --i)
+ busy = spiTransferByte (0xff);
+ }
+ return (ch);
+
+ case MmcR1 :
+ return (ch);
+
+ case MmcR2 :
+ Arg = ((U32) ch << 8) & 0x0000FF00;
+ Arg |= spiTransferByte (0xff) & 0xff;
+ return (Arg);
+
+ case MmcR3 :
+ default:
+ Arg = ((U32) ch << 24) & 0xff000000;
+ Arg |= ((U32) spiTransferByte (0xff) << 16) & 0x00FF0000;
+ Arg |= ((U32) spiTransferByte (0xff) << 8 ) & 0x0000FF00;
+ Arg |= spiTransferByte (0xff) & 0xff;
+ return (Arg);
+ }
+}
+
+/*************************************************************************
+ * Function Name: mmcSetBlockLen
+ * Parameters: U32 Length
+ *
+ * Return: U32
+ *
+ * Description: Set Block length Return command's result
+ *
+ *************************************************************************/
+static U32 mmcSetBlockLen (U32 length)
+{
+ U32 res = mmcSendCmd (CMD16, length);
+ spiChipSelect (0);
+ return (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcCSDImplement
+ * Parameters: none
+ *
+ * Return: none
+ *
+ * Description: Implemet data from CSD
+ *
+ *************************************************************************/
+static void mmcCSDImplement (void)
+{
+ U32 frequency;
+
+ //
+ // Calculate SPI max clock
+ //
+ frequency = mmcTransfExp [CSD_GET_TRAN_SPEED_EXP ()] * mmcCsdMant [CSD_GET_TRAN_SPEED_MANT ()];
+
+ if (frequency > 20000000)
+ frequency = 20000000;
+
+ frequency = spiSetClockFreq (frequency);
+
+ if (mmcDskStatus.DiskType == DiskMMC)
+ {
+ Tnac = mmmcAccessTime [CSD_GET_TAAC_EXP ()] * mmcAccessTimeMant [CSD_GET_TAAC_MANT ()];
+ Tnac = frequency / Tnac;
+ Tnac += 1 << (CSD_GET_NSAC () + 4);
+ Tnac *= 10;
+ Twr = Tnac * CSD_GET_R2W_FACTOR ();
+ }
+ else
+ {
+ Tnac = frequency / SD_READ_TIME_OUT;
+ Twr = frequency / SD_WRITE_TIME_OUT;
+ }
+
+ mmcDskStatus.BlockSize = 1 << CSD_GET_READ_BL_LEN ();
+ mmcDskStatus.BlockNumb = (CSD_GET_C_SIZE () + 1) * (4 << CSD_GET_C_SIZE_MULT ());
+ mmcDskStatus.WriteProtect = spiWriteProtect () | CSD_GET_PERM_WRITE_PROTECT () | CSD_GET_TMP_WRITE_PROTECT ();
+}
+
+/*************************************************************************
+ * Function Name: mmcInitMedia
+ * Parameters: none
+ *
+ * Return: mmcState_t
+ *
+ * Description: MMC detect and initialize
+ *
+ *************************************************************************/
+static mmcState_t mmcInitMedia (void)
+{
+ U32 i;
+ U32 res;
+
+ Tnac = 1;
+
+ if (!spiPresent ())
+ return (MmcNoPresent);
+
+ //
+ // Clock Freq. Identification Mode < 400kHz
+ //
+ spiSetClockFreq (IdentificationModeClock);
+
+ //
+ // Set maximum time out
+ //
+ Tnac = IdentificationModeClock / SD_READ_TIME_OUT;
+
+ //
+ // Power up cycles. After power up at least 74 clock cycles are required
+ // prior to starting bus communication
+ //
+ for (i = 0; i < 2; i++)
+ {
+ spiChipSelect (0);
+
+ for (res = 10; res; --res)
+ spiTransferByte (0xff);
+
+ //
+ // CMD0 (Go to IDLE) to put MMC in SPI mode
+ //
+ res = mmcSendCmd (CMD0, 0);
+ spiChipSelect (0);
+
+ if (res == MMC_IDLE_STATE)
+ break;
+ }
+
+ if (res != MMC_IDLE_STATE)
+ return (MmcNoResponse);
+
+ //
+ // Determinate Card type SD or MMC
+ //
+ mmcDskStatus.DiskType = DiskMMC;
+
+ for (i = 100; i; --i)
+ {
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+ res = mmcSendCmd (CMD55, 0);
+ spiChipSelect (0);
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+ res = mmcSendCmd (ACMD41, 0);
+ spiChipSelect (0);
+
+ if (res & MMC_ILLEGAL_CMD)
+ {
+ //
+ // MMC card may be CMD1 for MMC Init sequence will be complete within 500ms
+ //
+ for (i = 100; i; --i)
+ {
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+ res = mmcSendCmd (CMD1, 0);
+ spiChipSelect (0);
+
+ if (res == MMC_OK)
+ break;
+
+ spiDelay1ms (50);
+ }
+ break;
+ }
+
+ if (res == MMC_OK)
+ {
+ mmcDskStatus.DiskType = DiskSD;
+ break;
+ }
+
+ spiDelay1ms (50);
+ }
+
+ if (i == 0)
+ return (MmcNoResponse);
+
+ //
+ // Read CSD. CSD must always be valid
+ //
+ if ((res = mmcReadCardInfo (mmcSdCsd, CMD9)) != MmcOk)
+ return (MmcNoResponse);
+
+ //
+ // Implement CSD data, and set block size
+ //
+ mmcCSDImplement ();
+ mmcSetBlockLen (mmcDskStatus.BlockSize);
+
+ // mmcDecode (mmcSdCsd); // ###
+
+ return (MmcOk);
+}
+
+/*************************************************************************
+ * Function Name: mmcReadCardInfo
+ * Parameters: U8 *pData,
+ * mmcSpiCmdInd_t Command - CMD9, CMD10 are only allowed
+ *
+ * Return: mmcState_t
+ *
+ * Description: Read CSD or CID registers depend of commoand
+ *
+ *************************************************************************/
+static mmcState_t mmcReadCardInfo (U8 *pData, mmcSpiCmdInd_t Command)
+{
+ U32 i;
+ U32 res;
+
+ switch (Command)
+ {
+ case CMD9 :
+ case CMD10 :
+ break;
+
+ default:
+ return (MmmcParameterError);
+ }
+
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+
+ if ((res = mmcSendCmd (Command, 0)) == MMC_OK)
+ {
+ for (i = 8; i ; --i)
+ {
+ if (((res = spiTransferByte (0xff)) | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+ {
+ // printf ("line %d: spiTransferByte returned 0x%x\n", __LINE__, res); // ###
+ MMC_RET_DATA_ERR (res);
+ }
+ else if (res == MMC_DATA_TOKEN)
+ {
+ for (i = 0; i <16 ; ++i)
+ *pData++ = spiTransferByte (0xff);
+
+ //
+ // CRC receive
+ //
+ spiTransferByte (0xff);
+ spiTransferByte (0xff);
+ spiChipSelect (0);
+ return (MmcOk);
+ }
+ }
+ }
+ // else
+ // printf ("line %d: mmcSendCmd returned %d\n", __LINE__, res); // ###
+
+ spiChipSelect (0);
+ MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcRead
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Read from a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcRead (U8 *pData, U32 Add, U32 Length)
+{
+ U32 res;
+ U32 i;
+
+ //
+ // For synchronization
+ //
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+ res = mmcSendCmd (CMD17, Add);
+
+ if (res == MMC_OK)
+ {
+ for (i = Tnac; i; --i)
+ {
+ res = spiTransferByte (0xff);
+
+ if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+ MMC_RET_DATA_ERR (res);
+ else if (res == MMC_DATA_TOKEN)
+ {
+ spiReceiveBlock (pData, Length);
+
+ //
+ // CRC receive
+ //
+ spiTransferByte (0xff);
+ spiTransferByte (0xff);
+ spiChipSelect (0);
+ return (MmcOk);
+ }
+ }
+
+ spiChipSelect (0);
+ return (MmcNoResponse);
+ }
+
+ spiChipSelect (0);
+ MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcWrite
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Write to a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcWrite (U8 *pData, U32 Add, U32 Length)
+{
+ U32 res;
+ U32 i;
+
+ //
+ // For synchronization
+ //
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+
+ if ((res = mmcSendCmd (CMD24, Add)) == MMC_OK)
+ {
+ spiTransferByte (0xff);
+ spiTransferByte (MMC_DATA_TOKEN);
+ spiSendBlock (pData, Length);
+
+ //
+ // CRC Send
+ //
+ spiTransferByte (0xff);
+ spiTransferByte (0xff);
+
+ if ((spiTransferByte (0xff) & 0x1F) != 0x05)
+ MMC_RET_ERROR (res);
+
+ for (i = Twr; i ;i--)
+ if (spiTransferByte (0xff) == 0xff)
+ break;
+
+ spiChipSelect (0);
+
+ if (i == 0)
+ return (MmcNoResponse);
+
+ return (MmcOk);
+ }
+
+ spiChipSelect (0);
+ MMC_RET_ERROR (res);
+}
+
+/*************************************************************************
+ * Function Name: mmcVerify
+ * Parameters: U8 *pData, U32 Add, U32 Length
+ *
+ * Return: mmcState_t
+ *
+ * Description: Verify on a MMC
+ *
+ *************************************************************************/
+static inline mmcState_t mmcVerify (U8 *pData, U32 Add, U32 Length)
+{
+ U32 res,i;
+
+ //
+ // For synchronization
+ //
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+
+ if ((res = mmcSendCmd (CMD17, Add)) == MMC_OK)
+ {
+ for (i = Tnac; i; --i)
+ {
+ res = spiTransferByte (0xff);
+
+ if ((res | MMC_DATA_ERR_TOKEN) == MMC_DATA_ERR_TOKEN)
+ MMC_RET_DATA_ERR (res);
+ else if (res == MMC_DATA_TOKEN)
+ {
+ for (res = 0, i = 0; i < Length; ++i, ++pData)
+ {
+ *pData ^= spiTransferByte (0xff);
+
+ if (*pData != 0)
+ res = 1;
+ }
+
+ //
+ // CRC receive
+ //
+ spiTransferByte (0xff);
+ spiTransferByte (0xff);
+ spiChipSelect (0);
+ spiTransferByte (0xff);
+ spiTransferByte (0xff);
+
+ if (res)
+ return (MmcMiscompare);
+
+ return (MmcOk);
+ }
+ }
+
+ return (MmcNoResponse);
+ }
+
+ MMC_RET_ERROR (res);
+}
+
+//
+//
+//
+DSTATUS diskInitialize (U8 drv __attribute__ ((unused)))
+{
+ mmcDskStatus.BlockNumb = mmcDskStatus.BlockSize = mmcLastError = 0;
+
+ //
+ // Init SPI
+ //
+ spiInit ();
+
+ //
+ // Media Init
+ //
+ switch (mmcInitMedia ())
+ {
+ case MmcOk :
+ {
+ mmcCSDImplement ();
+ mmcDskStatus.DiskStatus = DiskCommandPass;
+ mmcDskStatus.MediaChanged = TRUE;
+ Stat = 0;
+ if (mmcDskStatus.WriteProtect)
+ Stat |= STA_PROTECT;
+ }
+ break;
+
+ case MmcCardError :
+ case MmcDataError :
+ {
+ mmcDskStatus.DiskStatus = DiskNotReady;
+ Stat = STA_NOINIT;
+ if (mmcDskStatus.WriteProtect)
+ Stat |= STA_PROTECT;
+ }
+ break;
+
+ default:
+ {
+ mmcDskStatus.DiskStatus = DiskNotPresent;
+ Stat = STA_NODISK;
+ }
+ break;
+ }
+
+ return Stat;
+}
+
+//
+//
+//
+DSTATUS diskShutdown (void)
+{
+ Stat |= STA_NOINIT;
+
+ return Stat;
+}
+
+//
+//
+//
+DSTATUS diskStatus (U8 drv __attribute__ ((unused)))
+{
+ return Stat;
+}
+
+//
+//
+//
+DRESULT diskRead (U8 disk __attribute__ ((unused)), U8 *buff, U32 sector, U8 count)
+{
+ U32 res;
+
+ if (Stat & STA_NOINIT)
+ return RES_NOTRDY;
+ if (!count)
+ return RES_PARERR;
+
+ res = mmcRead (buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
+
+ if (res == MMC_OK)
+ return RES_OK;
+ else
+ return RES_ERROR;
+}
+
+//
+//
+//
+#if _FS_READONLY == 0
+DRESULT diskWrite (U8 disk __attribute__ ((unused)), const U8 *buff, U32 sector, U8 count)
+{
+ U32 res;
+
+ if (Stat & STA_NOINIT)
+ return RES_NOTRDY;
+ if (Stat & STA_PROTECT)
+ return RES_WRPRT;
+ if (!count)
+ return RES_PARERR;
+
+ res = mmcWrite ((U8 *) buff, sector * mmcDskStatus.BlockSize, count * mmcDskStatus.BlockSize);
+
+ if (res == MMC_OK)
+ return RES_OK;
+ else
+ return RES_ERROR;
+}
+#endif
+
+//
+//
+//
+DRESULT diskIoctl (U8 drv, U8 ctrl, void *buff)
+{
+ DRESULT res;
+ U8 n;
+ U8 csd [16];
+ U16 csize;
+
+ if (drv)
+ return RES_PARERR;
+ if (Stat & STA_NOINIT)
+ return RES_NOTRDY;
+
+ res = RES_ERROR;
+
+ switch (ctrl)
+ {
+ case GET_SECTOR_COUNT :
+ {
+ mmcState_t jcwres; // ###
+ if ((jcwres = mmcReadCardInfo (csd, CMD9)) == MmcOk)
+ {
+ //
+ // SDC ver 2.00
+ //
+ if ((csd [0] >> 6) == 1)
+ {
+ csize = csd [9] + ((U16)csd [8] << 8) + 1;
+ *(U32 *) buff = (U32) csize << 10;
+ }
+ //
+ // MMC or SDC ver 1.XX
+ //
+ else
+ {
+ n = (csd [5] & 15) + ((csd [10] & 128) >> 7) + ((csd [9] & 3) << 1) + 2;
+ csize = (csd [8] >> 6) + ((U16) csd [7] << 2) + ((U16) (csd [6] & 3) << 10) + 1;
+ *(U32 *) buff = (U32) csize << (n - 9);
+ }
+
+ res = RES_OK;
+ }
+ // else // ###
+ // printf ("line %d: mmcReadCardInfo returned %d\n", __LINE__, jcwres); // ###
+ }
+ break;
+
+ case GET_SECTOR_SIZE :
+ {
+ *(U16 *) buff = 512;
+ res = RES_OK;
+ }
+ break;
+
+ case CTRL_SYNC :
+ {
+ if (spiWaitReady () == 0xff)
+ res = RES_OK;
+ }
+ break;
+
+ case MMC_GET_CSD :
+ {
+ if (mmcReadCardInfo (buff, CMD9) == MmcOk)
+ res = RES_OK;
+ }
+ break;
+
+ case MMC_GET_CID :
+ {
+ if (mmcReadCardInfo (buff, CMD10) == MmcOk)
+ res = RES_OK;
+ }
+ break;
+
+# if 0
+ case CTRL_POWER:
+ case CTRL_LOCK:
+ case CTRL_EJECT:
+ case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
+ case ATA_GET_REV:
+ case ATA_GET_MODEL:
+ case ATA_GET_SN:
+#endif
+
+ default:
+ res = RES_PARERR;
+ }
+
+ return res;
+}
+
+#if 0
+static void mmcDump (U8 *buff, U32 ofs, U8 cnt)
+{
+ U8 n;
+
+ printf ("\n\r%08X ", ofs);
+
+ for (n = 0; n < cnt; n++)
+ printf (" %02X", buff [n]);
+
+ putchar (' ');
+
+ for (n = 0; n < cnt; n++)
+ {
+ if ((buff [n] < 0x20) || (buff [n] >= 0x7F))
+ putchar ('.');
+ else
+ putchar (buff [n]);
+ }
+}
+#endif
+
+#if 0
+typedef struct csd_11_s
+{
+ unsigned int not_used_1 : 2; // 0..1 [121:120] 0x44
+ unsigned int mmc_prot : 4; // 2..5 [125:122]
+ unsigned int csd_structure : 2; // 6..7 [127:126]
+ unsigned int taac : 8; // 0..7 [119:112] 0x26
+ unsigned int nsac : 8; // 0..7 [111:104] 0x00
+ unsigned int tran_speed : 8; // 0..7 [103:96] 0x2a
+ unsigned int ccc_hi : 8; // 0..7 [95:88] 0x1f
+ unsigned int read_bl_len : 4; // 0..3 [83:80] 0xf9
+ unsigned int ccc_lo : 4; // 4..7 [87:84]
+
+ unsigned int c_size_hi : 2; // 0..1 [73:72] 0x83
+ unsigned int not_used_2 : 2; // 2..3 [75:74]
+ unsigned int dsr_imp : 1; // 4..4 [76:76]
+ unsigned int read_blk_misalign : 1; // 5..5 [77:77]
+ unsigned int write_blk_misalign : 1; // 6..6 [78:78]
+ unsigned int read_bl_partial : 1; // 7..7 [79:79]
+ unsigned int c_size_mid : 8; // 0..7 [71:64] 0xd3
+ unsigned int vdd_r_curr_max : 3; // 0..1 [58:56] 0xe3
+ unsigned int vdd_r_curr_min : 3; // 2..5 [61:59]
+ unsigned int c_size_lo : 2; // 6..7 [63:62]
+
+ unsigned int c_size_mult_hi : 2; // 0..1 [49:48] 0x91
+ unsigned int vdd_w_curr_max : 3; // 2..4 [52:50]
+ unsigned int vdd_w_curr_min : 3; // 4..7 [55:53]
+ unsigned int erase_grp_size_lo : 2; // 0..1 [41:40] 0x83
+ unsigned int sector_size : 5; // 2..6 [46:42]
+ unsigned int c_size_mult_lo : 1; // 7..7 [47:47]
+ unsigned int wp_grp_size : 5; // 0..4 [36:32] 0xff
+ unsigned int erase_grp_size_hi : 3; // 5..7 [39:37]
+
+ unsigned int write_bl_len_hi : 2; // 0..1 [25:24] 0x92
+ unsigned int r2w_factor : 3; // 2..4 [28:26]
+ unsigned int default_ecc : 2; // 5..6 [30:29]
+ unsigned int wp_grp_enable : 1; // 7..7 [31:31]
+ unsigned int not_used_3 : 5; // 0..4 [20:16] 0x40
+ unsigned int write_bl_partial : 1; // 5..5 [21:21]
+ unsigned int write_bl_len_lo : 2; // 6..7 [23:22]
+
+ unsigned int ecc : 2; // 0..1 [9:8] 0x40
+ unsigned int not_used_5 : 2; // 2..3 [11:10]
+ unsigned int tmp_write_protect : 1; // 4..4 [12:12]
+ unsigned int perm_write_protect : 1; // 5..5 [13:13]
+ unsigned int copy : 1; // 6..6 [14:14]
+ unsigned int not_used_4 : 1; // 7..7 [15:15]
+
+ unsigned int notused_6 : 1; // 0..0 [0:0] 0x67
+ unsigned int crc : 7; // 1..7 [7:1]
+}
+__attribute__ ((packed)) csd_11_t;
+
+static void mmcDecode (U8 *buffer)
+{
+ csd_11_t *p = (csd_11_t *) buffer;
+
+ printf ("\n");
+ printf ("sizeof (csd_11_t) : %lu\n", sizeof (csd_11_t));
+ printf ("CSD structure version : 1.%d\n", p->csd_structure);
+ printf ("MMC protocol version : %d\n", p->mmc_prot);
+ printf ("TAAC : 0x%02x\n", p->taac);
+ printf ("NSAC : 0x%02x\n", p->nsac);
+ printf ("TRAN_SPEED : 0x%02x\n", p->tran_speed);
+ printf ("CCC : 0x%03x\n", (p->ccc_hi << 4) | p->ccc_lo);
+ printf ("READ_BL_LEN : %d\n", p->read_bl_len);
+ printf ("READ_BL_PARTIAL : %d\n", p->read_bl_partial);
+ printf ("WRITE_BLK_MISALIGN : %d\n", p->write_blk_misalign);
+ printf ("READ_BLK_MISALIGN : %d\n", p->read_blk_misalign);
+ printf ("DSR_IMP : %d\n", p->read_blk_misalign);
+ printf ("C_SIZE : %d\n", (p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo);
+ printf ("VDD_R_CURR_MIN : %d\n", p->vdd_r_curr_min);
+ printf ("VDD_R_CURR_MAX : %d\n", p->vdd_r_curr_max);
+ printf ("VDD_W_CURR_MIN : %d\n", p->vdd_w_curr_min);
+ printf ("VDD_W_CURR_MAX : %d\n", p->vdd_w_curr_max);
+ printf ("VDD_W_CURR_MAX : %d\n", p->vdd_w_curr_max);
+ printf ("C_SIZE_MULT : %d\n", (p->c_size_mult_hi << 1) | p->c_size_mult_lo);
+ printf ("SECTOR_SIZE : %d\n", p->sector_size);
+ printf ("ERASE_GRP_SIZE : %d\n", (p->erase_grp_size_hi << 2) | p->erase_grp_size_lo);
+ printf ("WP_GRP_SIZE : %d\n", p->wp_grp_size);
+ printf ("WP_GRP_ENABLE : %d\n", p->wp_grp_enable);
+ printf ("DEFAULT_ECC : %d\n", p->default_ecc);
+ printf ("R2W_FACTOR : %d\n", p->r2w_factor);
+ printf ("WRITE_BL_LEN : %d\n", (p->write_bl_len_hi << 2) | p->write_bl_len_lo);
+ printf ("WRITE_BL_PARTIAL : %d\n", p->write_bl_partial);
+ printf ("COPY : %d\n", p->copy);
+ printf ("PERM_WRITE_PROTECT : %d\n", p->perm_write_protect);
+ printf ("TMP_WRITE_PROTECT : %d\n", p->tmp_write_protect);
+ printf ("ECC : %d\n", p->ecc);
+ printf ("MEDIA SIZE : %u\n", (U32) (((p->c_size_hi << 10) | (p->c_size_mid << 2) | p->c_size_lo) + 1) *
+ (U32) (4 << ((p->c_size_mult_hi << 1) | p->c_size_mult_lo)) *
+ (U32) (1 << (p->read_bl_len)));
+}
+#endif
+
--- /dev/null
+/*************************************************************************
+ *
+ * Used with ICCARM and AARM.
+ *
+ * (c) Copyright IAR Systems 2003
+ *
+ * File name : mmc.h
+ * Description : define MMC module
+ *
+ * History :
+ * 1. Data : July 1, 2005
+ * Author : Stanimir Bonev
+ * Description : Create
+ *
+ * $Revision: 1.4 $
+**************************************************************************/
+
+#ifndef _MMC_H_
+#define _MMC_H_
+
+#include "sysdefs.h"
+#include "disk.h"
+
+//
+// Hardware depends definitions
+//
+#define IdentificationModeClock 400000l
+#define SystemPeripherialClock 48000000l
+
+//
+// Time out definition for SD Read Time out ~100msec, Write Time out ~250ms
+//
+#define SD_READ_TIME_OUT 7 // [Hz]
+#define SD_WRITE_TIME_OUT 3 // [HZ]
+
+//
+//
+//
+#define MMC_OK 0x00
+#define MMC_IDLE_STATE 0x01
+#define MMC_ERASE_RST 0x02
+#define MMC_ILLEGAL_CMD 0x04
+#define MMC_CRC_ERROR 0x08
+#define MMC_ERASE_ERROR 0x10
+#define MMC_ADD_ERROR 0x20
+#define MMC_PARAM_ERROR 0x40
+
+#define MMC_DATA_TOKEN 0xfe
+#define MMC_DATA_ERR_TOKEN 0x1f
+#define MMC_STOP_TRAN 0xfd
+
+#define MMC_DLY_1MSEC 1000
+
+typedef enum
+{
+ MmcOk = 0,
+ MmcNoPresent,
+ MmcNoResponse,
+ MmcCardError,
+ MmcDataError,
+ MmcUknowError,
+ MmmcParameterError,
+ MmcMiscompare
+}
+mmcState_t;
+
+typedef enum
+{
+ CMD0 = 0, // Resets the MultiMediaCard
+ CMD1, // Activates the card initialization process
+ CMD9, // Asks the selected card to send its card-specific data (CSD)
+ CMD10, // Asks the selected card to send its card identification (CID)
+ CMD12, // Stop transmission on multiple block read
+ CMD13, // Asks the selected card to send its status register
+ CMD16, // Selects a block length (in bytes) for all following block commands (read and write)
+ CMD17, // Reads a block of the size selected by the SET_BLOCKLEN command
+ CMD18, // Continuously transfers data blocks from card to host until interrupted by a Stop command or the requested number of data blocks transmitted
+ CMD24, // Writes a block of the size selected by the SET_BLOCKLEN command
+ CMD25, // Continuously writes blocks of data until a "Stop Tran" token or the requested number of blocks received
+ CMD27, // Programming of the programmable bits of the CSD
+ CMD28, // If the card has write protection features, this command sets the write protection bit of the addressed group. The properties of write protection are coded in the card specific data (WP_GRP_SIZE).
+ CMD29, // If the card has write protection features, this command clears the write protection bit of the addressed group
+ CMD30, // If the card has write protection features, this command asks the card to send the status of the write protection bits
+ CMD32, // Sets the address of the first sector of the erase group
+ CMD33, // Sets the address of the last sector in a continuous range within the selected erase group, or the address of a single sector to be selected for erase
+ CMD34, // Removes one previously selected sector from the erase selection
+ CMD35, // Sets the address of the first erase group within a range to be selected for erase
+ CMD36, // Sets the address of the last erase group within a continuous range to be selected for erase
+ CMD37, // Removes one previously selected erase group from the erase selection.
+ CMD38, // Erases all previously selected sectors
+ CMD42, // Used to set/reset the password or lock/unlock the card. The size of the Data Block is defined by the SET_BLOCK_LEN command
+ CMD55, // Notifies the card that the next command is an application specific command rather than a standard command.
+ CMD56, // Used either to transfer a Data Block to the card or to get a Data Block from the card for general purpose/application specific commands. The size of the Data Block is defined with SET_BLOCK_LEN command
+ CMD58, // Reads the OCR register of a card
+ CMD59, // Turns the CRC option on or off. A \911\92 in the CRC option bit will turn the option on, a \910\92 will turn it off
+ ACMD41, // Activates the card\92s initialization process (Only for SD)
+ CMD_END // End of commands index
+}
+mmcSpiCmdInd_t;
+
+typedef enum
+{
+ MmcNoArg = 0,
+ MmcBlockLen,
+ MmcDataAdd,
+ MmcDummyWord
+}
+mmcAgmType_t;
+
+typedef enum
+{
+ MmcR1 = 0,
+ MmcR1b,
+ MmcR2,
+ MmcR3
+}
+mmcRespType_t;
+
+typedef struct
+{
+ U8 TxData;
+ mmcAgmType_t Arg;
+ mmcRespType_t Resp;
+}
+mmcCommads_t;
+
+#endif
--- /dev/null
+#include <stdio.h> // ###
+#include "lpc210x.h"
+#include "mmc.h"
+#include "spi.h"
+
+/*************************************************************************
+ *
+ * Used with ICCARM and AARM.
+ *
+ * (c) Copyright IAR Systems 2003
+ *
+ * File name : mmc_ll.h
+ * Description : define MMC module
+ *
+ * History :
+ * 1. Data : July 1, 2005
+ * Author : Stanimir Bonev
+ * Description : Create
+ * 2. Data : July 1, 2005
+ * Author : Stanimir Bonev
+ * Description : Modify
+ * Fix a lock problem in spiReceiveBlock
+ *
+ * $Revision: 1.4 $
+ * (C) Joel Winarske, 2006,2007
+**************************************************************************/
+
+/*************************************************************************
+ * Function Name: spiChipSelect
+ * Parameters: Boolean Select
+ * Return: none
+ *
+ * Description: MMC Chip select control
+ * Select = true - Chip is enabled
+ * Select = false - Chip is disabled
+ *
+ *************************************************************************/
+void spiChipSelect (BOOL select)
+{
+ if (select)
+ GPIO0_IOCLR = GPIO_IO_P20;
+ else
+ {
+ GPIO0_IOSET = GPIO_IO_P20;
+
+ while (!(SSP_SR & SSP_SR_TNF))
+ ;
+
+ SSP_DR = 0xff;
+
+ //
+ // Wait until TX fifo and TX shift buffer are empty
+ //
+ while (SSP_SR & SSP_SR_BSY)
+ ;
+ while (!(SSP_SR & SSP_SR_RNE))
+ ;
+
+ do
+ {
+ select = SSP_DR;
+ }
+ while (SSP_SR & SSP_SR_RNE);
+ }
+}
+
+/*************************************************************************
+ * Function Name: spiPresent
+ * Parameters: none
+ * Return: Boolean - true card present
+ * - false card not present
+ *
+ * Description: MMC present check
+ *
+ *************************************************************************/
+inline BOOL spiPresent (void)
+{
+ return TRUE;
+}
+
+/*************************************************************************
+ * Function Name: spiWriteProtect
+ * Parameters: none
+ * Return: Boolean - true card is protected
+ * - false card not protected
+ *
+ * Description: MMC Write protect check
+ *
+ *************************************************************************/
+inline BOOL spiWriteProtect (void)
+{
+ return FALSE;
+}
+
+/*************************************************************************
+ * Function Name: spiSetClockFreq
+ * Parameters: Int32U Frequency
+ * Return: Int32U
+ *
+ * Description: Set SPI ckl frequency
+ *
+ *************************************************************************/
+U32 spiSetClockFreq (U32 frequency)
+{
+ U32 Div = SystemPeripherialClock / frequency;
+
+ if (Div < 2)
+ Div = 2;
+ else if (Div > 254)
+ Div = 254;
+
+ ++Div;
+ Div &= ~1;
+ SSP_CPSR = Div;
+
+ return (SystemPeripherialClock / Div);
+}
+
+/*************************************************************************
+ * Function Name: spiInit
+ * Parameters: none
+ * Return: int
+ * 0 - no error
+ * 1 - speed is to high
+ *
+ * Description: Init SPI, Cart Present, Write Protect and Chip select pins
+ *
+ *************************************************************************/
+void spiInit (void)
+{
+ U32 i;
+ volatile U32 dummy;
+
+ //
+ // Chip select
+ //
+ GPIO0_IOSET = GPIO_IO_P20;
+ GPIO0_IODIR |= GPIO_IO_P20;
+
+ //
+ // SPI init
+ //
+ SCB_PCONP |= SCB_PCONP_PCSPI1;
+
+ SSP_CR0 = SSP_CR0_DSS_8 | SSP_CR0_FRF_SPI;
+ SSP_CR1 = 0x00;
+ SSP_IMSC = 0x00;
+
+ //
+ // Clock Freq. Identification Mode < 400kHz
+ //
+ spiSetClockFreq (400000);
+
+ PCB_PINSEL1 |= PCB_PINSEL1_P017_SCK1;
+ PCB_PINSEL1 |= PCB_PINSEL1_P018_MISO1;
+ PCB_PINSEL1 |= PCB_PINSEL1_P019_MOSI1;
+ PCB_PINSEL1 &= ~PCB_PINSEL1_P020_MASK;
+
+ //
+ // Enable SPI
+ //
+ SSP_CR1 |= SSP_CR1_SSE;
+
+ for (i = 0; i < 8; i++)
+ dummy = SSP_DR;
+}
+
+/*************************************************************************
+ * Function Name: spiTransferByte
+ * Parameters: U8 ch
+ * Return: U8
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+U8 spiTransferByte (U8 c)
+{
+ while (!(SSP_SR & SSP_SR_TNF))
+ ;
+
+ SSP_DR = c;
+
+ while (!(SSP_SR & SSP_SR_RNE))
+ ;
+
+ return SSP_DR;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Wait for card ready */
+/*-----------------------------------------------------------------------*/
+U8 spiWaitReady (void)
+{
+ U8 res;
+
+ do /* TODO: add in 500ms timeout */
+ {
+ SSP_DR = 0xff;
+
+ while (!(SSP_SR & SSP_SR_RNE))
+ ;
+
+ res = SSP_DR;
+ }
+ while (res != 0xff);
+
+ return res;
+}
+
+/*************************************************************************
+ * Function Name: spiSendBlock
+ * Parameters: pInt8U pData, Int32U Size
+ *
+ * Return: void
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+void spiSendBlock (U8 *pData, U32 size)
+{
+ U32 outCount = size;
+ volatile U32 dummy;
+
+ while (outCount)
+ {
+ while ((SSP_SR & SSP_SR_TNF) && outCount)
+ {
+ SSP_DR = *pData++;
+ --outCount;
+ }
+ }
+
+ while ((SSP_SR & SSP_SR_RNE) || !(SSP_SR & SSP_SR_TFE))
+ dummy = SSP_DR;
+}
+
+/*************************************************************************
+ * Function Name: spiReceiveBlock
+ * Parameters: pInt8U pData, Int32U Size
+ *
+ * Return: void
+ *
+ * Description: Read byte from SPI
+ *
+ *************************************************************************/
+void spiReceiveBlock (U8 *pData, U32 size)
+{
+ U32 delta = 0;
+
+ while (size || delta)
+ {
+ while ((SSP_SR & SSP_SR_TNF) && (delta < SSP_FIFO_DEPTH) && size)
+ {
+ SSP_DR = 0xff;
+ --size;
+ ++delta;
+ }
+
+ while (SSP_SR & SSP_SR_RNE)
+ {
+ *pData++ = SSP_DR;
+ --delta;
+ }
+ }
+}
+
+/*************************************************************************
+ * Function Name: spiDly_1ms
+ * Parameters: Int32U Delay
+ * Return: none
+ *
+ * Description: Delay [msec]
+ *
+ *************************************************************************/
+void spiDelay1ms (U32 delay)
+{
+ volatile U32 i;
+
+ for (;delay; --delay)
+ {
+ for (i = MMC_DLY_1MSEC; i; --i)
+ ;
+ }
+}
--- /dev/null
+#ifndef _MMCLLSPI1_H_
+#define _MMCLLSPI1_H_
+
+#include "sysdefs.h"
+
+//
+//
+//
+void spiChipSelect (BOOL select);
+inline BOOL spiPresent (void);
+inline BOOL spiWriteProtect (void);
+U32 spiSetClockFreq (U32 frequency);
+void spiInit (void);
+U8 spiTransferByte (U8 c);
+U8 spiWaitReady (void);
+void spiSendBlock (U8 *pData, U32 size);
+void spiReceiveBlock (U8 *pData, U32 size);
+void spiDelay1ms (U32 delay);
+
+#endif
--- /dev/null
+SRC_FILES=fiq.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include "fiq.h"
+
+//
+//
+//
+static volatile unsigned int fiqCounter;
+
+//
+//
+//
+void fiqInit (void)
+{
+ SCB_PCONP |= SCB_PCONP_PCTIM1;
+
+ VIC_IntSelect |= VIC_IntSelect_Timer1;
+ VIC_IntEnable = VIC_IntEnable_Timer1;
+
+ T1_PR = 0;
+ T1_MR0 = configCPU_CLOCK_HZ / 8;
+ T1_MCR = T_MCR_MR0R | T_MCR_MR0I;
+}
+
+int fiqEnable (void)
+{
+ unsigned int state = T1_TCR;
+
+ T1_TCR = T_TCR_CE;
+
+ return (state & T_TCR_CE) ? 1 : 0;
+}
+
+int fiqDisable (void)
+{
+ unsigned int state = T1_TCR;
+
+ T1_TCR = T_TCR_CR;
+
+ return (state & T_TCR_CE) ? 1 : 0;
+}
+
+unsigned int fiqGetCount (void)
+{
+ return fiqCounter;
+}
+
+void fiqClearCount (void)
+{
+ fiqCounter = 0;
+}
+
+void fiqISR (void) __attribute__ ((interrupt ("FIQ")));
+void fiqISR (void)
+{
+ ++fiqCounter;
+
+ T1_IR = T_IR_MASK;
+}
--- /dev/null
+#ifndef _FIQ_H_
+#define _FIQ_H_
+
+void fiqInit (void);
+int fiqEnable (void);
+int fiqDisable (void);
+unsigned int fiqGetCount (void);
+void fiqClearCount (void);
+void fiqISR (void);
+
+#endif
--- /dev/null
+SRC_FILES=gps.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+//
+//
+//
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include "gps.h"
+
+//
+//
+//
+#define GPS_MAX_NMEA_SENTENCE 128
+
+//
+//
+//
+static gpsData_t gpsData;
+static xSemaphoreHandle semaphore;
+
+//
+//
+//
+static void gpsNormalizeNMEA (char *s);
+static unsigned char gpsChecksumNMEA (char *sz);
+static void gpsHandlerGGA (char *nmeaSentence);
+static void gpsHandlerRMC (char *nmeaSentence);
+static void gpsHandlerRestart (char *nmeaSentence);
+static void gpsDispatchMessages (char *nmeaSentence);
+static int gpsProcessByte (unsigned char c, char *nmeaSentence);
+
+//
+//
+//
+static void gpsNormalizeNMEA (char *s)
+{
+ int l = -1;
+
+ while (*s && *s != '*')
+ {
+ if (*s == ',' && (*(s + 1) == ',' || *(s + 1) == '*'))
+ {
+ if (l == -1)
+ l = strlen (s) + 1;
+
+ memmove (s + 3, s + 1, l);
+ *++s = '-';
+ *++s = '1';
+ l += 2;
+ }
+
+ s++;
+
+ if (l != -1)
+ l--;
+ }
+}
+
+//
+//
+//
+static unsigned char gpsChecksumNMEA (char *sz)
+{
+ short i;
+ unsigned char cs;
+
+ for (cs = 0, i = 1; sz [i] && sz [i] != '*'; i++)
+ cs ^= ((unsigned char) sz [i]);
+
+ return cs;
+}
+
+//
+//
+//
+static void gpsHandlerGGA (char *nmeaSentence)
+{
+ char valid = 0;
+ double height = 0.0;
+ double latitude = 0.0, longitude = 0.0;
+ char latitudeSign = 0, longitudeSign = 0;
+
+ if (sscanf (nmeaSentence, "%*f,%lf,%c,%lf,%c,%c,%*d,%*f,%lf", &latitude, &latitudeSign, &longitude, &longitudeSign, &valid, &height) == 6)
+ {
+ if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+ {
+ gpsData.valid = (valid - '0');
+ gpsData.height = height;
+ gpsData.latitude = latitude * (latitudeSign == 'N' ? 1.0 : -1.0);
+ gpsData.longitude = longitude * (longitudeSign == 'E' ? 1.0 : -1.0);
+
+ xSemaphoreGive (semaphore);
+ }
+ }
+}
+
+static void gpsHandlerRMC (char *nmeaSentence)
+{
+ float speed, course;
+ int gpsdate, gpstime;
+
+ if (sscanf (nmeaSentence, "%d.%*d,%*c,%*f,%*c,%*f,%*c,%f,%f,%d", &gpstime, &speed, &course, &gpsdate) == 4)
+ {
+ if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+ {
+ gpsData.utcDay = gpsdate / 10000;
+ gpsData.utcMonth = (gpsdate / 100) % 100;
+ gpsData.utcYear = (gpsdate % 100) + 2000;
+ gpsData.utcHours = gpstime / 10000;
+ gpsData.utcMinutes = (gpstime / 100) % 100;
+ gpsData.utcSeconds = gpstime % 100;
+ gpsData.groundSpeed = speed;
+ gpsData.trueCourse = course;
+
+ xSemaphoreGive (semaphore);
+ }
+ }
+}
+
+static void gpsHandlerRestart (char *nmeaSentencemea __attribute__ ((unused)))
+{
+ if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+ {
+ gpsData.restarts++;
+ xSemaphoreGive (semaphore);
+ }
+}
+
+//
+//
+//
+typedef struct nmeaDispatch_s
+{
+ const char *sentence;
+ short length;
+ void (*handler) (char *sentence);
+ short normalize;
+}
+nmeaDispatch_t;
+
+static const nmeaDispatch_t nmeaDispatch [] =
+{
+ { "$GPGGA", 6, gpsHandlerGGA, 1 },
+ { "$GPRMC", 6, gpsHandlerRMC, 1 },
+ { "$HW Type", 8, gpsHandlerRestart, 0 },
+ { NULL, 0, NULL, 0 }
+};
+
+static void gpsDispatchMessages (char *nmeaSentence)
+{
+ int i;
+
+ for (i = 0; nmeaDispatch [i].handler; i++)
+ {
+ if (!strncmp (nmeaDispatch [i].sentence, nmeaSentence, nmeaDispatch [i].length))
+ {
+ if (nmeaDispatch [i].normalize)
+ {
+ gpsNormalizeNMEA (&nmeaSentence [7]);
+ (*nmeaDispatch [i].handler) (&nmeaSentence [7]);
+ }
+ else
+ (*nmeaDispatch [i].handler) (NULL);
+
+ break;
+ }
+ }
+}
+
+//
+//
+//
+static int gpsProcessByte (unsigned char c, char *nmeaSentence)
+{
+ short complete = 0;
+ static short state = 0;
+ static short pos = 0;
+
+ switch (state)
+ {
+ case 0 :
+ {
+ if (c == '$')
+ {
+ pos = 0;
+ nmeaSentence [pos++] = '$';
+ nmeaSentence [pos] = '\0';
+ state = 1;
+ }
+ else
+ state = 0;
+ }
+ break;
+
+ case 1 :
+ {
+ if (pos < GPS_MAX_NMEA_SENTENCE)
+ {
+ if (c == 0x0a)
+ {
+ char *s;
+
+ state = 0;
+
+ if ((s = strchr (nmeaSentence, '*')))
+ {
+ int cksum;
+
+ if (sscanf (s + 1, "%x", &cksum) == 1)
+ {
+ if (gpsChecksumNMEA (nmeaSentence) == cksum)
+ complete = 1;
+ }
+ else
+ fprintf (stderr, "NMEA checksum error: got 0x%02x, want %s", cksum, s);
+ }
+ else
+ fprintf (stderr, "NMEA checksum not found: \"%s\"", nmeaSentence);
+ }
+ else if (c != 0x0d)
+ {
+ nmeaSentence [pos++] = c;
+ nmeaSentence [pos] = '\0';
+ }
+ }
+ else
+ state = 0;
+ }
+ break;
+ }
+
+ return (complete);
+}
+
+//
+// Return 1 if got a copy, 0 if not.
+//
+int gpsCopyData (gpsData_t *dst)
+{
+#ifndef CFG_CONSOLE_UART1
+ if (xSemaphoreTake (semaphore, 100 / portTICK_RATE_MS) == pdTRUE)
+ {
+ memcpy (dst, &gpsData, sizeof (gpsData_t));
+ xSemaphoreGive (semaphore);
+ return 1;
+ }
+#endif
+
+ memset (dst, 0, sizeof (gpsData_t));
+ return 0;
+}
+
+//
+//
+//
+portTASK_FUNCTION (vGPSTask, pvParameters __attribute__ ((unused)))
+{
+ int fd;
+ static char nmeaSentence [GPS_MAX_NMEA_SENTENCE];
+
+ memset (&gpsData, 0, sizeof (gpsData));
+
+ vSemaphoreCreateBinary (semaphore);
+
+ fd = open ("/dev/uart1", O_RDONLY);
+
+ if ((fd == -1) || (semaphore == NULL))
+ for (;;)
+ vTaskDelay (100);
+
+ for (;;)
+ {
+ portCHAR c;
+
+ if (read (fd, &c, sizeof (c)) == sizeof (c))
+ if (gpsProcessByte (c, nmeaSentence))
+ gpsDispatchMessages (nmeaSentence);
+ }
+}
--- /dev/null
+#ifndef _GPS_H_
+#define _GPS_H_
+
+#include "semphr.h"
+
+//
+//
+//
+typedef struct gpsData_s
+{
+ unsigned char valid;
+ double latitude;
+ double longitude;
+ double height;
+ float groundSpeed;
+ float trueCourse;
+ unsigned char utcDay;
+ unsigned char utcMonth;
+ unsigned short utcYear;
+ unsigned char utcHours;
+ unsigned char utcMinutes;
+ unsigned char utcSeconds;
+ int restarts;
+}
+gpsData_t;
+
+//
+//
+//
+int gpsCopyData (gpsData_t *dst);
+portTASK_FUNCTION_PROTO (vGPSTask, pvParameters __attribute__ ((unused)));
+
+#endif
--- /dev/null
+SRC_FILES=i2c.c i2cInt.c lm75.c eeprom.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "i2c.h"
+#include "eeprom.h"
+
+//
+//
+//
+static U32 rwAddress;
+static U8 deviceAddress = EEPROM_ADDRESS;
+
+//
+//
+//
+void eepromInit (void)
+{
+}
+
+int eepromSetAddress (U32 address)
+{
+ int r = 0;
+
+ if (address >= EEPROM_SIZE)
+ r = -1;
+
+ address %= EEPROM_SIZE;
+
+ if ((rwAddress = address) >= 65536)
+ deviceAddress |= 0x02;
+ else
+ deviceAddress &= ~0x02;
+
+ return r;
+}
+
+static int eepromSetAddressEx (U32 address, U8 *buffer)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ return 0;
+}
+
+U32 eepromGetAddress (void)
+{
+ return rwAddress;
+}
+
+//
+//
+//
+int eepromRead (U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ if (!(r = i2cWriteReadBufferPoll (deviceAddress, buffer, sizeof (U16), bufferLength)))
+ eepromSetAddress (eepromGetAddress () + bufferLength);
+
+ return r;
+}
+
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ return eepromRead (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromWrite (U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ if (!(r = i2cWriteBufferPoll (deviceAddress, buffer, bufferLength + 2)))
+ eepromSetAddress (eepromGetAddress () + bufferLength);
+
+ return r;
+}
+
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ return eepromWrite (buffer, bufferLength);
+}
+
+//
+//
+//
+static int eepromFillAddressCommon (U32 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if (!(r = eepromSetAddressEx (address, buffer)))
+ r = i2cWriteBufferPoll (deviceAddress, buffer, bufferLength + 2);
+
+ return r;
+}
+
+int eepromFillAddress (U32 address, U32 bufferLength, U8 fillValue)
+{
+ int r;
+ U32 l;
+ U32 i;
+ U8 buffer [EEPROM_PAGESIZE + 2];
+
+ memset (buffer, fillValue, sizeof (buffer));
+
+ l = (EEPROM_PAGESIZE - ((address + EEPROM_PAGESIZE) % EEPROM_PAGESIZE)) % EEPROM_PAGESIZE;
+ l = MIN (l, bufferLength);
+
+ if (l && (r = eepromFillAddressCommon (address, buffer, l)))
+ return r;
+
+ address += l;
+ bufferLength -= l;
+ l = bufferLength - (bufferLength % EEPROM_PAGESIZE);
+
+ for (i = 0; i < l; i += EEPROM_PAGESIZE, address += (sizeof (buffer) - 2), bufferLength -= (sizeof (buffer) - 2))
+ if ((r = eepromFillAddressCommon (address, buffer, sizeof (buffer) - 2)))
+ return r;
+
+ if (bufferLength && (r = eepromFillAddressCommon (address, buffer, bufferLength)))
+ return r;
+
+ return 0;
+}
+
--- /dev/null
+#ifndef _EEPROM_H_
+#define _EEPROM_H_
+
+//
+//
+//
+#define EEPROM_ADDRESS (0xa0)
+#define EEPROM_SIZE (131072)
+#define EEPROM_PAGESIZE (256)
+
+//
+//
+//
+void eepromInit (void);
+int eepromSetAddress (U32 address);
+U32 eepromGetAddress (void);
+int eepromRead (U8 *buffer, U32 bufferLength);
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength);
+int eepromWrite (U8 *buffer, U32 bufferLength);
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength);
+int eepromFillAddress (U32 address, U32 length, U8 fillValue);
+
+#endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "i2c.h"
+#include "eeprom.h"
+
+//
+//
+//
+static U32 rwAddress;
+static U8 deviceAddress = EEPROM_ADDRESS;
+
+//
+//
+//
+void eepromInit (void)
+{
+}
+
+int eepromSetAddress (U32 address)
+{
+ int r = 0;
+
+ if (address >= EEPROM_SIZE)
+ r = -1;
+
+ address %= EEPROM_SIZE;
+
+ if ((rwAddress = address) >= 65536)
+ deviceAddress |= 0x02;
+ else
+ deviceAddress &= ~0x02;
+
+ return r;
+}
+
+static int eepromSetAddressEx (U32 address, U8 *buffer)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ return 0;
+}
+
+U32 eepromGetAddress (void)
+{
+ return rwAddress;
+}
+
+//
+//
+//
+int eepromRead (U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ if (!(r = i2cWriteReadBuffer (deviceAddress, buffer, sizeof (U16), bufferLength)))
+ eepromSetAddress (eepromGetAddress () + bufferLength);
+
+ return r;
+}
+
+int eepromReadAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ return eepromRead (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromWrite (U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ buffer [0] = rwAddress >> 8;
+ buffer [1] = rwAddress;
+
+ if (!(r = i2cWriteBuffer (deviceAddress, buffer, bufferLength + 2)))
+ eepromSetAddress (eepromGetAddress () + bufferLength);
+
+ return r;
+}
+
+int eepromWriteAddress (U32 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if ((r = eepromSetAddress (address)))
+ return r;
+
+ return eepromWrite (buffer, bufferLength);
+}
+
+//
+//
+//
+int eepromFillAddress (U32 address, U32 bufferLength, U8 fillValue)
+{
+ int r;
+ U32 l;
+ U32 i;
+ U8 buffer [EEPROM_PAGESIZE + 2];
+
+ memset (buffer, fillValue, sizeof (buffer));
+
+ l = (EEPROM_PAGESIZE - ((address + EEPROM_PAGESIZE) % EEPROM_PAGESIZE)) % EEPROM_PAGESIZE;
+ l = MIN (l, bufferLength);
+
+ if (l)
+ {
+ if ((r = eepromSetAddressEx (address, buffer)))
+ return r;
+
+ if ((r = i2cWriteBuffer (deviceAddress, buffer, l + 2)))
+ return r;
+ }
+
+ address += l;
+ bufferLength -= l;
+ l = bufferLength - (bufferLength % EEPROM_PAGESIZE);
+
+ for (i = 0; i < l; i += EEPROM_PAGESIZE, address += (sizeof (buffer) - 2), bufferLength -= (sizeof (buffer) - 2))
+ {
+ if ((r = eepromSetAddressEx (address, buffer)))
+ return r;
+
+ if ((r = i2cWriteBuffer (deviceAddress, buffer, sizeof (buffer))))
+ return r;
+ }
+
+ if (bufferLength)
+ {
+ if ((r = eepromSetAddressEx (address, buffer)))
+ return r;
+
+ if ((r = i2cWriteBuffer (deviceAddress, buffer, bufferLength + 2)))
+ return r;
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include "FreeRTOS.h"
+
+#include "i2c.h"
+
+//
+//
+//
+typedef struct i2cErrnoStr_s
+{
+ int errno;
+ const char *text;
+}
+i2cErrnoStr_t;
+
+static i2cErrnoStr_t i2cErrnoStr [] =
+{
+ { I2CERR_NONE, "I2CERR_NONE" },
+ { I2CERR_BUSY, "I2CERR_BUSY" },
+ { I2CERR_EMPTY, "I2CERR_EMPTY" },
+ { I2CERR_TIMEOUT, "I2CERR_TIMEOUT" },
+ { I2CERR_TIMEOUTWC, "I2CERR_TIMEOUTWC" },
+ { I2CERR_TIMEOUTACKPOLL, "I2CERR_TIMEOUTACKPOLL" },
+ { I2CERR_NOTIMPLEMENTED, "I2CERR_NOTIMPLEMENTED" },
+ { I2CERR_OTHER, "I2CERR_OTHER" },
+ { I2CERR_BUSERROR, "I2CERR_BUSERROR" },
+ { I2CERR_BUSERRORx, "I2CERR_BUSERRORx" },
+ { I2CERR_STARTTX, "I2CERR_STARTTX" },
+ { I2CERR_REPEATEDSTARTTX, "I2CERR_REPEATEDSTARTTX" },
+ { I2CERR_SLAWTX_ACKRX, "I2CERR_SLAWTX_ACKRX" },
+ { I2CERR_SLAWTX_NACKRX, "I2CERR_SLAWTX_NACKRX" },
+ { I2CERR_DATTX_ACKRX, "I2CERR_DATTX_ACKRX" },
+ { I2CERR_DATTX_NACKRX, "I2CERR_DATTX_NACKRX" },
+ { I2CERR_ARBLOST, "I2CERR_ARBLOST" },
+ { I2CERR_SLARTX_ACKRX, "I2CERR_SLARTX_ACKRX" },
+ { I2CERR_SLARTX_NACKRX, "I2CERR_SLARTX_NACKRX" },
+ { I2CERR_DATRX_ACKTX, "I2CERR_DATRX_ACKTX" },
+ { I2CERR_DATRX_NACKTX, "I2CERR_DATRX_NACKTX" },
+ { I2CERR_NOINFO, "I2CERR_NOINFO" },
+};
+
+i2cErr_e i2cErrno = I2CERR_NONE;
+
+//
+//
+//
+int i2cGetErrno (void)
+{
+ return i2cErrno;
+}
+
+const char *i2cStrerror (int err)
+{
+ unsigned int i;
+
+ for (i = 0; i < arrsizeof (i2cErrnoStr); i++)
+ if (i2cErrnoStr [i].errno == err)
+ return i2cErrnoStr [i].text;
+
+ return NULL;
+}
--- /dev/null
+#ifndef _I2C_H_
+#define _I2C_H_
+
+#include "sysdefs.h"
+
+//
+// Does not define slave RX statuses. Bus errors (I2C_STAT == 0) is remapped
+// to I2CERR_ERROR in i2cStatus() so that we can use a value of 0 to indicate
+// no error.
+//
+typedef enum
+{
+ I2CERR_NONE = 0,
+ I2CERR_BUSY,
+ I2CERR_EMPTY,
+ I2CERR_TIMEOUT,
+ I2CERR_TIMEOUTWC,
+ I2CERR_TIMEOUTACKPOLL,
+ I2CERR_NOTIMPLEMENTED,
+ I2CERR_OTHER,
+ I2CERR_BUSERROR,
+ I2CERR_BUSERRORx = 0x00,
+ I2CERR_STARTTX = 0x08,
+ I2CERR_REPEATEDSTARTTX = 0x10,
+ I2CERR_SLAWTX_ACKRX = 0x18,
+ I2CERR_SLAWTX_NACKRX = 0x20,
+ I2CERR_DATTX_ACKRX = 0x28,
+ I2CERR_DATTX_NACKRX = 0x30,
+ I2CERR_ARBLOST = 0x38,
+ I2CERR_SLARTX_ACKRX = 0x40,
+ I2CERR_SLARTX_NACKRX = 0x48,
+ I2CERR_DATRX_ACKTX = 0x50,
+ I2CERR_DATRX_NACKTX = 0x58,
+ I2CERR_NOINFO = 0xf8
+}
+i2cErr_e;
+
+//
+//
+//
+extern i2cErr_e i2cErrno;
+
+//
+//
+//
+void i2cInit (void);
+int i2cGetErrno (void);
+const char *i2cStrerror (int err);
+void i2cSetTimeout (unsigned int timeoutInMilliseconds);
+void i2cDump (void);
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength);
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength);
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength);
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength);
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength);
+
+
+#endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+// Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+#undef I2C_DEBUG
+
+//
+//
+//
+typedef enum
+{
+ ACKPOLL_NO = 0,
+ ACKPOLL_YES
+}
+ackPoll_e;
+
+//
+//
+//
+static volatile int i2cBusInUse;
+static U8 i2cAddress;
+static U8 *i2cDataBuffer;
+static int i2cDataLenWrite;
+static int i2cDataLenRead;
+static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
+static int i2cDataCnt;
+static ackPoll_e i2cAckPoll = ACKPOLL_NO;
+
+//
+//
+//
+#ifdef I2C_DEBUG
+static U8 i2cTransactions [64];
+static int i2cTransactionsIndex;
+#define i2cDebug(x) do { if (i2cAckPoll && (i2cTransactionsIndex < (int) sizeof (i2cTransactions))) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
+#define i2cDebugReset() do { i2cTransactionsIndex = 0; } while (0)
+#else
+#define i2cDebug(x) do { } while (0)
+#define i2cDebugReset() do { } while (0)
+#endif
+
+static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
+static void i2cISR (void)
+{
+ i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
+ i2cDebug (i2cErrno);
+
+ switch (i2cErrno)
+ {
+ //
+ // Transmit conditions
+ //
+ case I2CERR_BUSERRORx : // 0x00
+ {
+ I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+ i2cAckPoll = ACKPOLL_NO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_STARTTX : // 0x08
+ case I2CERR_REPEATEDSTARTTX : // 0x10
+ {
+ i2cDebug (i2cAddress);
+ I2C0_DAT = i2cAddress;
+ }
+ break;
+
+ case I2CERR_SLAWTX_ACKRX : // 0x18
+ case I2CERR_DATTX_ACKRX : // 0x28
+ {
+ i2cAckPoll = ACKPOLL_NO;
+
+ if (i2cDataLenWrite && (i2cDataCnt < i2cDataLenWrite))
+ {
+ i2cDebug (i2cDataBuffer [i2cDataCnt]);
+ I2C0_DAT = i2cDataBuffer [i2cDataCnt++];
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ else
+ {
+ if (!i2cDataLenRead)
+ {
+ i2cDebug (0xff);
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cErrno = I2CERR_NONE;
+ i2cBusInUse = FALSE;
+ }
+ else
+ {
+ i2cDebug (0xfe);
+ i2cAddress |= 0x01;
+ i2cDataCnt = 0;
+ I2C0_CONSET = I2C_CONSET_STA;
+ }
+ }
+ }
+ break;
+
+ case I2CERR_DATRX_NACKTX : // 0x58
+ {
+ i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
+ i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
+ i2cErrno = I2CERR_NONE;
+ }
+
+ case I2CERR_SLAWTX_NACKRX : // 0x20
+ case I2CERR_SLARTX_NACKRX : // 0x48
+ {
+ if (i2cAckPoll)
+ break;
+ }
+
+ case I2CERR_DATTX_NACKRX : // 0x30
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_ARBLOST : // 0x38
+ {
+ I2C0_CONSET = I2C_CONSET_STA;
+ }
+ break;
+
+ //
+ // Receive byte conditions (fall through is intentional)
+ //
+ case I2CERR_DATRX_ACKTX : // 0x50
+ {
+ i2cDataBuffer [i2cDataCnt++] = I2C0_DAT;
+ i2cDebug (i2cDataBuffer [i2cDataCnt - 1]);
+ }
+
+ case I2CERR_SLARTX_ACKRX : // 0x40
+ {
+ if (i2cDataCnt < i2cDataLenRead - 1)
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_AA;
+ }
+ else
+ I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
+ }
+ break;
+
+ case I2CERR_NOINFO :
+ break;
+
+ default:
+ {
+ I2C0_CONCLR = I2C_CONCLR_I2ENC;
+ i2cAckPoll = ACKPOLL_NO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+ }
+
+ I2C0_CONCLR = I2C_CONSET_SI;
+ VIC_VectAddr = 0;
+}
+
+//
+// i2c1Init
+//
+void i2cInit (void)
+{
+ i2cBusInUse = FALSE;
+ i2cAckPoll = ACKPOLL_NO;
+
+ SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+ PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+ I2C0_CONCLR = I2C_CONCLR_MASK;
+ I2C0_CONSET = I2C_CONSET_I2EN;
+ I2C0_SCLL = 240;
+ I2C0_SCLH = 240;
+
+ //
+ // Initialize the interrupt vector
+ //
+ VIC_IntSelect &= ~VIC_IntSelect_I2C0;
+ VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
+ VIC_VectAddr7 = (int) i2cISR;
+ VIC_IntEnable = VIC_IntEnable_I2C0;
+}
+
+//
+//
+//
+static int i2cWaitComplete (int ticks)
+{
+ if (i2cBusInUse)
+ {
+ clock_t theFuture;
+
+ for (theFuture = times (NULL) + ticks; i2cBusInUse; )
+ {
+ if (times (NULL) > theFuture)
+ {
+ I2C0_CONCLR = I2C_CONCLR_I2ENC;
+ i2cErrno = I2CERR_TIMEOUTWC;
+ return -1;
+ }
+ }
+ }
+
+ return (i2cErrno == I2CERR_NONE) ? 0 : -1;
+}
+
+static int i2cPoll (U8 address)
+{
+ clock_t theFuture = times (NULL) + 10;
+
+ VIC_IntEnClr = VIC_IntEnClr_I2C0;
+
+ while (times (NULL) < theFuture)
+ {
+ I2C0_CONCLR = I2C_CONSET_SI;
+ I2C0_CONSET = I2C_CONSET_STA;
+
+ while (!(I2C0_CONSET & I2C_CONSET_SI))
+ ;
+
+ I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC;
+ I2C0_DAT = address & ~0x01;
+
+ while (!(I2C0_CONSET & I2C_CONSET_SI))
+ ;
+
+ if ((i2cErrno = I2C0_STAT) == I2CERR_SLAWTX_ACKRX)
+ break;
+ }
+
+ if (i2cErrno != I2CERR_SLAWTX_ACKRX)
+ i2cErrno = I2CERR_TIMEOUTACKPOLL;
+
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+
+ while (I2C0_CONSET & I2C_CONSET_STO)
+ ;
+
+ VIC_IntEnable = VIC_IntEnable_I2C0;
+
+ return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
+}
+
+//
+//
+//
+static int i2cKickOff (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead, ackPoll_e ackPoll)
+{
+ //
+ // Determine if our first operation will be a write or read. If both, the
+ // write always occurs first.
+ //
+ if (bufferLenWrite)
+ address &= ~0x01;
+ else if (bufferLenRead)
+ address |= 0x01;
+ else
+ address &= ~0x01;
+
+ //
+ // Wait until last I2C operation has finished.
+ //
+ if (i2cBusInUse && i2cWaitComplete (i2cTimeoutInTicks))
+ {
+ i2cErrno = I2CERR_TIMEOUT;
+ return -1;
+ }
+
+ //
+ // Mark bus as in use, save the address, buffer and length
+ //
+ i2cBusInUse = TRUE;
+ i2cAddress = address;
+ i2cDataBuffer = buffer;
+ i2cDataLenWrite = bufferLenWrite;
+ i2cDataLenRead = bufferLenRead;
+ i2cDataCnt = 0;
+ i2cAckPoll = ackPoll;
+ i2cDebugReset ();
+
+ //
+ // Clear any outstanding bits, enable the interface, and send a start bit.
+ // Once the start bit goes out, the interrupt drive state machine begins.
+ //
+ I2C0_CONCLR = I2C_CONCLR_MASK;
+ I2C0_CONSET = I2C_CONSET_I2EN;
+ I2C0_CONSET = I2C_CONSET_STA;
+
+ return 0;
+}
+
+//
+//
+//
+static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+ int r;
+
+ if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
+ r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+ return r;
+}
+
+static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+ int r;
+
+ if (!(r = i2cKickOff (address, buffer, 0, bufferLength, ACKPOLL_NO)))
+ r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+ return r;
+}
+
+static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
+{
+ int r;
+
+ if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
+ r = i2cWaitComplete (milliseconds / portTICK_RATE_MS);
+
+ return r;
+}
+
+//
+//
+//
+void i2cSetTimeout (unsigned int timeoutInMilliseconds)
+{
+ if (timeoutInMilliseconds < portTICK_RATE_MS)
+ timeoutInMilliseconds = portTICK_RATE_MS;
+
+ i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
+}
+
+void i2cDump (void)
+{
+#ifdef I2C_DEBUG
+ int i;
+
+ for (i = 0; i < i2cTransactionsIndex; i++)
+ printf ("0x%02x ", i2cTransactions [i]);
+
+ printf ("\n");
+#else
+ printf ("Not compiled for i2c debugging\n");
+#endif
+}
+
+//
+// DANGER, WILL ROBINSON! The callers buffer must persist until we're done
+//
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeoutInTicks);
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+ return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeoutInTicks);
+}
+
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if (!(r = i2cKickOff (address, buffer, bufferLength, 0, ACKPOLL_NO)))
+ if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
+ r = i2cPoll (address);
+
+ return r;
+}
+
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+ int r;
+
+ if (!(r = i2cKickOff (address, buffer, putLength, getLength, ACKPOLL_NO)))
+ if (!(r = i2cWaitComplete (i2cTimeoutInTicks)))
+ r = i2cPoll (address);
+
+ return r;
+}
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+// Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+
+//
+//
+//
+static volatile int i2cBusInUse;
+static U8 i2cAddress;
+static U8 *i2cDataBuffer;
+static int i2cDataLenWrite;
+static int i2cDataLenRead;
+static int i2cTimeout = I2C_DEFAULT_TIMEOUT;
+static U8 *i2cDataPtr;
+static U8 i2cTransactions [64];
+static int i2cTransactionsIndex;
+
+//
+//
+//
+#define i2cDebug(x) do { if (i2cTransactionsIndex < (int) sizeof (i2cTransactions)) i2cTransactions [i2cTransactionsIndex++] = x; } while (0)
+
+static void i2cISR (void) __attribute__ ((interrupt ("IRQ")));
+static void i2cISR (void)
+{
+ i2cErrno = (I2C0_STAT & I2C_STAT_STATMASK);
+ i2cDebug (i2cErrno);
+
+ switch (i2cErrno)
+ {
+ //
+ // Transmit conditions
+ //
+ case I2CERR_BUSERRORx : // 0x00
+ {
+ I2C0_CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_STARTTX : // 0x08
+ {
+ i2cDebug (i2cAddress);
+ I2C0_DAT = i2cAddress;
+ }
+ break;
+
+ case I2CERR_REPEATEDSTARTTX : // 0x10
+ {
+ i2cDebug (i2cAddress);
+ I2C0_DAT = i2cAddress;
+ }
+ break;
+
+ case I2CERR_SLAWTX_ACKRX : // 0x18
+ {
+ i2cDebug (*i2cDataPtr);
+ I2C0_DAT = *i2cDataPtr++;
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ break;
+
+ case I2CERR_SLAWTX_NACKRX : // 0x20
+ {
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_DATTX_ACKRX : // 0x28
+ {
+ if (--i2cDataLenWrite)
+ {
+ i2cDebug (*i2cDataPtr);
+ I2C0_DAT = *i2cDataPtr++;
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ }
+ else
+ {
+ if (!i2cDataLenRead)
+ {
+ i2cDebug (0xff);
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ else
+ {
+ i2cDebug (0xfe);
+ i2cAddress |= 0x01;
+ i2cDataPtr = i2cDataBuffer;
+ I2C0_CONSET = I2C_CONSET_STA;
+ }
+ }
+ }
+ break;
+
+ case I2CERR_DATTX_NACKRX : // 0x30
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_ARBLOST : // 0x38
+ {
+ I2C0_CONSET = I2C_CONSET_STA;
+ }
+ break;
+
+ //
+ // Receive byte conditions
+ //
+ case I2CERR_SLARTX_ACKRX : // 0x40
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_AA;
+ }
+ break;
+
+ case I2CERR_SLARTX_NACKRX : // 0x48
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_DATRX_ACKTX : // 0x50
+ {
+ *i2cDataPtr++ = I2C0_DAT;
+ i2cDebug (*(i2cDataPtr - 1));
+
+ if (--i2cDataLenRead)
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_AA;
+ }
+ else
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_AAC;
+ i2cBusInUse = FALSE;
+ }
+ }
+ break;
+
+ case I2CERR_DATRX_NACKTX : // 0x58
+ {
+ // *i2cDataPtr = I2C0_DAT;
+ // i2cDebug (*i2cDataPtr);
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ I2C0_CONSET = I2C_CONSET_STO;
+ i2cBusInUse = FALSE;
+ }
+ break;
+
+ case I2CERR_NOINFO :
+ break;
+
+ default:
+ {
+ I2C0_CONCLR = I2C_CONCLR_I2ENC;
+ i2cBusInUse = FALSE;
+ }
+ break;
+ }
+
+ I2C0_CONCLR = I2C_CONSET_SI;
+ VIC_VectAddr = 0;
+}
+
+//
+// i2c1Init
+//
+void i2cInit (void)
+{
+ i2cBusInUse = FALSE;
+
+ SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+ PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+ I2C0_CONCLR = I2C_CONCLR_MASK;
+ I2C0_CONSET = I2C_CONSET_I2EN;
+ I2C0_SCLL = 240;
+ I2C0_SCLH = 240;
+
+ //
+ // Initialize the interrupt vector
+ //
+ VIC_IntSelect &= ~VIC_IntSelect_I2C0;
+ VIC_VectCntl7 = VIC_VectCntl_ENABLE | VIC_Channel_I2C0;
+ VIC_VectAddr7 = (int) i2cISR;
+ VIC_IntEnable = VIC_IntEnable_I2C0;
+}
+
+//
+//
+//
+static int i2cTransferBytes (U8 address, U8 *buffer, int bufferLenWrite, int bufferLenRead)
+{
+ //
+ // Determine if our first operation will be a write or read. If both, the
+ // write always occurs first.
+ //
+ if (bufferLenWrite)
+ address &= ~0x01;
+ else if (bufferLenRead)
+ address |= 0x01;
+ else
+ {
+ i2cErrno = I2CERR_OTHER;
+ return -1;
+ }
+
+ //
+ // Wait until last I2C operation has finished.
+ //
+ if (i2cBusInUse && i2cWaitComplete (i2cTimeout))
+ {
+ i2cErrno = I2CERR_TIMEOUT;
+ return -1;
+ }
+
+ //
+ // Mark bus as in use, save the address, buffer and length
+ //
+ i2cBusInUse = TRUE;
+ i2cAddress = address;
+ i2cDataBuffer = buffer;
+ i2cDataLenWrite = bufferLenWrite;
+ i2cDataLenRead = bufferLenRead;
+ i2cDataPtr = buffer;
+
+ i2cTransactionsIndex = 0; // ###
+
+ I2C0_CONCLR = I2C_CONCLR_MASK;
+ I2C0_CONSET = I2C_CONSET_I2EN;
+ I2C0_CONSET = I2C_CONSET_STA;
+
+ return 0;
+}
+
+//
+//
+//
+int i2cWaitComplete (int milliseconds)
+{
+ if (i2cBusInUse)
+ {
+ clock_t theFuture;
+
+ if (milliseconds < 10)
+ milliseconds = 10;
+
+ for (theFuture = times (NULL) + (milliseconds / 10); i2cBusInUse; )
+ {
+ if (times (NULL) > theFuture)
+ {
+ I2C0_CONCLR = I2C_CONCLR_I2ENC;
+ i2cErrno = I2CERR_TIMEOUTWC;
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//
+//
+//
+static int i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+ if (i2cTransferBytes (address, buffer, bufferLength, 0))
+ return -1;
+
+ return i2cWaitComplete (milliseconds);
+}
+
+static int i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, int milliseconds)
+{
+ if (i2cTransferBytes (address, buffer, 0, bufferLength))
+ return -1;
+
+ return i2cWaitComplete (milliseconds);
+}
+
+static int i2cWriteReadBufferEx (U8 address, U8 *buffer, U32 putLength, U32 getLength, int milliseconds)
+{
+ if (i2cTransferBytes (address, buffer, putLength, getLength))
+ return -1;
+
+ return i2cWaitComplete (milliseconds);
+}
+
+//
+// DANGER, WILL ROBINSON! The callers buffer must persist until we're done
+//
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ return i2cWriteBufferEx (address, buffer, bufferLength, i2cTimeout);
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ return i2cReadBufferEx (address, buffer, bufferLength, i2cTimeout);
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+ return i2cWriteReadBufferEx (address, buffer, putLength, getLength, i2cTimeout);
+}
+
+void i2cSetTimeout (int timeoutInMilliseconds)
+{
+ if (timeoutInMilliseconds < 10)
+ timeoutInMilliseconds = 10;
+
+ i2cTimeout = timeoutInMilliseconds;
+}
+
+void i2cDump (void)
+{
+ int i;
+
+ for (i = 0; i < i2cTransactionsIndex; i++)
+ printf ("0x%02x ", i2cTransactions [i]);
+
+ printf ("\n");
+}
+
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+#include <sys/times.h>
+
+#include "i2c.h"
+
+//
+// Default timeout, in milliseconds for generic read/write
+//
+#define I2C_DEFAULT_TIMEOUT 100
+
+//
+//
+//
+typedef enum
+{
+ I2CFLAGS_START = 0x0001,
+ I2CFLAGS_REPEATEDSTART = 0x0002,
+ I2CFLAGS_STOP = 0x0004,
+ I2CFLAGS_ADDRESS = 0x0008,
+ I2CFLAGS_WRITEDATA = 0x0010,
+ I2CFLAGS_READDATA = 0x0020,
+}
+i2cFlags_e;
+
+typedef enum
+{
+ I2CMODE_ACK = 0,
+ I2CMODE_NACK,
+ I2CMODE_READ
+}
+i2cMode_e;
+
+//
+//
+//
+static unsigned int i2cTimeoutInTicks = I2C_DEFAULT_TIMEOUT / portTICK_RATE_MS;
+
+//
+// Our PCLK is 48Mhz (12Mhz Xtal, PLL x 4, VBPDIV = /1), we want 100Khz SCLK
+//
+void i2cInit (void)
+{
+ SCB_PCONP |= SCB_PCONP_PCI2C0;
+
+ PCB_PINSEL0 = (PCB_PINSEL0 & ~(PCB_PINSEL0_P02_MASK | PCB_PINSEL0_P03_MASK)) | (PCB_PINSEL0_P02_SCL0 | PCB_PINSEL0_P03_SDA0);
+
+ I2C0_CONCLR = I2C_CONCLR_MASK;
+ I2C0_CONSET = I2C_CONSET_I2EN;
+ I2C0_SCLL = 480;
+ I2C0_SCLH = 480;
+}
+
+//
+//
+//
+static i2cErr_e i2cStatus (void)
+{
+ i2cErr_e status;
+
+ while (!(I2C0_CONSET & I2C_CONSET_SI))
+ ;
+
+ if ((status = I2C0_STAT) == I2CERR_BUSERRORx)
+ return I2CERR_BUSERROR;
+
+ return status;
+}
+
+//
+//
+//
+static i2cErr_e i2cStop (void)
+{
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_STO;
+
+ while (I2C0_CONSET & I2C_CONSET_STO)
+ ;
+
+ return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cStart (void)
+{
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_STA;
+
+ while (1)
+ {
+ i2cErr_e status;
+
+ if (((status = i2cStatus ()) == I2CERR_STARTTX) || (status == I2CERR_REPEATEDSTARTTX))
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ return I2CERR_NONE;
+ }
+ else if (status != I2CERR_NOINFO)
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ return status;
+ }
+ else
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ }
+}
+
+//
+//
+//
+static i2cErr_e i2cRepeatedStart (void)
+{
+ while (!(I2C0_CONSET & I2C_CONSET_SI))
+ ;
+
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_STA;
+
+ while (1)
+ {
+ i2cErr_e status;
+
+ if (((status = i2cStatus ()) == I2CERR_STARTTX) || (status == I2CERR_REPEATEDSTARTTX))
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ return I2CERR_NONE;
+ }
+ else if (status != I2CERR_NOINFO)
+ {
+ I2C0_CONCLR = I2C_CONCLR_STAC;
+ return status;
+ }
+ else
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ }
+}
+
+//
+//
+//
+static i2cErr_e i2cPutByte (U8 data)
+{
+ if (!(I2C0_CONSET & I2C_CONSET_SI))
+ return I2CERR_BUSY;
+
+ I2C0_DAT = data;
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+
+ return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cGetByte (i2cMode_e mode, U8 *pData)
+{
+ switch (mode)
+ {
+ case I2CMODE_ACK :
+ I2C0_CONCLR = I2C_CONCLR_SIC;
+ I2C0_CONSET = I2C_CONSET_AA;
+ break;
+
+ case I2CMODE_NACK :
+ I2C0_CONCLR = (I2C_CONCLR_AAC | I2C_CONCLR_SIC);
+ break;
+
+ case I2CMODE_READ :
+ {
+ if (!(I2C0_CONSET & I2C_CONSET_SI))
+ return I2CERR_EMPTY;
+
+ *pData = (U8) I2C0_DAT;
+ }
+ break;
+ }
+
+ return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cWriteBufferEx (U8 address, U8 *buffer, U32 bufferLength, i2cFlags_e flags)
+{
+ U32 i;
+ i2cErr_e status;
+
+ if (flags & I2CFLAGS_START)
+ {
+ if ((status = i2cStart ()) != I2CERR_NONE)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+ else if (flags & I2CFLAGS_REPEATEDSTART)
+ {
+ if ((status = i2cRepeatedStart ()) != I2CERR_NONE)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+
+ if (flags & I2CFLAGS_ADDRESS)
+ {
+ do
+ if (((status = i2cPutByte (address & ~0x01)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+ return status;
+ while (status == I2CERR_BUSY);
+ }
+
+ if (flags & I2CFLAGS_WRITEDATA)
+ {
+ for (i = 0; i < bufferLength; i++, buffer++)
+ {
+ while (1)
+ {
+ if (((status = i2cStatus ()) == I2CERR_SLAWTX_ACKRX) || (status == I2CERR_DATTX_ACKRX))
+ {
+ do
+ if (((status = i2cPutByte (*buffer)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+ return status;
+ while (status == I2CERR_BUSY);
+
+ break;
+ }
+ else if (status != I2CERR_NOINFO)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+ }
+ }
+
+ if (flags & I2CFLAGS_STOP)
+ {
+ while (1)
+ {
+ if (((status = i2cStatus ()) == I2CERR_SLAWTX_ACKRX) || (status == I2CERR_DATTX_ACKRX))
+ {
+ i2cStop ();
+ return I2CERR_NONE;
+ }
+ else if (status != I2CERR_NOINFO)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+ }
+
+ return I2CERR_NONE;
+}
+
+//
+//
+//
+static i2cErr_e i2cReadBufferEx (U8 address, U8 *buffer, U32 bufferLength, i2cFlags_e flags)
+{
+ U32 i;
+ i2cErr_e status;
+
+ if (flags & I2CFLAGS_START)
+ {
+ if ((status = i2cStart ()) != I2CERR_NONE)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+ else if (flags & I2CFLAGS_REPEATEDSTART)
+ {
+ if ((status = i2cRepeatedStart ()) != I2CERR_NONE)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+
+ if (flags & I2CFLAGS_ADDRESS)
+ {
+ do
+ if (((status = i2cPutByte (address | 0x01)) != I2CERR_NONE) && (status != I2CERR_BUSY))
+ return status;
+ while (status == I2CERR_BUSY);
+ }
+
+ if (flags & I2CFLAGS_READDATA)
+ {
+ for (i = 0; i < bufferLength; i++, buffer++)
+ {
+ while (1)
+ {
+ if (((status = i2cStatus ()) == I2CERR_SLARTX_ACKRX) || (status == I2CERR_SLARTX_NACKRX) || (status == I2CERR_DATRX_ACKTX))
+ {
+ i2cGetByte ((i != bufferLength - 1) ? I2CMODE_ACK : I2CMODE_NACK, NULL);
+
+ do
+ status = i2cGetByte (I2CMODE_READ, buffer);
+ while (status == I2CERR_EMPTY);
+
+ break;
+ }
+ else if (status != I2CERR_NOINFO)
+ {
+ i2cStop ();
+ return status;
+ }
+ }
+ }
+ }
+
+ if (flags & I2CFLAGS_STOP)
+ i2cStop ();
+
+ return I2CERR_NONE;
+}
+
+//
+//
+//
+static int i2cPoll (U8 address)
+{
+ clock_t theFuture = times (NULL) + i2cTimeoutInTicks;
+
+ while (times (NULL) < theFuture)
+ {
+ if ((i2cErrno = i2cStart ()) != I2CERR_NONE)
+ break;
+ if ((i2cErrno = i2cPutByte (address & ~0x01)) != I2CERR_NONE)
+ break;
+ if ((i2cErrno = i2cStatus ()) == I2CERR_SLAWTX_ACKRX)
+ break;
+ }
+
+ if (i2cErrno != I2CERR_SLAWTX_ACKRX)
+ i2cErrno = I2CERR_TIMEOUTACKPOLL;
+
+ i2cStop ();
+
+ return (i2cErrno == I2CERR_SLAWTX_ACKRX) ? 0 : -1;
+}
+
+//
+//
+//
+void i2cSetTimeout (unsigned int timeoutInMilliseconds)
+{
+ if (timeoutInMilliseconds < portTICK_RATE_MS)
+ timeoutInMilliseconds = portTICK_RATE_MS;
+
+ i2cTimeoutInTicks = timeoutInMilliseconds / portTICK_RATE_MS;
+}
+
+void i2cDump (void)
+{
+ printf ("i2cDump not implemented for polled mode\n");
+}
+
+int i2cWriteBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ if ((i2cErrno = i2cWriteBufferEx (address, buffer, bufferLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_WRITEDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+int i2cReadBuffer (U8 address, U8 *buffer, U32 bufferLength)
+{
+ if ((i2cErrno = i2cReadBufferEx (address, buffer, bufferLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_READDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+int i2cWriteReadBuffer (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+ if ((i2cErrno = i2cWriteBufferEx (address, buffer, putLength, I2CFLAGS_START | I2CFLAGS_ADDRESS | I2CFLAGS_WRITEDATA)) != I2CERR_NONE)
+ return -1;
+
+ if ((i2cErrno = i2cReadBufferEx (address, buffer, getLength, I2CFLAGS_REPEATEDSTART | I2CFLAGS_ADDRESS | I2CFLAGS_READDATA | I2CFLAGS_STOP)) != I2CERR_NONE)
+ return -1;
+
+ return 0;
+}
+
+int i2cWriteBufferPoll (U8 address, U8 *buffer, U32 bufferLength)
+{
+ int r;
+
+ if (!(r = i2cWriteBuffer (address, buffer, bufferLength)))
+ r = i2cPoll (address);
+
+ return r;
+}
+
+int i2cWriteReadBufferPoll (U8 address, U8 *buffer, U32 putLength, U32 getLength)
+{
+ int r;
+
+ if (!(r = i2cWriteReadBuffer (address, buffer, putLength, getLength)))
+ r = i2cPoll (address);
+
+ return r;
+}
--- /dev/null
+#include "FreeRTOS.h"
+
+#include "i2c.h"
+#include "lm75.h"
+
+//
+//
+//
+static U8 lm75Address = LM75_ADDRESS;
+static U8 lm75LastRegister = LM75_REGISTER_TEMPERATURE;
+static U8 lm75Mode = 0;
+
+//
+//
+//
+static int lm75Read8 (U8 reg, int *value)
+{
+ lm75LastRegister = reg;
+ *value = 0;
+
+ if (i2cWriteBuffer (lm75Address, (U8 *) ®, sizeof (U8)))
+ return -1;
+
+ return i2cReadBuffer (lm75Address, (U8 *) value, sizeof (U8));
+}
+
+static int lm75Write8 (U8 reg, int value)
+{
+ U8 buffer [2];
+
+ buffer [0] = lm75LastRegister = reg;
+ buffer [1] = value;
+
+ return i2cWriteBuffer (lm75Address, buffer, sizeof (buffer));
+}
+
+//
+// DANGER, WILL ROBINSON! 'value' is the desired temperature * 2, where
+// the low bit indicates 0.5C or not. So for -50C degrees, we see -100.
+// For -50.5C, we see -101.
+//
+static int lm75Read16 (U8 reg, int *value)
+{
+ U8 buffer [2];
+
+ buffer [0] = lm75LastRegister = reg;
+
+ if (!lm75Mode)
+ {
+ if (i2cWriteReadBuffer (lm75Address, buffer, sizeof (U8), sizeof (buffer)))
+ return -1;
+ }
+ else
+ {
+ if (i2cWriteBuffer (lm75Address, (U8 *) ®, sizeof (U8)))
+ return -1;
+
+ if (i2cReadBuffer (lm75Address, buffer, sizeof (buffer)))
+ return -1;
+ }
+
+ //
+ // Sign extend negative numbers
+ //
+ *value = ((buffer [0] << 8) | buffer [1]) >> 7;
+
+ if (buffer [0] & 0x80)
+ *value |= 0xfffffe00;
+
+ return I2CERR_NONE;
+}
+
+static int lm75Write16 (U8 reg, int value)
+{
+ U8 buffer [3];
+
+ value <<= 7;
+
+ buffer [0] = lm75LastRegister = reg;
+ buffer [1] = value >> 8;
+ buffer [2] = value;
+
+ return i2cWriteBuffer (lm75Address, buffer, sizeof (buffer));
+}
+
+//
+// Don't call lm75Init() before tasker is started. The I2C routines use the
+// newlib/syscalls.c _times function, which calls xTaskGetTickCount(), which
+// hasn't been initialized yet.
+//
+int lm75Init (void)
+{
+ return lm75ConfigWrite (0);
+}
+
+void lm75SetMode (int mode)
+{
+ lm75Mode = mode;
+}
+
+void lm75SetAddress (U8 address)
+{
+ lm75Address = address;
+}
+
+int lm75ReRead (int *value)
+{
+ *value = 0;
+
+ if (lm75LastRegister == LM75_REGISTER_CONFIGURATION)
+ return i2cReadBuffer (lm75Address, (U8 *) value, sizeof (U8));
+ else
+ {
+ U8 buffer [2];
+
+ if (i2cReadBuffer (lm75Address, buffer, sizeof (buffer)))
+ return -1;
+
+ *value = ((buffer [0] << 8) | buffer [1]) >> 7;
+ }
+
+ return I2CERR_NONE;
+}
+
+int lm75TemperatureRead (int *temp)
+{
+ return lm75Read16 (LM75_REGISTER_TEMPERATURE, temp);
+}
+
+int lm75ConfigRead (int *configValue)
+{
+ return lm75Read8 (LM75_REGISTER_CONFIGURATION, configValue);
+}
+
+int lm75ConfigWrite (int configValue)
+{
+ return lm75Write8 (LM75_REGISTER_CONFIGURATION, configValue);
+}
+
+int lm75THYSTRead (int *thystValue)
+{
+ return lm75Read16 (LM75_REGISTER_THYST, thystValue);
+}
+
+int lm75THYSTWrite (int thystValue)
+{
+ return lm75Write16 (LM75_REGISTER_THYST, thystValue);
+}
+
+int lm75TOSTRead (int *thystValue)
+{
+ return lm75Read16 (LM75_REGISTER_TOS, thystValue);
+}
+
+int lm75TOSWrite (int thystValue)
+{
+ return lm75Write16 (LM75_REGISTER_TOS, thystValue);
+}
--- /dev/null
+#ifndef _LM75_H_
+#define _LM75_H_
+
+//
+//
+//
+#define LM75_ADDRESS (0x90)
+
+#define LM75_REGISTER_TEMPERATURE (0x00)
+#define LM75_REGISTER_CONFIGURATION (0x01)
+#define LM75_REGISTER_THYST (0x02)
+#define LM75_REGISTER_TOS (0x03)
+
+//
+//
+//
+int lm75Init (void);
+void lm75SetMode (int mode);
+void lm75SetAddress (U8 address);
+int lm75ReRead (int *value);
+int lm75TemperatureRead (int *temp);
+int lm75ConfigRead (int *configValue);
+int lm75ConfigWrite (int configValue);
+int lm75THYSTRead (int *thystValue);
+int lm75THYSTWrite (int thystValue);
+int lm75TOSTRead (int *thystValue);
+int lm75TOSWrite (int thystValue);
+
+#endif
--- /dev/null
+SRC_FILES=iap.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <string.h>
+#include "../cpu/cpu.h"
+#include "iap.h"
+
+//
+//
+//
+#define CPUCLK_IN_KHZ 48000
+
+#define IRQ_MASK 0x00000080
+#define FIQ_MASK 0x00000040
+#define INTs_MASK (IRQ_MASK | FIQ_MASK)
+
+//
+//
+//
+typedef struct flashSectorToAddress_s
+{
+ unsigned long address;
+ int sizeInBytes;
+}
+flashSectorToAddress_t;
+
+static flashSectorToAddress_t flashSectorToAddress [] =
+{
+ { 0x00000000, 4096 }, // 0
+ { 0x00001000, 4096 }, // 1
+ { 0x00002000, 4096 }, // 2
+ { 0x00003000, 4096 }, // 3
+ { 0x00004000, 4096 }, // 4
+ { 0x00005000, 4096 }, // 5
+ { 0x00006000, 4096 }, // 6
+ { 0x00007000, 4096 }, // 7
+ { 0x00008000, 32768 }, // 8
+ { 0x00010000, 32768 }, // 9
+ { 0x00018000, 32768 }, // 10
+ { 0x00020000, 32768 }, // 11
+ { 0x00028000, 32768 }, // 12
+ { 0x00030000, 32768 }, // 13
+ { 0x00038000, 32768 }, // 14
+ { 0x00040000, 32768 }, // 15
+ { 0x00048000, 32768 }, // 16
+ { 0x00050000, 32768 }, // 17
+ { 0x00058000, 32768 }, // 18
+ { 0x00060000, 32768 }, // 19
+ { 0x00068000, 32768 }, // 20
+ { 0x00070000, 32768 }, // 21
+ { 0x00078000, 4096 }, // 22
+ { 0x00079000, 4096 }, // 23
+ { 0x0007a000, 4096 }, // 24
+ { 0x0007b000, 4096 }, // 25
+ { 0x0007c000, 4096 }, // 26
+};
+
+typedef struct iapErrnoStr_s
+{
+ int errno;
+ const char *text;
+}
+iapErrnoStr_t;
+
+static iapErrnoStr_t iapErrnoStr [] =
+{
+ { IAP_RESULT_CMD_SUCCESS, "success" },
+ { IAP_RESULT_INVALID_COMMAND, "invalid command" },
+ { IAP_RESULT_SRC_ADDR_ERROR, "source address error" },
+ { IAP_RESULT_DST_ADDR_ERROR, "destination address error" },
+ { IAP_RESULT_SRC_ADDR_NOT_MAPPED, "source address not mapped" },
+ { IAP_RESULT_DST_ADDR_NOT_MAPPED, "destination address not mapped" },
+ { IAP_RESULT_COUNT_ERROR, "count error" },
+ { IAP_RESULT_INVALID_SECTOR, "invalid sector" },
+ { IAP_RESULT_SECTOR_NOT_BLANK, "sector not blank" },
+ { IAP_RESULT_SECTOR_NOT_PREPARED, "sector not prepared" },
+ { IAP_RESULT_COMPARE_ERROR, "compare error" },
+ { IAP_RESULT_BUSY, "busy" },
+ { IAP_RESULT_PARAM_ERROR, "parameter error" },
+ { IAP_RESULT_ADDR_ERROR, "address error" },
+ { IAP_RESULT_ADDR_NOT_MAPPED, "address not mapped" },
+ { IAP_RESULT_CMD_LOCKED, "command locked" },
+ { IAP_RESULT_INVALID_CODE, "invalid code" },
+ { IAP_RESULT_INVALID_BAUD_RATE, "invalid baud rate" },
+ { IAP_RESULT_ANVALID_STOP_BIT, "invalid stop bit" },
+ { IAP_RESULT_CRP_ENABLED, "CRP enabled" },
+ { IAP_RESULT_X_NOTSAFEREGION, "sector or address not in safe region" },
+ { IAP_RESULT_X_NOSAFEREGIONAVAIL, "no safe sectors available (all of memory used?)" },
+};
+
+//
+//
+//
+static unsigned int iapCommands [5];
+static unsigned int iapResults [2];
+static int iapErrno = 0;
+extern unsigned long __end_of_text__;
+static unsigned int end_of_text = (unsigned int) &__end_of_text__;
+
+
+//
+//
+//
+void iapInit (void)
+{
+}
+
+//
+//
+//
+int iapSectorToAddress (int sectorNumber, unsigned long *address, int *sectorSize)
+{
+ if (sectorNumber >= (int) arrsizeof (flashSectorToAddress))
+ return -1;
+
+ if (address)
+ *address = flashSectorToAddress [sectorNumber].address;
+ if (sectorSize)
+ *sectorSize = flashSectorToAddress [sectorNumber].sizeInBytes;
+
+ return 0;
+}
+
+//
+// Convert address to sector, or -1 if address not in flash area
+//
+int iapAddressToSector (unsigned long address)
+{
+ int i;
+
+ for (i = 0; i < (int) arrsizeof (flashSectorToAddress); i++)
+ if (address < (flashSectorToAddress [i].address + flashSectorToAddress [i].sizeInBytes))
+ return i;
+
+ iapErrno = IAP_RESULT_INVALID_SECTOR;
+ return -1;
+}
+
+//
+// 1 == address in safe region, 0 if not
+//
+int iapIsSafeAddress (unsigned long address)
+{
+ int eotSector;
+ int addressSector;
+
+ if ((eotSector = iapAddressToSector (end_of_text)) == -1)
+ return 0;
+ if ((addressSector = iapAddressToSector (address)) == -1)
+ return 0;
+
+ if (addressSector <= eotSector)
+ {
+ iapErrno = IAP_RESULT_X_NOTSAFEREGION;
+ return 0;
+ }
+
+ return 1;
+}
+
+//
+// 0 == not safe sector, 1 == safe (not in a code sector)
+//
+int iapIsSafeSector (int sector)
+{
+ int eotSector;
+
+ if ((eotSector = iapAddressToSector (end_of_text)) == -1)
+ return 0;
+
+ if (sector <= eotSector)
+ {
+ iapErrno = IAP_RESULT_X_NOTSAFEREGION;
+ return 0;
+ }
+
+ return 1;
+}
+
+//
+// Returns a safe sector number or -1 if none available
+//
+int iapFindSafeSector (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < arrsizeof (flashSectorToAddress); i++)
+ if (iapIsSafeSector (i))
+ return i;
+
+ iapErrno = IAP_RESULT_X_NOSAFEREGIONAVAIL;
+ return -1;
+}
+
+//
+// 1 == sector is safe, 0 == not safe
+//
+int iapIsValidSector (int sector)
+{
+ if ((sector < 0) || (sector >= (int) arrsizeof (flashSectorToAddress)))
+ {
+ iapErrno = IAP_RESULT_INVALID_SECTOR;
+ return 0;
+ }
+
+ return 1;
+}
+
+//
+//
+//
+int iapGetErrno (void)
+{
+ return iapErrno;
+}
+
+const char *iapStrerror (int err)
+{
+ unsigned int i;
+
+ for (i = 0; i < arrsizeof (iapErrnoStr); i++)
+ if (iapErrnoStr [i].errno == err)
+ return iapErrnoStr [i].text;
+
+ return NULL;
+}
+
+//
+//
+//
+static void iapCall (void) __attribute ((naked));
+static void iapCall (void)
+{
+ register void *pFP0 asm("r0") = iapCommands;
+ register void *pFP1 asm("r1") = iapResults;
+
+ asm volatile(" bx %[iapLocation]"
+ :
+ : "r" (pFP0), "r" (pFP1), [iapLocation] "r" (IAP_LOCATION) );
+}
+
+//
+//
+//
+static inline unsigned __get_cpsr (void)
+{
+ unsigned long retval;
+
+ asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
+
+ return retval;
+}
+
+static inline void __set_cpsr (unsigned val)
+{
+ asm volatile (" msr cpsr, %0" : /* no outputs */ : "r" (val) );
+}
+
+static unsigned disableInts (void)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr ();
+
+ do
+ __set_cpsr (_cpsr | INTs_MASK);
+ while ((__get_cpsr () ^ INTs_MASK) & INTs_MASK);
+
+ return _cpsr;
+}
+
+static unsigned restoreInts (unsigned oldCPSR)
+{
+ unsigned _cpsr;
+
+ _cpsr = __get_cpsr();
+
+ do
+ __set_cpsr ((_cpsr & ~INTs_MASK) | (oldCPSR & INTs_MASK));
+ while ((__get_cpsr () ^ oldCPSR) & INTs_MASK);
+
+ return _cpsr;
+}
+
+//
+//
+//
+int iapPrepareSectors (int startingSector, int endingSector)
+{
+ unsigned int cpsr;
+
+ if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+ return -1;
+
+ iapCommands [0] = IAP_CMD_PREPARE;
+ iapCommands [1] = startingSector;
+ iapCommands [2] = endingSector;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+// IAP_CMD_COPYRAMTOFLASH can span multiple sectors (2, at any rate, since bufferLen
+// must be 256, 512, 1024 or 4096, and the smallest sectors are 4096 bytes). Although
+// more than 2 sectors can be prepared for writing, it's useless to do so, since
+// after each IAP_CMD_COPYRAMTOFLASH, the sectors are re-locked.
+//
+int iapWriteSectors (unsigned int address, unsigned char *buffer, int bufferLen)
+{
+ unsigned int cpsr;
+
+ iapCommands [0] = IAP_CMD_COPYRAMTOFLASH;
+ iapCommands [1] = address;
+ iapCommands [2] = (int) buffer;
+ iapCommands [3] = bufferLen;
+ iapCommands [4] = CPUCLK_IN_KHZ;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ if ((iapErrno = iapResults [0]) != IAP_RESULT_CMD_SUCCESS)
+ return -1;
+
+ return 0;
+}
+
+int iapFillSectors (int startingSector, int endingSector, int byte)
+{
+ int sector;
+ unsigned char buffer [256];
+
+ if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+ return -1;
+
+ memset (buffer, byte, sizeof (buffer));
+
+ for (sector = startingSector; sector <= endingSector; sector++)
+ {
+ int i;
+ unsigned long address;
+ int sectorSize;
+
+ if (iapSectorToAddress (sector, &address, §orSize))
+ return -1;
+
+ for (i = 0; i < sectorSize; i += sizeof (buffer))
+ {
+ if (iapPrepareSectors (sector, sector) == -1)
+ return -1;
+ if (iapWriteSectors (address + i, buffer, sizeof (buffer)) == -1)
+ return -1;
+ if (iapCompare (address + i, buffer, sizeof (buffer)) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int iapEraseSectors (int startingSector, int endingSector)
+{
+ unsigned int cpsr;
+
+ if (!iapIsSafeSector (startingSector) || !iapIsSafeSector (endingSector))
+ return -1;
+
+ if (iapPrepareSectors (startingSector, endingSector) == -1)
+ return -1;
+
+ iapCommands [0] = IAP_CMD_ERASE;
+ iapCommands [1] = startingSector;
+ iapCommands [2] = endingSector;
+ iapCommands [3] = CPUCLK_IN_KHZ;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+// -1 = error (iapErrno set)
+// 0 = sector blank
+// 1 = sector not blank
+//
+int iapBlankCheckSectors (int startingSector, int endingSector)
+{
+ unsigned int cpsr;
+
+ if (!iapIsValidSector (startingSector) || !iapIsValidSector (endingSector))
+ return -1;
+
+ iapCommands [0] = IAP_CMD_BLANKCHECK;
+ iapCommands [1] = startingSector;
+ iapCommands [2] = endingSector;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ if ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS)
+ return 0;
+ if (iapResults [0] == IAP_RESULT_SECTOR_NOT_BLANK)
+ return 1;
+
+ return -1;
+}
+
+//
+//
+//
+unsigned int iapReadPartID (void)
+{
+ unsigned int cpsr;
+
+ iapCommands [0] = IAP_CMD_READPARTID;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ return iapResults [1];
+}
+
+//
+//
+//
+unsigned int iapReadBootCodeVersion (void)
+{
+ unsigned int cpsr;
+
+ iapCommands [0] = IAP_CMD_READBOOTCODEVER;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ return iapResults [1];
+}
+
+//
+//
+//
+int iapCompare (unsigned int address, unsigned char *buffer, int bufferLen)
+{
+ unsigned int cpsr;
+
+ iapCommands [0] = IAP_CMD_COMPARE;
+ iapCommands [1] = address;
+ iapCommands [2] = (int) buffer;
+ iapCommands [3] = bufferLen;
+
+ cpsr = disableInts ();
+
+ iapCall ();
+
+ restoreInts (cpsr);
+
+ return ((iapErrno = iapResults [0]) == IAP_RESULT_CMD_SUCCESS) ? 0 : -1;
+}
+
+//
+//
+//
+void iapISP (void)
+{
+ int i;
+ REG32 *p;
+
+ portDISABLE_INTERRUPTS ();
+
+ VIC_IntEnClr = VIC_IntEnClr_MASK;
+
+ SCB_PLLCON = 0;
+ SCB_PLLCFG = 0;
+ SCB_PLLFEED = SCB_PLLFEED_FEED1;
+ SCB_PLLFEED = SCB_PLLFEED_FEED2;
+
+ USB_PLLCON = 0;
+ USB_PLLCFG = 0;
+ USB_PLLFEED = USB_PLLFEED_FEED1;
+ USB_PLLFEED = USB_PLLFEED_FEED2;
+
+ for (p = (REG32 *) T1_BASE_ADDR, i = 0; i< 0x74 / 4; i++)
+ *p++ = 0;
+
+ T1_IR = 0xff;
+
+ SCB_PCONP = 0x000003be;
+
+ UART0_IER = 0x00;
+ UART0_LCR = 0x80;
+ UART0_DLL = 0x01;
+ UART0_DLM = 0x00;
+ UART0_LCR = 0x00;
+ UART0_FCR = 0x06;
+ UART0_FDR = 0x10;
+
+ SCB_MEMMAP = 0;
+ SCB_VPBDIV = 0;
+
+ PCB_PINSEL0 = 0x00000000;
+ PCB_PINSEL1 = 0x00000000;
+
+ GPIO0_IODIR = 0x00004000;
+ GPIO0_IOCLR = 0x00004000;
+
+ WD_TC = 0x0ffffff;
+ WD_MOD = 0;
+ WD_FEED = WD_FEED_FEED1;
+ WD_FEED = WD_FEED_FEED2;
+
+ iapCommands [0] = IAP_CMD_REINVOKEISP;
+
+ // disableInts ();
+ // cpuPLLDisable ();
+ // cpuT1Disable ();
+
+ iapCall ();
+}
--- /dev/null
+#ifndef _IAP_H_
+#define _IAP_H_
+
+//
+//
+//
+#define IAP_RESULT_X_NOTSAFEREGION (IAP_RESULT_LAST + 1)
+#define IAP_RESULT_X_NOSAFEREGIONAVAIL (IAP_RESULT_LAST + 2)
+
+//
+//
+//
+void iapInit (void);
+int iapSectorToAddress (int sectorNumber, unsigned long *address, int *sectorSize);
+int iapAddressToSector (unsigned long address);
+int iapIsSafeAddress (unsigned long address);;
+int iapIsSafeSector (int sector);
+int iapFindSafeSector (void);
+int iapIsValidSector (int sector);
+int iapGetErrno (void);
+const char *iapStrerror (int err);
+int iapPrepareSectors (int startingSector, int endingSector);
+int iapFillSectors (int startingSector, int endingSector, int byte);
+int iapWriteSectors (unsigned int address, unsigned char *buffer, int bufferLen);
+int iapEraseSectors (int startingSector, int endingSector);
+int iapBlankCheckSectors (int startingSector, int endingSector);
+unsigned int iapReadPartID (void);
+unsigned int iapReadBootCodeVersion (void);
+int iapCompare (unsigned int address, unsigned char *buffer, int bufferLen);
+void iapISP (void);
+
+#endif
--- /dev/null
+SRC_FILES=leds.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+//
+//
+//
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../cpu/cpu.h"
+#include "leds.h"
+
+//
+//
+//
+typedef struct
+{
+ int timeOn;
+ int timeOff;
+}
+ledDutyCycles_t;
+
+static ledDutyCycles_t ledDutyCycles [] =
+{
+ { (200 / portTICK_RATE_MS), (800 / portTICK_RATE_MS) },
+ { (400 / portTICK_RATE_MS), (600 / portTICK_RATE_MS) },
+ { (600 / portTICK_RATE_MS), (400 / portTICK_RATE_MS) },
+ { (800 / portTICK_RATE_MS), (200 / portTICK_RATE_MS) },
+};
+
+xQueueHandle xLEDQueue;
+
+//
+//
+//
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)))
+{
+ portTickType ledTimeOn = 1;
+ portTickType ledTimeOff = 1;
+ portTickType lastTickTime;
+ int dutyCycle = 0;
+
+ //
+ // Create the queue, turn on LED and die if we can't
+ //
+ if ((xLEDQueue = xQueueCreate (1, sizeof (dutyCycle))) == 0)
+ {
+ GPIO0_IOSET = GPIO_IO_P10;
+
+ while (1)
+ vTaskDelay (100);
+ }
+
+ //
+ // Send ourselves a message to init the flash time
+ //
+ xQueueSend (xLEDQueue, &dutyCycle, (portTickType) 0);
+
+ //
+ // We need to initialise lastTickTime prior to the first call to vTaskDelayUntil()
+ //
+ lastTickTime = xTaskGetTickCount ();
+
+ for (;;)
+ {
+ vTaskDelayUntil (&lastTickTime, ledTimeOn);
+ GPIO0_IOSET = GPIO_IO_P10;
+ vTaskDelayUntil (&lastTickTime, ledTimeOff);
+ GPIO0_IOCLR = GPIO_IO_P10;
+
+ if (xQueueReceive (xLEDQueue, &dutyCycle, (portTickType) 0))
+ {
+ dutyCycle %= arrsizeof (ledDutyCycles);
+
+ ledTimeOn = ledDutyCycles [dutyCycle].timeOn;
+ ledTimeOff = ledDutyCycles [dutyCycle].timeOff;
+ }
+ }
+}
--- /dev/null
+#ifndef _LEDS_H_
+#define _LEDS_H_
+
+//
+//
+//
+extern xQueueHandle xLEDQueue;
+
+//
+//
+//
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)));
+
+#endif
--- /dev/null
+//
+// This code was from the original demo package. Although it is no longer
+// used, it shows an excellent example of how to reuse task code with
+// local variables.
+//
+// Each time the task is create with xTaskCreate, it increment the task
+// number, which it uses to calculate a flash rate and which LED to
+// flash.
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "../cpu/cpu.h"
+#include "leds.h"
+
+//
+//
+//
+#define ledFLASH_RATE_BASE ((portTickType) 333)
+static portBASE_TYPE uxFlashTaskNumber = 0;
+
+portTASK_FUNCTION (vLEDFlashTask, pvParameters __attribute__ ((unused)))
+{
+ portTickType xFlashRate;
+ portTickType xLastFlashTime;
+ unsigned portBASE_TYPE uxLED;
+
+ //
+ // Calculate the LED and flash rate
+ //
+ portENTER_CRITICAL ();
+ {
+ uxLED = uxFlashTaskNumber;
+ 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 (;;)
+ {
+ vTaskDelayUntil (&xLastFlashTime, xFlashRate);
+ cpuToggleLED (uxLED);
+ vTaskDelayUntil (&xLastFlashTime, xFlashRate);
+ cpuToggleLED (uxLED);
+ }
+}
--- /dev/null
+/*
+// Using typedef'ed structures instead of #define's would be much cleaner. However,
+// it's a damn lot of work to define them all, and there were a bunch of #defines
+// to start with, so I just expanded them.
+*/
+
+#ifndef _LPC210X_H_
+#define _LPC210X_H_
+
+#include "sysdefs.h"
+
+/*##############################################################################
+## MISC
+##############################################################################*/
+
+/* Constants for data to put in IRQ/FIQ Exception Vectors */
+#define VECTDATA_IRQ 0xe51ffff0 /* LDR PC,[PC,#-0xFF0] */
+#define VECTDATA_FIQ /* __TODO */
+
+
+/*##############################################################################
+## VECTORED INTERRUPT CONTROLLER
+##############################################################################*/
+
+#define VIC_IRQStatus (*(pREG32 (0xfffff000)))
+#define VIC_FIQStatus (*(pREG32 (0xfffff004)))
+#define VIC_RawIntr (*(pREG32 (0xfffff008)))
+#define VIC_IntSelect (*(pREG32 (0xfffff00c)))
+#define VIC_IntEnable (*(pREG32 (0xfffff010)))
+#define VIC_IntEnClr (*(pREG32 (0xfffff014)))
+#define VIC_SoftInt (*(pREG32 (0xfffff018)))
+#define VIC_SoftIntClear (*(pREG32 (0xfffff01c)))
+#define VIC_Protection (*(pREG32 (0xfffff020)))
+#define VIC_VectAddr (*(pREG32 (0xfffff030)))
+#define VIC_DefVectAddr (*(pREG32 (0xfffff034)))
+
+#define VIC_VectAddr0 (*(pREG32 (0xfffff100)))
+#define VIC_VectAddr1 (*(pREG32 (0xfffff104)))
+#define VIC_VectAddr2 (*(pREG32 (0xfffff108)))
+#define VIC_VectAddr3 (*(pREG32 (0xfffff10c)))
+#define VIC_VectAddr4 (*(pREG32 (0xfffff110)))
+#define VIC_VectAddr5 (*(pREG32 (0xfffff114)))
+#define VIC_VectAddr6 (*(pREG32 (0xfffff118)))
+#define VIC_VectAddr7 (*(pREG32 (0xfffff11c)))
+#define VIC_VectAddr8 (*(pREG32 (0xfffff120)))
+#define VIC_VectAddr9 (*(pREG32 (0xfffff124)))
+#define VIC_VectAddr10 (*(pREG32 (0xfffff128)))
+#define VIC_VectAddr11 (*(pREG32 (0xfffff12c)))
+#define VIC_VectAddr12 (*(pREG32 (0xfffff130)))
+#define VIC_VectAddr13 (*(pREG32 (0xfffff134)))
+#define VIC_VectAddr14 (*(pREG32 (0xfffff138)))
+#define VIC_VectAddr15 (*(pREG32 (0xfffff13c)))
+
+#define VIC_VectCntl0 (*(pREG32 (0xfffff200)))
+#define VIC_VectCntl1 (*(pREG32 (0xfffff204)))
+#define VIC_VectCntl2 (*(pREG32 (0xfffff208)))
+#define VIC_VectCntl3 (*(pREG32 (0xfffff20c)))
+#define VIC_VectCntl4 (*(pREG32 (0xfffff210)))
+#define VIC_VectCntl5 (*(pREG32 (0xfffff214)))
+#define VIC_VectCntl6 (*(pREG32 (0xfffff218)))
+#define VIC_VectCntl7 (*(pREG32 (0xfffff21c)))
+#define VIC_VectCntl8 (*(pREG32 (0xfffff220)))
+#define VIC_VectCntl9 (*(pREG32 (0xfffff224)))
+#define VIC_VectCntl10 (*(pREG32 (0xfffff228)))
+#define VIC_VectCntl11 (*(pREG32 (0xfffff22c)))
+#define VIC_VectCntl12 (*(pREG32 (0xfffff230)))
+#define VIC_VectCntl13 (*(pREG32 (0xfffff234)))
+#define VIC_VectCntl14 (*(pREG32 (0xfffff238)))
+#define VIC_VectCntl15 (*(pREG32 (0xfffff23c)))
+
+#define VIC_ITCR (*(pREG32 (0xfffff300)))
+#define VIC_ITIP1 (*(pREG32 (0xfffff304)))
+#define VIC_ITIP2 (*(pREG32 (0xfffff308)))
+#define VIC_ITOP1 (*(pREG32 (0xfffff30c)))
+#define VIC_ITOP2 (*(pREG32 (0xfffff310)))
+#define VIC_PeriphID0 (*(pREG32 (0xffffffe0)))
+#define VIC_PeriphID1 (*(pREG32 (0xffffffe4)))
+#define VIC_PeriphID2 (*(pREG32 (0xffffffe8)))
+#define VIC_PeriphID3 (*(pREG32 (0xffffffec)))
+
+#define VIC_SoftInt_WDT (0x00000001)
+#define VIC_SoftInt_ARMCore0 (0x00000004)
+#define VIC_SoftInt_ARMCore1 (0x00000008)
+#define VIC_SoftInt_Timer0 (0x00000010)
+#define VIC_SoftInt_Timer1 (0x00000020)
+#define VIC_SoftInt_UART0 (0x00000040)
+#define VIC_SoftInt_UART1 (0x00000080)
+#define VIC_SoftInt_PWM0 (0x00000100)
+#define VIC_SoftInt_I2C0 (0x00000200)
+#define VIC_SoftInt_SPI0 (0x00000400)
+#define VIC_SoftInt_SPI1 (0x00000800)
+#define VIC_SoftInt_SSP (0x00000800)
+#define VIC_SoftInt_PLL (0x00001000)
+#define VIC_SoftInt_RTC (0x00002000)
+#define VIC_SoftInt_EINT0 (0x00004000)
+#define VIC_SoftInt_EINT1 (0x00008000)
+#define VIC_SoftInt_EINT2 (0x00010000)
+#define VIC_SoftInt_EINT3 (0x00020000)
+#define VIC_SoftInt_AD0 (0x00040000)
+#define VIC_SoftInt_I2C1 (0x00080000)
+#define VIC_SoftInt_BOD (0x00100000)
+#define VIC_SoftInt_AD1 (0x00200000)
+#define VIC_SoftInt_USB (0x00400000)
+#define VIC_SoftInt_MASK (0x007ffffd)
+
+#define VIC_SoftIntClr_WDT (0x00000001)
+#define VIC_SoftIntClr_ARMCore0 (0x00000004)
+#define VIC_SoftIntClr_ARMCore1 (0x00000008)
+#define VIC_SoftIntClr_Timer0 (0x00000010)
+#define VIC_SoftIntClr_Timer1 (0x00000020)
+#define VIC_SoftIntClr_UART0 (0x00000040)
+#define VIC_SoftIntClr_UART1 (0x00000080)
+#define VIC_SoftIntClr_PWM0 (0x00000100)
+#define VIC_SoftIntClr_I2C0 (0x00000200)
+#define VIC_SoftIntClr_SPI0 (0x00000400)
+#define VIC_SoftIntClr_SPI1 (0x00000800)
+#define VIC_SoftIntClr_SSP (0x00000800)
+#define VIC_SoftIntClr_PLL (0x00001000)
+#define VIC_SoftIntClr_RTC (0x00002000)
+#define VIC_SoftIntClr_EINT0 (0x00004000)
+#define VIC_SoftIntClr_EINT1 (0x00008000)
+#define VIC_SoftIntClr_EINT2 (0x00010000)
+#define VIC_SoftIntClr_EINT3 (0x00020000)
+#define VIC_SoftIntClr_AD0 (0x00040000)
+#define VIC_SoftIntClr_I2C1 (0x00080000)
+#define VIC_SoftIntClr_BOD (0x00100000)
+#define VIC_SoftIntClr_AD1 (0x00200000)
+#define VIC_SoftIntClr_USB (0x00400000)
+#define VIC_SoftIntClr_MASK (0x007ffffd)
+
+#define VIC_RawIntr_WDT (0x00000001)
+#define VIC_RawIntr_ARMCore0 (0x00000004)
+#define VIC_RawIntr_ARMCore1 (0x00000008)
+#define VIC_RawIntr_Timer0 (0x00000010)
+#define VIC_RawIntr_Timer1 (0x00000020)
+#define VIC_RawIntr_UART0 (0x00000040)
+#define VIC_RawIntr_UART1 (0x00000080)
+#define VIC_RawIntr_PWM0 (0x00000100)
+#define VIC_RawIntr_I2C0 (0x00000200)
+#define VIC_RawIntr_SPI0 (0x00000400)
+#define VIC_RawIntr_SPI1 (0x00000800)
+#define VIC_RawIntr_SSP (0x00000800)
+#define VIC_RawIntr_PLL (0x00001000)
+#define VIC_RawIntr_RTC (0x00002000)
+#define VIC_RawIntr_EINT0 (0x00004000)
+#define VIC_RawIntr_EINT1 (0x00008000)
+#define VIC_RawIntr_EINT2 (0x00010000)
+#define VIC_RawIntr_EINT3 (0x00020000)
+#define VIC_RawIntr_AD0 (0x00040000)
+#define VIC_RawIntr_I2C1 (0x00080000)
+#define VIC_RawIntr_BOD (0x00100000)
+#define VIC_RawIntr_AD1 (0x00200000)
+#define VIC_RawIntr_USB (0x00400000)
+#define VIC_RawIntr_MASK (0x007ffffd)
+
+#define VIC_IntEnable_WDT (0x00000001)
+#define VIC_IntEnable_ARMCore0 (0x00000004)
+#define VIC_IntEnable_ARMCore1 (0x00000008)
+#define VIC_IntEnable_Timer0 (0x00000010)
+#define VIC_IntEnable_Timer1 (0x00000020)
+#define VIC_IntEnable_UART0 (0x00000040)
+#define VIC_IntEnable_UART1 (0x00000080)
+#define VIC_IntEnable_PWM0 (0x00000100)
+#define VIC_IntEnable_I2C0 (0x00000200)
+#define VIC_IntEnable_SPI0 (0x00000400)
+#define VIC_IntEnable_SPI1 (0x00000800)
+#define VIC_IntEnable_SSP (0x00000800)
+#define VIC_IntEnable_PLL (0x00001000)
+#define VIC_IntEnable_RTC (0x00002000)
+#define VIC_IntEnable_EINT0 (0x00004000)
+#define VIC_IntEnable_EINT1 (0x00008000)
+#define VIC_IntEnable_EINT2 (0x00010000)
+#define VIC_IntEnable_EINT3 (0x00020000)
+#define VIC_IntEnable_AD0 (0x00040000)
+#define VIC_IntEnable_I2C1 (0x00080000)
+#define VIC_IntEnable_BOD (0x00100000)
+#define VIC_IntEnable_AD1 (0x00200000)
+#define VIC_IntEnable_USB (0x00400000)
+#define VIC_IntEnable_MASK (0x007ffffd)
+
+#define VIC_IntEnClr_WDT (0x00000001)
+#define VIC_IntEnClr_ARMCore0 (0x00000004)
+#define VIC_IntEnClr_ARMCore1 (0x00000008)
+#define VIC_IntEnClr_Timer0 (0x00000010)
+#define VIC_IntEnClr_Timer1 (0x00000020)
+#define VIC_IntEnClr_UART0 (0x00000040)
+#define VIC_IntEnClr_UART1 (0x00000080)
+#define VIC_IntEnClr_PWM0 (0x00000100)
+#define VIC_IntEnClr_I2C0 (0x00000200)
+#define VIC_IntEnClr_SPI0 (0x00000400)
+#define VIC_IntEnClr_SPI1 (0x00000800)
+#define VIC_IntEnClr_SSP (0x00000800)
+#define VIC_IntEnClr_PLL (0x00001000)
+#define VIC_IntEnClr_RTC (0x00002000)
+#define VIC_IntEnClr_EINT0 (0x00004000)
+#define VIC_IntEnClr_EINT1 (0x00008000)
+#define VIC_IntEnClr_EINT2 (0x00010000)
+#define VIC_IntEnClr_EINT3 (0x00020000)
+#define VIC_IntEnClr_AD0 (0x00040000)
+#define VIC_IntEnClr_I2C1 (0x00080000)
+#define VIC_IntEnClr_BOD (0x00100000)
+#define VIC_IntEnClr_AD1 (0x00200000)
+#define VIC_IntEnClr_USB (0x00400000)
+#define VIC_IntEnClr_MASK (0x007ffffd)
+
+#define VIC_IntSelect_WDT (0x00000001)
+#define VIC_IntSelect_ARMCore0 (0x00000004)
+#define VIC_IntSelect_ARMCore1 (0x00000008)
+#define VIC_IntSelect_Timer0 (0x00000010)
+#define VIC_IntSelect_Timer1 (0x00000020)
+#define VIC_IntSelect_UART0 (0x00000040)
+#define VIC_IntSelect_UART1 (0x00000080)
+#define VIC_IntSelect_PWM0 (0x00000100)
+#define VIC_IntSelect_I2C0 (0x00000200)
+#define VIC_IntSelect_SPI0 (0x00000400)
+#define VIC_IntSelect_SPI1 (0x00000800)
+#define VIC_IntSelect_SSP (0x00000800)
+#define VIC_IntSelect_PLL (0x00001000)
+#define VIC_IntSelect_RTC (0x00002000)
+#define VIC_IntSelect_EINT0 (0x00004000)
+#define VIC_IntSelect_EINT1 (0x00008000)
+#define VIC_IntSelect_EINT2 (0x00010000)
+#define VIC_IntSelect_EINT3 (0x00020000)
+#define VIC_IntSelect_AD0 (0x00040000)
+#define VIC_IntSelect_I2C1 (0x00080000)
+#define VIC_IntSelect_BOD (0x00100000)
+#define VIC_IntSelect_AD1 (0x00200000)
+#define VIC_IntSelect_USB (0x00400000)
+#define VIC_IntSelect_MASK (0x007ffffd)
+
+#define VIC_IRQStatus_WDT (0x00000001)
+#define VIC_IRQStatus_ARMCore0 (0x00000004)
+#define VIC_IRQStatus_ARMCore1 (0x00000008)
+#define VIC_IRQStatus_Timer0 (0x00000010)
+#define VIC_IRQStatus_Timer1 (0x00000020)
+#define VIC_IRQStatus_UART0 (0x00000040)
+#define VIC_IRQStatus_UART1 (0x00000080)
+#define VIC_IRQStatus_PWM0 (0x00000100)
+#define VIC_IRQStatus_I2C0 (0x00000200)
+#define VIC_IRQStatus_SPI0 (0x00000400)
+#define VIC_IRQStatus_SPI1 (0x00000800)
+#define VIC_IRQStatus_SSP (0x00000800)
+#define VIC_IRQStatus_PLL (0x00001000)
+#define VIC_IRQStatus_RTC (0x00002000)
+#define VIC_IRQStatus_EINT0 (0x00004000)
+#define VIC_IRQStatus_EINT1 (0x00008000)
+#define VIC_IRQStatus_EINT2 (0x00010000)
+#define VIC_IRQStatus_EINT3 (0x00020000)
+#define VIC_IRQStatus_AD0 (0x00040000)
+#define VIC_IRQStatus_I2C1 (0x00080000)
+#define VIC_IRQStatus_BOD (0x00100000)
+#define VIC_IRQStatus_AD1 (0x00200000)
+#define VIC_IRQStatus_USB (0x00400000)
+#define VIC_IRQStatus_MASK (0x007ffffd)
+
+#define VIC_FIQStatus_WDT (0x00000001)
+#define VIC_FIQStatus_ARMCore0 (0x00000004)
+#define VIC_FIQStatus_ARMCore1 (0x00000008)
+#define VIC_FIQStatus_Timer0 (0x00000010)
+#define VIC_FIQStatus_Timer1 (0x00000020)
+#define VIC_FIQStatus_UART0 (0x00000040)
+#define VIC_FIQStatus_UART1 (0x00000080)
+#define VIC_FIQStatus_PWM0 (0x00000100)
+#define VIC_FIQStatus_I2C0 (0x00000200)
+#define VIC_FIQStatus_SPI0 (0x00000400)
+#define VIC_FIQStatus_SPI1 (0x00000800)
+#define VIC_FIQStatus_SSP (0x00000800)
+#define VIC_FIQStatus_PLL (0x00001000)
+#define VIC_FIQStatus_RTC (0x00002000)
+#define VIC_FIQStatus_EINT0 (0x00004000)
+#define VIC_FIQStatus_EINT1 (0x00008000)
+#define VIC_FIQStatus_EINT2 (0x00010000)
+#define VIC_FIQStatus_EINT3 (0x00020000)
+#define VIC_FIQStatus_AD0 (0x00040000)
+#define VIC_FIQStatus_I2C1 (0x00080000)
+#define VIC_FIQStatus_BOD (0x00100000)
+#define VIC_FIQStatus_AD1 (0x00200000)
+#define VIC_FIQStatus_USB (0x00400000)
+#define VIC_FIQStatus_MASK (0x007ffffd)
+
+#define VIC_VectCntl_SLOTMASK (0x0000001f)
+#define VIC_VectCntl_ENABLE (0x00000020)
+
+#define VIC_Protection_ACCESS (0x00000001)
+#define VIC_Protection_MASK (0x00000001)
+
+#define VIC_Mask_WDT (0x00000001)
+#define VIC_Mask_RSVD (0x00000002)
+#define VIC_Mask_ARMCore0 (0x00000004)
+#define VIC_Mask_ARMCore1 (0x00000008)
+#define VIC_Mask_Timer0 (0x00000010)
+#define VIC_Mask_Timer1 (0x00000020)
+#define VIC_Mask_UART0 (0x00000040)
+#define VIC_Mask_UART1 (0x00000080)
+#define VIC_Mask_PWM0 (0x00000100)
+#define VIC_Mask_I2C0 (0x00000200)
+#define VIC_Mask_SPI0 (0x00000400)
+#define VIC_Mask_SPI1 (0x00000800)
+#define VIC_Mask_SSP (0x00000800)
+#define VIC_Mask_PLL (0x00001000)
+#define VIC_Mask_RTC (0x00002000)
+#define VIC_Mask_EINT0 (0x00004000)
+#define VIC_Mask_EINT1 (0x00008000)
+#define VIC_Mask_EINT2 (0x00010000)
+#define VIC_Mask_EINT3 (0x00020000)
+#define VIC_Mask_AD0 (0x00040000)
+#define VIC_Mask_I2C1 (0x00080000)
+#define VIC_Mask_BOD (0x00100000)
+#define VIC_Mask_AD1 (0x00200000)
+#define VIC_Mask_USB (0x00400000)
+#define VIC_Mask_MASK (0x007ffffd)
+
+#define VIC_Channel_WDT (0)
+#define VIC_Channel_RSVD (1)
+#define VIC_Channel_ARMCore0 (2)
+#define VIC_Channel_ARMCore1 (3)
+#define VIC_Channel_Timer0 (4)
+#define VIC_Channel_Timer1 (5)
+#define VIC_Channel_UART0 (6)
+#define VIC_Channel_UART1 (7)
+#define VIC_Channel_PWM0 (8)
+#define VIC_Channel_I2C0 (9)
+#define VIC_Channel_SPI0 (10)
+#define VIC_Channel_SPI1 (11)
+#define VIC_Channel_SSP (11)
+#define VIC_Channel_PLL (12)
+#define VIC_Channel_RTC (13)
+#define VIC_Channel_EINT0 (14)
+#define VIC_Channel_EINT1 (15)
+#define VIC_Channel_EINT2 (16)
+#define VIC_Channel_EINT3 (17)
+#define VIC_Channel_AD0 (18)
+#define VIC_Channel_I2C1 (19)
+#define VIC_Channel_BOD (20)
+#define VIC_Channel_AD1 (21)
+#define VIC_Channel_USB (22)
+
+
+/*##############################################################################
+## PCB - Pin Connect Block
+##############################################################################*/
+
+#define PCB_PINSEL0 (*(pREG32 (0xe002c000)))
+#define PCB_PINSEL1 (*(pREG32 (0xe002c004)))
+
+#define PCB_PINSEL0_P00_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P00_TXD0 ((unsigned int) 0x00000001)
+#define PCB_PINSEL0_P00_PWM1 ((unsigned int) 0x00000002)
+#define PCB_PINSEL0_P00_RSVD3 ((unsigned int) 0x00000003)
+#define PCB_PINSEL0_P00_MASK ((unsigned int) 0x00000003)
+
+#define PCB_PINSEL0_P01_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P01_RXD0 ((unsigned int) 0x00000004)
+#define PCB_PINSEL0_P01_PWM3 ((unsigned int) 0x00000008)
+#define PCB_PINSEL0_P01_EINT0 ((unsigned int) 0x0000000c)
+#define PCB_PINSEL0_P01_MASK ((unsigned int) 0x0000000c)
+
+#define PCB_PINSEL0_P02_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P02_SCL0 ((unsigned int) 0x00000010)
+#define PCB_PINSEL0_P02_CAP00 ((unsigned int) 0x00000020)
+#define PCB_PINSEL0_P02_RSVD3 ((unsigned int) 0x00000030)
+#define PCB_PINSEL0_P02_MASK ((unsigned int) 0x00000030)
+
+#define PCB_PINSEL0_P03_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P03_SDA0 ((unsigned int) 0x00000040)
+#define PCB_PINSEL0_P03_MAT00 ((unsigned int) 0x00000080)
+#define PCB_PINSEL0_P03_EINT1 ((unsigned int) 0x000000c0)
+#define PCB_PINSEL0_P03_MASK ((unsigned int) 0x000000c0)
+
+#define PCB_PINSEL0_P04_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P04_SCK0 ((unsigned int) 0x00000100)
+#define PCB_PINSEL0_P04_CAP01 ((unsigned int) 0x00000200)
+#define PCB_PINSEL0_P04_RSVD3 ((unsigned int) 0x00000300)
+#define PCB_PINSEL0_P04_MASK ((unsigned int) 0x00000300)
+
+#define PCB_PINSEL0_P05_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P05_MISO0 ((unsigned int) 0x00000400)
+#define PCB_PINSEL0_P05_MAT01 ((unsigned int) 0x00000800)
+#define PCB_PINSEL0_P05_AD06 ((unsigned int) 0x00000c00)
+#define PCB_PINSEL0_P05_MASK ((unsigned int) 0x00000c00)
+
+#define PCB_PINSEL0_P06_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P06_MOSI0 ((unsigned int) 0x00001000)
+#define PCB_PINSEL0_P06_CAP02 ((unsigned int) 0x00002000)
+#define PCB_PINSEL0_P06_AD10 ((unsigned int) 0x00003000)
+#define PCB_PINSEL0_P06_MASK ((unsigned int) 0x00003000)
+
+#define PCB_PINSEL0_P07_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P07_SSEL0 ((unsigned int) 0x00004000)
+#define PCB_PINSEL0_P07_PWM2 ((unsigned int) 0x00008000)
+#define PCB_PINSEL0_P07_EINT2 ((unsigned int) 0x0000c000)
+#define PCB_PINSEL0_P07_MASK ((unsigned int) 0x0000c000)
+
+#define PCB_PINSEL0_P08_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P08_TXD1 ((unsigned int) 0x00010000)
+#define PCB_PINSEL0_P08_PWM4 ((unsigned int) 0x00020000)
+#define PCB_PINSEL0_P08_AD11 ((unsigned int) 0x00030000)
+#define PCB_PINSEL0_P08_MASK ((unsigned int) 0x00030000)
+
+#define PCB_PINSEL0_P09_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P09_RXD1 ((unsigned int) 0x00040000)
+#define PCB_PINSEL0_P09_PWM6 ((unsigned int) 0x00080000)
+#define PCB_PINSEL0_P09_EINT3 ((unsigned int) 0x000c0000)
+#define PCB_PINSEL0_P09_MASK ((unsigned int) 0x000c0000)
+
+#define PCB_PINSEL0_P010_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P010_RTS1 ((unsigned int) 0x00100000)
+#define PCB_PINSEL0_P010_CAP10 ((unsigned int) 0x00200000)
+#define PCB_PINSEL0_P010_AD12 ((unsigned int) 0x00300000)
+#define PCB_PINSEL0_P010_MASK ((unsigned int) 0x00300000)
+
+#define PCB_PINSEL0_P011_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P011_CTS1 ((unsigned int) 0x00400000)
+#define PCB_PINSEL0_P011_CAP11 ((unsigned int) 0x00800000)
+#define PCB_PINSEL0_P011_SCL1 ((unsigned int) 0x00c00000)
+#define PCB_PINSEL0_P011_MASK ((unsigned int) 0x00c00000)
+
+#define PCB_PINSEL0_P012_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P012_DSR1 ((unsigned int) 0x01000000)
+#define PCB_PINSEL0_P012_MAT10 ((unsigned int) 0x02000000)
+#define PCB_PINSEL0_P012_AD13 ((unsigned int) 0x03000000)
+#define PCB_PINSEL0_P012_MASK ((unsigned int) 0x03000000)
+
+#define PCB_PINSEL0_P013_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P013_DTR1 ((unsigned int) 0x04000000)
+#define PCB_PINSEL0_P013_MAT11 ((unsigned int) 0x08000000)
+#define PCB_PINSEL0_P013_AD14 ((unsigned int) 0x0c000000)
+#define PCB_PINSEL0_P013_MASK ((unsigned int) 0x0c000000)
+
+#define PCB_PINSEL0_P014_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P014_DCD1 ((unsigned int) 0x10000000)
+#define PCB_PINSEL0_P014_EINT1 ((unsigned int) 0x20000000)
+#define PCB_PINSEL0_P014_SDA1 ((unsigned int) 0x30000000)
+#define PCB_PINSEL0_P014_MASK ((unsigned int) 0x30000000)
+
+#define PCB_PINSEL0_P015_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL0_P015_RI1 ((unsigned int) 0x40000000)
+#define PCB_PINSEL0_P015_EINT2 ((unsigned int) 0x80000000)
+#define PCB_PINSEL0_P015_AD15 ((unsigned int) 0xc0000000)
+#define PCB_PINSEL0_P015_MASK ((unsigned int) 0xc0000000)
+
+#define PCB_PINSEL1_P016_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P016_EINT0 ((unsigned int) 0x00000001)
+#define PCB_PINSEL1_P016_MAT02 ((unsigned int) 0x00000002)
+#define PCB_PINSEL1_P016_CAP02 ((unsigned int) 0x00000003)
+#define PCB_PINSEL1_P016_MASK ((unsigned int) 0x00000003)
+
+#define PCB_PINSEL1_P017_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P017_CAP12 ((unsigned int) 0x00000004)
+#define PCB_PINSEL1_P017_SCK1 ((unsigned int) 0x00000008)
+#define PCB_PINSEL1_P017_MAT12 ((unsigned int) 0x0000000c)
+#define PCB_PINSEL1_P017_MASK ((unsigned int) 0x0000000c)
+
+#define PCB_PINSEL1_P018_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P018_CAP13 ((unsigned int) 0x00000010)
+#define PCB_PINSEL1_P018_MISO1 ((unsigned int) 0x00000020)
+#define PCB_PINSEL1_P018_MAT13 ((unsigned int) 0x00000030)
+#define PCB_PINSEL1_P018_MASK ((unsigned int) 0x00000030)
+
+#define PCB_PINSEL1_P019_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P019_MAT12 ((unsigned int) 0x00000040)
+#define PCB_PINSEL1_P019_MOSI1 ((unsigned int) 0x00000080)
+#define PCB_PINSEL1_P019_CAP12 ((unsigned int) 0x000000c0)
+
+#define PCB_PINSEL1_P020_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P020_MAT13 ((unsigned int) 0x00000100)
+#define PCB_PINSEL1_P020_SSEL1 ((unsigned int) 0x00000200)
+#define PCB_PINSEL1_P020_EINT3 ((unsigned int) 0x00000300)
+#define PCB_PINSEL1_P020_MASK ((unsigned int) 0x00000300)
+
+#define PCB_PINSEL1_P021_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P021_PWM5 ((unsigned int) 0x00000400)
+#define PCB_PINSEL1_P021_AD16 ((unsigned int) 0x00000800)
+#define PCB_PINSEL1_P021_CAP13 ((unsigned int) 0x00000c00)
+#define PCB_PINSEL1_P021_MASK ((unsigned int) 0x00000c00)
+
+#define PCB_PINSEL1_P022_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P022_AD17 ((unsigned int) 0x00001000)
+#define PCB_PINSEL1_P022_CAP00 ((unsigned int) 0x00002000)
+#define PCB_PINSEL1_P022_MAT00 ((unsigned int) 0x00003000)
+#define PCB_PINSEL1_P022_MASK ((unsigned int) 0x00003000)
+
+#define PCB_PINSEL1_P023_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P023_VBUS ((unsigned int) 0x00004000)
+#define PCB_PINSEL1_P023_RSVD2 ((unsigned int) 0x00008000)
+#define PCB_PINSEL1_P023_RSVD3 ((unsigned int) 0x0000c000)
+#define PCB_PINSEL1_P023_MASK ((unsigned int) 0x0000c000)
+
+#define PCB_PINSEL1_P024_RSVD0 ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P024_RSVD1 ((unsigned int) 0x00010000)
+#define PCB_PINSEL1_P024_RSVD2 ((unsigned int) 0x00020000)
+#define PCB_PINSEL1_P024_RSVD3 ((unsigned int) 0x00030000)
+#define PCB_PINSEL1_P024_MASK ((unsigned int) 0x00030000)
+
+#define PCB_PINSEL1_P025_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P025_AD04 ((unsigned int) 0x00040000)
+#define PCB_PINSEL1_P025_AOUT ((unsigned int) 0x00080000)
+#define PCB_PINSEL1_P025_RSVD3 ((unsigned int) 0x000c0000)
+#define PCB_PINSEL1_P025_MASK ((unsigned int) 0x000c0000)
+
+#define PCB_PINSEL1_P026_RSVD0 ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P026_RSVD1 ((unsigned int) 0x00100000)
+#define PCB_PINSEL1_P026_RSVD2 ((unsigned int) 0x00200000)
+#define PCB_PINSEL1_P026_RSVD3 ((unsigned int) 0x00300000)
+#define PCB_PINSEL1_P026_MASK ((unsigned int) 0x00300000)
+
+#define PCB_PINSEL1_P027_RSVD0 ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P027_RSVD1 ((unsigned int) 0x00400000)
+#define PCB_PINSEL1_P027_RSVD2 ((unsigned int) 0x00800000)
+#define PCB_PINSEL1_P027_RSVD3 ((unsigned int) 0x00c00000)
+#define PCB_PINSEL1_P027_MASK ((unsigned int) 0x00c00000)
+
+#define PCB_PINSEL1_P028_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P028_AD01 ((unsigned int) 0x01000000)
+#define PCB_PINSEL1_P028_CAP02 ((unsigned int) 0x02000000)
+#define PCB_PINSEL1_P028_MAT02 ((unsigned int) 0x03000000)
+#define PCB_PINSEL1_P028_MASK ((unsigned int) 0x03000000)
+
+#define PCB_PINSEL1_P029_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P029_AD02 ((unsigned int) 0x04000000)
+#define PCB_PINSEL1_P029_CAP03 ((unsigned int) 0x08000000)
+#define PCB_PINSEL1_P029_MAT03 ((unsigned int) 0x0c000000)
+#define PCB_PINSEL1_P029_MASK ((unsigned int) 0x0c000000)
+
+#define PCB_PINSEL1_P030_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P030_AD03 ((unsigned int) 0x10000000)
+#define PCB_PINSEL1_P030_EINT3 ((unsigned int) 0x20000000)
+#define PCB_PINSEL1_P030_CAP00 ((unsigned int) 0x30000000)
+#define PCB_PINSEL1_P030_MASK ((unsigned int) 0x30000000)
+
+#define PCB_PINSEL1_P031_GPIO ((unsigned int) 0x00000000)
+#define PCB_PINSEL1_P031_UPLED ((unsigned int) 0x40000000)
+#define PCB_PINSEL1_P031_CONNECT ((unsigned int) 0x80000000)
+#define PCB_PINSEL1_P031_RSVD3 ((unsigned int) 0xc0000000)
+#define PCB_PINSEL1_P031_MASK ((unsigned int) 0xc0000000)
+
+
+/*##############################################################################
+## GPIO - General Purpose I/O
+##############################################################################*/
+
+#define GPIO0_IOPIN (*(pREG32 (0xe0028000)))
+#define GPIO0_IOSET (*(pREG32 (0xe0028004)))
+#define GPIO0_IODIR (*(pREG32 (0xe0028008)))
+#define GPIO0_IOCLR (*(pREG32 (0xe002800c)))
+#define GPIO1_IOPIN (*(pREG32 (0xe0028010)))
+#define GPIO1_IOSET (*(pREG32 (0xe0028014)))
+#define GPIO1_IODIR (*(pREG32 (0xe0028018)))
+#define GPIO1_IOCLR (*(pREG32 (0xe002801c)))
+
+#define GPIO_IO_P0 ((unsigned int) 0x00000001)
+#define GPIO_IO_P1 ((unsigned int) 0x00000002)
+#define GPIO_IO_P2 ((unsigned int) 0x00000004)
+#define GPIO_IO_P3 ((unsigned int) 0x00000008)
+#define GPIO_IO_P4 ((unsigned int) 0x00000010)
+#define GPIO_IO_P5 ((unsigned int) 0x00000020)
+#define GPIO_IO_P6 ((unsigned int) 0x00000040)
+#define GPIO_IO_P7 ((unsigned int) 0x00000080)
+#define GPIO_IO_P8 ((unsigned int) 0x00000100)
+#define GPIO_IO_P9 ((unsigned int) 0x00000200)
+#define GPIO_IO_P10 ((unsigned int) 0x00000400)
+#define GPIO_IO_P11 ((unsigned int) 0x00000800)
+#define GPIO_IO_P12 ((unsigned int) 0x00001000)
+#define GPIO_IO_P13 ((unsigned int) 0x00002000)
+#define GPIO_IO_P14 ((unsigned int) 0x00004000)
+#define GPIO_IO_P15 ((unsigned int) 0x00008000)
+#define GPIO_IO_P16 ((unsigned int) 0x00010000)
+#define GPIO_IO_P17 ((unsigned int) 0x00020000)
+#define GPIO_IO_P18 ((unsigned int) 0x00040000)
+#define GPIO_IO_P19 ((unsigned int) 0x00080000)
+#define GPIO_IO_P20 ((unsigned int) 0x00100000)
+#define GPIO_IO_P21 ((unsigned int) 0x00200000)
+#define GPIO_IO_P22 ((unsigned int) 0x00400000)
+#define GPIO_IO_P23 ((unsigned int) 0x00800000)
+#define GPIO_IO_P24 ((unsigned int) 0x01000000)
+#define GPIO_IO_P25 ((unsigned int) 0x02000000)
+#define GPIO_IO_P26 ((unsigned int) 0x04000000)
+#define GPIO_IO_P27 ((unsigned int) 0x08000000)
+#define GPIO_IO_P28 ((unsigned int) 0x10000000)
+#define GPIO_IO_P29 ((unsigned int) 0x20000000)
+#define GPIO_IO_P30 ((unsigned int) 0x40000000)
+#define GPIO_IO_P31 ((unsigned int) 0x80000000)
+#define GPIO_IO_JTAG ((unsigned int) 0x003e0000)
+
+
+/*##############################################################################
+## UART0 / UART1
+##############################################################################*/
+
+#define UART0_RBR (*(pREG32 (0xe000c000)))
+#define UART0_THR (*(pREG32 (0xe000c000)))
+#define UART0_IER (*(pREG32 (0xe000c004)))
+#define UART0_IIR (*(pREG32 (0xe000c008)))
+#define UART0_FCR (*(pREG32 (0xe000c008)))
+#define UART0_LCR (*(pREG32 (0xe000c00c)))
+#define UART0_LSR (*(pREG32 (0xe000c014)))
+#define UART0_SCR (*(pREG32 (0xe000c01c)))
+#define UART0_ACR (*(pREG32 (0xe0000020)))
+#define UART0_FDR (*(pREG32 (0xe0000028)))
+#define UART0_TER (*(pREG32 (0xe0000030)))
+#define UART0_DLL (*(pREG32 (0xe000c000)))
+#define UART0_DLM (*(pREG32 (0xe000c004)))
+
+#define UART1_RBR (*(pREG32 (0xe0010000)))
+#define UART1_THR (*(pREG32 (0xe0010000)))
+#define UART1_IER (*(pREG32 (0xe0010004)))
+#define UART1_IIR (*(pREG32 (0xe0010008)))
+#define UART1_FCR (*(pREG32 (0xe0010008)))
+#define UART1_LCR (*(pREG32 (0xe001000c)))
+#define UART1_LSR (*(pREG32 (0xe0010014)))
+#define UART1_SCR (*(pREG32 (0xe001001c)))
+#define UART1_ACR (*(pREG32 (0xe0010020)))
+#define UART1_FDR (*(pREG32 (0xe0010028)))
+#define UART1_TER (*(pREG32 (0xe0010030)))
+#define UART1_DLL (*(pREG32 (0xe0010000)))
+#define UART1_DLM (*(pREG32 (0xe0010004)))
+#define UART1_MCR (*(pREG32 (0xe0010010)))
+#define UART1_MSR (*(pREG32 (0xe0010018)))
+
+#define UART_LCR_DLAB (0x00000080)
+#define UART_LCR_NOPAR (0x00000000)
+#define UART_LCR_1STOP (0x00000000)
+#define UART_LCR_8BITS (0x00000003)
+#define UART_IER_EI (0x00000003)
+#define UART_FCR_EN (0x00000001)
+#define UART_FCR_CLR (0x00000006)
+
+
+/*##############################################################################
+## I2C
+##############################################################################*/
+
+#define I2C0_CONSET (*(pREG32 (0xe001c000)))
+#define I2C0_STAT (*(pREG32 (0xe001c004)))
+#define I2C0_DAT (*(pREG32 (0xe001c008)))
+#define I2C0_ADR (*(pREG32 (0xe001c00c)))
+#define I2C0_SCLH (*(pREG32 (0xe001c010)))
+#define I2C0_SCLL (*(pREG32 (0xe001c014)))
+#define I2C0_CONCLR (*(pREG32 (0xe001c018)))
+
+#define I2C1_CONSET (*(pREG32 (0xe005c000)))
+#define I2C1_STAT (*(pREG32 (0xe005c004)))
+#define I2C1_DAT (*(pREG32 (0xe005c008)))
+#define I2C1_ADR (*(pREG32 (0xe005c00c)))
+#define I2C1_SCLH (*(pREG32 (0xe005c010)))
+#define I2C1_SCLL (*(pREG32 (0xe005c014)))
+#define I2C1_CONCLR (*(pREG32 (0xe005c018)))
+
+#define I2C_CONSET_AA (0x00000004)
+#define I2C_CONSET_SI (0x00000008)
+#define I2C_CONSET_STO (0x00000010)
+#define I2C_CONSET_STA (0x00000020)
+#define I2C_CONSET_I2EN (0x00000040)
+#define I2C_CONSET_MASK (0x0000007c)
+
+#define I2C_STAT_STATMASK (0x000000f8)
+#define I2C_STAT_STATSHIFT (3)
+
+#define I2C_ADDR_GC (0x00000001)
+#define I2C_ADDR_ADDRMASK (0x000000fe)
+#define I2C_ADDR_ADDRSHIFT (1)
+
+#define I2C_CONCLR_AAC (0x00000004)
+#define I2C_CONCLR_SIC (0x00000008)
+#define I2C_CONCLR_STAC (0x00000020)
+#define I2C_CONCLR_I2ENC (0x00000040)
+#define I2C_CONCLR_MASK (0x0000006c)
+
+
+/*##############################################################################
+## SPI - Serial Peripheral Interface
+##############################################################################*/
+
+#define SPI_SPCR (*(pREG32 (0xe0020000)))
+#define SPI_SPSR (*(pREG32 (0xe0020004)))
+#define SPI_SPDR (*(pREG32 (0xe0020008)))
+#define SPI_SPCCR (*(pREG32 (0xe002000c)))
+#define SPI_SPTCR (*(pREG32 (0xe0020010)))
+#define SPI_SPTSR (*(pREG32 (0xe0020014)))
+#define SPI_SPTOR (*(pREG32 (0xe0020018)))
+#define SPI_SPINT (*(pREG32 (0xe002001c)))
+
+
+/*##############################################################################
+## SSP - Synchronous Serial Port
+##############################################################################*/
+
+#define SSP_CR0 (*(pREG32 (0xe0068000)))
+#define SSP_CR1 (*(pREG32 (0xe0068004)))
+#define SSP_DR (*(pREG32 (0xe0068008)))
+#define SSP_SR (*(pREG32 (0xe006800C)))
+#define SSP_CPSR (*(pREG32 (0xe0068010)))
+#define SSP_IMSC (*(pREG32 (0xe0068014)))
+#define SSP_RIS (*(pREG32 (0xe0068018)))
+#define SSP_MIS (*(pREG32 (0xe006801C)))
+#define SSP_ICR (*(pREG32 (0xe0068020)))
+
+#define SSP_FIFO_DEPTH (8)
+
+#define SSP_CR0_DSS_4 ((unsigned int) 0x00000003)
+#define SSP_CR0_DSS_5 ((unsigned int) 0x00000004)
+#define SSP_CR0_DSS_6 ((unsigned int) 0x00000005)
+#define SSP_CR0_DSS_7 ((unsigned int) 0x00000006)
+#define SSP_CR0_DSS_8 ((unsigned int) 0x00000007)
+#define SSP_CR0_DSS_9 ((unsigned int) 0x00000008)
+#define SSP_CR0_DSS 10 ((unsigned int) 0x00000009)
+#define SSP_CR0_DSS_11 ((unsigned int) 0x0000000a)
+#define SSP_CR0_DSS_12 ((unsigned int) 0x0000000b)
+#define SSP_CR0_DSS_13 ((unsigned int) 0x0000000c)
+#define SSP_CR0_DSS_14 ((unsigned int) 0x0000000d)
+#define SSP_CR0_DSS_15 ((unsigned int) 0x0000000e)
+#define SSP_CR0_DSS_16 ((unsigned int) 0x0000000f)
+#define SSP_CR0_FRF_SPI ((unsigned int) 0x00000000)
+#define SSP_CR0_FRF_SSI ((unsigned int) 0x00000010)
+#define SSP_CR0_FRF_MW ((unsigned int) 0x00000020)
+#define SSP_CR0_CPOL ((unsigned int) 0x00000040)
+#define SSP_CR0_CPHA ((unsigned int) 0x00000080)
+#define SSP_CR0_SCR ((unsigned int) 0x0000ff00)
+
+#define SSP_CR1_LBM ((unsigned int) 0x00000001)
+#define SSP_CR1_SSE ((unsigned int) 0x00000002)
+#define SSP_CR1_MS ((unsigned int) 0x00000004)
+#define SSP_CR1_SOD ((unsigned int) 0x00000008)
+
+#define SSP_SR_TFE ((unsigned int) 0x00000001)
+#define SSP_SR_TNF ((unsigned int) 0x00000002)
+#define SSP_SR_RNE ((unsigned int) 0x00000004)
+#define SSP_SR_RFF ((unsigned int) 0x00000008)
+#define SSP_SR_BSY ((unsigned int) 0x00000010)
+
+#define SSP_IMSC_RORIM ((unsigned int) 0x00000001)
+#define SSP_IMSC_RTIM ((unsigned int) 0x00000002)
+#define SSP_IMSC_RXIM ((unsigned int) 0x00000004)
+#define SSP_IMSC_TXIM ((unsigned int) 0x00000008)
+
+#define SSP_RIS_RORRIS ((unsigned int) 0x00000001)
+#define SSP_RIS_RTRIS ((unsigned int) 0x00000002)
+#define SSP_RIS_RXRIS ((unsigned int) 0x00000004)
+#define SSP_RIS_TXRIS ((unsigned int) 0x00000008)
+
+#define SSP_MIS_RORMIS ((unsigned int) 0x00000001)
+#define SSP_MIS_RTMIS ((unsigned int) 0x00000002)
+#define SSP_MIS_RXMIS ((unsigned int) 0x00000004)
+#define SSP_MIS_TXMIS ((unsigned int) 0x00000008)
+
+#define SSP_ICR_RORIC ((unsigned int) 0x00000001)
+#define SSP_ICR_RTIC ((unsigned int) 0x00000002)
+
+
+/*##############################################################################
+## Timer 0 and Timer 1
+##############################################################################*/
+
+#define T0_BASE_ADDR (pREG32 (0xe0004000))
+#define T0_IR (*(pREG32 (0xe0004000)))
+#define T0_TCR (*(pREG32 (0xe0004004)))
+#define T0_TC (*(pREG32 (0xe0004008)))
+#define T0_PR (*(pREG32 (0xe000400c)))
+#define T0_PC (*(pREG32 (0xe0004010)))
+#define T0_MCR (*(pREG32 (0xe0004014)))
+#define T0_MR0 (*(pREG32 (0xe0004018)))
+#define T0_MR1 (*(pREG32 (0xe000401c)))
+#define T0_MR2 (*(pREG32 (0xe0004020)))
+#define T0_MR3 (*(pREG32 (0xe0004024)))
+#define T0_CCR (*(pREG32 (0xe0004028)))
+#define T0_CR0 (*(pREG32 (0xe000402c)))
+#define T0_CR1 (*(pREG32 (0xe0004030)))
+#define T0_CR2 (*(pREG32 (0xe0004034)))
+#define T0_CR3 (*(pREG32 (0xe0004038)))
+#define T0_EMR (*(pREG32 (0xe000403c)))
+#define T0_CTCR (*(pREG32 (0xe0004070)))
+
+#define T1_BASE_ADDR (pREG32 (0xe0008000))
+#define T1_IR (*(pREG32 (0xe0008000)))
+#define T1_TCR (*(pREG32 (0xe0008004)))
+#define T1_TC (*(pREG32 (0xe0008008)))
+#define T1_PR (*(pREG32 (0xe000800c)))
+#define T1_PC (*(pREG32 (0xe0008010)))
+#define T1_MCR (*(pREG32 (0xe0008014)))
+#define T1_MR0 (*(pREG32 (0xe0008018)))
+#define T1_MR1 (*(pREG32 (0xe000801c)))
+#define T1_MR2 (*(pREG32 (0xe0008020)))
+#define T1_MR3 (*(pREG32 (0xe0008024)))
+#define T1_CCR (*(pREG32 (0xe0008028)))
+#define T1_CR0 (*(pREG32 (0xe000802c)))
+#define T1_CR1 (*(pREG32 (0xe0008030)))
+#define T1_CR2 (*(pREG32 (0xe0008034)))
+#define T1_CR3 (*(pREG32 (0xe0008038)))
+#define T1_EMR (*(pREG32 (0xe000803c)))
+#define T1_CTCR (*(pREG32 (0xe0008070)))
+
+#define T_IR_MR0 (0x00000001)
+#define T_IR_MR1 (0x00000002)
+#define T_IR_MR2 (0x00000004)
+#define T_IR_MR3 (0x00000008)
+#define T_IR_CR0 (0x00000010)
+#define T_IR_CR1 (0x00000020)
+#define T_IR_CR2 (0x00000040)
+#define T_IR_CR3 (0x00000080)
+#define T_IR_MASK (0x000000ff)
+
+#define T_TCR_CE (0x00000001)
+#define T_TCR_CR (0x00000002)
+
+#define T_CTCR_MODE_PCLK (0x00000000)
+#define T_CTCR_MODE_CAPRISE (0x00000001)
+#define T_CTCR_MODE_CAPFALL (0x00000002)
+#define T_CTCR_MODE_CAPBOTH (0x00000003)
+#define T_CTCR_MODE_MASK (0x00000003)
+#define T_CTCR_CIS_CAPN0 (0x00000000)
+#define T_CTCR_CIS_CAPN1 (0x00000004)
+#define T_CTCR_CIS_CAPN2 (0x00000008)
+#define T_CTCR_CIS_CAPN3 (0x0000000c)
+#define T_CTCR_CIS_MASK (0x0000000c)
+
+#define T_MCR_MR0I (0x00000001)
+#define T_MCR_MR0R (0x00000002)
+#define T_MCR_MR0S (0x00000004)
+#define T_MCR_MR1I (0x00000008)
+#define T_MCR_MR1R (0x00000010)
+#define T_MCR_MR1S (0x00000020)
+#define T_MCR_MR2I (0x00000040)
+#define T_MCR_MR2R (0x00000080)
+#define T_MCR_MR2S (0x00000100)
+#define T_MCR_MR3I (0x00000200)
+#define T_MCR_MR3R (0x00000400)
+#define T_MCR_MR3S (0x00000800)
+
+#define T_CCR_CAP0RE (0x00000001)
+#define T_CCR_CAP0FE (0x00000002)
+#define T_CCR_CAP0I (0x00000004)
+#define T_CCR_CAP1RE (0x00000008)
+#define T_CCR_CAP1FE (0x00000010)
+#define T_CCR_CAP1I (0x00000020)
+#define T_CCR_CAP2RE (0x00000040)
+#define T_CCR_CAP2FE (0x00000080)
+#define T_CCR_CAP2I (0x00000100)
+#define T_CCR_CAP3RE (0x00000200)
+#define T_CCR_CAP3FE (0x00000400)
+#define T_CCR_CAP3I (0x00000800)
+
+#define T_EMR_EM0 (0x00000001)
+#define T_EMR_EM1 (0x00000002)
+#define T_EMR_EM2 (0x00000004)
+#define T_EMR_EM3 (0x00000008)
+#define T_EMR_EMC0_NONE (0x00000000)
+#define T_EMR_EMC0_CLEAR (0x00000010)
+#define T_EMR_EMC0_SET (0x00000020)
+#define T_EMR_EMC0_TOGGLE (0x00000030)
+#define T_EMR_EMC0_MASK (0x00000030)
+#define T_EMR_EMC1_NONE (0x00000000)
+#define T_EMR_EMC1_CLEAR (0x00000040)
+#define T_EMR_EMC1_SET (0x00000080)
+#define T_EMR_EMC1_TOGGLE (0x000000c0)
+#define T_EMR_EMC1_MASK (0x000000c0)
+#define T_EMR_EMC2_NONE (0x00000000)
+#define T_EMR_EMC2_CLEAR (0x00000100)
+#define T_EMR_EMC2_SET (0x00000200)
+#define T_EMR_EMC2_TOGGLE (0x00000300)
+#define T_EMR_EMC2_MASK (0x00000300)
+#define T_EMR_EMC3_NONE (0x00000000)
+#define T_EMR_EMC3_CLEAR (0x00000400)
+#define T_EMR_EMC3_SET (0x00000800)
+#define T_EMR_EMC3_TOGGLE (0x00000c00)
+#define T_EMR_EMC3_MASK (0x00000c00)
+
+
+/*##############################################################################
+## ADC
+##############################################################################*/
+
+#define AD0_CR (*(pREG32 (0xe0034000)))
+#define AD0_GDR (*(pREG32 (0xe0034004)))
+#define AD0_STAT (*(pREG32 (0xe0034030)))
+#define AD0_GSR (*(pREG32 (0xe0034008)))
+#define AD0_INTEN (*(pREG32 (0xe003400c)))
+#define AD0_DR0 (*(pREG32 (0xe0034010)))
+#define AD0_DR1 (*(pREG32 (0xe0034014)))
+#define AD0_DR2 (*(pREG32 (0xe0034018)))
+#define AD0_DR3 (*(pREG32 (0xe003401c)))
+#define AD0_DR4 (*(pREG32 (0xe0034020)))
+#define AD0_DR5 (*(pREG32 (0xe0034024)))
+#define AD0_DR6 (*(pREG32 (0xe0034028)))
+#define AD0_DR7 (*(pREG32 (0xe003402c)))
+
+#define AD1_CR (*(pREG32 (0xe0064000)))
+#define AD1_GDR (*(pREG32 (0xe0064004)))
+#define AD1_STAT (*(pREG32 (0xe0064030)))
+#define AD1_GSR (*(pREG32 (0xe0034008)))
+#define AD1_INTEN (*(pREG32 (0xe006400c)))
+#define AD1_DR0 (*(pREG32 (0xe0064010)))
+#define AD1_DR1 (*(pREG32 (0xe0064014)))
+#define AD1_DR2 (*(pREG32 (0xe0064018)))
+#define AD1_DR3 (*(pREG32 (0xe006401c)))
+#define AD1_DR4 (*(pREG32 (0xe0064020)))
+#define AD1_DR5 (*(pREG32 (0xe0064024)))
+#define AD1_DR6 (*(pREG32 (0xe0064028)))
+#define AD1_DR7 (*(pREG32 (0xe006402c)))
+
+#define AD_CR_SEL0 (0x00000001)
+#define AD_CR_SEL1 (0x00000002)
+#define AD_CR_SEL2 (0x00000004)
+#define AD_CR_SEL3 (0x00000008)
+#define AD_CR_SEL4 (0x00000010)
+#define AD_CR_SEL5 (0x00000020)
+#define AD_CR_SEL6 (0x00000040)
+#define AD_CR_SEL7 (0x00000080)
+#define AD_CR_CLKDIV (0x0000ff00)
+#define AD_CR_CLKDIVMASK (0x0000ff00)
+#define AD_CR_CLKDIVSHIFT (8)
+#define AD_CR_BURST (0x00010000)
+#define AD_CR_CLKS10 (0x00000000)
+#define AD_CR_CLKS9 (0x00020000)
+#define AD_CR_CLKS8 (0x00040000)
+#define AD_CR_CLKS7 (0x00060000)
+#define AD_CR_CLKS6 (0x00080000)
+#define AD_CR_CLKS5 (0x000a0000)
+#define AD_CR_CLKS4 (0x000c0000)
+#define AD_CR_CLKS3 (0x000e0000)
+#define AD_CR_PDN (0x00200000)
+#define AD_CR_START_NONE (0x00000000)
+#define AD_CR_START_NOW (0x01000000)
+#define AD_CR_START_P016 (0x02000000)
+#define AD_CR_START_P022 (0x03000000)
+#define AD_CR_START_MAT01 (0x04000000)
+#define AD_CR_START_MAT03 (0x05000000)
+#define AD_CR_START_MAT10 (0x06000000)
+#define AD_CR_START_MAT11 (0x07000000)
+#define AD_CR_EDGE (0x08000000)
+#define AD_CR_MASK (0x0f2fffff)
+
+#define AD_GDR_RESULT (0x0000ffc0)
+#define AD_GDR_CHN (0x07000000)
+#define AD_GDR_CHNMASK (0x07000000)
+#define AD_GDR_CHNSHIFT (24)
+#define AD_GDR_OVERRUN (0x40000000)
+#define AD_GDR_DONE (0x80000000)
+#define AD_GDR_MASK (0xc700ffc0)
+
+#define AD_GSR_BURST (0x00010000)
+#define AD_GSR_START_NONE (0x00000000)
+#define AD_GSR_START_NOW (0x01000000)
+#define AD_GSR_START_P016 (0x02000000)
+#define AD_GSR_START_P022 (0x03000000)
+#define AD_GSR_START_MAT01 (0x04000000)
+#define AD_GSR_START_MAT03 (0x05000000)
+#define AD_GSR_START_MAT10 (0x06000000)
+#define AD_GSR_START_MAT11 (0x07000000)
+#define AD_GSR_EDGE (0x08000000)
+#define AD_GSR_MASK (0x0f010000)
+
+#define AD_STAT_RSVD (0x00000001)
+#define AD_STAT_DONE0 (0x00000001)
+#define AD_STAT_DONE1 (0x00000002)
+#define AD_STAT_DONE2 (0x00000004)
+#define AD_STAT_DONE3 (0x00000008)
+#define AD_STAT_DONE4 (0x00000010)
+#define AD_STAT_DONE5 (0x00000020)
+#define AD_STAT_DONE6 (0x00000040)
+#define AD_STAT_DONE7 (0x00000080)
+#define AD_STAT_OVERRUN0 (0x00000100)
+#define AD_STAT_OVERRUN1 (0x00000200)
+#define AD_STAT_OVERRUN2 (0x00000400)
+#define AD_STAT_OVERRUN3 (0x00000800)
+#define AD_STAT_OVERRUN4 (0x00001000)
+#define AD_STAT_OVERRUN5 (0x00002000)
+#define AD_STAT_OVERRUN6 (0x00004000)
+#define AD_STAT_OVERRUN7 (0x00008000)
+#define AD_STAT_ADINT (0x00010000)
+#define AD_STAT_MASK (0x0001ffff)
+
+#define AD_INTEN_AD0 (0x00000001)
+#define AD_INTEN_AD1 (0x00000002)
+#define AD_INTEN_AD2 (0x00000004)
+#define AD_INTEN_AD3 (0x00000008)
+#define AD_INTEN_AD4 (0x00000010)
+#define AD_INTEN_AD5 (0x00000020)
+#define AD_INTEN_AD6 (0x00000040)
+#define AD_INTEN_AD7 (0x00000080)
+#define AD_INTEN_DONE (0x00000100)
+#define AD_INTEN_MASK (0x000001ff)
+
+#define AD_DR_RESULT (0x0000ffc0)
+#define AD_DR_RESULTMASK (0x0000ffc0)
+#define AD_DR_RESULTSHIFT (6)
+#define AD_DR_OVERRUN (0x40000000)
+#define AD_DR_DONE (0x80000000)
+#define AD_DR_MASK (0xc000ffc0)
+
+
+/*##############################################################################
+## DAC
+##############################################################################*/
+
+#define DAC_CR (*(pREG32 (0xe006c000)))
+
+#define DAC_CR_VALUE (0x0000ffc0)
+#define DAC_CR_VALUEMASK (0x0000ffc0)
+#define DAC_CR_VALUESHIFT (6)
+#define DAC_CR_BIAS (0x00010000)
+#define DAC_CR_MASK (0x0001ffc0)
+
+
+/*##############################################################################
+## PWM
+##############################################################################*/
+
+#define PWM_IR (*(pREG32 (0xe0014000)))
+#define PWM_TCR (*(pREG32 (0xe0014004)))
+#define PWM_TC (*(pREG32 (0xe0014008)))
+#define PWM_PR (*(pREG32 (0xe001400c)))
+#define PWM_PC (*(pREG32 (0xe0014010)))
+#define PWM_MCR (*(pREG32 (0xe0014014)))
+#define PWM_MR0 (*(pREG32 (0xe0014018)))
+#define PWM_MR1 (*(pREG32 (0xe001401c)))
+#define PWM_MR2 (*(pREG32 (0xe0014020)))
+#define PWM_MR3 (*(pREG32 (0xe0014024)))
+#define PWM_MR4 (*(pREG32 (0xe0014040)))
+#define PWM_MR5 (*(pREG32 (0xe0014044)))
+#define PWM_MR6 (*(pREG32 (0xe0014048)))
+#define PWM_EMR (*(pREG32 (0xe001403c)))
+#define PWM_PCR (*(pREG32 (0xe001404c)))
+#define PWM_LER (*(pREG32 (0xe0014050)))
+#define PWM_CCR (*(pREG32 (0xe0014028)))
+#define PWM_CR0 (*(pREG32 (0xe001402c)))
+#define PWM_CR1 (*(pREG32 (0xe0014030)))
+#define PWM_CR2 (*(pREG32 (0xe0014034)))
+#define PWM_CR3 (*(pREG32 (0xe0014038)))
+
+
+/*##############################################################################
+## RTC
+##############################################################################*/
+
+#define RTC_ILR (*(pREG32 (0xe0024000)))
+#define RTC_CTC (*(pREG32 (0xe0024004)))
+#define RTC_CCR (*(pREG32 (0xe0024008)))
+#define RTC_CIIR (*(pREG32 (0xe002400c)))
+#define RTC_AMR (*(pREG32 (0xe0024010)))
+#define RTC_CTIME0 (*(pREG32 (0xe0024014)))
+#define RTC_CTIME1 (*(pREG32 (0xe0024018)))
+#define RTC_CTIME2 (*(pREG32 (0xe002401c)))
+
+#define RTC_SEC (*(pREG32 (0xe0024020)))
+#define RTC_MIN (*(pREG32 (0xe0024024)))
+#define RTC_HOUR (*(pREG32 (0xe0024028)))
+#define RTC_DOM (*(pREG32 (0xe002402c)))
+#define RTC_DOW (*(pREG32 (0xe0024030)))
+#define RTC_DOY (*(pREG32 (0xe0024034)))
+#define RTC_MONTH (*(pREG32 (0xe0024038)))
+#define RTC_YEAR (*(pREG32 (0xe002403c)))
+
+#define RTC_ALSEC (*(pREG32 (0xe0024060)))
+#define RTC_ALMIN (*(pREG32 (0xe0024064)))
+#define RTC_ALHOUR (*(pREG32 (0xe0024068)))
+#define RTC_ALDOM (*(pREG32 (0xe002406c)))
+#define RTC_ALDOW (*(pREG32 (0xe0024070)))
+#define RTC_ALDOY (*(pREG32 (0xe0024074)))
+#define RTC_ALMON (*(pREG32 (0xe0024078)))
+#define RTC_ALYEAR (*(pREG32 (0xe002407c)))
+
+#define RTC_PREINT (*(pREG32 (0xe0024080)))
+#define RTC_PREFRAC (*(pREG32 (0xe0024084)))
+
+#define RTC_ILR_RTCCIF (0x00000001)
+#define RTC_ILR_RTCALF (0x00000002)
+#define RTC_ILR_MASK (0x00000003)
+
+#define RTC_CCR_CLKEN (0x00000001)
+#define RTC_CCR_CTCRST (0x00000002)
+#define RTC_CCR_TEST (0x0000000c)
+#define RTC_CCR_CLKSRC (0x00000010)
+
+#define RTC_CIIR_IMSEC (0x00000001)
+#define RTC_CIIR_IMMIN (0x00000002)
+#define RTC_CIIR_IMHOUR (0x00000004)
+#define RTC_CIIR_IMDOM (0x00000008)
+#define RTC_CIIR_IMDOW (0x00000010)
+#define RTC_CIIR_IMDOY (0x00000020)
+#define RTC_CIIR_IMMON (0x00000040)
+#define RTC_CIIR_IMYEAR (0x00000080)
+#define RTC_CIIR_IMMASK (0x000000ff)
+
+#define RTC_AMR_AMRSEC (0x00000001)
+#define RTC_AMR_AMRMIN (0x00000002)
+#define RTC_AMR_AMRHOUR (0x00000004)
+#define RTC_AMR_AMRDOM (0x00000008)
+#define RTC_AMR_AMRDOW (0x00000010)
+#define RTC_AMR_AMRDOY (0x00000020)
+#define RTC_AMR_AMRMON (0x00000040)
+#define RTC_AMR_AMRYEAR (0x00000080)
+#define RTC_AMR_AMRMASK (0x000000ff)
+
+typedef struct __attribute__ ((packed))
+{
+ union
+ {
+ struct
+ {
+ unsigned int counter : 14;
+ unsigned int rsvd15_31 : 18;
+ };
+
+ unsigned int i;
+ };
+}
+rtcCTC_t;
+
+typedef struct __attribute__ ((packed))
+{
+ union
+ {
+ struct
+ {
+ unsigned int seconds : 6;
+ unsigned int rsvd7_6 : 2;
+ unsigned int minutes : 6;
+ unsigned int rsvd14_15 : 2;
+ unsigned int hours : 5;
+ unsigned int rsvd21_23 : 3;
+ unsigned int dow : 3;
+ unsigned int rsvd27_31 : 5;
+ };
+
+ unsigned int i;
+ };
+}
+rtcCTIME0_t;
+
+typedef struct __attribute__ ((packed))
+{
+ union
+ {
+ struct
+ {
+ unsigned int dom : 5;
+ unsigned int rsvd5_7 : 3;
+ unsigned int month : 4;
+ unsigned int rsvd12_15 : 4;
+ unsigned int year : 12;
+ unsigned int rsvd28_31 : 4;
+ };
+
+ unsigned int i;
+ };
+}
+rtcCTIME1_t;
+
+typedef struct __attribute__ ((packed))
+{
+ union
+ {
+ struct
+ {
+ unsigned int doy : 12;
+ unsigned int rsvd12_31 : 20;
+ };
+
+ unsigned int i;
+ };
+}
+rtcCTIME2_t;
+
+
+/*##############################################################################
+## WD - Watchdog
+##############################################################################*/
+
+#define WD_MOD (*(pREG32 (0xe0000000)))
+#define WD_TC (*(pREG32 (0xe0000004)))
+#define WD_FEED (*(pREG32 (0xe0000008)))
+#define WD_TV (*(pREG32 (0xe000000c)))
+
+#define WD_MOD_WDEN (0x00000001)
+#define WD_MOD_RESET (0x00000002)
+#define WD_MOD_TOF (0x00000004)
+#define WD_MOD_INT (0x00000008)
+#define WD_MOD_MASK (0x0000000f)
+
+#define WD_FEED_FEED1 (0x000000aa)
+#define WD_FEED_FEED2 (0x00000055)
+
+
+/*##############################################################################
+## System Control Block
+##############################################################################*/
+
+#define SCB_MEMMAP (*(pREG32 (0xe01fc040)))
+#define SCB_PLLCON (*(pREG32 (0xe01fc080)))
+#define SCB_PLLCFG (*(pREG32 (0xe01fc084)))
+#define SCB_PLLSTAT (*(pREG32 (0xe01fc088)))
+#define SCB_PLLFEED (*(pREG32 (0xe01fc08c)))
+#define SCB_PCON (*(pREG32 (0xe01fc0c0)))
+#define SCB_PCONP (*(pREG32 (0xe01fc0c4)))
+#define SCB_VPBDIV (*(pREG32 (0xe01fc100)))
+#define SCB_EXTINT (*(pREG32 (0xe01fc140)))
+#define SCB_INTWAKE (*(pREG32 (0xe01fc144)))
+#define SCB_EXTMODE (*(pREG32 (0xe01fc148)))
+#define SCB_EXTPOLAR (*(pREG32 (0xe01fc14c)))
+#define SCB_RSIR (*(pREG32 (0xe01fc180)))
+#define SCB_CSPR (*(pREG32 (0xe01fc184)))
+#define SCB_SCS (*(pREG32 (0xe01fc1a0)))
+
+#define SCB_MEMMAP_BLM (0x00000000)
+#define SCB_MEMMAP_UFL (0x00000001)
+#define SCB_MEMMAP_URM (0x00000002)
+#define SCB_MEMMAP_RSVD (0x00000003)
+#define SCB_MEMMAP_MASK (0x00000003)
+
+#define SCB_PLLCON_PLLE (0x00000001)
+#define SCB_PLLCON_PLLC (0x00000002)
+#define SCB_PLLCON_MASK (0x00000003)
+
+#define SCB_PLLCFG_MSEL (0x0000001f)
+#define SCB_PLLCFG_PSEL (0x00000060)
+#define SCB_PLLCFG_MUL1 (0x00000000)
+#define SCB_PLLCFG_MUL2 (0x00000001)
+#define SCB_PLLCFG_MUL3 (0x00000002)
+#define SCB_PLLCFG_MUL4 (0x00000003)
+#define SCB_PLLCFG_MUL5 (0x00000004)
+#define SCB_PLLCFG_MUL6 (0x00000005)
+#define SCB_PLLCFG_MUL7 (0x00000006)
+#define SCB_PLLCFG_MUL8 (0x00000007)
+#define SCB_PLLCFG_MUL9 (0x00000008)
+#define SCB_PLLCFG_MUL10 (0x00000009)
+#define SCB_PLLCFG_MUL11 (0x0000000a)
+#define SCB_PLLCFG_MUL12 (0x0000000b)
+#define SCB_PLLCFG_MUL13 (0x0000000c)
+#define SCB_PLLCFG_MUL14 (0x0000000d)
+#define SCB_PLLCFG_MUL15 (0x0000000e)
+#define SCB_PLLCFG_MUL16 (0x0000000f)
+#define SCB_PLLCFG_MUL17 (0x00000010)
+#define SCB_PLLCFG_MUL18 (0x00000011)
+#define SCB_PLLCFG_MUL19 (0x00000012)
+#define SCB_PLLCFG_MUL20 (0x00000013)
+#define SCB_PLLCFG_MUL21 (0x00000014)
+#define SCB_PLLCFG_MUL22 (0x00000015)
+#define SCB_PLLCFG_MUL23 (0x00000016)
+#define SCB_PLLCFG_MUL24 (0x00000017)
+#define SCB_PLLCFG_MUL25 (0x00000018)
+#define SCB_PLLCFG_MUL26 (0x00000019)
+#define SCB_PLLCFG_MUL27 (0x0000001a)
+#define SCB_PLLCFG_MUL28 (0x0000001b)
+#define SCB_PLLCFG_MUL29 (0x0000001c)
+#define SCB_PLLCFG_MUL30 (0x0000001d)
+#define SCB_PLLCFG_MUL31 (0x0000001e)
+#define SCB_PLLCFG_MUL32 (0x0000001f)
+#define SCB_PLLCFG_DIV1 (0x00000000)
+#define SCB_PLLCFG_DIV2 (0x00000020)
+#define SCB_PLLCFG_DIV4 (0x00000040)
+#define SCB_PLLCFG_DIV8 (0x00000060)
+#define SCB_PLLCFG_MASK (0x0000007f)
+
+#define SCB_PLLSTAT_MSEL (0x0000001f)
+#define SCB_PLLSTAT_PSEL (0x00000060)
+#define SCB_PLLSTAT_PLLE (0x00000100)
+#define SCB_PLLSTAT_PLLC (0x00000200)
+#define SCB_PLLSTAT_PLOCK (0x00000400)
+
+#define SCB_PLLFEED_FEED1 (0x000000aa)
+#define SCB_PLLFEED_FEED2 (0x00000055)
+
+#define SCB_PCON_IDL (0x00000001)
+#define SCB_PCON_PD (0x00000002)
+#define SCB_PCON_PDBOD (0x00000004)
+#define SCB_PCON_BODPDM (0x00000008)
+#define SCB_PCON_BOGD (0x00000010)
+#define SCB_PCON_BORD (0x00000020)
+#define SCB_PCON_MASK (0x0000003f)
+
+#define SCB_PCONP_PCTIM0 (0x00000002)
+#define SCB_PCONP_PCTIM1 (0x00000004)
+#define SCB_PCONP_PCUART0 (0x00000008)
+#define SCB_PCONP_PCUART1 (0x00000010)
+#define SCB_PCONP_PCPWM0 (0x00000020)
+#define SCB_PCONP_PCI2C0 (0x00000080)
+#define SCB_PCONP_PCSPI0 (0x00000100)
+#define SCB_PCONP_PCRTC (0x00000200)
+#define SCB_PCONP_PCSPI1 (0x00000400)
+#define SCB_PCONP_PCAD0 (0x00001000)
+#define SCB_PCONP_PCI2C1 (0x00080000)
+#define SCB_PCONP_PCAD1 (0x00100000)
+#define SCB_PCONP_PUSB (0x80000000)
+#define SCB_PCONP_MASK (0x801817be)
+
+#define SCB_VPBDIV_25 (0x00000000)
+#define SCB_VPBDIV_100 (0x00000001)
+#define SCB_VPBDIV_50 (0x00000002)
+#define SCB_VPBDIV_RSVD (0x00000003)
+#define SCB_VPBDIV_MASK (0x00000003)
+
+#define SCB_EXTINT_EINT0 (0x00000001)
+#define SCB_EXTINT_EINT1 (0x00000002)
+#define SCB_EXTINT_EINT2 (0x00000004)
+#define SCB_EXTINT_EINT3 (0x00000008)
+#define SCB_EXTINT_MASK (0x0000000f)
+
+#define SCB_INTWAKE_EINT0 (0x00000001)
+#define SCB_INTWAKE_EINT1 (0x00000002)
+#define SCB_INTWAKE_EINT2 (0x00000004)
+#define SCB_INTWAKE_EINT3 (0x00000008)
+#define SCB_INTWAKE_USB (0x00000020)
+#define SCB_INTWAKE_BOD (0x00004000)
+#define SCB_INTWAKE_RTC (0x00008000)
+#define SCB_INTWAKE_MASK (0x0000c02f)
+
+#define SCB_EXTMODE_EINT0 (0x00000001)
+#define SCB_EXTMODE_EINT1 (0x00000002)
+#define SCB_EXTMODE_EINT2 (0x00000004)
+#define SCB_EXTMODE_EINT3 (0x00000008)
+#define SCB_EXTMODE_MASK (0x0000000f)
+
+#define SCB_EXTPOLAR_EINT0 (0x00000001)
+#define SCB_EXTPOLAR_EINT1 (0x00000002)
+#define SCB_EXTPOLAR_EINT2 (0x00000004)
+#define SCB_EXTPOLAR_EINT3 (0x00000008)
+#define SCB_EXTPOLAR_MASK (0x0000000f)
+
+#define SCB_RSIR_POR (0x00000001)
+#define SCB_RSIR_EXTR (0x00000002)
+#define SCB_RSIR_WDTR (0x00000004)
+#define SCB_RSIR_BODR (0x00000008)
+#define SCB_RSIR_MASK (0x0000000f)
+
+#define SCB_SCS_GPIO0M (0x00000001)
+#define SCB_SCS_GPIO1M (0x00000002)
+#define SCB_SCS_MASK (0x00000003)
+
+
+/*##############################################################################
+## System Control Block (USB)
+##############################################################################*/
+
+#define USB_PLLCON (*(pREG32 (0xe01fc0a0)))
+#define USB_PLLCFG (*(pREG32 (0xe01fc0a4)))
+#define USB_PLLSTAT (*(pREG32 (0xe01fc0a8)))
+#define USB_PLLFEED (*(pREG32 (0xe01fc0ac)))
+
+#define USB_IntSt (*(pREG32 (0xe01fc1c0)))
+
+#define USB_DevIntSt (*(pREG32 (0xe0090000)))
+#define USB_DevIntEn (*(pREG32 (0xe0090004)))
+#define USB_DevIntClr (*(pREG32 (0xe0090008)))
+#define USB_DevIntSet (*(pREG32 (0xe009000c)))
+#define USB_DevIntPri (*(pREG32 (0xe009002c)))
+
+#define USB_EpIntSt (*(pREG32 (0xe0090030)))
+#define USB_EpIntEn (*(pREG32 (0xe0090034)))
+#define USB_EpIntClr (*(pREG32 (0xe0090038)))
+#define USB_EpIntSet (*(pREG32 (0xe009003c)))
+#define USB_EpIntPri (*(pREG32 (0xe0090040)))
+
+#define USB_ReEP (*(pREG32 (0xe0090044)))
+#define USB_EpInd (*(pREG32 (0xe0090048)))
+#define USB_MaxPSize (*(pREG32 (0xe009004c)))
+
+#define USB_RxData (*(pREG32 (0xe0090018)))
+#define USB_RxPLen (*(pREG32 (0xe0090020)))
+#define USB_TxData (*(pREG32 (0xe009001c)))
+#define USB_TxPLen (*(pREG32 (0xe0090024)))
+#define USB_Ctrl (*(pREG32 (0xe0090028)))
+
+#define USB_CmdCode (*(pREG32 (0xe0090010)))
+#define USB_CmdData (*(pREG32 (0xe0090014)))
+
+#define USB_DMARSt (*(pREG32 (0xe0090050)))
+#define USB_DMARClr (*(pREG32 (0xe0090054)))
+#define USB_DMARSet (*(pREG32 (0xe0090058)))
+#define USB_UDCAH (*(pREG32 (0xe0090080)))
+#define USB_EpDMASt (*(pREG32 (0xe0090084)))
+#define USB_EpDMAEn (*(pREG32 (0xe0090088)))
+#define USB_EpDMADis (*(pREG32 (0xe009008c)))
+#define USB_DMAIntSt (*(pREG32 (0xe0090090)))
+#define USB_DMAIntEn (*(pREG32 (0xe0090094)))
+#define USB_EoTIntSt (*(pREG32 (0xe00900a0)))
+#define USB_EoTIntClr (*(pREG32 (0xe00900a4)))
+#define USB_EoTIntSet (*(pREG32 (0xe00900a8)))
+#define USB_NDDRIntSt (*(pREG32 (0xe00900ac)))
+#define USB_NDDRIntClr (*(pREG32 (0xe00900b0)))
+#define USB_NDDRIntSet (*(pREG32 (0xe00900b4)))
+#define USB_SysErrIntSt (*(pREG32 (0xe00900b8)))
+#define USB_SysErrIntClr (*(pREG32 (0xe00900bc)))
+#define USB_SysErrIntSet (*(pREG32 (0xe00900c0)))
+
+#define USB_PLLCON_PLLE (0x00000001)
+#define USB_PLLCON_PLLC (0x00000002)
+#define USB_PLLCON_MASK (0x00000003)
+
+#define USB_PLLCFG_MSEL (0x0000001f)
+#define USB_PLLCFG_PSEL (0x00000060)
+#define USB_PLLCFG_MUL1 (0x00000000)
+#define USB_PLLCFG_MUL2 (0x00000001)
+#define USB_PLLCFG_MUL3 (0x00000002)
+#define USB_PLLCFG_MUL4 (0x00000003)
+#define USB_PLLCFG_MUL5 (0x00000004)
+#define USB_PLLCFG_MUL6 (0x00000005)
+#define USB_PLLCFG_MUL7 (0x00000006)
+#define USB_PLLCFG_MUL8 (0x00000007)
+#define USB_PLLCFG_MUL9 (0x00000008)
+#define USB_PLLCFG_MUL10 (0x00000009)
+#define USB_PLLCFG_MUL11 (0x0000000a)
+#define USB_PLLCFG_MUL12 (0x0000000b)
+#define USB_PLLCFG_MUL13 (0x0000000c)
+#define USB_PLLCFG_MUL14 (0x0000000d)
+#define USB_PLLCFG_MUL15 (0x0000000e)
+#define USB_PLLCFG_MUL16 (0x0000000f)
+#define USB_PLLCFG_MUL17 (0x00000010)
+#define USB_PLLCFG_MUL18 (0x00000011)
+#define USB_PLLCFG_MUL19 (0x00000012)
+#define USB_PLLCFG_MUL20 (0x00000013)
+#define USB_PLLCFG_MUL21 (0x00000014)
+#define USB_PLLCFG_MUL22 (0x00000015)
+#define USB_PLLCFG_MUL23 (0x00000016)
+#define USB_PLLCFG_MUL24 (0x00000017)
+#define USB_PLLCFG_MUL25 (0x00000018)
+#define USB_PLLCFG_MUL26 (0x00000019)
+#define USB_PLLCFG_MUL27 (0x0000001a)
+#define USB_PLLCFG_MUL28 (0x0000001b)
+#define USB_PLLCFG_MUL29 (0x0000001c)
+#define USB_PLLCFG_MUL30 (0x0000001d)
+#define USB_PLLCFG_MUL31 (0x0000001e)
+#define USB_PLLCFG_MUL32 (0x0000001f)
+#define USB_PLLCFG_DIV1 (0x00000000)
+#define USB_PLLCFG_DIV2 (0x00000020)
+#define USB_PLLCFG_DIV4 (0x00000040)
+#define USB_PLLCFG_DIV8 (0x00000060)
+#define USB_PLLCFG_MASK (0x0000007f)
+
+#define USB_PLLSTAT_MSEL (0x0000001f)
+#define USB_PLLSTAT_PSEL (0x00000060)
+#define USB_PLLSTAT_PLLE (0x00000100)
+#define USB_PLLSTAT_PLLC (0x00000200)
+#define USB_PLLSTAT_PLOCK (0x00000400)
+
+#define USB_PLLFEED_FEED1 (0x000000aa)
+#define USB_PLLFEED_FEED2 (0x00000055)
+
+#define USB_IntSt_REQLP (0x00000001)
+#define USB_IntSt_REQHP (0x00000002)
+#define USB_IntSt_REQDMA (0x00000004)
+#define USB_IntSt_NeedClock (0x00000100)
+#define USB_IntSt_EnUSBInts (0x80000000)
+#define USB_IntSt_MASK (0x80000107)
+
+#define USB_DevIntSt_FRAME (0x00000001)
+#define USB_DevIntSt_EPFAST (0x00000002)
+#define USB_DevIntSt_EPSLOW (0x00000004)
+#define USB_DevIntSt_DEVSTAT (0x00000008)
+#define USB_DevIntSt_CCEMTY (0x00000010)
+#define USB_DevIntSt_CDFULL (0x00000020)
+#define USB_DevIntSt_RxENDPKT (0x00000040)
+#define USB_DevIntSt_TxENDPKT (0x00000080)
+#define USB_DevIntSt_EPRLZED (0x00000100)
+#define USB_DevIntSt_EPRINT (0x00000200)
+#define USB_DevIntSt_MASK (0x000003ff)
+
+#define USB_DevIntEn_NONE (0x00000000)
+#define USB_DevIntEn_FRAME (0x00000001)
+#define USB_DevIntEn_EPFAST (0x00000002)
+#define USB_DevIntEn_EPSLOW (0x00000004)
+#define USB_DevIntEn_DEVSTAT (0x00000008)
+#define USB_DevIntEn_CCEMTY (0x00000010)
+#define USB_DevIntEn_CDFULL (0x00000020)
+#define USB_DevIntEn_RxENDPKT (0x00000040)
+#define USB_DevIntEn_TxENDPKT (0x00000080)
+#define USB_DevIntEn_EPRLZED (0x00000100)
+#define USB_DevIntEn_EPRINT (0x00000200)
+#define USB_DevIntEn_MASK (0x000003ff)
+
+#define USB_DevIntClr_FRAME (0x00000001)
+#define USB_DevIntClr_EPFAST (0x00000002)
+#define USB_DevIntClr_EPSLOW (0x00000004)
+#define USB_DevIntClr_DEVSTAT (0x00000008)
+#define USB_DevIntClr_CCEMTY (0x00000010)
+#define USB_DevIntClr_CDFULL (0x00000020)
+#define USB_DevIntClr_RxENDPKT (0x00000040)
+#define USB_DevIntClr_TxENDPKT (0x00000080)
+#define USB_DevIntClr_EPRLZED (0x00000100)
+#define USB_DevIntClr_EPRINT (0x00000200)
+#define USB_DevIntClr_ALL (0x000003ff)
+#define USB_DevIntClr_MASK (0x000003ff)
+
+#define USB_DevIntSet_FRAME (0x00000001)
+#define USB_DevIntSet_EPFAST (0x00000002)
+#define USB_DevIntSet_EPSLOW (0x00000004)
+#define USB_DevIntSet_DEVSTAT (0x00000008)
+#define USB_DevIntSet_CCEMTY (0x00000010)
+#define USB_DevIntSet_CDFULL (0x00000020)
+#define USB_DevIntSet_RxENDPKT (0x00000040)
+#define USB_DevIntSet_TxENDPKT (0x00000080)
+#define USB_DevIntSet_EPRLZED (0x00000100)
+#define USB_DevIntSet_EPRINT (0x00000200)
+#define USB_DevIntSet_MASK (0x000003ff)
+
+#define USB_DevIntPri_FRAME (0x00000001)
+#define USB_DevIntPri_EPFAST (0x00000002)
+#define USB_DevIntPri_MASK (0x00000003)
+
+#define USB_EpIntSt_EP0RX (0x00000001)
+#define USB_EpIntSt_EP0TX (0x00000002)
+#define USB_EpIntSt_EP1RX (0x00000004)
+#define USB_EpIntSt_EP1TX (0x00000008)
+#define USB_EpIntSt_EP2RX (0x00000010)
+#define USB_EpIntSt_EP2TX (0x00000020)
+#define USB_EpIntSt_EP3RX (0x00000040)
+#define USB_EpIntSt_EP3TX (0x00000080)
+#define USB_EpIntSt_EP4RX (0x00000100)
+#define USB_EpIntSt_EP4TX (0x00000200)
+#define USB_EpIntSt_EP5RX (0x00000400)
+#define USB_EpIntSt_EP5TX (0x00000800)
+#define USB_EpIntSt_EP6RX (0x00001000)
+#define USB_EpIntSt_EP6TX (0x00002000)
+#define USB_EpIntSt_EP7RX (0x00004000)
+#define USB_EpIntSt_EP7TX (0x00008000)
+#define USB_EpIntSt_EP8RX (0x00010000)
+#define USB_EpIntSt_EP8TX (0x00020000)
+#define USB_EpIntSt_EP9RX (0x00040000)
+#define USB_EpIntSt_EP9TX (0x00080000)
+#define USB_EpIntSt_EP10RX (0x00100000)
+#define USB_EpIntSt_EP10TX (0x00200000)
+#define USB_EpIntSt_EP11RX (0x00400000)
+#define USB_EpIntSt_EP11TX (0x00800000)
+#define USB_EpIntSt_EP12RX (0x01000000)
+#define USB_EpIntSt_EP12TX (0x02000000)
+#define USB_EpIntSt_EP13RX (0x04000000)
+#define USB_EpIntSt_EP13TX (0x08000000)
+#define USB_EpIntSt_EP14RX (0x10000000)
+#define USB_EpIntSt_EP14TX (0x20000000)
+#define USB_EpIntSt_EP15RX (0x40000000)
+#define USB_EpIntSt_EP15TX (0x80000000)
+#define USB_EpIntSt_MASK (0xffffffff)
+
+#define USB_EpIntEn_NONE (0x00000000)
+#define USB_EpIntEn_EP0RX (0x00000001)
+#define USB_EpIntEn_EP0TX (0x00000002)
+#define USB_EpIntEn_EP1RX (0x00000004)
+#define USB_EpIntEn_EP1TX (0x00000008)
+#define USB_EpIntEn_EP2RX (0x00000010)
+#define USB_EpIntEn_EP2TX (0x00000020)
+#define USB_EpIntEn_EP3RX (0x00000040)
+#define USB_EpIntEn_EP3TX (0x00000080)
+#define USB_EpIntEn_EP4RX (0x00000100)
+#define USB_EpIntEn_EP4TX (0x00000200)
+#define USB_EpIntEn_EP5RX (0x00000400)
+#define USB_EpIntEn_EP5TX (0x00000800)
+#define USB_EpIntEn_EP6RX (0x00001000)
+#define USB_EpIntEn_EP6TX (0x00002000)
+#define USB_EpIntEn_EP7RX (0x00004000)
+#define USB_EpIntEn_EP7TX (0x00008000)
+#define USB_EpIntEn_EP8RX (0x00010000)
+#define USB_EpIntEn_EP8TX (0x00020000)
+#define USB_EpIntEn_EP9RX (0x00040000)
+#define USB_EpIntEn_EP9TX (0x00080000)
+#define USB_EpIntEn_EP10RX (0x00100000)
+#define USB_EpIntEn_EP10TX (0x00200000)
+#define USB_EpIntEn_EP11RX (0x00400000)
+#define USB_EpIntEn_EP11TX (0x00800000)
+#define USB_EpIntEn_EP12RX (0x01000000)
+#define USB_EpIntEn_EP12TX (0x02000000)
+#define USB_EpIntEn_EP13RX (0x04000000)
+#define USB_EpIntEn_EP13TX (0x08000000)
+#define USB_EpIntEn_EP14RX (0x10000000)
+#define USB_EpIntEn_EP14TX (0x20000000)
+#define USB_EpIntEn_EP15RX (0x40000000)
+#define USB_EpIntEn_EP15TX (0x80000000)
+#define USB_EpIntEn_MASK (0xffffffff)
+
+#define USB_EpIntClr_EP0RX (0x00000001)
+#define USB_EpIntClr_EP0TX (0x00000002)
+#define USB_EpIntClr_EP1RX (0x00000004)
+#define USB_EpIntClr_EP1TX (0x00000008)
+#define USB_EpIntClr_EP2RX (0x00000010)
+#define USB_EpIntClr_EP2TX (0x00000020)
+#define USB_EpIntClr_EP3RX (0x00000040)
+#define USB_EpIntClr_EP3TX (0x00000080)
+#define USB_EpIntClr_EP4RX (0x00000100)
+#define USB_EpIntClr_EP4TX (0x00000200)
+#define USB_EpIntClr_EP5RX (0x00000400)
+#define USB_EpIntClr_EP5TX (0x00000800)
+#define USB_EpIntClr_EP6RX (0x00001000)
+#define USB_EpIntClr_EP6TX (0x00002000)
+#define USB_EpIntClr_EP7RX (0x00004000)
+#define USB_EpIntClr_EP7TX (0x00008000)
+#define USB_EpIntClr_EP8RX (0x00010000)
+#define USB_EpIntClr_EP8TX (0x00020000)
+#define USB_EpIntClr_EP9RX (0x00040000)
+#define USB_EpIntClr_EP9TX (0x00080000)
+#define USB_EpIntClr_EP10RX (0x00100000)
+#define USB_EpIntClr_EP10TX (0x00200000)
+#define USB_EpIntClr_EP11RX (0x00400000)
+#define USB_EpIntClr_EP11TX (0x00800000)
+#define USB_EpIntClr_EP12RX (0x01000000)
+#define USB_EpIntClr_EP12TX (0x02000000)
+#define USB_EpIntClr_EP13RX (0x04000000)
+#define USB_EpIntClr_EP13TX (0x08000000)
+#define USB_EpIntClr_EP14RX (0x10000000)
+#define USB_EpIntClr_EP14TX (0x20000000)
+#define USB_EpIntClr_EP15RX (0x40000000)
+#define USB_EpIntClr_EP15TX (0x80000000)
+#define USB_EpIntClr_ALL (0xffffffff)
+#define USB_EpIntClr_MASK (0xffffffff)
+
+#define USB_EpIntSet_EP0RX (0x00000001)
+#define USB_EpIntSet_EP0TX (0x00000002)
+#define USB_EpIntSet_EP1RX (0x00000004)
+#define USB_EpIntSet_EP1TX (0x00000008)
+#define USB_EpIntSet_EP2RX (0x00000010)
+#define USB_EpIntSet_EP2TX (0x00000020)
+#define USB_EpIntSet_EP3RX (0x00000040)
+#define USB_EpIntSet_EP3TX (0x00000080)
+#define USB_EpIntSet_EP4RX (0x00000100)
+#define USB_EpIntSet_EP4TX (0x00000200)
+#define USB_EpIntSet_EP5RX (0x00000400)
+#define USB_EpIntSet_EP5TX (0x00000800)
+#define USB_EpIntSet_EP6RX (0x00001000)
+#define USB_EpIntSet_EP6TX (0x00002000)
+#define USB_EpIntSet_EP7RX (0x00004000)
+#define USB_EpIntSet_EP7TX (0x00008000)
+#define USB_EpIntSet_EP8RX (0x00010000)
+#define USB_EpIntSet_EP8TX (0x00020000)
+#define USB_EpIntSet_EP9RX (0x00040000)
+#define USB_EpIntSet_EP9TX (0x00080000)
+#define USB_EpIntSet_EP10RX (0x00100000)
+#define USB_EpIntSet_EP10TX (0x00200000)
+#define USB_EpIntSet_EP11RX (0x00400000)
+#define USB_EpIntSet_EP11TX (0x00800000)
+#define USB_EpIntSet_EP12RX (0x01000000)
+#define USB_EpIntSet_EP12TX (0x02000000)
+#define USB_EpIntSet_EP13RX (0x04000000)
+#define USB_EpIntSet_EP13TX (0x08000000)
+#define USB_EpIntSet_EP14RX (0x10000000)
+#define USB_EpIntSet_EP14TX (0x20000000)
+#define USB_EpIntSet_EP15RX (0x40000000)
+#define USB_EpIntSet_EP15TX (0x80000000)
+#define USB_EpIntSet_MASK (0xffffffff)
+
+#define USB_EpIntPri_EP0RX (0x00000001)
+#define USB_EpIntPri_EP0TX (0x00000002)
+#define USB_EpIntPri_EP1RX (0x00000004)
+#define USB_EpIntPri_EP1TX (0x00000008)
+#define USB_EpIntPri_EP2RX (0x00000010)
+#define USB_EpIntPri_EP2TX (0x00000020)
+#define USB_EpIntPri_EP3RX (0x00000040)
+#define USB_EpIntPri_EP3TX (0x00000080)
+#define USB_EpIntPri_EP4RX (0x00000100)
+#define USB_EpIntPri_EP4TX (0x00000200)
+#define USB_EpIntPri_EP5RX (0x00000400)
+#define USB_EpIntPri_EP5TX (0x00000800)
+#define USB_EpIntPri_EP6RX (0x00001000)
+#define USB_EpIntPri_EP6TX (0x00002000)
+#define USB_EpIntPri_EP7RX (0x00004000)
+#define USB_EpIntPri_EP7TX (0x00008000)
+#define USB_EpIntPri_EP8RX (0x00010000)
+#define USB_EpIntPri_EP8TX (0x00020000)
+#define USB_EpIntPri_EP9RX (0x00040000)
+#define USB_EpIntPri_EP9TX (0x00080000)
+#define USB_EpIntPri_EP10RX (0x00100000)
+#define USB_EpIntPri_EP10TX (0x00200000)
+#define USB_EpIntPri_EP11RX (0x00400000)
+#define USB_EpIntPri_EP11TX (0x00800000)
+#define USB_EpIntPri_EP12RX (0x01000000)
+#define USB_EpIntPri_EP12TX (0x02000000)
+#define USB_EpIntPri_EP13RX (0x04000000)
+#define USB_EpIntPri_EP13TX (0x08000000)
+#define USB_EpIntPri_EP14RX (0x10000000)
+#define USB_EpIntPri_EP14TX (0x20000000)
+#define USB_EpIntPri_EP15RX (0x40000000)
+#define USB_EpIntPri_EP15TX (0x80000000)
+#define USB_EpIntPri_MASK (0xffffffff)
+
+#define USB_EpRE_EP0 (0x00000001)
+#define USB_EpRE_EP1 (0x00000002)
+#define USB_EpRE_EP2 (0x00000004)
+#define USB_EpRE_EP3 (0x00000008)
+#define USB_EpRE_EP4 (0x00000010)
+#define USB_EpRE_EP5 (0x00000020)
+#define USB_EpRE_EP6 (0x00000040)
+#define USB_EpRE_EP7 (0x00000080)
+#define USB_EpRE_EP8 (0x00000100)
+#define USB_EpRE_EP9 (0x00000200)
+#define USB_EpRE_EP10 (0x00000400)
+#define USB_EpRE_EP11 (0x00000800)
+#define USB_EpRE_EP12 (0x00001000)
+#define USB_EpRE_EP13 (0x00002000)
+#define USB_EpRE_EP14 (0x00004000)
+#define USB_EpRE_EP15 (0x00008000)
+#define USB_EpRE_EP16 (0x00010000)
+#define USB_EpRE_EP17 (0x00020000)
+#define USB_EpRE_EP18 (0x00040000)
+#define USB_EpRE_EP19 (0x00080000)
+#define USB_EpRE_EP20 (0x00100000)
+#define USB_EpRE_EP21 (0x00200000)
+#define USB_EpRE_EP22 (0x00400000)
+#define USB_EpRE_EP23 (0x00800000)
+#define USB_EpRE_EP24 (0x01000000)
+#define USB_EpRE_EP25 (0x02000000)
+#define USB_EpRE_EP26 (0x04000000)
+#define USB_EpRE_EP27 (0x08000000)
+#define USB_EpRE_EP28 (0x10000000)
+#define USB_EpRE_EP29 (0x20000000)
+#define USB_EpRE_EP30 (0x40000000)
+#define USB_EpRE_EP31 (0x80000000)
+#define USB_EpRE_MASK (0xffffffff)
+
+#define USB_EpIn_MASK (0x0000001f)
+
+#define USB_MaxPSize_MASK (0x000003ff)
+
+#define USB_RxPLen_PKTLENGTH (0x000003ff)
+#define USB_RxPLen_PKTLENGTH_MASK (0x000003ff)
+#define USB_RxPLen_DV (0x00000400)
+#define USB_RxPLen_PKTRDY (0x00000800)
+#define USB_RxPLen_MASK (0x00000fff)
+
+#define USB_TxPLen_PKTLENGTH (0x000003ff)
+#define USB_TxPLen_MASK (0x000003ff)
+
+#define USB_Ctrl_RDEN (0x00000001)
+#define USB_Ctrl_WREN (0x00000002)
+#define USB_Ctrl_LOGENDPOINT (0x0000003c)
+#define USB_Ctrl_MASK (0x0000003f)
+
+#define USB_CmdCode_CMDPHASE (0x0000ff00)
+#define USB_CmdCode_CMDCODE (0x00ff0000)
+#define USB_CmdCode_MASK (0x00ffff00)
+
+#define USB_CmdData_MASK (0x000000ff)
+
+#define USB_DMARSt_EP0 (0x00000001)
+#define USB_DMARSt_EP1 (0x00000002)
+#define USB_DMARSt_EP2 (0x00000004)
+#define USB_DMARSt_EP3 (0x00000008)
+#define USB_DMARSt_EP4 (0x00000010)
+#define USB_DMARSt_EP5 (0x00000020)
+#define USB_DMARSt_EP6 (0x00000040)
+#define USB_DMARSt_EP7 (0x00000080)
+#define USB_DMARSt_EP8 (0x00000100)
+#define USB_DMARSt_EP9 (0x00000200)
+#define USB_DMARSt_EP10 (0x00000400)
+#define USB_DMARSt_EP11 (0x00000800)
+#define USB_DMARSt_EP12 (0x00001000)
+#define USB_DMARSt_EP13 (0x00002000)
+#define USB_DMARSt_EP14 (0x00004000)
+#define USB_DMARSt_EP15 (0x00008000)
+#define USB_DMARSt_EP16 (0x00010000)
+#define USB_DMARSt_EP17 (0x00020000)
+#define USB_DMARSt_EP18 (0x00040000)
+#define USB_DMARSt_EP19 (0x00080000)
+#define USB_DMARSt_EP20 (0x00100000)
+#define USB_DMARSt_EP21 (0x00200000)
+#define USB_DMARSt_EP22 (0x00400000)
+#define USB_DMARSt_EP23 (0x00800000)
+#define USB_DMARSt_EP24 (0x01000000)
+#define USB_DMARSt_EP25 (0x02000000)
+#define USB_DMARSt_EP26 (0x04000000)
+#define USB_DMARSt_EP27 (0x08000000)
+#define USB_DMARSt_EP28 (0x10000000)
+#define USB_DMARSt_EP29 (0x20000000)
+#define USB_DMARSt_EP30 (0x40000000)
+#define USB_DMARSt_EP31 (0x80000000)
+#define USB_DMARSt_MASK (0xffffffff)
+
+#define USB_DMARClr_EP0 (0x00000001)
+#define USB_DMARClr_EP1 (0x00000002)
+#define USB_DMARClr_EP2 (0x00000004)
+#define USB_DMARClr_EP3 (0x00000008)
+#define USB_DMARClr_EP4 (0x00000010)
+#define USB_DMARClr_EP5 (0x00000020)
+#define USB_DMARClr_EP6 (0x00000040)
+#define USB_DMARClr_EP7 (0x00000080)
+#define USB_DMARClr_EP8 (0x00000100)
+#define USB_DMARClr_EP9 (0x00000200)
+#define USB_DMARClr_EP10 (0x00000400)
+#define USB_DMARClr_EP11 (0x00000800)
+#define USB_DMARClr_EP12 (0x00001000)
+#define USB_DMARClr_EP13 (0x00002000)
+#define USB_DMARClr_EP14 (0x00004000)
+#define USB_DMARClr_EP15 (0x00008000)
+#define USB_DMARClr_EP16 (0x00010000)
+#define USB_DMARClr_EP17 (0x00020000)
+#define USB_DMARClr_EP18 (0x00040000)
+#define USB_DMARClr_EP19 (0x00080000)
+#define USB_DMARClr_EP20 (0x00100000)
+#define USB_DMARClr_EP21 (0x00200000)
+#define USB_DMARClr_EP22 (0x00400000)
+#define USB_DMARClr_EP23 (0x00800000)
+#define USB_DMARClr_EP24 (0x01000000)
+#define USB_DMARClr_EP25 (0x02000000)
+#define USB_DMARClr_EP26 (0x04000000)
+#define USB_DMARClr_EP27 (0x08000000)
+#define USB_DMARClr_EP28 (0x10000000)
+#define USB_DMARClr_EP29 (0x20000000)
+#define USB_DMARClr_EP30 (0x40000000)
+#define USB_DMARClr_EP31 (0x80000000)
+#define USB_DMARClr_MASK (0xffffffff)
+
+#define USB_DMARSet_EP0 (0x00000001)
+#define USB_DMARSet_EP1 (0x00000002)
+#define USB_DMARSet_EP2 (0x00000004)
+#define USB_DMARSet_EP3 (0x00000008)
+#define USB_DMARSet_EP4 (0x00000010)
+#define USB_DMARSet_EP5 (0x00000020)
+#define USB_DMARSet_EP6 (0x00000040)
+#define USB_DMARSet_EP7 (0x00000080)
+#define USB_DMARSet_EP8 (0x00000100)
+#define USB_DMARSet_EP9 (0x00000200)
+#define USB_DMARSet_EP10 (0x00000400)
+#define USB_DMARSet_EP11 (0x00000800)
+#define USB_DMARSet_EP12 (0x00001000)
+#define USB_DMARSet_EP13 (0x00002000)
+#define USB_DMARSet_EP14 (0x00004000)
+#define USB_DMARSet_EP15 (0x00008000)
+#define USB_DMARSet_EP16 (0x00010000)
+#define USB_DMARSet_EP17 (0x00020000)
+#define USB_DMARSet_EP18 (0x00040000)
+#define USB_DMARSet_EP19 (0x00080000)
+#define USB_DMARSet_EP20 (0x00100000)
+#define USB_DMARSet_EP21 (0x00200000)
+#define USB_DMARSet_EP22 (0x00400000)
+#define USB_DMARSet_EP23 (0x00800000)
+#define USB_DMARSet_EP24 (0x01000000)
+#define USB_DMARSet_EP25 (0x02000000)
+#define USB_DMARSet_EP26 (0x04000000)
+#define USB_DMARSet_EP27 (0x08000000)
+#define USB_DMARSet_EP28 (0x10000000)
+#define USB_DMARSet_EP29 (0x20000000)
+#define USB_DMARSet_EP30 (0x40000000)
+#define USB_DMARSet_EP31 (0x80000000)
+#define USB_DMARSet_MASK (0xffffffff)
+
+#define USB_EpDMASt_EP0 (0x00000001)
+#define USB_EpDMASt_EP1 (0x00000002)
+#define USB_EpDMASt_EP2 (0x00000004)
+#define USB_EpDMASt_EP3 (0x00000008)
+#define USB_EpDMASt_EP4 (0x00000010)
+#define USB_EpDMASt_EP5 (0x00000020)
+#define USB_EpDMASt_EP6 (0x00000040)
+#define USB_EpDMASt_EP7 (0x00000080)
+#define USB_EpDMASt_EP8 (0x00000100)
+#define USB_EpDMASt_EP9 (0x00000200)
+#define USB_EpDMASt_EP10 (0x00000400)
+#define USB_EpDMASt_EP11 (0x00000800)
+#define USB_EpDMASt_EP12 (0x00001000)
+#define USB_EpDMASt_EP13 (0x00002000)
+#define USB_EpDMASt_EP14 (0x00004000)
+#define USB_EpDMASt_EP15 (0x00008000)
+#define USB_EpDMASt_EP16 (0x00010000)
+#define USB_EpDMASt_EP17 (0x00020000)
+#define USB_EpDMASt_EP18 (0x00040000)
+#define USB_EpDMASt_EP19 (0x00080000)
+#define USB_EpDMASt_EP20 (0x00100000)
+#define USB_EpDMASt_EP21 (0x00200000)
+#define USB_EpDMASt_EP22 (0x00400000)
+#define USB_EpDMASt_EP23 (0x00800000)
+#define USB_EpDMASt_EP24 (0x01000000)
+#define USB_EpDMASt_EP25 (0x02000000)
+#define USB_EpDMASt_EP26 (0x04000000)
+#define USB_EpDMASt_EP27 (0x08000000)
+#define USB_EpDMASt_EP28 (0x10000000)
+#define USB_EpDMASt_EP29 (0x20000000)
+#define USB_EpDMASt_EP30 (0x40000000)
+#define USB_EpDMASt_EP31 (0x80000000)
+#define USB_EpDMASt_MASK (0xffffffff)
+
+#define USB_EpDMAEn_EP0 (0x00000001)
+#define USB_EpDMAEn_EP1 (0x00000002)
+#define USB_EpDMAEn_EP2 (0x00000004)
+#define USB_EpDMAEn_EP3 (0x00000008)
+#define USB_EpDMAEn_EP4 (0x00000010)
+#define USB_EpDMAEn_EP5 (0x00000020)
+#define USB_EpDMAEn_EP6 (0x00000040)
+#define USB_EpDMAEn_EP7 (0x00000080)
+#define USB_EpDMAEn_EP8 (0x00000100)
+#define USB_EpDMAEn_EP9 (0x00000200)
+#define USB_EpDMAEn_EP10 (0x00000400)
+#define USB_EpDMAEn_EP11 (0x00000800)
+#define USB_EpDMAEn_EP12 (0x00001000)
+#define USB_EpDMAEn_EP13 (0x00002000)
+#define USB_EpDMAEn_EP14 (0x00004000)
+#define USB_EpDMAEn_EP15 (0x00008000)
+#define USB_EpDMAEn_EP16 (0x00010000)
+#define USB_EpDMAEn_EP17 (0x00020000)
+#define USB_EpDMAEn_EP18 (0x00040000)
+#define USB_EpDMAEn_EP19 (0x00080000)
+#define USB_EpDMAEn_EP20 (0x00100000)
+#define USB_EpDMAEn_EP21 (0x00200000)
+#define USB_EpDMAEn_EP22 (0x00400000)
+#define USB_EpDMAEn_EP23 (0x00800000)
+#define USB_EpDMAEn_EP24 (0x01000000)
+#define USB_EpDMAEn_EP25 (0x02000000)
+#define USB_EpDMAEn_EP26 (0x04000000)
+#define USB_EpDMAEn_EP27 (0x08000000)
+#define USB_EpDMAEn_EP28 (0x10000000)
+#define USB_EpDMAEn_EP29 (0x20000000)
+#define USB_EpDMAEn_EP30 (0x40000000)
+#define USB_EpDMAEn_EP31 (0x80000000)
+#define USB_EpDMAEn_MASK (0xffffffff)
+
+#define USB_EpDMADis_EP0 (0x00000001)
+#define USB_EpDMADis_EP1 (0x00000002)
+#define USB_EpDMADis_EP2 (0x00000004)
+#define USB_EpDMADis_EP3 (0x00000008)
+#define USB_EpDMADis_EP4 (0x00000010)
+#define USB_EpDMADis_EP5 (0x00000020)
+#define USB_EpDMADis_EP6 (0x00000040)
+#define USB_EpDMADis_EP7 (0x00000080)
+#define USB_EpDMADis_EP8 (0x00000100)
+#define USB_EpDMADis_EP9 (0x00000200)
+#define USB_EpDMADis_EP10 (0x00000400)
+#define USB_EpDMADis_EP11 (0x00000800)
+#define USB_EpDMADis_EP12 (0x00001000)
+#define USB_EpDMADis_EP13 (0x00002000)
+#define USB_EpDMADis_EP14 (0x00004000)
+#define USB_EpDMADis_EP15 (0x00008000)
+#define USB_EpDMADis_EP16 (0x00010000)
+#define USB_EpDMADis_EP17 (0x00020000)
+#define USB_EpDMADis_EP18 (0x00040000)
+#define USB_EpDMADis_EP19 (0x00080000)
+#define USB_EpDMADis_EP20 (0x00100000)
+#define USB_EpDMADis_EP21 (0x00200000)
+#define USB_EpDMADis_EP22 (0x00400000)
+#define USB_EpDMADis_EP23 (0x00800000)
+#define USB_EpDMADis_EP24 (0x01000000)
+#define USB_EpDMADis_EP25 (0x02000000)
+#define USB_EpDMADis_EP26 (0x04000000)
+#define USB_EpDMADis_EP27 (0x08000000)
+#define USB_EpDMADis_EP28 (0x10000000)
+#define USB_EpDMADis_EP29 (0x20000000)
+#define USB_EpDMADis_EP30 (0x40000000)
+#define USB_EpDMADis_EP31 (0x80000000)
+#define USB_EpDMADis_MASK (0xffffffff)
+
+#define USB_DMAInstSt_EOT (0x00000001)
+#define USB_DMAInstSt_NDDR (0x00000002)
+#define USB_DMAInstSt_SE (0x00000004)
+#define USB_DMAInstSt_MASK (0x00000007)
+
+#define USB_DMAInstEn_EOT (0x00000001)
+#define USB_DMAInstEn_NDDR (0x00000002)
+#define USB_DMAInstEn_SE (0x00000004)
+#define USB_DMAInstEn_MASK (0x00000007)
+
+#define USB_EoTIntSt_EP0 (0x00000001)
+#define USB_EoTIntSt_EP1 (0x00000002)
+#define USB_EoTIntSt_EP2 (0x00000004)
+#define USB_EoTIntSt_EP3 (0x00000008)
+#define USB_EoTIntSt_EP4 (0x00000010)
+#define USB_EoTIntSt_EP5 (0x00000020)
+#define USB_EoTIntSt_EP6 (0x00000040)
+#define USB_EoTIntSt_EP7 (0x00000080)
+#define USB_EoTIntSt_EP8 (0x00000100)
+#define USB_EoTIntSt_EP9 (0x00000200)
+#define USB_EoTIntSt_EP10 (0x00000400)
+#define USB_EoTIntSt_EP11 (0x00000800)
+#define USB_EoTIntSt_EP12 (0x00001000)
+#define USB_EoTIntSt_EP13 (0x00002000)
+#define USB_EoTIntSt_EP14 (0x00004000)
+#define USB_EoTIntSt_EP15 (0x00008000)
+#define USB_EoTIntSt_EP16 (0x00010000)
+#define USB_EoTIntSt_EP17 (0x00020000)
+#define USB_EoTIntSt_EP18 (0x00040000)
+#define USB_EoTIntSt_EP19 (0x00080000)
+#define USB_EoTIntSt_EP20 (0x00100000)
+#define USB_EoTIntSt_EP21 (0x00200000)
+#define USB_EoTIntSt_EP22 (0x00400000)
+#define USB_EoTIntSt_EP23 (0x00800000)
+#define USB_EoTIntSt_EP24 (0x01000000)
+#define USB_EoTIntSt_EP25 (0x02000000)
+#define USB_EoTIntSt_EP26 (0x04000000)
+#define USB_EoTIntSt_EP27 (0x08000000)
+#define USB_EoTIntSt_EP28 (0x10000000)
+#define USB_EoTIntSt_EP29 (0x20000000)
+#define USB_EoTIntSt_EP30 (0x40000000)
+#define USB_EoTIntSt_EP31 (0x80000000)
+#define USB_EoTIntSt_MASK (0xffffffff)
+
+#define USB_EoTIntClr_EP0 (0x00000001)
+#define USB_EoTIntClr_EP1 (0x00000002)
+#define USB_EoTIntClr_EP2 (0x00000004)
+#define USB_EoTIntClr_EP3 (0x00000008)
+#define USB_EoTIntClr_EP4 (0x00000010)
+#define USB_EoTIntClr_EP5 (0x00000020)
+#define USB_EoTIntClr_EP6 (0x00000040)
+#define USB_EoTIntClr_EP7 (0x00000080)
+#define USB_EoTIntClr_EP8 (0x00000100)
+#define USB_EoTIntClr_EP9 (0x00000200)
+#define USB_EoTIntClr_EP10 (0x00000400)
+#define USB_EoTIntClr_EP11 (0x00000800)
+#define USB_EoTIntClr_EP12 (0x00001000)
+#define USB_EoTIntClr_EP13 (0x00002000)
+#define USB_EoTIntClr_EP14 (0x00004000)
+#define USB_EoTIntClr_EP15 (0x00008000)
+#define USB_EoTIntClr_EP16 (0x00010000)
+#define USB_EoTIntClr_EP17 (0x00020000)
+#define USB_EoTIntClr_EP18 (0x00040000)
+#define USB_EoTIntClr_EP19 (0x00080000)
+#define USB_EoTIntClr_EP20 (0x00100000)
+#define USB_EoTIntClr_EP21 (0x00200000)
+#define USB_EoTIntClr_EP22 (0x00400000)
+#define USB_EoTIntClr_EP23 (0x00800000)
+#define USB_EoTIntClr_EP24 (0x01000000)
+#define USB_EoTIntClr_EP25 (0x02000000)
+#define USB_EoTIntClr_EP26 (0x04000000)
+#define USB_EoTIntClr_EP27 (0x08000000)
+#define USB_EoTIntClr_EP28 (0x10000000)
+#define USB_EoTIntClr_EP29 (0x20000000)
+#define USB_EoTIntClr_EP30 (0x40000000)
+#define USB_EoTIntClr_EP31 (0x80000000)
+#define USB_EoTIntClr_MASK (0xffffffff)
+
+#define USB_EoTIntSet_EP0 (0x00000001)
+#define USB_EoTIntSet_EP1 (0x00000002)
+#define USB_EoTIntSet_EP2 (0x00000004)
+#define USB_EoTIntSet_EP3 (0x00000008)
+#define USB_EoTIntSet_EP4 (0x00000010)
+#define USB_EoTIntSet_EP5 (0x00000020)
+#define USB_EoTIntSet_EP6 (0x00000040)
+#define USB_EoTIntSet_EP7 (0x00000080)
+#define USB_EoTIntSet_EP8 (0x00000100)
+#define USB_EoTIntSet_EP9 (0x00000200)
+#define USB_EoTIntSet_EP10 (0x00000400)
+#define USB_EoTIntSet_EP11 (0x00000800)
+#define USB_EoTIntSet_EP12 (0x00001000)
+#define USB_EoTIntSet_EP13 (0x00002000)
+#define USB_EoTIntSet_EP14 (0x00004000)
+#define USB_EoTIntSet_EP15 (0x00008000)
+#define USB_EoTIntSet_EP16 (0x00010000)
+#define USB_EoTIntSet_EP17 (0x00020000)
+#define USB_EoTIntSet_EP18 (0x00040000)
+#define USB_EoTIntSet_EP19 (0x00080000)
+#define USB_EoTIntSet_EP20 (0x00100000)
+#define USB_EoTIntSet_EP21 (0x00200000)
+#define USB_EoTIntSet_EP22 (0x00400000)
+#define USB_EoTIntSet_EP23 (0x00800000)
+#define USB_EoTIntSet_EP24 (0x01000000)
+#define USB_EoTIntSet_EP25 (0x02000000)
+#define USB_EoTIntSet_EP26 (0x04000000)
+#define USB_EoTIntSet_EP27 (0x08000000)
+#define USB_EoTIntSet_EP28 (0x10000000)
+#define USB_EoTIntSet_EP29 (0x20000000)
+#define USB_EoTIntSet_EP30 (0x40000000)
+#define USB_EoTIntSet_EP31 (0x80000000)
+#define USB_EoTIntSet_MASK (0xffffffff)
+
+#define USB_NDDRIntSt_EP0 (0x00000001)
+#define USB_NDDRIntSt_EP1 (0x00000002)
+#define USB_NDDRIntSt_EP2 (0x00000004)
+#define USB_NDDRIntSt_EP3 (0x00000008)
+#define USB_NDDRIntSt_EP4 (0x00000010)
+#define USB_NDDRIntSt_EP5 (0x00000020)
+#define USB_NDDRIntSt_EP6 (0x00000040)
+#define USB_NDDRIntSt_EP7 (0x00000080)
+#define USB_NDDRIntSt_EP8 (0x00000100)
+#define USB_NDDRIntSt_EP9 (0x00000200)
+#define USB_NDDRIntSt_EP10 (0x00000400)
+#define USB_NDDRIntSt_EP11 (0x00000800)
+#define USB_NDDRIntSt_EP12 (0x00001000)
+#define USB_NDDRIntSt_EP13 (0x00002000)
+#define USB_NDDRIntSt_EP14 (0x00004000)
+#define USB_NDDRIntSt_EP15 (0x00008000)
+#define USB_NDDRIntSt_EP16 (0x00010000)
+#define USB_NDDRIntSt_EP17 (0x00020000)
+#define USB_NDDRIntSt_EP18 (0x00040000)
+#define USB_NDDRIntSt_EP19 (0x00080000)
+#define USB_NDDRIntSt_EP20 (0x00100000)
+#define USB_NDDRIntSt_EP21 (0x00200000)
+#define USB_NDDRIntSt_EP22 (0x00400000)
+#define USB_NDDRIntSt_EP23 (0x00800000)
+#define USB_NDDRIntSt_EP24 (0x01000000)
+#define USB_NDDRIntSt_EP25 (0x02000000)
+#define USB_NDDRIntSt_EP26 (0x04000000)
+#define USB_NDDRIntSt_EP27 (0x08000000)
+#define USB_NDDRIntSt_EP28 (0x10000000)
+#define USB_NDDRIntSt_EP29 (0x20000000)
+#define USB_NDDRIntSt_EP30 (0x40000000)
+#define USB_NDDRIntSt_EP31 (0x80000000)
+#define USB_NDDRIntSt_MASK (0xffffffff)
+
+#define USB_NDDRIntClr_EP0 (0x00000001)
+#define USB_NDDRIntClr_EP1 (0x00000002)
+#define USB_NDDRIntClr_EP2 (0x00000004)
+#define USB_NDDRIntClr_EP3 (0x00000008)
+#define USB_NDDRIntClr_EP4 (0x00000010)
+#define USB_NDDRIntClr_EP5 (0x00000020)
+#define USB_NDDRIntClr_EP6 (0x00000040)
+#define USB_NDDRIntClr_EP7 (0x00000080)
+#define USB_NDDRIntClr_EP8 (0x00000100)
+#define USB_NDDRIntClr_EP9 (0x00000200)
+#define USB_NDDRIntClr_EP10 (0x00000400)
+#define USB_NDDRIntClr_EP11 (0x00000800)
+#define USB_NDDRIntClr_EP12 (0x00001000)
+#define USB_NDDRIntClr_EP13 (0x00002000)
+#define USB_NDDRIntClr_EP14 (0x00004000)
+#define USB_NDDRIntClr_EP15 (0x00008000)
+#define USB_NDDRIntClr_EP16 (0x00010000)
+#define USB_NDDRIntClr_EP17 (0x00020000)
+#define USB_NDDRIntClr_EP18 (0x00040000)
+#define USB_NDDRIntClr_EP19 (0x00080000)
+#define USB_NDDRIntClr_EP20 (0x00100000)
+#define USB_NDDRIntClr_EP21 (0x00200000)
+#define USB_NDDRIntClr_EP22 (0x00400000)
+#define USB_NDDRIntClr_EP23 (0x00800000)
+#define USB_NDDRIntClr_EP24 (0x01000000)
+#define USB_NDDRIntClr_EP25 (0x02000000)
+#define USB_NDDRIntClr_EP26 (0x04000000)
+#define USB_NDDRIntClr_EP27 (0x08000000)
+#define USB_NDDRIntClr_EP28 (0x10000000)
+#define USB_NDDRIntClr_EP29 (0x20000000)
+#define USB_NDDRIntClr_EP30 (0x40000000)
+#define USB_NDDRIntClr_EP31 (0x80000000)
+#define USB_NDDRIntClr_MASK (0xffffffff)
+
+#define USB_NDDRIntSet_EP0 (0x00000001)
+#define USB_NDDRIntSet_EP1 (0x00000002)
+#define USB_NDDRIntSet_EP2 (0x00000004)
+#define USB_NDDRIntSet_EP3 (0x00000008)
+#define USB_NDDRIntSet_EP4 (0x00000010)
+#define USB_NDDRIntSet_EP5 (0x00000020)
+#define USB_NDDRIntSet_EP6 (0x00000040)
+#define USB_NDDRIntSet_EP7 (0x00000080)
+#define USB_NDDRIntSet_EP8 (0x00000100)
+#define USB_NDDRIntSet_EP9 (0x00000200)
+#define USB_NDDRIntSet_EP10 (0x00000400)
+#define USB_NDDRIntSet_EP11 (0x00000800)
+#define USB_NDDRIntSet_EP12 (0x00001000)
+#define USB_NDDRIntSet_EP13 (0x00002000)
+#define USB_NDDRIntSet_EP14 (0x00004000)
+#define USB_NDDRIntSet_EP15 (0x00008000)
+#define USB_NDDRIntSet_EP16 (0x00010000)
+#define USB_NDDRIntSet_EP17 (0x00020000)
+#define USB_NDDRIntSet_EP18 (0x00040000)
+#define USB_NDDRIntSet_EP19 (0x00080000)
+#define USB_NDDRIntSet_EP20 (0x00100000)
+#define USB_NDDRIntSet_EP21 (0x00200000)
+#define USB_NDDRIntSet_EP22 (0x00400000)
+#define USB_NDDRIntSet_EP23 (0x00800000)
+#define USB_NDDRIntSet_EP24 (0x01000000)
+#define USB_NDDRIntSet_EP25 (0x02000000)
+#define USB_NDDRIntSet_EP26 (0x04000000)
+#define USB_NDDRIntSet_EP27 (0x08000000)
+#define USB_NDDRIntSet_EP28 (0x10000000)
+#define USB_NDDRIntSet_EP29 (0x20000000)
+#define USB_NDDRIntSet_EP30 (0x40000000)
+#define USB_NDDRIntSet_EP31 (0x80000000)
+#define USB_NDDRIntSet_MASK (0xffffffff)
+
+#define USB_SysErrIntSt_EP0 (0x00000001)
+#define USB_SysErrIntSt_EP1 (0x00000002)
+#define USB_SysErrIntSt_EP2 (0x00000004)
+#define USB_SysErrIntSt_EP3 (0x00000008)
+#define USB_SysErrIntSt_EP4 (0x00000010)
+#define USB_SysErrIntSt_EP5 (0x00000020)
+#define USB_SysErrIntSt_EP6 (0x00000040)
+#define USB_SysErrIntSt_EP7 (0x00000080)
+#define USB_SysErrIntSt_EP8 (0x00000100)
+#define USB_SysErrIntSt_EP9 (0x00000200)
+#define USB_SysErrIntSt_EP10 (0x00000400)
+#define USB_SysErrIntSt_EP11 (0x00000800)
+#define USB_SysErrIntSt_EP12 (0x00001000)
+#define USB_SysErrIntSt_EP13 (0x00002000)
+#define USB_SysErrIntSt_EP14 (0x00004000)
+#define USB_SysErrIntSt_EP15 (0x00008000)
+#define USB_SysErrIntSt_EP16 (0x00010000)
+#define USB_SysErrIntSt_EP17 (0x00020000)
+#define USB_SysErrIntSt_EP18 (0x00040000)
+#define USB_SysErrIntSt_EP19 (0x00080000)
+#define USB_SysErrIntSt_EP20 (0x00100000)
+#define USB_SysErrIntSt_EP21 (0x00200000)
+#define USB_SysErrIntSt_EP22 (0x00400000)
+#define USB_SysErrIntSt_EP23 (0x00800000)
+#define USB_SysErrIntSt_EP24 (0x01000000)
+#define USB_SysErrIntSt_EP25 (0x02000000)
+#define USB_SysErrIntSt_EP26 (0x04000000)
+#define USB_SysErrIntSt_EP27 (0x08000000)
+#define USB_SysErrIntSt_EP28 (0x10000000)
+#define USB_SysErrIntSt_EP29 (0x20000000)
+#define USB_SysErrIntSt_EP30 (0x40000000)
+#define USB_SysErrIntSt_EP31 (0x80000000)
+#define USB_SysErrIntSt_MASK (0xffffffff)
+
+#define USB_SysErrIntClr_EP0 (0x00000001)
+#define USB_SysErrIntClr_EP1 (0x00000002)
+#define USB_SysErrIntClr_EP2 (0x00000004)
+#define USB_SysErrIntClr_EP3 (0x00000008)
+#define USB_SysErrIntClr_EP4 (0x00000010)
+#define USB_SysErrIntClr_EP5 (0x00000020)
+#define USB_SysErrIntClr_EP6 (0x00000040)
+#define USB_SysErrIntClr_EP7 (0x00000080)
+#define USB_SysErrIntClr_EP8 (0x00000100)
+#define USB_SysErrIntClr_EP9 (0x00000200)
+#define USB_SysErrIntClr_EP10 (0x00000400)
+#define USB_SysErrIntClr_EP11 (0x00000800)
+#define USB_SysErrIntClr_EP12 (0x00001000)
+#define USB_SysErrIntClr_EP13 (0x00002000)
+#define USB_SysErrIntClr_EP14 (0x00004000)
+#define USB_SysErrIntClr_EP15 (0x00008000)
+#define USB_SysErrIntClr_EP16 (0x00010000)
+#define USB_SysErrIntClr_EP17 (0x00020000)
+#define USB_SysErrIntClr_EP18 (0x00040000)
+#define USB_SysErrIntClr_EP19 (0x00080000)
+#define USB_SysErrIntClr_EP20 (0x00100000)
+#define USB_SysErrIntClr_EP21 (0x00200000)
+#define USB_SysErrIntClr_EP22 (0x00400000)
+#define USB_SysErrIntClr_EP23 (0x00800000)
+#define USB_SysErrIntClr_EP24 (0x01000000)
+#define USB_SysErrIntClr_EP25 (0x02000000)
+#define USB_SysErrIntClr_EP26 (0x04000000)
+#define USB_SysErrIntClr_EP27 (0x08000000)
+#define USB_SysErrIntClr_EP28 (0x10000000)
+#define USB_SysErrIntClr_EP29 (0x20000000)
+#define USB_SysErrIntClr_EP30 (0x40000000)
+#define USB_SysErrIntClr_EP31 (0x80000000)
+#define USB_SysErrIntClr_MASK (0xffffffff)
+
+#define USB_SysErrIntSet_EP0 (0x00000001)
+#define USB_SysErrIntSet_EP1 (0x00000002)
+#define USB_SysErrIntSet_EP2 (0x00000004)
+#define USB_SysErrIntSet_EP3 (0x00000008)
+#define USB_SysErrIntSet_EP4 (0x00000010)
+#define USB_SysErrIntSet_EP5 (0x00000020)
+#define USB_SysErrIntSet_EP6 (0x00000040)
+#define USB_SysErrIntSet_EP7 (0x00000080)
+#define USB_SysErrIntSet_EP8 (0x00000100)
+#define USB_SysErrIntSet_EP9 (0x00000200)
+#define USB_SysErrIntSet_EP10 (0x00000400)
+#define USB_SysErrIntSet_EP11 (0x00000800)
+#define USB_SysErrIntSet_EP12 (0x00001000)
+#define USB_SysErrIntSet_EP13 (0x00002000)
+#define USB_SysErrIntSet_EP14 (0x00004000)
+#define USB_SysErrIntSet_EP15 (0x00008000)
+#define USB_SysErrIntSet_EP16 (0x00010000)
+#define USB_SysErrIntSet_EP17 (0x00020000)
+#define USB_SysErrIntSet_EP18 (0x00040000)
+#define USB_SysErrIntSet_EP19 (0x00080000)
+#define USB_SysErrIntSet_EP20 (0x00100000)
+#define USB_SysErrIntSet_EP21 (0x00200000)
+#define USB_SysErrIntSet_EP22 (0x00400000)
+#define USB_SysErrIntSet_EP23 (0x00800000)
+#define USB_SysErrIntSet_EP24 (0x01000000)
+#define USB_SysErrIntSet_EP25 (0x02000000)
+#define USB_SysErrIntSet_EP26 (0x04000000)
+#define USB_SysErrIntSet_EP27 (0x08000000)
+#define USB_SysErrIntSet_EP28 (0x10000000)
+#define USB_SysErrIntSet_EP29 (0x20000000)
+#define USB_SysErrIntSet_EP30 (0x40000000)
+#define USB_SysErrIntSet_EP31 (0x80000000)
+#define USB_SysErrIntSet_MASK (0xffffffff)
+
+
+/*##############################################################################
+## Memory Accelerator Module (MAM)
+##############################################################################*/
+
+#define MAM_CR (*(pREG32 (0xe01fc000)))
+#define MAM_TIM (*(pREG32 (0xe01fc004)))
+
+#define MAM_CR_DISABLE (0x000000000)
+#define MAM_CR_PARTIAL (0x000000001)
+#define MAM_CR_FULL (0x000000002)
+#define MAM_CR_RSVD (0x000000003)
+#define MAM_CR_MASK (0x000000003)
+
+#define MAM_TIM_RSVD (0x000000000)
+#define MAM_TIM_1 (0x000000001)
+#define MAM_TIM_2 (0x000000002)
+#define MAM_TIM_3 (0x000000003)
+#define MAM_TIM_4 (0x000000004)
+#define MAM_TIM_5 (0x000000005)
+#define MAM_TIM_6 (0x000000006)
+#define MAM_TIM_7 (0x000000007)
+#define MAM_TIM_MASK (0x000000007)
+
+
+/*##############################################################################
+## IAP/ISP
+##############################################################################*/
+
+#define IAP_LOCATION (0x7ffffff1)
+#define IAP_CMD_PREPARE (50)
+#define IAP_CMD_COPYRAMTOFLASH (51)
+#define IAP_CMD_ERASE (52)
+#define IAP_CMD_BLANKCHECK (53)
+#define IAP_CMD_READPARTID (54)
+#define IAP_CMD_READBOOTCODEVER (55)
+#define IAP_CMD_COMPARE (56)
+#define IAP_CMD_REINVOKEISP (57)
+
+#define IAP_RESULT_CMD_SUCCESS (0)
+#define IAP_RESULT_INVALID_COMMAND (1)
+#define IAP_RESULT_SRC_ADDR_ERROR (2)
+#define IAP_RESULT_DST_ADDR_ERROR (3)
+#define IAP_RESULT_SRC_ADDR_NOT_MAPPED (4)
+#define IAP_RESULT_DST_ADDR_NOT_MAPPED (5)
+#define IAP_RESULT_COUNT_ERROR (6)
+#define IAP_RESULT_INVALID_SECTOR (7)
+#define IAP_RESULT_SECTOR_NOT_BLANK (8)
+#define IAP_RESULT_SECTOR_NOT_PREPARED (9)
+#define IAP_RESULT_COMPARE_ERROR (10)
+#define IAP_RESULT_BUSY (11)
+#define IAP_RESULT_PARAM_ERROR (12)
+#define IAP_RESULT_ADDR_ERROR (13)
+#define IAP_RESULT_ADDR_NOT_MAPPED (14)
+#define IAP_RESULT_CMD_LOCKED (15)
+#define IAP_RESULT_INVALID_CODE (16)
+#define IAP_RESULT_INVALID_BAUD_RATE (17)
+#define IAP_RESULT_ANVALID_STOP_BIT (18)
+#define IAP_RESULT_CRP_ENABLED (19)
+#define IAP_RESULT_LAST (19)
+
+#endif
--- /dev/null
+MEMORY
+{
+ flash : ORIGIN = 0, LENGTH = 500K
+ ram : ORIGIN = 0x40000000, LENGTH = 32K - 32
+}
+
+__stack_end__ = 0x40000000 + 32K - 36;
+
+SECTIONS
+{
+ . = 0;
+ startup :
+ {
+ __start_of_startup__ = .;
+ *(.startup)
+ __end_of_startup__ = .;
+ } >flash
+
+ prog :
+ {
+ __start_of_text__ = .;
+ __start_of_prog__ = .;
+ *(.text)
+ __end_of_prog__ = .;
+ __start_of_rodata__ = .;
+ *(.rodata)
+ *(.rodata*)
+ __end_of_rodata__ = .;
+ __start_of_glue7__ = .;
+ *(.glue_7)
+ *(.glue_7t)
+ __end_of_glue7__ = .;
+ } >flash
+
+ __end_of_text__ = .;
+
+ .protected :
+ {
+ __protected_beg__ = .;
+ *(.protected)
+ __protected_end__ = .;
+ } >ram
+
+ .data :
+ {
+ __data_beg__ = .;
+ __data_beg_src__ = __end_of_text__;
+ *(.data)
+ __data_end__ = .;
+ } >ram AT>flash
+
+ .bss :
+ {
+ __bss_beg__ = .;
+ *(.bss)
+ } >ram
+
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+}
+ . = ALIGN(32 / 8);
+ _end = .;
+ _bss_end__ = .;
+ __bss_end__ = .;
+ __heap_beg__ = .;
+ __heap_end__ = .;
+ __end__ = . ;
+ PROVIDE (end = .);
--- /dev/null
+[main]
+interface=None (ISP)
+comport=COM 1
+baudrate=9600
+oscfrequency=16.000000
+i2caddr=26
+device=LPC2148
+hexfile=F:\Katana\LPC2148_Demo\lpc2148.hex
+blocknum=27
+block0=0
+block1=0
+block2=0
+block3=0
+block4=0
+block5=0
+block6=0
+block7=0
+block8=0
+block9=0
+block10=0
+block11=0
+block12=0
+block13=0
+block14=0
+block15=0
+block16=0
+block17=0
+block18=0
+block19=0
+block20=0
+block21=0
+block22=0
+block23=0
+block24=0
+block25=0
+block26=0
+allflash=0
+neededflash=1
+verify=0
+fill=0
+checksums=0
+securitybit1=0
+securitybit2=0
+securitybit3=0
+clocks=0
+reset=0
+securitybitslist0=0
+securitybitslist1=0
+securitybitslist2=0
+securitybitslist3=0
+securitybitslist4=0
+securitybitslist5=0
+securitybitslist6=0
+securitybitslist7=0
+securitybitslist8=0
+securitybitslist9=0
+securitybitslist10=0
+securitybitslist11=0
+securitybitslist12=0
+securitybitslist13=0
+securitybitslist14=0
+securitybitslist15=0
+securitybitslist16=0
+securitybitslist17=0
+securitybitslist18=0
+securitybitslist19=0
+securitybitslist20=0
+securitybitslist21=0
+securitybitslist22=0
+securitybitslist23=0
+securitybitslist24=0
+securitybitslist25=0
+securitybitslist26=0
+securitybitslist27=0
+securitybitslist28=0
+securitybitslist29=0
+securitybitslist30=0
+securitybitslist31=0
+securitybitslist32=0
+securitybitslist33=0
+securitybitslist34=0
+securitybitslist35=0
+securitybitslist36=0
+securitybitslist37=0
+securitybitslist38=0
+securitybitslist39=0
+securitybitslist40=0
+securitybitslist41=0
+securitybitslist42=0
+securitybitslist43=0
+securitybitslist44=0
+securitybitslist45=0
+securitybitslist46=0
+securitybitslist47=0
+securitybitslist48=0
+securitybitslist49=0
+securitybitslist50=0
+securitybitslist51=0
+securitybitslist52=0
+securitybitslist53=0
+securitybitslist54=0
+securitybitslist55=0
+securitybitslist56=0
+securitybitslist57=0
+securitybitslist58=0
+securitybitslist59=0
+securitybitslist60=0
+securitybitslist61=0
+securitybitslist62=0
+securitybitslist63=0
+securitybitslist64=0
+securitybitslist65=0
+securitybitslist66=0
+securitybitslist67=0
+securitybitslist68=0
+securitybitslist69=0
+securitybitslist70=0
+securitybitslist71=0
+securitybitslist72=0
+securitybitslist73=0
+securitybitslist74=0
+securitybitslist75=0
+securitybitslist76=0
+securitybitslist77=0
+securitybitslist78=0
+securitybitslist79=0
+securitybitslist80=0
+securitybitslist81=0
+securitybitslist82=0
+securitybitslist83=0
+securitybitslist84=0
+securitybitslist85=0
+securitybitslist86=0
+securitybitslist87=0
+securitybitslist88=0
+securitybitslist89=0
+securitybitslist90=0
+securitybitslist91=0
+securitybitslist92=0
+securitybitslist93=0
+securitybitslist94=0
+securitybitslist95=0
+[advanced]
+highspeed=0
+highspeedmax=230400
+clocks6=1
+clocks12=0
+halfduplex=0
+hwenable=1
+hwbootexecrts=0
+hwassert=0
+hwassertlpc=0
+hwt1=50
+hwt2=100
+hwbootlpc=1
+hwbootlpcselector=0
+protectisp=1
+playwav=0
+wavfile=
+jitmodule=
+jitoptions=
+jittimeout=
+mytimeouts=0
+regulartimeout=4
+longtimeout=60
+disablesignature=0
+[startbootrom]
+command=boot
+baudrate=9600
+append=noctrl
+send=command
+[terminal]
+comport=1
+baudrate=9600
+modifycomport=0
+dtrrts=0
+usedelaychar=0
+delaychar=35
+chardelay=1000
+newline=1
+[eeprom]
+hexfile=
+crchexfilesnum=0
--- /dev/null
+//
+// Standard includes
+//
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "task.h"
+
+//
+// Demo application includes
+//
+#include "main.h"
+#include "adc/adc.h"
+#include "cpu/cpu.h"
+#include "dac/dac.h"
+#include "eints/eints.h"
+#include "gps/gps.h"
+#include "fiq/fiq.h"
+#include "i2c/i2c.h"
+#include "iap/iap.h"
+#include "leds/leds.h"
+#include "monitor/monitor.h"
+#include "rtc/rtc.h"
+#include "sensors/sensors.h"
+#include "uart/uart.h"
+#include "usbser/usbser.h"
+#include "usbmass/usbmass.h"
+
+//
+//
+//
+#define BAUD_UART0 115200
+#define BAUD_UART1 4800
+
+#ifdef CFG_CONSOLE_UART1
+#undef BAUD_UART1
+#define BAUD_UART1 115200
+#endif
+
+#if defined CFG_CONSOLE_USB && defined CFG_USB_MSC
+#error Cannot have USB console and MSC defined at the same time
+#endif
+
+//
+//
+//
+xTaskHandle taskHandles [TASKHANDLE_LAST];
+
+//
+//
+//
+int main (void)
+{
+ cpuSetupHardware ();
+ uartInit (0, BAUD_UART0, 64);
+ uartInit (1, BAUD_UART1, 64);
+#ifndef CFG_USB_MSC
+ usbserInit ();
+#else
+ usbmassInit ();
+#endif
+ rtcInit ();
+ adcInit ();
+ dacInit ();
+ i2cInit ();
+ eintsInit ();
+ fiqInit ();
+ iapInit ();
+
+ memset (taskHandles, 0, sizeof (taskHandles));
+
+ xTaskCreate (vSensorsTask, (const signed portCHAR * const) "Sensors", 512, NULL, (configMAX_PRIORITIES - 2), &taskHandles [TASKHANDLE_SENSORS]);
+#ifndef CFG_CONSOLE_UART1
+ xTaskCreate (vGPSTask, (const signed portCHAR * const) "GPS", 768, NULL, (tskIDLE_PRIORITY + 1), &taskHandles [TASKHANDLE_GPS]);
+#endif
+ xTaskCreate (vMonitorTask, (const signed portCHAR * const) "Monitor", 1024, NULL, (tskIDLE_PRIORITY + 1), &taskHandles [TASKHANDLE_MONITOR]);
+ xTaskCreate (vLEDFlashTask, (const signed portCHAR * const) "LEDx", configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 1), &taskHandles [TASKHANDLE_LED]);
+ vTaskStartScheduler ();
+
+ return 0;
+}
--- /dev/null
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+//
+//
+//
+#define __VERSION "1.20"
+
+//
+//
+//
+typedef enum
+{
+ TASKHANDLE_GPS = 0,
+ TASKHANDLE_SENSORS,
+ TASKHANDLE_MONITOR,
+ TASKHANDLE_LED,
+ TASKHANDLE_LAST
+}
+taskHandle_e;
+
+extern xTaskHandle taskHandles [TASKHANDLE_LAST];
+
+#endif
--- /dev/null
+SRC_FILES=args.c monitor.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "args.h"
+
+//
+//
+//
+static char *strtrim (char *s)
+{
+ char *t = s + strlen (s) - 1;
+
+ while (t >= s && *t && isspace (*t))
+ *t-- = '\0';
+
+ while (*s && isspace (*s))
+ s++;
+
+ return s;
+}
+
+//
+// bufferLength includes the space reserved for the \0
+//
+int argsGetLine (int fd __attribute__ ((unused)), U8 *buffer, int bufferLength)
+{
+ U8 *p;
+
+ p = buffer;
+ *p = '\0';
+
+ while (1)
+ {
+ U8 c;
+
+ fflush (stdout);
+
+ if (read (fd, &c, sizeof (c)) == sizeof (c))
+ {
+ switch (c)
+ {
+ case '\n' :
+ case '\r' :
+ printf ("\n");
+ return strlen ((char *) buffer);
+
+ case '\b' :
+ if (p > buffer)
+ *--p = '\0';
+ printf ("\b \b");
+ break;
+
+ case 0x15 : // CTRL-U
+ while (p != buffer)
+ {
+ printf ("\b \b");
+ --p;
+ }
+ *p = '\0';
+ break;
+
+ case 0xfe :
+ case 0xff :
+ *buffer++ = c;
+ *buffer = '\0';
+ return 1;
+
+ default :
+ if (p < buffer + bufferLength - 1 && c >= ' ' && c < 0x7f)
+ {
+ *p++ = c;
+ *p = '\0';
+ printf ("%c", c);
+ }
+ else
+ printf ("%c", c);
+
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//
+//
+//
+typedef enum
+{
+ P_EATWHITESPACE = 0,
+ P_GETCHARFIRST,
+ P_GETCHAR,
+ P_QUOTEDGETCHAR
+}
+PSTATE;
+
+int argsParse (char *cmd, char **argv, int sizeofArgv, int *argc)
+{
+ int maxArgs = (sizeofArgv / sizeof (argv [0])) - 1;
+ char *s = strtrim (cmd);
+ PSTATE pstate = P_EATWHITESPACE;
+
+ *argc = 0;
+ memset (argv, 0, sizeofArgv);
+
+ while (*s)
+ {
+ switch (pstate)
+ {
+ case P_EATWHITESPACE :
+ {
+ if (!isspace (*s))
+ pstate = P_GETCHARFIRST;
+ else
+ s++;
+ }
+ break;
+
+ case P_GETCHARFIRST :
+ {
+ *argv++ = s;
+
+ if (++*argc == maxArgs)
+ return 1;
+ if (*s == '"')
+ pstate = P_QUOTEDGETCHAR;
+ else
+ pstate = P_GETCHAR;
+
+ s++;
+ }
+ break;
+
+ case P_GETCHAR :
+ {
+ if (isspace (*s)) {
+ pstate = P_EATWHITESPACE;
+ *s = '\0';
+ }
+ else if (*s == '"')
+ pstate = P_QUOTEDGETCHAR;
+
+ s++;
+ }
+ break;
+
+ case P_QUOTEDGETCHAR :
+ {
+ if (*s == '"')
+ pstate = P_GETCHAR;
+
+ s++;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#ifndef _ARGS_H_
+#define _ARGS_H_
+
+int argsGetLine (int fd, U8 *buffer, int bufferLength);
+int argsParse (char *cmd, char **argv, int sizeofArgv, int *argc);
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <sys/times.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "args.h"
+#include "../fatfs/diskio.h"
+#include "../fatfs/ff.h"
+#include "../fiq/fiq.h"
+#include "../gps/gps.h"
+#include "../i2c/eeprom.h"
+#include "../i2c/i2c.h"
+#include "../i2c/lm75.h"
+#include "../iap/iap.h"
+#include "../main.h"
+#include "../rtc/rtc.h"
+#include "../sensors/sensors.h"
+#include "../swi/swi.h"
+#include "monitor.h"
+
+//
+//
+//
+typedef enum
+{
+ CMDTYPE_CMDLIST = 0,
+ CMDTYPE_FUNCTION
+}
+cmdType_e;
+
+typedef struct abortDat_s
+{
+ unsigned int dummy;
+ unsigned int sigil;
+ unsigned int count;
+ unsigned int type;
+ unsigned int pc;
+ unsigned int opcode;
+ unsigned int cpsr;
+ unsigned int lr;
+ unsigned int sp;
+ unsigned int r0;
+ unsigned int r1;
+ unsigned int r2;
+ unsigned int r3;
+ unsigned int r4;
+ unsigned int r5;
+ unsigned int r6;
+ unsigned int r7;
+ unsigned int r8;
+ unsigned int r9;
+ unsigned int r10;
+ unsigned int r11;
+ unsigned int r12;
+ unsigned int stack [8];
+}
+__attribute__ ((packed)) abortDat_t;
+
+typedef struct commandList_s
+{
+ const portCHAR *command;
+ portCHAR minArgs;
+ portCHAR maxArgs;
+ cmdType_e cmdType;
+ union
+ {
+ void *trickGCC;
+ int (*handler) (int argc, portCHAR **argv);
+ struct commandList_s *commandList;
+ };
+ const portCHAR *description;
+ const portCHAR *parameters;
+}
+commandList_t;
+
+//
+// Prototypes
+//
+static int monitorHelp (int argc, portCHAR **argv);
+static int monitorDiskInit (int argc, portCHAR **argv);
+static int monitorDiskMount (int argc, portCHAR **argv);
+static int monitorFileMkfs (int argc, portCHAR **argv);
+static int monitorFileDf (int argc, portCHAR **argv);
+static int monitorFileLs (int argc, portCHAR **argv);
+static int monitorFileMkdir (int argc, portCHAR **argv);
+static int monitorFileRmdir (int argc, portCHAR **argv);
+static int monitorFileRm (int argc, portCHAR **argv);
+static int monitorFileMv (int argc, portCHAR **argv);
+static int monitorFileCp (int argc, portCHAR **argv);
+static int monitorFileCpCon (int argc, portCHAR **argv);
+static int monitorFileChmod (int argc, portCHAR **argv);
+static int monitorFileSync (int argc, portCHAR **argv);
+static int monitorFileThruPut (int argc, portCHAR **argv);
+static int monitorGPS (int argc, portCHAR **argv);
+static int monitorSensors (int argc, portCHAR **argv);
+static int monitorMd (int argc, portCHAR **argv);
+static int monitorAbortRegs (int argc, portCHAR **argv);
+static int monitorAbortClear (int argc, portCHAR **argv);
+static int monitorAbortDirty (int argc, portCHAR **argv);
+static int monitorAbortUndef (int argc, portCHAR **argv);
+static int monitorAbortPabort (int argc, portCHAR **argv);
+static int monitorAbortDabort (int argc, portCHAR **argv);
+static int monitorEEAddr (int argc, portCHAR **argv);
+static int monitorEERead (int argc, portCHAR **argv);
+static int monitorEEReadAddr (int argc, portCHAR **argv);
+static int monitorEEWrite (int argc, portCHAR **argv);
+static int monitorEEWriteAddr (int argc, portCHAR **argv);
+static int monitorEEFillAddr (int argc, portCHAR **argv);
+static int monitorFIQOn (int argc, portCHAR **argv);
+static int monitorFIQOff (int argc, portCHAR **argv);
+static int monitorFIQCount (int argc, portCHAR **argv);
+static int monitorFIQClear (int argc, portCHAR **argv);
+static int monitorI2CRead (int argc, portCHAR **argv);
+static int monitorI2CWrite (int argc, portCHAR **argv);
+static int monitorI2CWriteRead (int argc, portCHAR **argv);
+static int monitorI2CDump (int argc, portCHAR **argv);
+static int monitorI2CErrno (int argc, portCHAR **argv);
+static int monitorIAPFSS (int argc, portCHAR **argv);
+static int monitorIAPSTOA (int argc, portCHAR **argv);
+static int monitorIAPFill (int argc, portCHAR **argv);
+static int monitorIAPErase (int argc, portCHAR **argv);
+static int monitorIAPBlank (int argc, portCHAR **argv);
+static int monitorIAPID (int argc, portCHAR **argv);
+static int monitorIAPVer(int argc, portCHAR **argv);
+static int monitorIAPISP (int argc, portCHAR **argv);
+static int monitorLM75Init (int argc, portCHAR **argv);
+static int monitorLM75Mode (int argc, portCHAR **argv);
+static int monitorLM75Addr (int argc, portCHAR **argv);
+static int monitorLM75ReRead (int argc, portCHAR **argv);
+static int monitorLM75Temp (int argc, portCHAR **argv);
+static int monitorLM75Config (int argc, portCHAR **argv);
+static int monitorLM75Thyst (int argc, portCHAR **argv);
+static int monitorLM75Tos (int argc, portCHAR **argv);
+static int monitorMemTask (int argc, portCHAR **argv);
+static int monitorMemMap (int argc, portCHAR **argv);
+static int monitorMemAlloc (int argc, portCHAR **argv);
+static int monitorMemRealloc (int argc, portCHAR **argv);
+static int monitorMemFree (int argc, portCHAR **argv);
+static int monitorMemList (int argc, portCHAR **argv);
+static int monitorMiscSizeof (int argc, portCHAR **argv);
+static int monitorRTCGet (int argc, portCHAR **argv);
+static int monitorRTCSet (int argc, portCHAR **argv);
+static int monitorRTCAlarm (int argc, portCHAR **argv);
+static int monitorRTCPeriodic (int argc, portCHAR **argv);
+static int monitorSWISetAsm (int argc, portCHAR **argv);
+static int monitorSWIOnAsm (int argc, portCHAR **argv);
+static int monitorSWIOffAsm (int argc, portCHAR **argv);
+static int monitorSWIToggleAsm (int argc, portCHAR **argv);
+static int monitorSWISetC (int argc, portCHAR **argv);
+static int monitorSWIOnC (int argc, portCHAR **argv);
+static int monitorSWIOffC (int argc, portCHAR **argv);
+static int monitorSWIToggleC (int argc, portCHAR **argv);
+static int monitorWDTTest (int argc, portCHAR **argv);
+static int monitorWDTStatus (int argc, portCHAR **argv);
+static int monitorWDTClear (int argc, portCHAR **argv);
+static int monitorVersion (int argc, portCHAR **argv);
+
+//
+// Ye olde globals
+//
+static commandList_t commandListAbort [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "regs", 0, 0, CMDTYPE_FUNCTION, { monitorAbortRegs }, "Print abort registers", "'regs' has no parameters" },
+ { "clear", 0, 0, CMDTYPE_FUNCTION, { monitorAbortClear }, "Clear abort registers", "'clear' has no parameters" },
+ { "dirty", 0, 0, CMDTYPE_FUNCTION, { monitorAbortDirty }, "Dirty sigil flag", "'dirty' has no parameters" },
+ { "undef", 0, 0, CMDTYPE_FUNCTION, { monitorAbortUndef }, "Execute undefined instruction","'undef' has no parameters" },
+ { "pabort", 0, 0, CMDTYPE_FUNCTION, { monitorAbortPabort }, "Cause prefetch abort", "'pabort' has no parameters" },
+ { "dabort", 0, 0, CMDTYPE_FUNCTION, { monitorAbortDabort }, "Cause data abort", "'dabort' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListEE [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "a", 1, 1, CMDTYPE_FUNCTION, { monitorEEAddr }, "Set eeprom r/w address", "'ee <address>'" },
+ { "r", 0, 1, CMDTYPE_FUNCTION, { monitorEERead }, "Read from current address", "'r <# bytes>'" },
+ { "ra", 1, 2, CMDTYPE_FUNCTION, { monitorEEReadAddr }, "Read EEPROM", "'ra <address> <# bytes>'" },
+ { "w", 1, 16, CMDTYPE_FUNCTION, { monitorEEWrite }, "Write to current address", "'w <byte> [<byte> [...<byte>]]'" },
+ { "wa", 2, 17, CMDTYPE_FUNCTION, { monitorEEWriteAddr }, "Write EEPOM", "'wa <address> <byte> [<byte> [...<byte>]]'" },
+ { "fa", 3, 3, CMDTYPE_FUNCTION, { monitorEEFillAddr }, "Fill EEPOM", "'fa <address> <len> <byte>'" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListFIQ [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "on", 0, 0, CMDTYPE_FUNCTION, { monitorFIQOn }, "Enable FIQ interrupt", "'on' has no parameters" },
+ { "off", 0, 0, CMDTYPE_FUNCTION, { monitorFIQOff }, "Disable FIQ interrupt", "'off' has no parameters" },
+ { "count", 0, 0, CMDTYPE_FUNCTION, { monitorFIQCount }, "Show number of FIQ interrupts", "'show' has no parameters" },
+ { "clear", 0, 0, CMDTYPE_FUNCTION, { monitorFIQClear }, "Clear FIQ interrupt counter", "'clear' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListI2C [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "r", 2, 2, CMDTYPE_FUNCTION, { monitorI2CRead }, "Read from I2C device", "'r <address> <# bytes>'" },
+ { "w", 2, 17, CMDTYPE_FUNCTION, { monitorI2CWrite }, "Write to I2C device", "'w <address> <byte> [<byte> [...<byte>]]'" },
+ { "wr", 2, 18, CMDTYPE_FUNCTION, { monitorI2CWriteRead}, "Write to then read from I2C device", "'wr <address> <byte> [<byte> [...<byte>]] <# bytes to read>'" },
+ { "dump", 0, 0, CMDTYPE_FUNCTION, { monitorI2CDump }, "Dump I2C Debug Buffer", "'dump' has no parameters" },
+ { "errno", 0, 0, CMDTYPE_FUNCTION, { monitorI2CErrno }, "Display i2cErrno value", "'errno' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListIAP [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "fss", 0, 0, CMDTYPE_FUNCTION, { monitorIAPFSS }, "Find safe sector", "'fss' has no parameters" },
+ { "stoa", 1, 1, CMDTYPE_FUNCTION, { monitorIAPSTOA }, "Convert sector to address for 'md'", "'fss' has no parameters" },
+ { "fill", 2, 2, CMDTYPE_FUNCTION, { monitorIAPFill }, "Fill sector with byte", "'fill <sector> <byte>'" },
+ { "erase", 1, 1, CMDTYPE_FUNCTION, { monitorIAPErase }, "Erase sector", "'erase <sector>'" },
+ { "blank", 1, 1, CMDTYPE_FUNCTION, { monitorIAPBlank }, "Blank check sector", "'blank <sector>'" },
+ { "id", 0, 0, CMDTYPE_FUNCTION, { monitorIAPID }, "Read part ID", "'id' has no parameters" },
+ { "ver", 0, 0, CMDTYPE_FUNCTION, { monitorIAPVer }, "Read boot loader version", "'ver' has no parameters" },
+ { "isp", 0, 0, CMDTYPE_FUNCTION, { monitorIAPISP }, "Restart into ISP bootloader", "'isp' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListLM75 [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "init", 0, 0, CMDTYPE_FUNCTION, { monitorLM75Init }, "Initialize LM75", "'init' has no parameters" },
+ { "mode", 1, 1, CMDTYPE_FUNCTION, { monitorLM75Mode }, "Set LM75 mode", "'mode <value>'" },
+ { "addr", 1, 1, CMDTYPE_FUNCTION, { monitorLM75Addr }, "Set LM75 address", "'addr <value>'" },
+ { "reread", 0, 0, CMDTYPE_FUNCTION, { monitorLM75ReRead }, "Re-read last register", "'reread' has no parameters" },
+ { "temp", 0, 0, CMDTYPE_FUNCTION, { monitorLM75Temp }, "Read LM75 temperature", "'temp' has no parameters" },
+ { "config", 0, 1, CMDTYPE_FUNCTION, { monitorLM75Config }, "Read part ID", "'id' has no parameters" },
+ { "thyst", 0, 1, CMDTYPE_FUNCTION, { monitorLM75Thyst }, "Read or set THYST register", "'thyst [value]'" },
+ { "tos", 0, 1, CMDTYPE_FUNCTION, { monitorLM75Tos }, "Read or set TOS register", "'tos [value]'" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListMem [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "task", 0, 0, CMDTYPE_FUNCTION, { monitorMemTask }, "Show FreeRTOS task memory", "'task' has no parameters" },
+ { "map", 0, 0, CMDTYPE_FUNCTION, { monitorMemMap }, "Show various addresses", "'map' has no parameters" },
+ { "alloc", 2, 2, CMDTYPE_FUNCTION, { monitorMemAlloc }, "Allocate memory", "'alloc <slot> <size>'" },
+ { "realloc", 2, 2, CMDTYPE_FUNCTION, { monitorMemRealloc }, "Reallocate memory", "'realloc <slot> <size>'" },
+ { "free", 1, 1, CMDTYPE_FUNCTION, { monitorMemFree }, "Free memory", "'free <slot>'" },
+ { "list", 0, 0, CMDTYPE_FUNCTION, { monitorMemList }, "List memory", "'list' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListMisc [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "sizeof", 0, 0, CMDTYPE_FUNCTION, { monitorMiscSizeof }, "Sizeof() variable data types", "'sizeof' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListRTC [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "get", 0, 0, CMDTYPE_FUNCTION, { monitorRTCGet }, "Display system date/time", "'get' has no parameters" },
+ { "set", 1, 2, CMDTYPE_FUNCTION, { monitorRTCSet }, "Set system date/time", "'set <gps|YYYY/MM/DD HH:MM:SS>'" },
+ { "alarm", 0, 2, CMDTYPE_FUNCTION, { monitorRTCAlarm }, "Set date/time for alarm", "'alarm <off|YYYY/MM/DD HH:MM:SS>'" },
+ { "periodic", 0, 1, CMDTYPE_FUNCTION, { monitorRTCPeriodic }, "Alarm every minute change", "'periodic <on|off>'" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListSWI [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "aset", 1, 1, CMDTYPE_FUNCTION, { monitorSWISetAsm }, "Set LED2 state (asm)", "'aset <on|of>'" },
+ { "aon", 0, 0, CMDTYPE_FUNCTION, { monitorSWIOnAsm }, "Turn LED2 on (asm)", "'aon' has no parameters" },
+ { "aoff", 0, 0, CMDTYPE_FUNCTION, { monitorSWIOffAsm }, "Turn LED2 off (asm)", "'aoff' has no parameters" },
+ { "atoggle", 0, 0, CMDTYPE_FUNCTION, { monitorSWIToggleAsm}, "Toggle LED2 state (asm)", "'atoggle' has no parameters" },
+ { "cset", 1, 1, CMDTYPE_FUNCTION, { monitorSWISetC }, "Set LED2 state (C)", "'cset <on|off>'" },
+ { "con", 0, 0, CMDTYPE_FUNCTION, { monitorSWIOnC }, "Turn LED2 on (C)", "'con' has no parameters" },
+ { "coff", 0, 0, CMDTYPE_FUNCTION, { monitorSWIOffC }, "Turn LED2 off (C)", "'coff' has no parameters" },
+ { "ctoggle", 0, 0, CMDTYPE_FUNCTION, { monitorSWIToggleC }, "Toggle LED2 state (C)", "'ctoggle' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandListWDT [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "test", 0, 0, CMDTYPE_FUNCTION, { monitorWDTTest }, "Test watchdog", "'test' has no parameters" },
+ { "status", 0, 0, CMDTYPE_FUNCTION, { monitorWDTStatus }, "Display RSIR register", "'status' has no parameters" },
+ { "clear", 0, 0, CMDTYPE_FUNCTION, { monitorWDTClear }, "Clear RSIR status", "'rsir' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static commandList_t commandList [] =
+{
+ { "help", 0, 0, CMDTYPE_FUNCTION, { monitorHelp }, "This help list", "'help' has no parameters" },
+ { "init", 0, 0, CMDTYPE_FUNCTION, { monitorDiskInit }, "Initialize disk subsystem", "'init' has no parameters" },
+ { "mount", 0, 0, CMDTYPE_FUNCTION, { monitorDiskMount }, "Mount disk", "'mount' has no parameters" },
+ { "mkfs", 0, 0, CMDTYPE_FUNCTION, { monitorFileMkfs }, "Create a FAT filesystem", "'mkfs' has no parameters" },
+ { "df", 0, 0, CMDTYPE_FUNCTION, { monitorFileDf }, "File system status & info", "'fd' has no parameters" },
+ { "ls", 0, 1, CMDTYPE_FUNCTION, { monitorFileLs }, "Display directory", "'ls [optional path]'" },
+ { "mkdir", 1, 1, CMDTYPE_FUNCTION, { monitorFileMkdir }, "Create directory", "'mkdir <[path]directory'" },
+ { "rmdir", 1, 1, CMDTYPE_FUNCTION, { monitorFileRmdir }, "Delete directory", "'rmdir <[path]directory>'" },
+ { "rm", 1, 1, CMDTYPE_FUNCTION, { monitorFileRm }, "Delete file", "'rm <[path]filename>'" },
+ { "mv", 2, 2, CMDTYPE_FUNCTION, { monitorFileMv }, "Rename a file or directory", "'mv <[path]old_filename> <[path]new_filename>'" },
+ { "cp", 1, 2, CMDTYPE_FUNCTION, { monitorFileCp }, "Copy a file", "'mv <[path]old_filename> <[path]new_filename>'" },
+ { "cpcon", 1, 1, CMDTYPE_FUNCTION, { monitorFileCpCon }, "Copy console input to file", "'cp <[path]filename>' (ctrl-d exits and saves)" },
+ { "chmod", 2, 2, CMDTYPE_FUNCTION, { monitorFileChmod }, "Change file mode", "'chmod <+w|-w> <[path]filename>'" },
+ { "sync", 0, 0, CMDTYPE_FUNCTION, { monitorFileSync }, "Sync filesystem", "'sync' has no parameters" },
+ { "thruput", 1, 1, CMDTYPE_FUNCTION, { monitorFileThruPut }, "Measure MMC/SD throughput", "'thruput <normal|noints|high|suspendall>'" },
+ { "gps", 0, 0, CMDTYPE_FUNCTION, { monitorGPS }, "Display GPS data", "'gps' has no parameters" },
+ { "sensors", 0, 0, CMDTYPE_FUNCTION, { monitorSensors }, "Display sensor data", "'sensors' has no parameters" },
+ { "md", 0, 2, CMDTYPE_FUNCTION, { monitorMd }, "Display memory", "'md [address [length]]'" },
+
+ { "abort", 1, 0, CMDTYPE_CMDLIST, { commandListAbort }, "Read/clear abort registers", "'abort help' for help list" },
+ { "ee", 1, 0, CMDTYPE_CMDLIST, { commandListEE }, "Read/write I2C EEPROM", "'ee help' for help list" },
+ { "fiq", 1, 0, CMDTYPE_CMDLIST, { commandListFIQ }, "Demonstrate FIQ functions", "'fiq help' for help list" },
+ { "i2c", 1, 0, CMDTYPE_CMDLIST, { commandListI2C }, "Perform I2C commands", "'i2c help' for help list" },
+ { "iap", 1, 0, CMDTYPE_CMDLIST, { commandListIAP }, "Perform IAP commands", "'iap help' for help list" },
+ { "lm75", 1, 0, CMDTYPE_CMDLIST, { commandListLM75 }, "Read/set LM75 temp sensor", "'lm75 help' for help list" },
+ { "mem", 1, 0, CMDTYPE_CMDLIST, { commandListMem }, "Various memory functions", "'mem help' for help list" },
+ { "misc", 1, 0, CMDTYPE_CMDLIST, { commandListMisc }, "Miscellaneous stuff", "'misc help' for help list" },
+ { "rtc", 1, 0, CMDTYPE_CMDLIST, { commandListRTC }, "Demonstrate RTC functions", "'rtc help' for help list" },
+ { "swi", 1, 0, CMDTYPE_CMDLIST, { commandListSWI }, "Demonstrate SWI functions", "'swi help' for help list" },
+ { "wdt", 1, 0, CMDTYPE_CMDLIST, { commandListWDT }, "Manipulate watchdog timer", "'wdt help' for help list" },
+ { "version", 0, 0, CMDTYPE_FUNCTION, { monitorVersion }, "Display version information", "'version' has no parameters" },
+ { NULL, 0, 0, CMDTYPE_FUNCTION, { NULL }, NULL, NULL },
+};
+
+static FATFS fatfs;
+static FILINFO fileInfo;
+commandList_t *activeCommandList = NULL;
+
+//
+// External variables
+//
+extern unsigned int __abort_dat;
+extern unsigned long __start_of_text__;
+extern unsigned long __end_of_text__;
+extern unsigned long __start_of_startup__;
+extern unsigned long __end_of_startup__;
+extern unsigned long __start_of_prog__;
+extern unsigned long __end_of_prog__;
+extern unsigned long __start_of_rodata__;
+extern unsigned long __end_of_rodata__;
+extern unsigned long __start_of_glue7__;
+extern unsigned long __end_of_glue7__;
+extern unsigned long __data_beg__;
+extern unsigned long __data_end__;
+extern unsigned long __bss_beg__;
+extern unsigned long __bss_end__;
+extern unsigned long __heap_max;
+extern unsigned long __heap_beg;
+extern unsigned long __heap_end;
+extern unsigned long __stack_end__;
+extern unsigned long __stack_beg_und;
+extern unsigned long __stack_end_und;
+extern unsigned long __stack_beg_abt;
+extern unsigned long __stack_end_abt;
+extern unsigned long __stack_beg_fiq;
+extern unsigned long __stack_end_fiq;
+extern unsigned long __stack_beg_irq;
+extern unsigned long __stack_end_irq;
+extern unsigned long __stack_beg_svc;
+extern unsigned long __stack_end_svc;
+extern unsigned long __stack_beg_sys;
+extern unsigned long __stack_end_sys;
+
+
+//
+// Recursion is our friend... fileInfo is global to avoid eating stack space
+//
+static FRESULT scan_files_ex (char *path, int *total_size, int *total_files, int *total_dirs)
+{
+ DIR dirs;
+ FRESULT res;
+
+ if ((res = f_opendir (&dirs, path)) == FR_OK)
+ {
+ int i = strlen (path);
+
+ while (((res = f_readdir (&dirs, &fileInfo)) == FR_OK) && fileInfo.fname [0])
+ {
+ if (fileInfo.fattrib & AM_DIR)
+ {
+ *total_dirs += 1;
+ *(path + i) = '/';
+ strcpy (path + i + 1, &fileInfo.fname [0]);
+ res = scan_files_ex (path, total_size, total_files, total_dirs);
+ *(path + i) = '\0';
+
+ if (res != FR_OK)
+ return res;
+ }
+ else
+ {
+ *total_files += 1;
+ *total_size += fileInfo.fsize;
+ }
+ }
+ }
+
+ return res;
+}
+
+static FRESULT scan_files (char *path, int *total_size, int *total_files, int *total_dirs)
+{
+ *total_size = 0;
+ *total_files = 0;
+ *total_dirs = 0;
+
+ return scan_files_ex (path, total_size, total_files, total_dirs);
+}
+
+//
+// These two really ought to be in the FatFS code
+//
+U32 get_fattime ()
+{
+ U32 tmr;
+ time_t now;
+ struct tm tm;
+
+ now = time (NULL);
+ localtime_r (&now, &tm);
+
+ tmr = 0
+ | ((tm.tm_year - 80) << 25)
+ | ((tm.tm_mon + 1) << 21)
+ | (tm.tm_mday << 16)
+ | (tm.tm_hour << 11)
+ | (tm.tm_min << 5)
+ | (tm.tm_sec >> 1);
+
+ return tmr;
+}
+
+//
+// Functions newlib doesn't know about (but should)
+//
+void _sync (void);
+int _mkdir (const char *path, mode_t mode);
+int _chmod (const char *path, mode_t mode);
+
+void sync (void);
+int chmod (const char *path, mode_t mode);
+
+void sync (void)
+{
+ _sync ();
+}
+
+int mkdir (const char *path, mode_t mode)
+{
+ return _mkdir (path, mode);
+}
+
+int chmod (const char *path, mode_t mode)
+{
+ return _chmod (path, mode);
+}
+
+//
+//
+//
+static int getNumber (char *s, unsigned int *result)
+{
+ unsigned int value;
+ unsigned int mustBeHex = FALSE;
+ int sgn = 1;
+ const unsigned char hexToDec [] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15};
+
+ if (!s)
+ return 0;
+
+ if ((strlen (s) > 2) && (!strncmp (s, "0x", 2) || !strncmp (s, "0X", 2)))
+ {
+ mustBeHex = TRUE;
+ s += 2;
+ }
+
+ if (!mustBeHex && *s && (*s == '-'))
+ {
+ sgn = -1;
+ s++;
+ }
+
+ for (value = 0; *s; s++)
+ {
+ if (mustBeHex && isxdigit (*s))
+ value = (value << 4) | hexToDec [toupper (*s) - '0'];
+ else if (isdigit (*s))
+ value = (value * 10) + (*s - '0');
+ else
+ {
+ printf ("Malformed number. Must be decimal number, or hex value preceeded by '0x'\n");
+ return 0;
+ }
+ }
+
+ if (!mustBeHex)
+ value *= sgn;
+
+ *result = value;
+
+ return 1;
+}
+
+static int monitorDumpMemory (unsigned int displayAddress, unsigned int address, int length)
+{
+ unsigned char *buffer;
+ int i;
+
+ if (!length)
+ {
+ printf ("Error: monitorDumpMemory() passed 0 for length\n");
+ return address;
+ }
+
+ for (buffer = (unsigned char *) address, i = 0; i < length; i += 16)
+ {
+ unsigned int l;
+ unsigned int j;
+
+ if (i)
+ printf ("\n");
+
+ printf ("%08x: ", displayAddress + i);
+
+ if ((length - i) < 16)
+ l = length & 15;
+ else
+ l = 16;
+
+ for (j = 0; j < 16; j++)
+ {
+ if (j < l)
+ printf ("%02x ", buffer [i+j]);
+ else
+ printf (" ");
+ }
+
+ printf (" ");
+
+ for (j = 0; j < l; j++)
+ {
+ unsigned char c = buffer [i+j];
+
+ if (c < 32 || c > 127)
+ c = '.';
+
+ printf ("%c", c);
+ }
+ }
+
+ printf ("\n");
+
+ address += length;
+
+ return address;
+}
+
+//
+//
+//
+static int monitorHelp (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ unsigned int i;
+ int t;
+ int longestCmd;
+ portCHAR spaces [32];
+
+ memset (spaces, ' ', sizeof (spaces));
+
+ for (longestCmd = 0, i = 0; activeCommandList [i].command; i++)
+ if ((t = strlen (activeCommandList [i].command)) > longestCmd)
+ longestCmd = t;
+
+ spaces [longestCmd] = '\0';
+
+ for (i = 0; activeCommandList [i].command; i++)
+ {
+ const commandList_t *cl = &activeCommandList [i];
+
+ printf ("%s%s -- %s\n", cl->command, &spaces [strlen (cl->command)], cl->description);
+ }
+
+ printf ("\nUse '<command> ?' for details on parameters to command\n");
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorDiskInit (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("RRC=%d\n", diskInitialize (0));
+
+ return 0;
+}
+
+static int monitorDiskMount (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ f_printerror (f_mount (0, &fatfs));
+
+ return 0;
+}
+
+static int monitorFileMkfs (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ f_printerror (f_mkfs (0, 0, 64));
+
+ return 0;
+}
+
+static int monitorFileDf (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ U32 p2;
+ FATFS *fs;
+ char buffer [100];
+ FRESULT res;
+ int acc_size;
+ int acc_files;
+ int acc_dirs;
+
+ if ((res = f_getfree ("", (U32 *) &p2, &fs)))
+ {
+ f_printerror (res);
+ return 0;
+ }
+
+ printf ("FAT type = %u\nBytes/Cluster = %u\nNumber of FATs = %u\n"
+ "Root DIR entries = %u\nSectors/FAT = %u\nNumber of clusters = %u\n"
+ "FAT start (lba) = %u\nDIR start (lba,clustor) = %u\nData start (lba) = %u\n",
+ fs->fs_type, fs->sects_clust * 512, fs->n_fats,
+ fs->n_rootdir, fs->sects_fat, fs->max_clust - 2,
+ fs->fatbase, fs->dirbase, fs->database
+ );
+
+ acc_size = acc_files = acc_dirs = 0;
+
+ buffer [0] = '\0';
+
+ if ((res = scan_files (buffer, &acc_size, &acc_files, &acc_dirs)))
+ {
+ f_printerror (res);
+ return 0;
+ }
+
+ printf ("\n%u files, %u bytes.\n%u folders.\n"
+ "%u bytes total disk space.\n%u bytes available\n",
+ acc_files, acc_size, acc_dirs,
+ (fs->max_clust - 2) * fs->sects_clust * 512, p2 * fs->sects_clust * 512
+ );
+
+ return 0;
+}
+
+static int monitorFileLs (int argc, portCHAR **argv)
+{
+ DIR dir;
+ FRESULT res;
+ U32 size;
+ U16 files;
+ U16 dirs;
+ FATFS *fs;
+ char *path;
+
+ path = argc ? argv [0] : "";
+
+ if ((res = f_opendir (&dir, path)))
+ {
+ f_printerror (res);
+ return 0;
+ }
+
+ for (size = files = dirs = 0;;)
+ {
+ if (((res = f_readdir (&dir, &fileInfo)) != FR_OK) || !fileInfo.fname [0])
+ break;
+
+ if (fileInfo.fattrib & AM_DIR)
+ dirs++;
+ else
+ {
+ files++;
+ size += fileInfo.fsize;
+ }
+
+ printf ("\n%c%c%c%c%c %u/%02u/%02u %02u:%02u %9u %s",
+ (fileInfo.fattrib & AM_DIR) ? 'D' : '-',
+ (fileInfo.fattrib & AM_RDO) ? 'R' : '-',
+ (fileInfo.fattrib & AM_HID) ? 'H' : '-',
+ (fileInfo.fattrib & AM_SYS) ? 'S' : '-',
+ (fileInfo.fattrib & AM_ARC) ? 'A' : '-',
+ (fileInfo.fdate >> 9) + 1980, (fileInfo.fdate >> 5) & 15, fileInfo.fdate & 31,
+ (fileInfo.ftime >> 11), (fileInfo.ftime >> 5) & 63,
+ fileInfo.fsize, &(fileInfo.fname [0]));
+ }
+
+ printf ("\n%4u File(s),%10u bytes\n%4u Dir(s)", files, size, dirs);
+
+ if (f_getfree (path, (U32 *) &size, &fs) == FR_OK)
+ printf (", %10uK bytes free", size * fs->sects_clust / 2);
+
+ printf ("\n");
+
+ return 0;
+}
+
+static int monitorFileMkdir (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ f_printerror (f_mkdir (argv [0]));
+
+ return 0;
+}
+
+static int monitorFileRmCommon (char *path, int mode)
+{
+ FRESULT f;
+
+ if ((f = f_stat (path, &fileInfo)) != FR_OK)
+ {
+ f_printerror (f);
+ return 0;
+ }
+
+ if (mode == AM_DIR)
+ {
+ if (!(fileInfo.fattrib & AM_DIR))
+ printf ("Not a directory\n");
+ else
+ f_printerror (f_unlink (path));
+ }
+ else
+ {
+ if (fileInfo.fattrib & AM_DIR)
+ printf ("Not a regular file\n");
+ else
+ f_printerror (f_unlink (path));
+ }
+
+ return 0;
+}
+
+static int monitorFileRmdir (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ return monitorFileRmCommon (argv [0], AM_DIR);
+}
+
+static int monitorFileRm (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ return monitorFileRmCommon (argv [0], 0);
+}
+
+static int monitorFileMv (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ if (rename (argv [0], argv [1]) == -1)
+ printf ("rename failed, errno=%d/%s\n", errno, strerror (errno));
+
+ return 0;
+}
+
+static int monitorFileCp (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ int fdIn;
+ int fdOut;
+ int l;
+ char buffer [128];
+
+ if ((fdIn = open (argv [0], O_RDONLY)) == -1)
+ {
+ printf ("Cannot open input file \"%s\", errno=%d/%s\n", argv [0], errno, strerror (errno));
+ return 0;
+ }
+
+ if (argc == 1)
+ {
+ fdOut = fileno (stdout);
+ fflush (stdout);
+ }
+ else if ((fdOut = open (argv [1], O_CREAT | O_TRUNC | O_WRONLY)) == -1)
+ {
+ printf ("Cannot open output file \"%s\", errno=%d/%s\n", argv [1], errno, strerror (errno));
+ close (fdIn);
+ return 0;
+ }
+
+ while ((l = read (fdIn, buffer, sizeof (buffer))))
+ {
+ if (write (fdOut, buffer, l) != l)
+ {
+ printf ("write() returned error %d/%s (l=%d)\n", errno, strerror (errno), l);
+ break;
+ }
+ }
+
+ close (fdIn);
+
+ if (fdOut != fileno (stdout))
+ close (fdOut);
+
+ return 0;
+}
+
+static int monitorFileSync (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ sync ();
+
+ return 0;
+}
+
+int monitorTimevalSubtract (struct timeval *result, struct timeval *x, struct timeval *y);
+int monitorTimevalSubtract (struct timeval *result, struct timeval *x, struct timeval *y)
+{
+ if (x->tv_usec < y->tv_usec)
+ {
+ int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
+ y->tv_usec -= 1000000 * nsec;
+ y->tv_sec += nsec;
+ }
+
+ if (x->tv_usec - y->tv_usec > 1000000)
+ {
+ int nsec = (x->tv_usec - y->tv_usec) / 1000000;
+ y->tv_usec += 1000000 * nsec;
+ y->tv_sec -= nsec;
+ }
+
+ result->tv_sec = x->tv_sec - y->tv_sec;
+ result->tv_usec = x->tv_usec - y->tv_usec;
+
+ return x->tv_sec < y->tv_sec;
+}
+
+typedef enum
+{
+ MODE_NORMAL = 0,
+ MODE_NOINTS,
+ MODE_SUSPENDALL,
+ MODE_HIGH
+}
+mode_e;
+
+static int monitorFileThruPut (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int i;
+ mode_e mode;
+ int fileSizes [] = { 1*1024, 8*1024, 16*1024, 64*1024, 128*1024, 512*1024, 1024*1024, 2048*1024 };
+
+ if (!strcmp (argv [0], "normal"))
+ mode = MODE_NORMAL;
+ else if (!strcmp (argv [0], "noints"))
+ mode = MODE_NOINTS;
+ else if (!strcmp (argv [0], "suspendall"))
+ mode = MODE_SUSPENDALL;
+ else if (!strcmp (argv [0], "high"))
+ mode = MODE_HIGH;
+ else
+ {
+ printf ("arguments must be 'normal', 'noints', 'suspendall', or 'high'\n");
+ return 0;
+ }
+
+ printf ("%lu tests, with ", arrsizeof (fileSizes));
+
+ switch (mode)
+ {
+ case MODE_NORMAL : printf ("interrupts enabled, no tasks suspended, default priority\n\n"); break;
+ case MODE_NOINTS : printf ("interrupts disabled (no tasking)\n\n"); break;
+ case MODE_SUSPENDALL : printf ("interrupts enabled, all tasks suspended\n\n"); break;
+ case MODE_HIGH : printf ("interrupts enabled, this task promoted to highest priority\n\n");
+ }
+
+ for (i = 0; i < arrsizeof (fileSizes); i++)
+ {
+ int j;
+
+ for (j = 0; j < 2; j++)
+ {
+ int fd;
+ int k;
+ char buffer [512];
+ struct timeval tv_start;
+ struct timeval tv_end;
+ struct timeval tv_diff;
+ unsigned long ticks10ms;
+ unsigned portBASE_TYPE taskPriority = 0;
+
+ if ((fd = open ("testfile.bin", !j ? (O_TRUNC | O_CREAT | O_WRONLY) : (O_RDONLY))) == -1)
+ {
+ printf ("Cannot open \"testfile.bin\", errno=%d/%s\n", errno, strerror (errno));
+ return 0;
+ }
+
+ if (!j)
+ memset (buffer, 0xe5, sizeof (buffer));
+
+
+ switch (mode)
+ {
+ case MODE_NORMAL : break;
+ case MODE_NOINTS : portENTER_CRITICAL (); break;
+ case MODE_SUSPENDALL : vTaskSuspendAll (); break;
+ case MODE_HIGH : taskPriority = uxTaskPriorityGet (NULL); vTaskPrioritySet (NULL, (configMAX_PRIORITIES - 1)); break;
+ }
+
+ gettimeofday (&tv_start, NULL);
+
+ if (!j)
+ {
+ for (k = fileSizes [i]; k > 0; k -= sizeof (buffer))
+ {
+ if (write (fd, buffer, sizeof (buffer)) != sizeof (buffer))
+ {
+ printf ("write() failed, errno=%d/%s\n", errno, strerror (errno));
+ close (fd);
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ for (k = fileSizes [i]; k > 0; k -= sizeof (buffer))
+ {
+ if (read (fd, buffer, sizeof (buffer)) != sizeof (buffer))
+ {
+ printf ("read() failed, errno=%d/%s\n", errno, strerror (errno));
+ close (fd);
+ return 0;
+ }
+ }
+ }
+
+ gettimeofday (&tv_end, NULL);
+
+ switch (mode)
+ {
+ case MODE_NORMAL : break;
+ case MODE_NOINTS : portEXIT_CRITICAL (); break;
+ case MODE_SUSPENDALL : xTaskResumeAll (); break;
+ case MODE_HIGH : vTaskPrioritySet (NULL, taskPriority); break;
+ }
+
+ if (close (fd) == -1)
+ {
+ printf ("close() failed, errno=%d/%s\n", errno, strerror (errno));
+ return 0;
+ }
+
+ {
+ struct timeval tempStart = tv_start;
+ struct timeval tempEnd = tv_end;
+
+ monitorTimevalSubtract (&tv_diff, &tv_end, &tv_start);
+ ticks10ms = (tv_diff.tv_sec * 100) + (tv_diff.tv_usec / 10000);
+
+ printf ("%5s: %9u bytes, %7lu milliseconds (%4ld seconds), %7lu bytes/sec\n",
+ !j ? "Write" : "Read",
+ fileSizes [i],
+ ticks10ms * 10,
+ ticks10ms / 100,
+ (fileSizes [i] * 100) / ticks10ms);
+
+ if (ticks10ms > 10000)
+ {
+ printf ("tv_start = %ld, %ld\n", tempStart.tv_sec, tempStart.tv_usec);
+ printf ("tv_end = %ld, %ld\n", tempEnd.tv_sec, tempEnd.tv_usec);
+ printf ("tv_diff = %ld, %ld\n", tv_diff.tv_sec, tv_diff.tv_usec);
+ }
+ }
+
+ if (j && unlink ("testfile.bin") == -1)
+ {
+ printf ("unlink() failed, errno=%d/%s\n", errno, strerror (errno));
+ return 0;
+ }
+ }
+ }
+
+ printf ("\nDone\n");
+
+ return 0;
+}
+
+static int monitorFileCpCon (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ int fdOut;
+ char c;
+
+ if ((fdOut = open (argv [0], O_CREAT | O_TRUNC | O_WRONLY)) == -1)
+ {
+ printf ("Cannot open output file \"%s\", errno=%d/%s\n", argv [0], errno, strerror (errno));
+ return 0;
+ }
+
+ while (read (fileno (stdin), &c, sizeof (c)))
+ {
+ if (c == 0x04)
+ break;
+
+ if (c == '\r')
+ c = '\n';
+
+ if (write (fdOut, &c, sizeof (c)) != sizeof (c))
+ {
+ printf ("write() returned error %d/%s\n", errno, strerror (errno));
+ break;
+ }
+
+ printf ("%c", c);
+ fflush (stdout);
+ }
+
+ if (close (fdOut) == -1)
+ printf ("close() returned error %d/%s\n", errno, strerror (errno));
+
+ return 0;
+}
+
+static int monitorFileChmod (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ mode_t mode;
+
+ if (!strcmp (argv [0], "-w"))
+ mode = 0;
+ else if (!strcmp (argv [0], "+w"))
+ mode = S_IWUSR;
+ else
+ {
+ printf ("mode must be +w (writable) or -w (not writable)\n");
+ return 0;
+ }
+
+ if (chmod (argv [1], mode) == -1)
+ printf ("chmod() failed, errno=%d/%s\n", errno, strerror (errno));
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorGPS (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ gpsData_t gpsData;
+
+ if (gpsCopyData (&gpsData))
+ {
+ printf ("Valid ...... : %d\n", gpsData.valid);
+ printf ("Date ....... : %04d/%02d/%02d\n", gpsData.utcYear, gpsData.utcMonth, gpsData.utcDay);
+ printf ("Time ....... : %02d:%02d:%02d\n", gpsData.utcHours, gpsData.utcMinutes, gpsData.utcSeconds);
+ printf ("Speed ...... : %f\n", gpsData.groundSpeed);
+ printf ("Heading .... : %f\n", gpsData.trueCourse);
+ printf ("Altitude ... : %f\n", gpsData.height);
+ printf ("Latitude ... : %f\n", gpsData.latitude);
+ printf ("Longitude .. : %f\n", gpsData.longitude);
+ printf ("Restarts ... : %d\n", gpsData.restarts);
+ printf ("Sizeof () .. : %ld\n", sizeof (gpsData));
+ }
+ else
+ printf ("Unable to get GPS data\n");
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorSensors (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ sensorData_t sensorData;
+
+ if (sensorsCopyData (&sensorData))
+ {
+ printf ("Sensor count .. : %d\n", sensorData.sensorCount);
+ printf ("ADC changes ... : %d\n", sensorData.adcChanges);
+ }
+ else
+ printf ("Unable to get sensor data\n");
+
+ return 0;
+}
+
+static int monitorMd (int argc, portCHAR **argv)
+{
+ static unsigned int address = 0x00000000;
+ unsigned int length = 256;
+
+ if ((argc >= 1))
+ {
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (argc == 2)
+ if (!getNumber (argv [1], &length))
+ return 0;
+ }
+
+ address = monitorDumpMemory (address, address, length);
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorAbortRegs (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+ printf ("contents=%s, sigil=0x%08x, count=%d\n", (ad->sigil == 0xdeadc0de) ? "probable" : "invalid", ad->sigil, ad->count);
+ printf ("abort type=%s\n", (ad->type == 0) ? "undefined instruction" : (ad->type == 1) ? "prefetch abort" : (ad->type == 2) ? "data abort" : "unknown");
+ printf ("pc=0x%08x, opcode=0x%08x\n", ad->pc, ad->opcode);
+ printf ("cpsr=0x%08x, sp=0x%08x, lr=0x%08x\n", ad->cpsr, ad->sp, ad->lr);
+ printf ("r0=0x%08x, r1=0x%08x, r2=0x%08x, r3=0x%08x\n", ad->r0, ad->r1, ad->r2, ad->r3);
+ printf ("r4=0x%08x, r5=0x%08x, r6=0x%08x, r7=0x%08x\n", ad->r4, ad->r5, ad->r6, ad->r7);
+ printf ("r8=0x%08x, r9=0x%08x, r10=0x%08x, r11=0x%08x\n", ad->r8, ad->r9, ad->r10, ad->r11);
+ printf ("r12=0x%08x\n", ad->r12);
+ printf ("\n");
+
+ printf ("sp[0]=0x%08x, sp[1]=0x%08x, sp[2]=0x%08x, sp[3]=0x%08x\n", ad->stack [0], ad->stack [1], ad->stack [2], ad->stack [3]);
+ printf ("sp[4]=0x%08x, sp[5]=0x%08x, sp[6]=0x%08x, sp[7]=0x%08x\n", ad->stack [4], ad->stack [5], ad->stack [6], ad->stack [7]);
+
+ return 0;
+}
+
+static int monitorAbortClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+ memset (ad, 0, sizeof (* ad));
+
+ return 0;
+}
+
+static int monitorAbortDirty (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ abortDat_t *ad = (abortDat_t *) &__abort_dat;
+
+ ad->sigil = 0;
+
+ return 0;
+}
+
+static int monitorAbortUndef (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ asm volatile (" .word 0x06000010" : /* no output */ : /* no inputs */ );
+
+ return 0;
+}
+
+static int monitorAbortPabort (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ asm volatile (" ldr r0, =0x00080000" : /* no output */ : /* no inputs */ );
+ asm volatile (" mov pc, r0" : /* no output */ : /* no inputs */ );
+
+ return 0;
+}
+
+static int monitorAbortDabort (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ unsigned char c;
+ volatile unsigned char *ptr = (unsigned char *) 0x40008000;
+
+ c = *ptr;
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorEEAddr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int address;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (eepromSetAddress (address))
+ {
+ printf ("Error: address out of range\n");
+ eepromSetAddress (0);
+ }
+
+ return 0;
+}
+
+static int monitorEERead (int argc, portCHAR **argv)
+{
+ unsigned int address;
+ unsigned int length = 256;
+ unsigned char buffer [64];
+ unsigned int i;
+
+ if (argc && !getNumber (argv [0], &length))
+ return 0;
+
+ for (address = eepromGetAddress(), i = 0; i < length; i += sizeof (buffer), address = (address + sizeof (buffer)) % EEPROM_SIZE)
+ {
+ unsigned int l;
+
+ if (!(l = i % sizeof (buffer)))
+ l = MIN (length, sizeof (buffer));
+
+ if (eepromRead (buffer, l))
+ {
+ printf ("eepromRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ return 0;
+ }
+
+ monitorDumpMemory (address, (unsigned int) buffer, l);
+ }
+
+ return 0;
+}
+
+static int monitorEEReadAddr (int argc, portCHAR **argv)
+{
+ unsigned int address;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (eepromSetAddress (address))
+ {
+ printf ("Error: address out of range\n");
+ return 0;
+ }
+
+ return monitorEERead (--argc, ++argv);
+}
+
+static int monitorEEWriteCommon (int argc, portCHAR **argv, unsigned char *buffer, int bufferLength)
+{
+ int i;
+
+ for (i = 0; i < argc; i++)
+ {
+ unsigned int n;
+
+ if (i >= bufferLength)
+ {
+ printf ("Error: buffer too small for number arguments\n");
+ return -1;
+ }
+
+ if (!getNumber (argv [i], &n))
+ return 0;
+
+ if (n > 255)
+ {
+ printf ("Error: data must be 0x00..0xff (0..255)\n");
+ return -1;
+ }
+
+ buffer [i] = n;
+ }
+
+ return 0;
+}
+
+//
+// Note the two reserved bytes at the beginning of the buffer. These are
+// reserved for the address we're writing to in the EEPROM. They're populated
+// by the eepromWrite() routine. This feel hackish, but unlike the read
+// routines, we can't send the address, then a repeated start bit to switch to
+// write.
+//
+static int monitorEEWrite (int argc, portCHAR **argv)
+{
+ unsigned char buffer [18];
+
+ if (monitorEEWriteCommon (argc, argv, &buffer [2], sizeof (buffer) - 2))
+ return 0;
+
+ if (eepromWrite (buffer, argc))
+ printf ("eepromWrite() returned %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+ return 0;
+}
+
+static int monitorEEWriteAddr (int argc, portCHAR **argv)
+{
+ unsigned int address;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (eepromSetAddress (address))
+ {
+ printf ("Error: address out of range\n");
+ return 0;
+ }
+
+ return monitorEEWrite (--argc, ++argv);
+}
+
+static int monitorEEFillAddr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int address;
+ unsigned int length;
+ unsigned int fillChar;
+
+ if (!getNumber (argv [0], &address) || !getNumber (argv [1], &length) || !getNumber (argv [2], &fillChar))
+ return 0;
+
+ if (fillChar > 255)
+ printf ("Error: fill value must be 0x00..0xff (0..255)\n");
+ else if (eepromFillAddress (address, length, fillChar))
+ printf ("eepromFillAddress() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorFIQOn (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("FIQ interrupts enabled, previous state was %s\n", fiqEnable () ? "enabled" : "disabled");
+
+ return 0;
+}
+
+static int monitorFIQOff (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("FIQ interrupts disabled, previous state was %s\n", fiqDisable () ? "enabled" : "disabled");
+
+ return 0;
+}
+
+static int monitorFIQCount (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("FIQ counter = %u\n", fiqGetCount ());
+
+ return 0;
+}
+
+static int monitorFIQClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ fiqClearCount ();
+
+ return 0;
+}
+
+//
+//
+//
+int monitorI2CRead (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int address;
+ unsigned int numBytes;
+ unsigned char buffer [16];
+ int r;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+ if (!getNumber (argv [1], &numBytes))
+ return 0;
+
+ if (address > 255)
+ {
+ printf ("Error: address must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ if ((numBytes < 1) || (numBytes > sizeof (buffer)))
+ {
+ printf ("Error: number of bytes must be 1..%ld\n", sizeof (buffer));
+ return 0;
+ }
+
+ r = i2cReadBuffer (address, buffer, numBytes);
+
+ printf ("i2cReadBuffer() returned %d/%s (%s)\n\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()), r ? "error" : "no error");
+
+ monitorDumpMemory (0, (unsigned int) buffer, (int) sizeof (buffer));
+
+ return 0;
+}
+
+int monitorI2CWrite (int argc, portCHAR **argv)
+{
+ unsigned int address;
+ unsigned char buffer [16];
+ int i;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (address > 255)
+ {
+ printf ("Error: address must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ for (i = 0; i < argc - 1; i++)
+ {
+ unsigned int n;
+
+ if (!getNumber (argv [i + 1], &n))
+ return 0;
+
+ if (n > 255)
+ {
+ printf ("Error: data must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ buffer [i] = n;
+ }
+
+ i = i2cWriteBuffer (address, buffer, argc - 1);
+
+ printf ("i2cWriteBuffer() returned %d/%s (%s)\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()), i ? "error" : "no error");
+
+ return 0;
+}
+
+int monitorI2CWriteRead (int argc, portCHAR **argv)
+{
+ unsigned int address;
+ unsigned int bytesToWrite;
+ unsigned int bytesToRead;
+ unsigned char buffer [16];
+ unsigned int i;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (address > 255)
+ {
+ printf ("Error: address must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ for (bytesToWrite = argc - 2, i = 0; i < bytesToWrite; i++)
+ {
+ unsigned int n;
+
+ if (!getNumber (argv [i + 1], &n))
+ return 0;
+
+ if (n > 255)
+ {
+ printf ("Error: data must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ buffer [i] = n;
+ }
+
+ if (!getNumber (argv [argc - 1], &bytesToRead))
+ return 0;
+
+ if ((bytesToRead < 1) || (bytesToRead > sizeof (buffer)))
+ {
+ printf ("Error: number of bytes must be 1..%ld\n", sizeof (buffer));
+ return 0;
+ }
+
+ i2cWriteReadBuffer (address, buffer, bytesToWrite, bytesToRead);
+
+ printf ("i2cWriteReadBuffer() returned %d/%s\n\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+ monitorDumpMemory (0, (unsigned int) buffer, (int) sizeof (buffer));
+
+ return 0;
+}
+
+int monitorI2CDump (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ i2cDump ();
+
+ return 0;
+}
+
+int monitorI2CErrno (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("i2cErrno=%d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+ return 0;
+}
+
+//
+// Note that although the iapXXX calls can deal with multiple sectors, we only ever
+// deal with one at a time. This simplifies the user interface.
+//
+static int monitorIAPFSS (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int ss;
+
+ if ((ss = iapFindSafeSector ()) == -1)
+ printf ("Can't find a safe sector! All of flash in use?\n");
+ else
+ printf ("Sector number %d is safe for IAP operations (won't overwrite any code)\n", ss);
+
+ return 0;
+}
+
+static int monitorIAPSTOA (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int sector;
+ unsigned long address;
+ int sectorSize;
+
+ if (!getNumber (argv [0], §or))
+ return 0;
+
+ if (iapSectorToAddress (sector, &address, §orSize) == -1)
+ printf ("Sector number out of range\n");
+ else
+ printf ("Sector %d occupies address 0x%08lx for 0x%04x bytes\n", sector, address, sectorSize);
+
+ return 0;
+}
+
+static int monitorIAPFill (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int sector;
+ unsigned int byte;
+
+ if (!getNumber (argv [0], §or))
+ return 0;
+ if (!getNumber (argv [1], &byte))
+ return 0;
+
+ if (!iapIsSafeSector ((int) sector))
+ {
+ printf ("Sector number out of range or not in safe region\n");
+ return 0;
+ }
+
+ if (byte > 255)
+ {
+ printf ("Fill character must be 0x00..0xff (0..255)\n");
+ return 0;
+ }
+
+ if (iapFillSectors (sector, sector, byte) == -1)
+ printf ("iapFillSectors returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+ else
+ printf ("Sector %d filled with 0x%02x\n", sector, byte);
+
+ return 0;
+}
+
+static int monitorIAPErase (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int sector;
+
+ if (!getNumber (argv [0], §or))
+ return 0;
+
+ if (!iapIsSafeSector ((int) sector))
+ {
+ printf ("Sector number out of range or not in safe region\n");
+ return 0;
+ }
+
+ if (iapEraseSectors (sector, sector) == -1)
+ printf ("iapEraseSectors returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+ else
+ printf ("Sector %d erased\n", sector);
+
+ return 0;
+}
+
+static int monitorIAPBlank (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int sector;
+
+ if (!getNumber (argv [0], §or))
+ return 0;
+
+ if (!iapIsValidSector ((int) sector))
+ {
+ printf ("Sector number out of range\n");
+ return 0;
+ }
+
+ switch (iapBlankCheckSectors (sector, sector))
+ {
+ case 0 :
+ printf ("Sector %d is blank\n", sector);
+ break;
+
+ case 1 :
+ printf ("Sector %d is not blank\n", sector);
+ break;
+
+ default :
+ printf ("iapBlankCheckSector returned error %d/%s\n", iapGetErrno (), iapStrerror (iapGetErrno ()));
+ break;
+ }
+
+ return 0;
+}
+
+static int monitorIAPID (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("IAP ID=0x%08x\n", iapReadPartID ());
+
+ return 0;
+}
+
+static int monitorIAPVer (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("IAP ID=0x%08x\n", iapReadBootCodeVersion ());
+
+ return 0;
+}
+
+static int monitorIAPISP (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ iapISP ();
+
+ return 0;
+}
+
+//
+//
+//
+int monitorLM75Init (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ if (lm75Init ())
+ printf ("lm75Init() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+
+ return 0;
+}
+
+int monitorLM75Mode (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int mode;
+
+ if (!getNumber (argv [0], &mode))
+ return 0;
+
+ if (mode > 1)
+ printf ("Error: mode must be 0 or 1\n");
+ else
+ {
+ lm75SetMode (mode);
+
+ if (!mode)
+ printf ("lm75 using I2C repeated start for write then read\n");
+ else
+ printf ("lm75 using I2C stop then start for read\n");
+ }
+
+ return 0;
+}
+
+int monitorLM75Addr (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int address;
+
+ if (!getNumber (argv [0], &address))
+ return 0;
+
+ if (address > 0xff)
+ printf ("Error: address must be 0x00..0xff (0..255)\n");
+ else
+ lm75SetAddress (address);
+
+ return 0;
+}
+
+int monitorLM75ReRead (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int value;
+
+ if (lm75ReRead (&value))
+ printf ("lm75Read() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ else
+ printf ("value=0x%x\n", value);
+
+ return 0;
+}
+
+int monitorLM75Temp (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int temp;
+
+ if (lm75TemperatureRead (&temp))
+ printf ("lm75TemperatureRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ else
+ printf ("temp=%d.%dC\n", temp >> 1, (temp & 0x01) ? 5 : 0);
+
+ return 0;
+}
+
+int monitorLM75Config (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int config;
+
+ if (lm75ConfigRead (&config))
+ printf ("lm75ConfigRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ else
+ printf ("config=0x%02x\n", config);
+
+ return 0;
+}
+
+int monitorLM75Thyst (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int thyst;
+
+ if (!argc)
+ {
+ if (lm75THYSTRead (&thyst))
+ printf ("lm75THYSTRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ else
+ printf ("THYST=%d.%dC\n", thyst / 2, (thyst & 0x01) ? 5 : 0);
+ }
+ else
+ {
+ if (!getNumber (argv [0], (unsigned int *) &thyst))
+ return 0;
+
+ if ((thyst < -55) || (thyst > 125))
+ printf ("Error: THYST range is -55C to +125C\n");
+ else if (lm75THYSTWrite (thyst << 1))
+ printf ("lm75THYSTWrite() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ }
+ return 0;
+}
+
+int monitorLM75Tos (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int tos;
+
+ if (!argc)
+ {
+ if (lm75TOSTRead (&tos))
+ printf ("lm75TOSRead() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ else
+ printf ("TOS=%d.%dC\n", tos / 2, (tos & 0x01) ? 5 : 0);
+ }
+ else
+ {
+ if (!getNumber (argv [0], (unsigned int *) &tos))
+ return 0;
+
+ if ((tos < -55) || (tos > 125))
+ printf ("Error: TOS range is -55C to +125C\n");
+ else if (lm75TOSWrite (tos << 1))
+ printf ("lm75TOSWrite() returned error %d/%s\n", i2cGetErrno (), i2cStrerror (i2cGetErrno ()));
+ }
+
+ return 0;
+}
+
+//
+// 6 tasks, each task needs about 42 bytes to display
+//
+#define monitorTask_BUFFERSIZE (6 * 42)
+
+static int monitorMemTask (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+#if configUSE_TRACE_FACILITY == 1
+ signed portCHAR buffer [monitorTask_BUFFERSIZE];
+ int bytesFree;
+ int bytesUsed;
+ int blocksFree;
+
+ vTaskList (buffer);
+ vPortUsedMem (&bytesFree, &bytesUsed, &blocksFree);
+ printf ("%s\nHeap size=%ld, used=%d, free=%d (%d blocks)\n", buffer, configTOTAL_HEAP_SIZE, bytesUsed, bytesFree, blocksFree);
+#else
+ printf ("Not implemented (requires configUSE_TRACE_FACILITY in FreeRTOSConfig.h)\n");
+#endif
+
+ return 0;
+}
+
+typedef struct memMap_s
+{
+ char *desc;
+ int m;
+ unsigned int start;
+ unsigned int end;
+}
+memMap_t;
+
+typedef union
+{
+ void *v;
+ unsigned int i;
+}
+sbrkConv_t;
+
+static inline unsigned __get_cpsr (void)
+{
+ unsigned long retval;
+
+ asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
+
+ return retval;
+}
+
+static int monitorMemMap (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ unsigned int i;
+ sbrkConv_t sbrkConv;
+ static memMap_t memMap [] =
+ {
+ { ".startup .....", 0, (unsigned int) &__start_of_startup__, (unsigned int) &__end_of_startup__ },
+ { ".text ........", 0, (unsigned int) &__start_of_text__, (unsigned int) &__end_of_text__ },
+ { ".code ........", 0, (unsigned int) &__start_of_prog__, (unsigned int) &__end_of_prog__ },
+ { ".rodata ......", 0, (unsigned int) &__start_of_rodata__, (unsigned int) &__end_of_rodata__ },
+ { ".data ........", 0, (unsigned int) &__data_beg__, (unsigned int) &__data_end__ },
+ { ".bss .........", 0, (unsigned int) &__bss_beg__, (unsigned int) &__bss_end__ },
+ { "heap .........", 1, (unsigned int) &__heap_beg, (unsigned int) &__heap_end },
+ { "heap range ...", 1, (unsigned int) &__heap_beg, (unsigned int) &__heap_max },
+// { "SYS stack ....", 1, (unsigned int) &__stack_beg_sys, (unsigned int) &__stack_end_sys }, // Not relevant to FreeRTOS
+ { "SVC stack ....", 1, (unsigned int) &__stack_beg_svc, (unsigned int) &__stack_end_svc },
+ { "IRQ stack ....", 1, (unsigned int) &__stack_beg_irq, (unsigned int) &__stack_end_irq },
+ { "FIQ stack ....", 1, (unsigned int) &__stack_beg_fiq, (unsigned int) &__stack_end_fiq },
+ { "abort stack ..", 1, (unsigned int) &__stack_beg_abt, (unsigned int) &__stack_end_abt },
+ { "undef stack ..", 1, (unsigned int) &__stack_beg_und, (unsigned int) &__stack_end_und },
+ };
+
+ sbrkConv.v = sbrk (0);
+ __heap_end = sbrkConv.i;
+ __stack_end_sys = sbrkConv.i;
+
+ printf ("Section Start End Length\n");
+ printf ("-------------------------------------------\n");
+
+ for (i = 0; i < arrsizeof (memMap); i++)
+ {
+ if (!memMap [i].m)
+ printf ("%s 0x%08x 0x%08x 0x%x\n", memMap [i].desc, memMap [i].start, memMap [i].end, abs (memMap [i].end - memMap [i].start));
+ else
+ printf ("%s 0x%08x 0x%08x 0x%x\n", memMap [i].desc, *(unsigned int *) memMap [i].start, *(unsigned int *) memMap [i].end, abs (*(unsigned int *) memMap [i].end - *(unsigned int *) memMap [i].start));
+ }
+
+#if 0
+ printf ("\nProcessor mode ");
+
+ switch ((i = __get_cpsr ()) & 0x1f)
+ {
+ case 0x10 : printf ("User"); break;
+ case 0x11 : printf ("FIQ"); break;
+ case 0x12 : printf ("IRQ"); break;
+ case 0x13 : printf ("Supervisor"); break;
+ case 0x17 : printf ("Abort"); break;
+ case 0x1b : printf ("Undefined"); break;
+ case 0x1f : printf ("System"); break;
+ default : printf ("Unknown");
+ }
+
+ printf (", IRQ %s", (i & 0x80) ? "disabled" : "enabled");
+ printf (", FIQ %s", (i & 0x40) ? "disabled" : "enabled");
+ printf (", mode %s\n", (i & 0x20) ? "THUMB" : "ARM");
+#endif
+
+ printf ("\n");
+ malloc_stats ();
+
+ return 0;
+}
+
+typedef struct memorySlots_s
+{
+ unsigned char *p;
+ unsigned int size;
+}
+memorySlots_t;
+
+memorySlots_t memorySlots [8];
+
+static int monitorMemAlloc (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int size;
+ unsigned int slot;
+ unsigned char *p;
+
+ if (!getNumber (argv [0], &slot) || !getNumber (argv [0], &size))
+ return 0;
+
+ if (slot >= arrsizeof (memorySlots))
+ {
+ printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+ return 0;
+ }
+
+ if (memorySlots [slot].p)
+ printf ("Slot %d in use, free it first, or use realloc\n", slot);
+ else if (!(p = malloc (size)))
+ printf ("malloc() failed, error %d/%s\n", errno, strerror (errno));
+ else
+ {
+ memorySlots [slot].p = p;
+ memorySlots [slot].size = size;
+ }
+
+ return 0;
+}
+
+static int monitorMemRealloc (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int size;
+ unsigned int slot;
+ unsigned char *p;
+
+ if (!getNumber (argv [0], &slot) || !getNumber (argv [0], &size))
+ return 0;
+
+ if (slot >= arrsizeof (memorySlots))
+ {
+ printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+ return 0;
+ }
+
+ if (!(p = realloc (memorySlots [slot].p, size)))
+ printf ("realloc() failed, error %d/%s\n", errno, strerror (errno));
+ else
+ {
+ memorySlots [slot].p = p;
+ memorySlots [slot].size = size;
+ }
+
+ return 0;
+}
+
+static int monitorMemFree (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int slot;
+
+ if (!getNumber (argv [0], &slot))
+ return 0;
+
+ if (slot >= arrsizeof (memorySlots))
+ {
+ printf ("slot must be 0..%lu\n", arrsizeof (memorySlots) - 1);
+ return 0;
+ }
+
+ if (!memorySlots [slot].p)
+ printf ("Can't free it, slot %d not in use\n", slot);
+ else
+ {
+ free (memorySlots [slot].p);
+ memorySlots [slot].p = NULL;
+ memorySlots [slot].size = 0;
+ }
+
+ return 0;
+}
+
+static int monitorMemList (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ unsigned int i;
+
+ printf ("Slot Address Size\n");
+ printf ("----------------------\n");
+
+ for (i = 0; i < arrsizeof (memorySlots); i++)
+ printf ("%4d 0x%08x %d\n", i, (unsigned int) memorySlots [i].p, memorySlots [i].size);
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorMiscSizeof (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("sizeof (char) = %lu\n", sizeof (char));
+ printf ("sizeof (short) = %lu\n", sizeof (short));
+ printf ("sizeof (int) = %lu\n", sizeof (int));
+ printf ("sizeof (long) = %lu\n", sizeof (long));
+ printf ("sizeof (long long) = %lu\n", sizeof (long long));
+ printf ("sizeof (float) = %lu\n", sizeof (float));
+ printf ("sizeof (double) = %lu\n", sizeof (double));
+ printf ("sizeof (void *) = %lu\n", sizeof (void *));
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorRTCGet (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ time_t now;
+ char buffer [32];
+
+ now = time (NULL);
+ ctime_r (&now, buffer);
+ printf ("%s", buffer);
+
+ return 0;
+}
+
+//
+// This works because atoi() stops on a non-digit. We already know the
+// string values are digits, because of isGoodString().
+//
+static int tmSetElement (int *element, int minValue, int maxValue, int adjustValue, char *s)
+{
+ int v;
+
+ if (((v = atoi (s)) < minValue) || (v > maxValue))
+ {
+ printf ("Illegal value encountered in parameter\n");
+ return FALSE;
+ }
+
+ *element = (v + adjustValue);
+
+ return TRUE;
+}
+
+static int isGoodString (char *s, char *fmt)
+{
+ unsigned int i;
+ unsigned int l;
+
+ if ((l = strlen (s)) != strlen (fmt))
+ return FALSE;
+
+ for (i = 0; i < l; i++, s++, fmt++)
+ {
+ if (*fmt == 'N')
+ {
+ if (!isdigit (*s))
+ return FALSE;
+ }
+ else if (*fmt != *s)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int monitorRTCSet (int argc, portCHAR **argv)
+{
+ if ((argc == 1) && !strcmp (argv [0], "gps"))
+ {
+ gpsData_t gpsData;
+
+ if (gpsCopyData (&gpsData))
+ {
+ if (gpsData.valid)
+ {
+ struct tm tm;
+
+ tm.tm_sec = gpsData.utcSeconds;
+ tm.tm_min = gpsData.utcMinutes;
+ tm.tm_hour = gpsData.utcHours;
+ tm.tm_mday = gpsData.utcDay;
+ tm.tm_mon = gpsData.utcMonth - 1;
+ tm.tm_year = gpsData.utcYear - 1900;
+ tm.tm_wday = 0;
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+
+ rtcSetEpochSeconds (mktime (&tm));
+
+ printf ("Date/time set from GPS\n");
+ }
+ else
+ printf ("GPS data not valid\n");
+ }
+ else
+ printf ("Unable to get GPS data\n");
+ }
+ else if (isGoodString (argv [0], "NNNN/NN/NN") && isGoodString (argv [1], "NN:NN:NN"))
+ {
+ struct tm tm;
+
+ if (!tmSetElement (&tm.tm_year, 1900, 2038, -1900, &argv [0][0]))
+ return 0;
+ if (!tmSetElement (&tm.tm_mon, 1, 12, -1, &argv [0][5]))
+ return 0;
+ if (!tmSetElement (&tm.tm_mday, 1, 31, 0, &argv [0][8]))
+ return 0;
+ if (!tmSetElement (&tm.tm_hour, 0, 23, 0, &argv [1][0]))
+ return 0;
+ if (!tmSetElement (&tm.tm_min, 0, 59, 0, &argv [1][3]))
+ return 0;
+ if (!tmSetElement (&tm.tm_sec, 0, 59, 0, &argv [1][6]))
+ return 0;
+
+ tm.tm_wday = 0;
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+
+ rtcSetEpochSeconds (mktime (&tm));
+ }
+ else
+ printf ("Parameter(s) either not 'gps' or not 'YYYYY/MM/DD HH:MM:SS'\n");
+
+ return 0;
+}
+
+static int monitorRTCAlarm (int argc, portCHAR **argv)
+{
+ if (argc == 0)
+ {
+ time_t a;
+
+ if ((a = rtcGetAlarmEpochSeconds ()))
+ {
+ char buffer [32];
+ ctime_r (&a, buffer);
+ printf ("%s", buffer);
+ }
+ else
+ printf ("alarm not enabled\n");
+ }
+ else if (argc == 1)
+ {
+ if (!strcmp (argv [0], "off"))
+ rtcSetAlarm (NULL);
+ else
+ printf ("'rtc alarm' requires either 'off' or 'YYYY/MM/DD HH:MM:SS' as arguments\n");
+ }
+ else if (isGoodString (argv [0], "NNNN/NN/NN") && isGoodString (argv [1], "NN:NN:NN"))
+ {
+ struct tm tm;
+
+ if (!tmSetElement (&tm.tm_year, 1900, 2038, -1900, &argv [0][0]))
+ return 0;
+ if (!tmSetElement (&tm.tm_mon, 1, 12, -1, &argv [0][5]))
+ return 0;
+ if (!tmSetElement (&tm.tm_mday, 1, 31, 0, &argv [0][8]))
+ return 0;
+ if (!tmSetElement (&tm.tm_hour, 0, 23, 0, &argv [1][0]))
+ return 0;
+ if (!tmSetElement (&tm.tm_min, 0, 59, 0, &argv [1][3]))
+ return 0;
+ if (!tmSetElement (&tm.tm_sec, 0, 59, 0, &argv [1][6]))
+ return 0;
+
+ if (rtcSetAlarm (&tm))
+ printf ("Cannot set the alarm for the past\n");
+ }
+ else
+ printf ("Parameter(s) either not 'off' or not 'YYYYY/MM/DD HH:MM:SS'\n");
+
+ return 0;
+}
+
+static int monitorRTCPeriodic (int argc, portCHAR **argv)
+{
+ if (!argc)
+ printf ("Current periodic alarm state is %s\n", rtcPeriodicAlarm (-1) ? "on" : "off");
+ else if (!strcmp (argv [0], "off"))
+ rtcPeriodicAlarm (0);
+ else if (!strcmp (argv [0], "on"))
+ rtcPeriodicAlarm (1);
+ else
+ printf ("Error: if argument present, must be 'off' or 'on'\n");
+
+ return 0;
+}
+
+//
+//
+//
+static inline unsigned long monitorSWICommon (unsigned long swi);
+static inline unsigned long monitorSWICommon (unsigned long swi)
+{
+ unsigned long result;
+
+ SWICALL (swi, result);
+
+ return result;
+}
+
+static inline unsigned long monitorSWICommon2 (unsigned long swi, unsigned long state);
+static inline unsigned long monitorSWICommon2 (unsigned long swi, unsigned long state)
+{
+ unsigned long result;
+
+ SWICALL1 (swi, state, result);
+
+ return result;
+}
+
+int monitorSWISetAsm (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int state;
+
+ if (!strcmp (argv [0], "on"))
+ state = 0;
+ else if (!strcmp (argv [0], "off"))
+ state = 1;
+ else
+ {
+ printf ("State must be 'on' or 'off'\n");
+ return 0;
+ }
+
+ printf ("Setting LED2 %s via C, previous state was %s\n", state ? "off" : "on", monitorSWICommon2 (SWICALL_A_LED2SET, state) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIOnAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Setting LED2 on via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2ON) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIOffAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Setting LED2 off via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2OFF) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIToggleAsm (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Toggling LED2 via assembly, previous state was %s\n", monitorSWICommon (SWICALL_A_LED2TOGGLE) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWISetC (int argc __attribute__ ((unused)), portCHAR **argv)
+{
+ unsigned int state;
+
+ if (!strcmp (argv [0], "on"))
+ state = 0;
+ else if (!strcmp (argv [0], "off"))
+ state = 1;
+ else
+ {
+ printf ("State must be 'on' or 'off'\n");
+ return 0;
+ }
+
+ printf ("Setting LED2 %s via C, previous state was %s\n", state ? "off" : "on", monitorSWICommon2 (SWICALL_C_LED2SET, state) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIOnC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Setting LED2 on via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2ON) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIOffC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Setting LED2 off via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2OFF) ? "off" : "on");
+
+ return 0;
+}
+
+int monitorSWIToggleC (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("Toggling LED2 via C, previous state was %s\n", monitorSWICommon (SWICALL_C_LED2TOGGLE) ? "off" : "on");
+
+ return 0;
+}
+
+//
+//
+//
+int monitorWDTTest (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("The watchdog is disabled, by default. This command enables the watchdog, and if\n"
+ "no command is typed for 10 seconds, the watchdog will cause the system reset.\n"
+ "The 10 seconds is based on a 48Mhz PCLK (12Mhz xtal, PLL x 4, VBPDIV = /1). The\n"
+ "'wdt status' command will show the cause of a system reset. RSIR is reset by\n"
+ "this command.\n");
+
+ SCB_RSIR = SCB_RSIR_MASK;
+ WD_MOD = WD_MOD_WDEN | WD_MOD_RESET;
+ WD_TC = 120000000;
+ WD_FEED = WD_FEED_FEED1;
+ WD_FEED = WD_FEED_FEED2;
+
+ return 0;
+}
+
+int monitorWDTStatus (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ int regRSIR = SCB_RSIR;
+ int regWDMOD = WD_MOD;
+ int regWDTC = WD_TC;
+ int regWDTV = WD_TV;
+
+ printf ("Watchdog enabled .................. : %s\n", (regWDMOD & WD_MOD_WDEN) ? "Yes" : "No");
+ printf ("Watchdog timeout generates reset .. : %s\n", (regWDMOD & WD_MOD_RESET) ? "Yes" : "No");
+ printf ("Watchdog timeout (in PCLK/4's) .... : %d\n", regWDTC);
+ printf ("Watchdog timeout counter .......... : %d\n", regWDTV);
+ printf ("\n");
+ printf ("Reset because of POR .............. : %s\n", (regRSIR & SCB_RSIR_POR) ? "Yes" : "No");
+ printf ("Reset because of /RESET ........... : %s\n", (regRSIR & SCB_RSIR_EXTR) ? "Yes" : "No");
+ printf ("Reset because of watchdog ......... : %s\n", (regRSIR & SCB_RSIR_WDTR) ? "Yes" : "No");
+ printf ("Reset because of BOD .............. : %s\n", (regRSIR & SCB_RSIR_BODR) ? "Yes" : "No");
+
+ return 0;
+}
+
+int monitorWDTClear (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ SCB_RSIR = SCB_RSIR_MASK;
+ WD_MOD = 0;
+
+ return 0;
+}
+
+//
+//
+//
+static int monitorVersion (int argc __attribute__ ((unused)), portCHAR **argv __attribute__ ((unused)))
+{
+ printf ("LPC-P2148 Demo, Version " __VERSION ", " __DATE__ " " __TIME__ "\n");
+ printf ("Copyright (c) 2007, J.C. Wren\n");
+
+ return 0;
+}
+
+//
+//
+//
+#if defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1
+static void monitorReassignFD (FILE *fp, int fd);
+static void monitorReassignFD (FILE *fp, int fd)
+{
+ fp->_file = fd;
+}
+#endif
+
+static void argsDispatch (commandList_t *cl, int argc, char **argv)
+{
+ activeCommandList = cl;
+
+ while (cl->command)
+ {
+ if (!strcmp (cl->command, argv [0]))
+ {
+ if ((argc == 2) && !strcmp (argv [1], "?"))
+ printf ("%s\n", cl->parameters);
+ else if ((argc - 1) < cl->minArgs)
+ printf ("Too few arguments to command (%d expected)\n", cl->minArgs);
+ else if (cl->cmdType == CMDTYPE_CMDLIST)
+ argsDispatch (cl->commandList, argc - 1, &argv [1]);
+ else if ((argc - 1) > cl->maxArgs)
+ printf ("Too many arguments to command (%d maximum)\n", cl->maxArgs);
+ else
+ (*cl->handler) (argc - 1, &argv [1]);
+
+ return;
+ }
+
+ cl++;
+ }
+
+ if (!cl->command)
+ printf ("Unknown command \"%s\"\n", argv [0]);
+}
+
+portTASK_FUNCTION (vMonitorTask, pvParameters __attribute__ ((unused)))
+{
+ static U8 buffer [256];
+ static portCHAR *argv [34];
+ int argc;
+ int fd = fileno (stdin);
+
+ fclose (stderr);
+ stderr = stdout;
+
+#if defined CFG_CONSOLE_USB
+ fd = open ("/dev/usb", O_RDWR);
+#elif defined CFG_CONSOLE_UART1
+ fd = open ("/dev/uart1", O_RDWR);
+#endif
+
+#if defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1
+ monitorReassignFD (stdin, fd);
+ monitorReassignFD (stdout, fd);
+#endif
+
+ monitorVersion (0, NULL);
+
+#ifndef CFG_USB_MSC
+ //
+ // If CFG_USB_MSC defined, this gets done by mscblockInit()
+ //
+ {
+ FRESULT f;
+
+ if ((f = diskInitialize (0)) != FR_OK)
+ f_printerror (f);
+ }
+#endif
+
+ for (;;)
+ {
+ int l;
+
+ if ((l = argsGetLine (fd, buffer, sizeof (buffer))))
+ {
+ if ((l == 1) && ((buffer [0] == 0xfe) || (buffer [0] == 0xff)))
+ {
+ int type = buffer [0];
+ time_t now = time (NULL);
+ ctime_r (&now, (char *) buffer);
+ printf ("%s -- %s", (type == 0xfe) ? "ALARM" : "PERIODIC", buffer);
+ }
+ else if (argsParse ((char *) buffer, argv, sizeof (argv), &argc))
+ printf ("Too many arguments (max %ld)\n", arrsizeof (argv));
+ else if (argv [0])
+ argsDispatch (commandList, argc, &argv [0]);
+ }
+
+ WD_FEED = WD_FEED_FEED1;
+ WD_FEED = WD_FEED_FEED2;
+ }
+}
--- /dev/null
+#ifndef _MONITOR_H_
+#define _MONITOR_H_
+
+portTASK_FUNCTION_PROTO (vMonitorTask, pvParameters __attribute__ ((unused)));
+
+#endif
--- /dev/null
+SRC_FILES=syscalls.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+//
+// Support files for GNU libc. Files in the system namespace go here.
+// Files in the C namespace (ie those that do not start with an underscore) go in .c
+//
+#include <_ansi.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <errno.h>
+#include <reent.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "../uart/uart.h"
+#include "../usbser/usbser.h"
+#include "../rtc/rtc.h"
+#include "../fatfs/ff.h"
+
+//
+// Forward prototypes
+//
+int _mkdir _PARAMS ((const char *, mode_t));
+int _chmod _PARAMS ((const char *, mode_t));
+int _read _PARAMS ((int, char *, int));
+int _lseek _PARAMS ((int, int, int));
+int _write _PARAMS ((int, const char *, int));
+int _open _PARAMS ((const char *, int, ...));
+int _close _PARAMS ((int));
+int _kill _PARAMS ((int, int));
+void _exit _PARAMS ((int));
+int _getpid _PARAMS ((int));
+caddr_t _sbrk _PARAMS ((int));
+int _fstat _PARAMS ((int, struct stat *));
+int _stat _PARAMS ((const char *, struct stat *));
+int _link _PARAMS ((void));
+int _unlink _PARAMS ((const char *));
+void _raise _PARAMS ((void));
+int _gettimeofday _PARAMS ((struct timeval *, struct timezone *));
+clock_t _times _PARAMS ((struct tms *));
+int isatty _PARAMS ((int));
+int _rename _PARAMS ((const char *, const char *));
+int _system _PARAMS ((const char *));
+void _sync _PARAMS ((void));
+void syscallsInit _PARAMS ((void));
+
+int rename _PARAMS ((const char *, const char *));
+
+static int set_errno _PARAMS ((int));
+static time_t fatfs_time_to_timet _PARAMS ((FILINFO *));
+static int remap_handle _PARAMS ((int));
+static int findslot _PARAMS ((int));
+
+//
+// Register name faking - works in collusion with the linker
+//
+register char *stack_ptr asm ("sp");
+
+//
+// Following is copied from libc/stdio/local.h to check std streams
+//
+extern void _EXFUN (__sinit,( struct _reent *));
+
+#define CHECK_INIT(ptr) \
+do \
+{ \
+ if ((ptr) && !(ptr)->__sdidinit) \
+ __sinit (ptr); \
+} \
+while (0)
+
+//
+// Adjust our internal handles to stay away from std* handles
+//
+#define FILE_HANDLE_OFFSET (0x20)
+
+#define MONITOR_STDIN 0
+#define MONITOR_STDOUT 1
+#define MONITOR_STDERR 2
+#define MONITOR_UART0 3
+#define MONITOR_UART1 4
+#define MONITOR_USB 5
+#define MONITOR_FATFS 6
+
+//
+//
+//
+typedef struct
+{
+ int handle;
+ int pos;
+ int flags;
+ FIL *fatfsFCB;
+}
+openFiles_t;
+
+//
+//
+//
+#define MAX_OPEN_FILES 10
+static openFiles_t openfiles [MAX_OPEN_FILES];
+
+static int findslot (int fh)
+{
+ static int slot;
+ static int lastfh = -1;
+
+ if ((fh != -1) && (fh == lastfh))
+ return slot;
+
+ for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+ if (openfiles [slot].handle == fh)
+ break;
+
+ lastfh = fh;
+
+ return slot;
+}
+
+//
+// Function to convert std(in|out|err) handles to internal versions.
+//
+static int remap_handle (int fh)
+{
+ CHECK_INIT(_REENT);
+
+ if (fh == STDIN_FILENO)
+ return MONITOR_STDIN;
+ if (fh == STDOUT_FILENO)
+ return MONITOR_STDOUT;
+ if (fh == STDERR_FILENO)
+ return MONITOR_STDERR;
+
+ return fh - FILE_HANDLE_OFFSET;
+}
+
+static int remap_fatfs_errors (FRESULT f)
+{
+ switch (f)
+ {
+ case FR_NO_FILE : errno = ENOENT; break;
+ case FR_NO_PATH : errno = ENOENT; break;
+ case FR_INVALID_NAME : errno = EINVAL; break;
+ case FR_INVALID_DRIVE : errno = ENODEV; break;
+ case FR_DENIED : errno = EACCES; break;
+ case FR_EXIST : errno = EEXIST; break;
+ case FR_NOT_READY : errno = EIO; break;
+ case FR_WRITE_PROTECTED : errno = EACCES; break;
+ case FR_RW_ERROR : errno = EIO; break;
+ case FR_NOT_ENABLED : errno = EIO; break;
+ case FR_NO_FILESYSTEM : errno = EIO; break;
+ case FR_INVALID_OBJECT : errno = EBADF; break;
+ default : errno = EIO; break;
+ }
+
+ return -1;
+}
+
+static time_t fatfs_time_to_timet (FILINFO *f)
+{
+ struct tm tm;
+
+ tm.tm_sec = (f->ftime & 0x001f) << 1;
+ tm.tm_min = (f->ftime & 0x07e0) >> 5;
+ tm.tm_hour = (f->ftime & 0xf800) >> 11;
+ tm.tm_mday = (f->fdate & 0x001f);
+ tm.tm_mon = ((f->fdate & 0x01e0) >> 5) - 1;
+ tm.tm_year = ((f->fdate & 0xfe00) >> 9) + 80;
+ tm.tm_isdst = 0;
+
+ return mktime (&tm);
+}
+
+static int set_errno (int errval)
+{
+ errno = errval;
+
+ return -1;
+}
+
+void syscallsInit (void)
+{
+ int slot;
+ static int initialized = 0;
+
+ if (initialized)
+ return;
+
+ initialized = 1;
+
+ __builtin_memset (openfiles, 0, sizeof (openfiles));
+
+ for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+ openfiles [slot].handle = -1;
+
+ openfiles [0].handle = MONITOR_STDIN;
+ openfiles [1].handle = MONITOR_STDOUT;
+ openfiles [2].handle = MONITOR_STDERR;
+}
+
+int _mkdir (const char *path, mode_t mode __attribute__ ((unused)))
+{
+ FRESULT f;
+
+ if ((f = f_mkdir (path)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ return 0;
+}
+
+int _chmod (const char *path, mode_t mode)
+{
+ FRESULT f;
+
+ if ((f = f_chmod (path, (mode & S_IWUSR) ? 0 : AM_RDO, AM_RDO)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ return 0;
+}
+
+int _read (int fd, char *ptr, int len)
+{
+ int i;
+ int fh;
+ int slot;
+ portTickType xBlockTime;
+ int bytesUnRead = -1;
+
+ if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
+ return set_errno (EBADF);
+
+ if (openfiles [slot].flags & O_WRONLY)
+ return set_errno (EBADF);
+
+ xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
+
+ switch (fh)
+ {
+ case MONITOR_STDIN :
+ {
+ for (i = 0; i < len; i++)
+ if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
+ break;
+
+ bytesUnRead = len - i;
+ }
+ break;
+
+ case MONITOR_STDOUT :
+ case MONITOR_STDERR :
+ break;
+
+ case MONITOR_UART0 :
+ {
+ for (i = 0; i < len; i++)
+ if (!uartGetChar (0, (signed portCHAR *) ptr++, xBlockTime))
+ break;
+
+ bytesUnRead = len - i;
+ }
+ break;
+
+ case MONITOR_UART1 :
+ {
+ for (i = 0; i < len; i++)
+ if (!uartGetChar (1, (signed portCHAR *) ptr++, xBlockTime))
+ break;
+
+ bytesUnRead = len - i;
+ }
+ break;
+
+ case MONITOR_USB :
+ {
+ for (i = 0; i < len; i++)
+ if (!usbserGetChar ((signed portCHAR *) ptr++, xBlockTime))
+ break;
+
+ bytesUnRead = len - i;
+ }
+ break;
+
+ default :
+ {
+ if (openfiles [slot].fatfsFCB)
+ {
+ FRESULT f;
+ U16 fatfsBytesRead;
+
+ if ((f = f_read (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesRead)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ bytesUnRead = len - fatfsBytesRead;
+ }
+ }
+ break;
+ }
+
+ if (bytesUnRead < 0)
+ return -1;
+
+ openfiles [slot].pos += len - bytesUnRead;
+
+ return len - bytesUnRead;
+}
+
+int _lseek (int fd, int ptr, int dir)
+{
+ int fh;
+ int slot;
+ FRESULT f = FR_INVALID_OBJECT;
+
+ if (((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES) || !openfiles [slot].fatfsFCB)
+ return set_errno (EBADF);
+
+ if (dir == SEEK_SET)
+ f = f_lseek (openfiles [slot].fatfsFCB, ptr);
+ else if (dir == SEEK_CUR)
+ f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fptr + ptr);
+ else if (dir == SEEK_END)
+ f = f_lseek (openfiles [slot].fatfsFCB, openfiles [slot].fatfsFCB->fsize + ptr);
+
+ if (f != FR_OK)
+ return remap_fatfs_errors (f);
+
+ return openfiles [slot].pos = openfiles [slot].fatfsFCB->fptr;
+}
+
+int _write (int fd, const char *ptr, int len)
+{
+ int i;
+ int fh;
+ int slot;
+ portTickType xBlockTime;
+ int bytesUnWritten = -1;
+
+ if ((slot = findslot (fh = remap_handle (fd))) == MAX_OPEN_FILES)
+ return set_errno (EBADF);
+
+ if (openfiles [slot].flags & O_RDONLY)
+ return set_errno (EBADF);
+
+ xBlockTime = (openfiles [slot].flags & O_NONBLOCK) ? 0 : portMAX_DELAY;
+
+ switch (fh)
+ {
+ case MONITOR_STDIN :
+ break;
+
+ case MONITOR_STDOUT :
+ case MONITOR_STDERR :
+ {
+ for (i = 0; i < len; i++)
+ {
+ if (*ptr == '\n')
+ if (!uartPutChar (0, '\r', xBlockTime))
+ break;
+ if (!uartPutChar (0, *ptr++, xBlockTime))
+ break;
+ }
+
+ bytesUnWritten = len - i;
+ }
+ break;
+
+ case MONITOR_UART0 :
+ {
+ for (i = 0; i < len; i++)
+ if (!uartPutChar (0, *ptr++, xBlockTime))
+ break;
+
+ bytesUnWritten = len - i;
+ }
+ break;
+
+ case MONITOR_UART1 :
+ {
+ for (i = 0; i < len; i++)
+ {
+#ifdef CFG_CONSOLE_UART1
+ if (*ptr == '\n')
+ if (!uartPutChar (1, '\r', xBlockTime))
+ break;
+#endif
+ if (!uartPutChar (1, *ptr++, xBlockTime))
+ break;
+ }
+
+ bytesUnWritten = len - i;
+ }
+ break;
+
+ case MONITOR_USB :
+ {
+ for (i = 0; i < len; i++)
+ {
+#ifdef CFG_CONSOLE_USB
+ if (*ptr == '\n')
+ if (!usbserPutChar ('\r', xBlockTime))
+ break;
+#endif
+ if (!usbserPutChar (*ptr++, xBlockTime))
+ break;
+ }
+
+ bytesUnWritten = len - i;
+ }
+ break;
+
+ default :
+ {
+ if (openfiles [slot].fatfsFCB)
+ {
+ FRESULT f;
+ U16 fatfsBytesWritten;
+
+ if ((f = f_write (openfiles [slot].fatfsFCB, ptr, len, &fatfsBytesWritten)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ bytesUnWritten = len - fatfsBytesWritten;
+ }
+ else
+ return set_errno (EBADF);
+ }
+ break;
+ }
+
+ if (bytesUnWritten == -1 || bytesUnWritten == len)
+ return -1;
+
+ openfiles [slot].pos += len - bytesUnWritten;
+
+ return len - bytesUnWritten;
+}
+
+int _open (const char *path, int flags, ...)
+{
+ int fh = 0;
+ int slot;
+
+ if ((slot = findslot (-1)) == MAX_OPEN_FILES)
+ return set_errno (ENFILE);
+
+ if (flags & O_APPEND)
+ flags &= ~O_TRUNC;
+
+ if (!__builtin_strcmp (path, "/dev/uart0"))
+ fh = MONITOR_UART0;
+ else if (!__builtin_strcmp (path, "/dev/uart1"))
+ fh = MONITOR_UART1;
+ else if (!__builtin_strcmp (path, "/dev/usb"))
+ fh = MONITOR_USB;
+ else
+ {
+ U8 fatfsFlags = FA_OPEN_EXISTING;
+ FRESULT f;
+
+ //
+ // FA_OPEN_EXISTING Opens the file. The function fails if the file is not existing. (Default)
+ // FA_OPEN_ALWAYS Opens the file, if it is existing. If not, the function creates the new file.
+ // FA_CREATE_NEW Creates a new file. The function fails if the file is already existing.
+ // FA_CREATE_ALWAYS Creates a new file. If the file is existing, it is truncated and overwritten.
+ //
+ // O_CREAT If the file does not exist it will be created.
+ // O_EXCL When used with O_CREAT, if the file already exists it is an error and the open() will fail.
+ // O_TRUNC If the file already exists and is a regular file and the open mode allows writing (i.e., is O_RDWR or O_WRONLY) it will be truncated to length 0.
+ //
+ if (((flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) && (flags & (O_RDWR | O_WRONLY)))
+ fatfsFlags = FA_CREATE_ALWAYS;
+ else if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+ fatfsFlags = FA_OPEN_EXISTING;
+ else if ((flags & O_CREAT) == O_CREAT)
+ fatfsFlags = FA_OPEN_ALWAYS;
+ else if ((flags == O_RDONLY) || (flags == O_WRONLY) || (flags == O_RDWR))
+ fatfsFlags = FA_OPEN_EXISTING;
+ else
+ return set_errno (EINVAL);
+
+ if ((flags & O_ACCMODE) == O_RDONLY)
+ fatfsFlags |= FA_READ;
+ else if ((flags & O_ACCMODE) == O_WRONLY)
+ fatfsFlags |= FA_WRITE;
+ else if ((flags & O_ACCMODE) == O_RDWR)
+ fatfsFlags |= (FA_READ | FA_WRITE);
+ else
+ return set_errno (EINVAL);
+
+ fh = -1;
+ errno = EIO;
+
+ if (!openfiles [slot].fatfsFCB)
+ if ((openfiles [slot].fatfsFCB = __builtin_calloc (1, sizeof (FIL))))
+ if ((fh = ((f = f_open (openfiles [slot].fatfsFCB, path, fatfsFlags)) == FR_OK) ? (slot + MONITOR_FATFS) : -1) == -1)
+ return remap_fatfs_errors (f);
+ }
+
+ if (fh >= 0)
+ {
+ openfiles [slot].handle = fh;
+ openfiles [slot].pos = 0;
+ openfiles [slot].flags = flags;
+ }
+
+ return fh >= 0 ? (fh + FILE_HANDLE_OFFSET) : -1;
+}
+
+int _close (int fd)
+{
+ int slot;
+
+ if ((slot = findslot (remap_handle (fd))) == MAX_OPEN_FILES)
+ return set_errno (EBADF);
+
+ openfiles [slot].handle = -1;
+
+ if (openfiles [slot].fatfsFCB)
+ {
+ FRESULT f;
+
+ f = f_close (openfiles [slot].fatfsFCB);
+ free (openfiles [slot].fatfsFCB);
+ openfiles [slot].fatfsFCB = NULL;
+
+ if (f != FR_OK)
+ return remap_fatfs_errors (f);
+ }
+
+ return 0;
+}
+
+int _kill (int pid __attribute__ ((unused)), int sig __attribute__ ((unused)))
+{
+ return set_errno (ENOTSUP);
+}
+
+void _exit (int status)
+{
+ /* There is only one SWI for both _exit and _kill. For _exit, call
+ the SWI with the second argument set to -1, an invalid value for
+ signum, so that the SWI handler can distinguish the two calls.
+ Note: The RDI implementation of _kill throws away both its
+ arguments. */
+ _kill (status, -1);
+
+ while (1);
+}
+
+int _getpid (int n)
+{
+ return 1;
+ n = n;
+}
+
+caddr_t _sbrk (int incr)
+{
+ extern char end asm ("end"); /* Defined by the linker. */
+ extern unsigned long __heap_max;
+ static char *heap_end;
+ char *prev_heap_end;
+ char *eom;
+
+ if (!heap_end)
+ heap_end = & end;
+
+ prev_heap_end = heap_end;
+
+ //
+ // If FreeRTOS is not running, the stack pointer will be in the SVC region,
+ // and therefore greater than the start of the heap (end of .bss). In this
+ // case, we see if the heap allocation will run past the current stack
+ // pointer, and if so, return ENOMEM (this does not guarantee subsequent
+ // stack operations won't overflow into the heap!).
+ //
+ // If FreeRTOS is running, then we define the end of the heap to be the
+ // start of end of the supervisor stack (since FreeRTOS is running, the
+ // system stack, and very little of the supervisor stack space is used).
+ //
+ eom = (stack_ptr > & end) ? stack_ptr : (char *) __heap_max;
+
+ if (heap_end + incr > eom)
+ {
+ errno = ENOMEM;
+ return (caddr_t) -1;
+ }
+
+ heap_end += incr;
+
+ return (caddr_t) prev_heap_end;
+}
+
+//
+// Tihs is a problem. FatFS has no way to go from a file handle back to a file,
+// since file name information isn't stored with the handle. Tried to think of
+// a good way to handle this, couldn't come up with anything. For now, it
+// returns ENOSYS (not implemented).
+//
+int _fstat (int fd __attribute__ ((unused)), struct stat *st __attribute__ ((unused)))
+{
+ return set_errno (ENOSYS);
+}
+
+int _stat (const char *fname, struct stat *st)
+{
+ FRESULT f;
+ FILINFO fi;
+
+ if ((f = f_stat (fname, &fi)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ __builtin_memset (st, 0, sizeof (* st));
+
+ st->st_mode |= (fi.fattrib & AM_DIR) ? S_IFDIR : S_IFREG;
+ st->st_mode |= (fi.fattrib & AM_RDO) ? ((S_IRWXU & ~S_IWUSR) | (S_IRWXG & ~S_IWGRP) | (S_IRWXO & ~S_IWOTH)) : (S_IRWXU | S_IRWXG | S_IRWXO);
+ st->st_size = fi.fsize;
+ st->st_ctime = fatfs_time_to_timet (&fi);
+ st->st_mtime = st->st_ctime;
+ st->st_atime = st->st_ctime;
+ st->st_blksize = 512;
+
+ return 0;
+}
+
+//
+// FatFS and FAT file systems don't support links
+//
+int _link (void)
+{
+ return set_errno (ENOSYS);
+}
+
+int _unlink (const char *path)
+{
+ FRESULT f;
+
+ if ((f = f_unlink (path)) != FR_OK)
+ return remap_fatfs_errors (f);
+
+ return 0;
+}
+
+void _raise (void)
+{
+ return;
+}
+
+int _gettimeofday (struct timeval *tp, struct timezone *tzp)
+{
+ unsigned int milliseconds;
+
+ if (tp)
+ {
+ tp->tv_sec = rtcGetEpochSeconds (&milliseconds);
+ tp->tv_usec = milliseconds * 1000;
+ }
+
+ //
+ // Return fixed data for the timezone
+ //
+ if (tzp)
+ {
+ tzp->tz_minuteswest = 0;
+ tzp->tz_dsttime = 0;
+ }
+
+ return 0;
+}
+
+//
+// Return a clock that ticks at 100Hz
+//
+clock_t _times (struct tms *tp)
+{
+ clock_t timeval = (clock_t) xTaskGetTickCount ();
+
+ if (tp)
+ {
+ tp->tms_utime = timeval;
+ tp->tms_stime = 0;
+ tp->tms_cutime = 0;
+ tp->tms_cstime = 0;
+ }
+
+ return timeval;
+};
+
+int isatty (int fd)
+{
+ return (fd <= 2) ? 1 : 0; /* one of stdin, stdout, stderr */
+}
+
+int _system (const char *s)
+{
+ if (s == NULL)
+ return 0;
+
+ return set_errno (ENOSYS);
+}
+
+int _rename (const char *oldpath, const char *newpath)
+{
+ FRESULT f;
+
+ if ((f = f_rename (oldpath, newpath)))
+ return remap_fatfs_errors (f);
+
+ return 0;
+}
+
+//
+// Default crossdev -t options for ARM newlib doesn't define HAVE_RENAME, so
+// it's trying to use the link/unlink process. FatFS doesn't support link(),
+// so override the newlib rename() to make it work correctly.
+//
+int rename (const char *oldpath, const char *newpath)
+{
+ return _rename (oldpath, newpath);
+}
+
+void _sync (void)
+{
+ int slot;
+
+ for (slot = 0; slot < MAX_OPEN_FILES; slot++)
+ if (openfiles [slot].fatfsFCB)
+ f_sync (openfiles [slot].fatfsFCB);
+}
--- /dev/null
+SRC_FILES=rtc.c rtcISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/times.h>
+
+#include "rtcISR.h"
+#include "rtc.h"
+
+//
+// Place RTC on 32kHz xtal and disconnect power.
+//
+static inline void rtcSleep (void)
+{
+ RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+ SCB_PCONP &= ~SCB_PCONP_PCRTC;
+}
+
+//
+// Prepare clock for interactive use.
+//
+static inline void rtcWake (void)
+{
+ RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+ SCB_PCONP |= SCB_PCONP_PCRTC;
+}
+
+//
+// Read clock registers and return tm structure.
+//
+static void rtcRead (struct tm *theTime, unsigned int *milliseconds)
+{
+ unsigned int ticks32Khz;
+ rtcCTIME0_t ctime0;
+ rtcCTIME1_t ctime1;
+ rtcCTIME2_t ctime2;
+
+ rtcWake ();
+ portENTER_CRITICAL ();
+
+ do
+ {
+ ctime0.i = RTC_CTIME0;
+ ctime1.i = RTC_CTIME1;
+ ctime2.i = RTC_CTIME2;
+
+ do
+ ticks32Khz = (RTC_CTC & 0xfffe);
+ while (ticks32Khz != (RTC_CTC & 0xfffe));
+ }
+ while (ctime0.i != RTC_CTIME0);
+
+ portEXIT_CRITICAL ();
+ rtcSleep ();
+
+ if (milliseconds)
+ *milliseconds = (((ticks32Khz / 2) * 1000u) / 32768u);
+
+ theTime->tm_sec = ctime0.seconds;
+ theTime->tm_min = ctime0.minutes;
+ theTime->tm_hour = ctime0.hours;
+ theTime->tm_mday = ctime1.dom;
+ theTime->tm_mon = ctime1.month - 1;
+ theTime->tm_year = ctime1.year - 1900;
+ theTime->tm_wday = ctime0.dow;
+ theTime->tm_yday = ctime2.doy - 1;
+ theTime->tm_isdst = 0;
+}
+
+//
+// Set clock to new values.
+//
+static void rtcWrite (struct tm *newTime)
+{
+ rtcWake ();
+ portENTER_CRITICAL ();
+
+ RTC_CCR &= ~RTC_CCR_CLKEN;
+ RTC_CCR |= RTC_CCR_CTCRST;
+
+ RTC_SEC = newTime->tm_sec;
+ RTC_MIN = newTime->tm_min;
+ RTC_HOUR = newTime->tm_hour;
+ RTC_DOM = newTime->tm_mday;
+ RTC_MONTH = newTime->tm_mon + 1;
+ RTC_YEAR = newTime->tm_year + 1900;
+ RTC_DOW = newTime->tm_wday;
+ RTC_DOY = newTime->tm_yday + 1;
+
+ RTC_CCR &= ~RTC_CCR_CTCRST;
+ RTC_CCR |= RTC_CCR_CLKEN;
+
+ portEXIT_CRITICAL ();
+ rtcSleep ();
+}
+
+//
+//
+//
+time_t rtcGetEpochSeconds (unsigned int *milliseconds)
+{
+ struct tm tm;
+
+ rtcRead (&tm, milliseconds);
+ return mktime (&tm);
+}
+
+void rtcSetEpochSeconds (time_t now)
+{
+ struct tm tm;
+
+ localtime_r (&now, &tm);
+ rtcWrite (&tm);
+}
+
+//
+// Start clock so that the sytsem may use it.
+//
+static void rtcInitClockCalendar (void)
+{
+ int nonsense = 0;
+ rtcCTIME0_t ctime0;
+ rtcCTIME1_t ctime1;
+ rtcCTIME2_t ctime2;
+
+ rtcWake ();
+
+ ctime0.i = RTC_CTIME0;
+ ctime1.i = RTC_CTIME1;
+ ctime2.i = RTC_CTIME2;
+
+ //
+ // Leisurely tear the packed time apart into individual time.
+ //
+ if ((ctime0.seconds < 0) || (ctime0.seconds > 59)) nonsense = 1;
+ if ((ctime0.minutes < 0) || (ctime0.minutes > 59)) nonsense = 1;
+ if ((ctime0.hours < 0) || (ctime0.hours > 23)) nonsense = 1;
+ if ((ctime1.dom < 1) || (ctime1.dom > 31)) nonsense = 1;
+ if ((ctime1.month < 1) || (ctime1.month > 12)) nonsense = 1;
+ if ((ctime1.year < 1980) || (ctime1.year > 2050)) nonsense = 1;
+ if ((ctime0.dow < 0) || (ctime0.dow > 6)) nonsense = 1;
+ if ((ctime2.doy < 0) || (ctime2.doy > 366)) nonsense = 1;
+
+ rtcSleep ();
+
+ //
+ // Set the clock to Jan 1, 2006 00:00:00
+ //
+ if (nonsense)
+ rtcSetEpochSeconds ((time_t) 1136073600);
+}
+
+//
+//
+//
+void rtcInit (void)
+{
+ rtcISRInit ();
+
+ SCB_PCONP |= SCB_PCONP_PCRTC;
+
+ RTC_CCR = 0;
+
+ RTC_CCR |= RTC_CCR_CLKSRC;
+
+ RTC_AMR = RTC_AMR_AMRMASK;
+ RTC_CIIR = 0;
+
+ RTC_ILR = RTC_ILR_MASK;
+
+ RTC_CCR |= RTC_CCR_CLKEN;
+
+ VIC_IntSelect &= ~VIC_IntSelect_RTC;
+#ifdef RTC_NONVECTOREDIRQ
+ VIC_DefVectAddr = (portLONG) rtcISR;
+#else
+ VIC_VectAddr6 = (portLONG) rtcISR;
+ VIC_VectCntl6 = VIC_VectCntl_ENABLE | VIC_Channel_RTC;
+#endif
+ VIC_IntEnable = VIC_IntEnable_RTC;
+
+ rtcInitClockCalendar ();
+}
+
+int rtcSetAlarm (struct tm *tm)
+{
+ if (tm && (mktime (tm) < time (NULL)))
+ return -1;
+
+ rtcWake ();
+
+ RTC_AMR = RTC_AMR_AMRMASK;
+
+ if (tm)
+ {
+ RTC_ALYEAR = tm->tm_year + 1900;
+ RTC_ALMON = tm->tm_mon + 1;
+ RTC_ALDOM = tm->tm_mday;
+ RTC_ALHOUR = tm->tm_hour;
+ RTC_ALMIN = tm->tm_min;
+ RTC_ALSEC = tm->tm_sec;
+ RTC_ALDOW = 0;
+ RTC_ALDOY = 0;
+
+ RTC_AMR = RTC_AMR_AMRDOW | RTC_AMR_AMRDOY;
+ }
+
+ rtcSleep ();
+
+ return 0;
+}
+
+struct tm *rtcGetAlarmTm (struct tm *tm)
+{
+ if (tm)
+ {
+ memset (tm, 0, sizeof (* tm));
+
+ rtcWake ();
+
+ if (RTC_AMR != RTC_AMR_AMRMASK)
+ {
+ tm->tm_year = RTC_ALYEAR - 1900;
+ tm->tm_mon = RTC_ALMON - 1;
+ tm->tm_mday = RTC_ALDOM;
+ tm->tm_hour = RTC_ALHOUR;
+ tm->tm_min = RTC_ALMIN;
+ tm->tm_sec = RTC_ALSEC;
+ }
+ else
+ {
+ time_t now = 0;
+ memcpy (tm, localtime (&now), sizeof (* tm));
+ }
+
+ rtcSleep ();
+ }
+
+ return tm;
+}
+
+time_t rtcGetAlarmEpochSeconds (void)
+{
+ struct tm tm;
+
+ return mktime (rtcGetAlarmTm (&tm));
+}
+
+int rtcPeriodicAlarm (int mode)
+{
+ int state;
+
+ rtcWake ();
+
+ state = RTC_CIIR & RTC_CIIR_IMMIN;
+
+ if (!mode)
+ RTC_CIIR &= ~RTC_CIIR_IMMIN;
+ else if (mode > 0)
+ RTC_CIIR |= RTC_CIIR_IMMIN;
+
+ rtcSleep ();
+
+ return state ? 1 : 0;
+}
--- /dev/null
+#ifndef _RTC_H_
+#define _RTC_H_
+
+#include <time.h>
+
+//
+// Define this for using non-vectored IRQs. Undef it if a regular vectored
+// IRQ is preferred.
+//
+#define RTC_NONVECTOREDIRQ
+
+//
+//
+//
+void rtcInit (void);
+time_t rtcGetEpochSeconds (unsigned int *milliseconds);
+void rtcSetEpochSeconds (time_t now);
+int rtcSetAlarm (struct tm *tm);
+struct tm *rtcGetAlarmTm (struct tm *tm);
+time_t rtcGetAlarmEpochSeconds (void);
+int rtcPeriodicAlarm (int mode);
+
+#endif
--- /dev/null
+#include <stdlib.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../uart/uart.h"
+#include "../usbser/usbser.h"
+#include "rtcISR.h"
+#include "rtc.h"
+
+//
+//
+//
+static xQueueHandle consoleQueue = NULL;
+
+//
+//
+//
+void rtcISRInit (void)
+{
+#if defined CFG_CONSOLE_USB
+ usbserGetRxQueue (&consoleQueue);
+#elif defined CFG_CONSOLE_UART0
+ uart0GetRxQueue (&consoleQueue);
+#elif defined CFG_CONSOLE_UART1
+ uart1GetRxQueue (&consoleQueue);
+#else
+#error "Eeek! No console devices defined!"
+#endif
+}
+
+//
+//
+//
+void rtcISR (void) __attribute__ ((naked));
+void rtcISR (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ portBASE_TYPE taskWoken = pdFALSE;
+
+ RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+ SCB_PCONP |= SCB_PCONP_PCRTC;
+
+ if (RTC_ILR & RTC_ILR_RTCCIF)
+ {
+ U8 c = 0xff;
+
+ if (consoleQueue && xQueueSendFromISR (consoleQueue, &c, (portBASE_TYPE) pdFALSE))
+ taskWoken = pdTRUE;
+
+ RTC_ILR = RTC_ILR_RTCCIF;
+ }
+
+ if (RTC_ILR & RTC_ILR_RTCALF)
+ {
+ U8 c = 0xfe;
+
+ if (consoleQueue && xQueueSendFromISR (consoleQueue, &c, (portBASE_TYPE) pdFALSE))
+ taskWoken = pdTRUE;
+
+ RTC_ILR = RTC_ILR_RTCALF;
+ }
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ RTC_CCR = (RTC_CCR_CLKEN | RTC_CCR_CLKSRC);
+ SCB_PCONP &= ~SCB_PCONP_PCRTC;
+
+ portEXIT_SWITCHING_ISR (taskWoken);
+}
--- /dev/null
+#ifndef _RTCISR_H_
+#define _RTCISR_H_
+
+void rtcISRInit (void);
+void rtcISR (void);
+
+#endif
+
--- /dev/null
+SRC_FILES=sensors.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+//
+//
+//
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+#include "../main.h"
+#include "../adc/adc.h"
+#include "../dac/dac.h"
+#include "../leds/leds.h"
+#include "sensors.h"
+
+//
+//
+//
+static sensorData_t sensorData;
+static xSemaphoreHandle semaphore;
+
+//
+// Return 1 if got a copy, 0 if not.
+//
+int sensorsCopyData (sensorData_t *dst)
+{
+ if (xSemaphoreTake (semaphore, 100 / portTICK_RATE_MS) == pdTRUE)
+ {
+ memcpy (dst, &sensorData, sizeof (sensorData));
+ xSemaphoreGive (semaphore);
+ return 1;
+ }
+
+ memset (dst, 0, sizeof (sensorData_t));
+ return 0;
+}
+
+//
+//
+//
+portTASK_FUNCTION (vSensorsTask, pvParameters __attribute__ ((unused)))
+{
+ portTickType xTickCount;
+ int adcValue;
+ int adcLastValue = -1;
+ int adcChanged = -1;
+ int dacValue = 0;
+ int dacDirection = -16;
+
+ memset (&sensorData, 0, sizeof (sensorData));
+
+ vSemaphoreCreateBinary (semaphore);
+
+ xTickCount = xTaskGetTickCount ();
+
+ for (;;)
+ {
+ vTaskDelayUntil (&xTickCount, 100 / portTICK_RATE_MS);
+
+ //
+ // Adjust the DAC value so we output a slow sine wave
+ //
+ if ((dacValue <= 0) || (dacValue >= (1024 - dacDirection)))
+ dacDirection = 0 - dacDirection;
+
+ dacSet (dacValue);
+ dacValue += dacDirection;
+
+ //
+ // Read the current ADC value, keep only top 2 bits. If it changes,
+ // tell the LED task to change the blink rate.
+ //
+ if ((adcValue = (adcRead0_3 () >> 8)) != adcLastValue)
+ {
+ xQueueSend (xLEDQueue, &adcValue, (portTickType) 0);
+ adcLastValue = adcValue;
+ adcChanged++;
+ }
+
+ //
+ // Update the sensors data
+ //
+ if (xSemaphoreTake (semaphore, portMAX_DELAY) == pdTRUE)
+ {
+ sensorData.sensorCount++;
+ sensorData.adcChanges = adcChanged;
+
+ xSemaphoreGive (semaphore);
+ }
+ }
+}
--- /dev/null
+#ifndef _SENSORS_H_
+#define _SENSORS_H_
+
+#include "semphr.h"
+
+//
+//
+//
+typedef struct sensorData_s
+{
+ int sensorCount;
+ int adcChanges;
+}
+sensorData_t;
+
+//
+//
+//
+int sensorsCopyData (sensorData_t *dst);
+portTASK_FUNCTION_PROTO (vSensorsTask, pvParameters __attribute__ ((unused)));
+
+#endif
--- /dev/null
+SRC_FILES=swi.c
+ASMSRC_FILES=swidispatch.s
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+ARM_ASMOBJ = $(ASMSRC_FILES:.s=.o)
+
+.PHONY: all
+all: $(ARM_OBJ) $(ARM_ASMOBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+$(ARM_ASMOBJ) : %.o : %.s Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+
+#include "swi.h"
+
+//
+//
+//
+#define LED2 GPIO_IO_P11
+
+//
+//
+//
+void swiInit (void)
+{
+}
+
+int swiDispatchC (unsigned long r0, unsigned long r1 __attribute__ ((unused)), unsigned long r2 __attribute__ ((unused)), unsigned long swi)
+{
+ int state = 0;
+
+ switch (swi)
+ {
+ case SWICALL_YIELDPROCESSOR :
+ case SWICALL_A_LED2SET :
+ case SWICALL_A_LED2ON :
+ case SWICALL_A_LED2OFF :
+ case SWICALL_A_LED2TOGGLE :
+ printf ("Eeek! This should have been handled in the asm code\n");
+ break;
+
+ case SWICALL_C_LED2SET :
+ {
+ state = GPIO0_IOPIN & LED2;
+
+ if (r0)
+ GPIO0_IOSET = LED2;
+ else
+ GPIO0_IOCLR = LED2;
+ }
+ break;
+
+ case SWICALL_C_LED2ON :
+ {
+ state = GPIO0_IOPIN & LED2;
+ GPIO0_IOCLR = LED2;
+ }
+ break;
+
+ case SWICALL_C_LED2OFF :
+ {
+ state = GPIO0_IOPIN & LED2;
+ GPIO0_IOSET = LED2;
+ }
+ break;
+
+ case SWICALL_C_LED2TOGGLE :
+ {
+ if ((state = GPIO0_IOPIN & LED2))
+ GPIO0_IOCLR = LED2;
+ else
+ GPIO0_IOSET = LED2;
+ }
+ break;
+
+ default :
+ printf ("Eeek! Unhandled SWI value\n");
+ break;
+ }
+
+ return state;
+}
--- /dev/null
+#ifndef _SWI_H_
+#define _SWI_H_
+
+//
+//
+//
+typedef enum
+{
+ SWICALL_YIELDPROCESSOR = 0, // FreeRTOS xYieldTask (asm)
+ SWICALL_A_LED2SET, // Set LED2 on or off, return previous state (asm)
+ SWICALL_A_LED2ON, // LED2 on, return previous state (asm)
+ SWICALL_A_LED2OFF, // LED2 off, return previous state (asm)
+ SWICALL_A_LED2TOGGLE, // LED2 toggle, return previous state (asm)
+ SWICALL_C_LED2SET, // Set LED2 on or off, return previous state (C)
+ SWICALL_C_LED2ON, // LED2 on, return previous state (C)
+ SWICALL_C_LED2OFF, // LED2 off, return previous state (C)
+ SWICALL_C_LED2TOGGLE, // LED2 toggle, return previous state (C)
+}
+swiCalls_e;
+
+//
+//
+//
+#define SWICALL(swiID, swiOut) \
+ asm volatile (\
+ "swi %a1 \n\t" \
+ "mov %0,r0 \n\t" \
+ : "=r" (swiOut) : "I" (swiID) : "r0", "lr")
+
+#define SWICALL1(swiID, swiIn, swiOut) \
+ asm volatile (\
+ "mov r0,%1 \t\n" \
+ "swi %a2 \n\t" \
+ "mov %0,r0 \n\t" \
+ : "=r" (swiOut) : "r" (swiIn), "I" (swiID) : "r0", "lr")
+
+#define SWICALL2(swiID, swiIn1, swiIn2, swiOut) \
+ asm volatile ( \
+ "mov r0,%1 \t\n" \
+ "mov r1,%2 \t\n" \
+ "swi %a3 \n\t" \
+ "mov %0,r0 \n\t" \
+ : "=r" (swiOut) : "r" (swiIn1), "r" (swiIn2), "I" (swiID) : "r0", "lr")
+
+#define SWICALL3(swiID, swiIn1, swiIn2, swiIn3, swiOut) \
+ asm volatile ( \
+ "mov r0,%1 \t\n" \
+ "mov r1,%2 \t\n" \
+ "mov r2,%3 \t\n" \
+ "swi %a4 \n\t" \
+ "mov %0,r0 \n\t" \
+ : "=r" (swiOut) : "r" (swiIn1), "r" (swiIn2), "r" (swiIn3), "I" (swiID) : "r0", "lr")
+
+//
+//
+//
+void swiInit (void);
+int swiDispatchC (unsigned long r0, unsigned long r1, unsigned long r2, unsigned long swi);
+
+#endif
--- /dev/null
+@
+@ This code expects to find a function named 'swiDispatchC' (which should be
+@ in swi.c) to dispatch any functions that aren't written in assembly.
+@ (What nut-case picked '@' as the comment character for .s files?)
+@
+ .text
+ .extern swiDispatchC
+ .global swiDispatch
+ .func swiDispatch
+
+@
+@ Equates for GPIO0 registers
+@
+ .set GPIO0_IOPIN, 0xe0028000
+ .set GPIO0_IOSET, 0xe0028004
+ .set GPIO0_IODIR, 0xe0028008
+ .set GPIO0_IOCLR, 0xe002800c
+ .set GPIO_IO_P11, 0x00000800
+
+@
+@ No check for Thumb mode. The LPC2148 demo code doesn't do Thumb
+@
+swiDispatch:
+ stmfd sp!, {r4, lr} @ Save r4, lr
+ ldr r4, [lr, #-4] @ Fetch the SWI instruction that invoked us
+ bic r4, r4, #0xff000000 @ Clear top 8 bits leaving swi "comment field"=number
+ cmp r4, #SWI_LAST @ <= SWI_LAST, handled in assembly, otherwise, in C handler
+ ldrls pc, [pc, r4, lsl #2] @ If <= SWI_LAST, we're handling it in assembly
+ b swiDispatchToC @ Not handled in here, switch to the C handler
+
+@
+@ Dispatch table for functions in assembly. The swiEntriesStart label isn't
+@ referenced directly by the code. Rather, it must directly follow the
+@ swiDispatch code, because it is relatively referenced.
+@
+swiEntriesStart:
+ .word swiPYP @ 0 - FreeRTOS Yield Process
+ .word LED2Set @ 1 - Set LED2 state, return previous state
+ .word LED2On @ 2 - Turn LED2 on, return previous state
+ .word LED2Off @ 3 - Turn LED2 off, return previous state
+ .word LED2Toggle @ 4 - Toggle LED2, return previous state
+swiEntriesEnd:
+ .set SWI_LAST, ((swiEntriesEnd-swiEntriesStart)/4)-1
+
+@
+@ FreeRTOS uses SWI to yield process, but it's greedy and wants SWI all to its
+@ self. So... Special handling it is!
+@
+swiPYP:
+ ldmfd sp!, {r4, lr} @ Recover r4, lr
+ b vPortYieldProcessor @ Yield... yield like the wind!
+
+@
+@ Values are returned in r0. LED2 is hardwired in this code (bad programmer!) Also
+@ remember that LED2 (and LED1) have their anodes tied to +3.3V, so we have to drive
+@ the port pin LOW to turn them on. When the caller wants to turn an LED off, it
+@ passes in a non-zero value (keeping the same software logic as the hardware logic)
+@
+LED2Set:
+ stmfd sp!, {r1} @ Save r1
+ cmp r0, #0 @ Turn LED2 off?
+ ldreq r4, =GPIO0_IOCLR @ Get GPIO0_IOCLR address (0 == on)
+ ldrne r4, =GPIO0_IOSET @ Get GPIO0_IOSET address (!0 == off)
+ ldr r0, =GPIO0_IOPIN @ Load GPIO0_IOPIN address
+ ldr r0, [r0] @ Get GPIO0_IOPIN contents
+ ldr r1, =GPIO_IO_P11 @ Constant for port pin LED2 attached to
+ and r0, r0, r1 @ R0 has bit that reflects LED2 current state
+ str r1, [r4] @ Set LED2 on
+ ldmfd sp!, {r1} @ Recover r1
+ b swiExit @ Exit SWI handler
+
+LED2On:
+ stmfd sp!, {r1} @ Save r1
+ ldr r0, =GPIO0_IOPIN @ Load GPIO0_IOPIN address
+ ldr r0, [r0] @ Get GPIO0_IOPIN contents
+ ldr r1, =GPIO_IO_P11 @ Constant for port pin LED2 attached to
+ and r0, r0, r1 @ R0 has bit that reflects LED2 current state
+ ldr r4, =GPIO0_IOCLR @ Get GPIO0_IOCLR address
+ str r1, [r4] @ Set LED2 on
+ ldmfd sp!, {r1} @ Recover r1
+ b swiExit @ Exit SWI handler
+
+LED2Off:
+ stmfd sp!, {r1} @ Save r1
+ ldr r0, =GPIO0_IOPIN @ Load GPIO0_IOPIN address
+ ldr r0, [r0] @ Get GPIO0_IOPIN contents
+ ldr r1, =GPIO_IO_P11 @ Constant for port pin LED2 attached to
+ and r0, r0, r1 @ R0 has bit that reflects LED2 current state
+ ldr r4, =GPIO0_IOSET @ Get GPIO0_IOSET address
+ str r1, [r4] @ Set LED2 off
+ ldmfd sp!, {r1} @ Recover r1
+ b swiExit @ Exit SWI handler
+
+LED2Toggle:
+ stmfd sp!, {r1} @ Save r1
+ ldr r0, =GPIO0_IOPIN @ Load GPIO0_IOPIN address
+ ldr r0, [r0] @ Get GPIO0_IOPIN contents
+ ldr r1, =GPIO_IO_P11 @ Constant for port pin LED2 attached to
+ ands r0, r0, r1 @ R0 has bit that reflects LED2 current state
+ ldrne r4, =GPIO0_IOCLR @ Get GPIO0_IOCLR address (!0 == off, so turn on)
+ ldreq r4, =GPIO0_IOSET @ Get GPIO0_IOSET address (0 == on, so turn off)
+ str r1, [r4] @ Set LED2 off
+ ldmfd sp!, {r1} @ Recover r1
+ b swiExit @ Exit SWI handler
+
+@
+@ Not an internal function, try the C dispatch handler. r0, r1, r2 will be
+@ passed through as set. r3 will contain the SWI number. Return value will
+@ be in r0.
+@
+swiDispatchToC:
+ stmfd sp!,{r1-r12, lr} @ Save r1..r12, lr on stack
+ mrs r12, spsr @ Saved Process Status Register (SPSR) to r12
+ stmfd sp!, {r12} @ Save r12
+ ldr r12, =swiDispatchC @ Get the address of the C handler function
+ mov r3, r4 @ Pass SWI number as parameter in r3
+ mov lr, pc @ Save current PC to lr
+ bx r12 @ Branch to r12 (C handler function), return to next instruction
+ ldmfd sp!, {r12} @ Recover old SPSR to r12
+ msr spsr_cxsf, r12 @ Set SPSR from r12
+ ldmfd sp!, {r1-r12, pc}^ @ Recover r1..r12, return value in r0
+ b swiExit @ And exit
+
+@
+@ Exit SWI handler. Recover r4, return to caller
+@
+swiExit:
+ ldmfd sp!, {r4, pc}^ @ Recover r4, return to caller
+
+ .endfunc
+ .end
--- /dev/null
+#ifndef _SYSDEFS_H_
+#define _SYSDEFS_H_
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+typedef unsigned char U8;
+typedef signed char N8;
+typedef unsigned short U16;
+typedef signed short N16;
+typedef unsigned int U32;
+typedef signed int N32;
+typedef int BOOL;
+
+typedef volatile U8 REG8;
+typedef volatile U16 REG16;
+typedef volatile U32 REG32;
+
+#define pREG8 (REG8 *)
+#define pREG16 (REG16 *)
+#define pREG32 (REG32 *)
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+#define MAX(x,y)((x)>(y)?(x):(y))
+#define arrsizeof(x) ((sizeof (x))/(sizeof (x [0])))
+
+//
+// Yuck. Don't like this here, but what the heck...
+//
+#if !defined CFG_CONSOLE_USB && !defined CFG_CONSOLE_UART0 && !defined CFG_CONSOLE_UART1
+#error "Must define CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1
+#endif
+
+#if defined CFG_CONSOLE_USB && (defined CFG_CONSOLE_UART0 || defined CFG_CONSOLE_UART1)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+#if defined CFG_CONSOLE_UART0 && (defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART1)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+#if defined CFG_CONSOLE_UART1 && (defined CFG_CONSOLE_USB || defined CFG_CONSOLE_UART0)
+#error "Only one of CFG_CONSOLE_USB, CFG_CONSOLE_UART0 or CFG_CONSOLE_UART1 may be defined"
+#endif
+
+#endif
--- /dev/null
+SRC_FILES=uart.c uartISR.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*
+ INTERRUPT DRIVEN SERIAL PORT DRIVER FOR UART0 and UART1.
+
+ This file contains all the serial port components that can be compiled to
+ either ARM or THUMB mode. Components that must be compiled to ARM mode are
+ contained in serialISR.c.
+ */
+
+//
+// Standard includes
+//
+#include <stdlib.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+//
+// Demo application includes
+//
+#include "uart.h"
+#include "uartISR.h"
+
+//
+// Constants to setup and access the UART
+//
+#define serWANTED_CLOCK_SCALING ((unsigned portLONG) 16)
+
+//
+// Constants to setup and access the VIC
+//
+#define serINVALID_QUEUE ((xQueueHandle) 0)
+#define serHANDLE ((xComPortHandle) 1)
+#define serNO_BLOCK ((portTickType) 0)
+
+//
+// Queues used to hold received characters, and characters waiting to be transmitted
+//
+static xQueueHandle xRX0Queue;
+static xQueueHandle xTX0Queue;
+static xQueueHandle xRX1Queue;
+static xQueueHandle xTX1Queue;
+
+//
+// Communication flag between the interrupt service routine and serial API
+//
+static volatile portLONG *plTHREEmpty;
+static volatile portLONG *plTHREEmpty1;
+
+//
+//
+//
+xComPortHandle uartInit (portCHAR pxPort, unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength)
+{
+ unsigned portLONG ulDivisor;
+ unsigned portLONG ulWantedClock;
+ xComPortHandle xReturn = serHANDLE;
+
+ switch (pxPort)
+ {
+ case 0 :
+ {
+ uartISRCreateQueues (0, uxQueueLength, &xRX0Queue, &xTX0Queue, &plTHREEmpty);
+
+ if ((xRX0Queue != serINVALID_QUEUE) &&
+ (xTX0Queue != serINVALID_QUEUE) &&
+ (ulWantedBaud != (unsigned portLONG) 0)
+ )
+ {
+ portENTER_CRITICAL ();
+
+ {
+ SCB_PCONP |= SCB_PCONP_PCUART0;
+
+ //
+ // Setup the baud rate: Calculate the divisor value
+ //
+ ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
+ ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
+
+ //
+ // Set the DLAB bit so we can access the divisor
+ //
+ UART0_LCR |= UART_LCR_DLAB;
+
+ //
+ // Setup the divisor
+ //
+ UART0_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+ ulDivisor >>= 8;
+ UART0_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+
+ //
+ // Turn on the FIFO's and clear the buffers
+ //
+ UART0_FCR = UART_FCR_EN | UART_FCR_CLR;
+
+ //
+ // Setup transmission format
+ //
+ UART0_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
+
+ //
+ // Setup the VIC for the UART
+ //
+ VIC_IntSelect &= ~VIC_IntSelect_UART0;
+ VIC_VectAddr2 = (portLONG) uartISR0;
+ VIC_VectCntl2 = VIC_VectCntl_ENABLE | VIC_Channel_UART0;
+ VIC_IntEnable = VIC_IntEnable_UART0;
+
+ //
+ // Enable UART0 interrupts
+ //
+ UART0_IER |= UART_IER_EI;
+ }
+
+ portEXIT_CRITICAL ();
+ }
+ else
+ xReturn = (xComPortHandle) 0;
+ }
+ break;
+
+ case 1:
+ {
+ uartISRCreateQueues (1, uxQueueLength, &xRX1Queue, &xTX1Queue, &plTHREEmpty1);
+
+ if ((xRX1Queue != serINVALID_QUEUE) &&
+ (xTX1Queue != serINVALID_QUEUE) &&
+ (ulWantedBaud != (unsigned portLONG) 0)
+ )
+ {
+ portENTER_CRITICAL ();
+
+ {
+ SCB_PCONP |= SCB_PCONP_PCUART1;
+
+ //
+ // Setup the baud rate: Calculate the divisor value
+ //
+ ulWantedClock = ulWantedBaud * serWANTED_CLOCK_SCALING;
+ ulDivisor = configCPU_CLOCK_HZ / ulWantedClock;
+
+ //
+ // Set the DLAB bit so we can access the divisor
+ //
+ UART1_LCR |= UART_LCR_DLAB;
+
+ //
+ // Setup the divisor
+ //
+ UART1_DLL = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+ ulDivisor >>= 8;
+ UART1_DLM = (unsigned portCHAR) (ulDivisor & (unsigned portLONG) 0xff);
+
+ //
+ // Turn on the FIFO's and clear the buffers
+ //
+ UART1_FCR = UART_FCR_EN | UART_FCR_CLR;
+
+ //
+ // Setup transmission format
+ //
+ UART1_LCR = UART_LCR_NOPAR | UART_LCR_1STOP | UART_LCR_8BITS;
+
+ //
+ // Setup the VIC for the UART
+ //
+ VIC_IntSelect &= ~VIC_IntSelect_UART1;
+ VIC_VectAddr3 = (portLONG) uartISR1;
+ VIC_VectCntl3 = VIC_VectCntl_ENABLE | VIC_Channel_UART1;
+ VIC_IntEnable = VIC_IntEnable_UART1;
+
+ //
+ // Enable UART0 interrupts//
+ //
+ UART1_IER |= UART_IER_EI;
+ }
+
+ portEXIT_CRITICAL ();
+ }
+ else
+ xReturn = (xComPortHandle) 0;
+ }
+ break;
+ }
+
+ return xReturn;
+}
+
+signed portBASE_TYPE uartGetChar (portCHAR pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime)
+{
+ switch (pxPort)
+ {
+ //
+ // Get the next character from the buffer. Return false if no characters are available, or arrive before xBlockTime expires
+ //
+ case 0:
+ {
+ if (xQueueReceive (xRX0Queue, pcRxedChar, xBlockTime))
+ return pdTRUE;
+ else
+ return pdFALSE;
+ }
+ break;
+
+ //
+ // Get the next character from the buffer. Return false if no characters are available, or arrive before xBlockTime expires
+ //
+ case 1:
+ {
+ if (xQueueReceive (xRX1Queue, pcRxedChar, xBlockTime))
+ return pdTRUE;
+ else
+ return pdFALSE;
+ }
+ break;
+ }
+
+ return pdFALSE;
+}
+
+//
+//
+//
+void uartPutString (portCHAR pxPort, const signed portCHAR * const pcString, portTickType xBlockTime)
+{
+ signed portCHAR *pxNext;
+
+ pxNext = (signed portCHAR *) pcString;
+
+ while (*pxNext)
+ {
+ uartPutChar (pxPort, *pxNext, xBlockTime);
+ pxNext++;
+ }
+}
+
+//
+//
+//
+signed portBASE_TYPE uartPutChar (portCHAR pxPort, signed portCHAR cOutChar, portTickType xBlockTime)
+{
+ signed portBASE_TYPE xReturn = 0;
+
+ switch (pxPort)
+ {
+ case 0 :
+ {
+ portENTER_CRITICAL ();
+
+ {
+ //
+ // Is there space to write directly to the UART?
+ //
+ if (*plTHREEmpty == (portLONG) pdTRUE)
+ {
+ *plTHREEmpty = pdFALSE;
+ UART0_THR = cOutChar;
+ xReturn = pdPASS;
+ }
+ else
+ {
+ //
+ // We cannot write directly to the UART, so queue the character. Block for a maximum of
+ // xBlockTime if there is no space in the queue.
+ //
+ xReturn = xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
+
+ //
+ // Depending on queue sizing and task prioritisation: While we were blocked waiting to post
+ // interrupts were not disabled. It is possible that the serial ISR has emptied the Tx queue,
+ // in which case we need to start the Tx off again.
+ //
+ if ((*plTHREEmpty == (portLONG) pdTRUE) && (xReturn == pdPASS))
+ {
+ xQueueReceive (xTX0Queue, &cOutChar, serNO_BLOCK);
+ *plTHREEmpty = pdFALSE;
+ UART0_THR = cOutChar;
+ }
+ }
+ }
+
+ portEXIT_CRITICAL ();
+ }
+ break;
+
+ case 1 :
+ {
+ portENTER_CRITICAL ();
+
+ {
+ //
+ // Is there space to write directly to the UART?
+ //
+ if (*plTHREEmpty1 == (portLONG) pdTRUE)
+ {
+ *plTHREEmpty1 = pdFALSE;
+ UART1_THR = cOutChar;
+ xReturn = pdPASS;
+ }
+ else
+ {
+ //
+ // We cannot write directly to the UART, so queue the character. Block for a maximum of
+ // xBlockTime if there is no space in the queue.
+ //
+ xReturn = xQueueSend (xTX1Queue, &cOutChar, xBlockTime);
+
+ //
+ // Depending on queue sizing and task prioritisation: While we were blocked waiting to post
+ // interrupts were not disabled. It is possible that the serial ISR has emptied the Tx queue,
+ // in which case we need to start the Tx off again.
+ //
+ if ((*plTHREEmpty1 == (portLONG) pdTRUE) && (xReturn == pdPASS))
+ {
+ xQueueReceive (xTX1Queue, &cOutChar, serNO_BLOCK);
+ *plTHREEmpty1 = pdFALSE;
+ UART1_THR = cOutChar;
+ }
+ }
+ }
+
+ portEXIT_CRITICAL ();
+ }
+ break;
+
+ default:
+ return xReturn;
+ break;
+ }
+
+ return xReturn;
+}
+
+//
+//
+//
+void uart0GetRxQueue (xQueueHandle *qh)
+{
+ *qh = xRX0Queue;
+}
+
+void uart1GetRxQueue (xQueueHandle *qh)
+{
+ *qh = xRX1Queue;
+}
--- /dev/null
+#ifndef _UART_H_
+#define _UART_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+typedef void *xComPortHandle;
+
+xComPortHandle uartInit (portCHAR pxPort, unsigned portLONG ulWantedBaud, unsigned portBASE_TYPE uxQueueLength);
+void uartPutString (portCHAR pxPort, const signed portCHAR * const pcString, portTickType xBlockTime);
+signed portBASE_TYPE uartGetChar (portCHAR pxPort, signed portCHAR *pcRxedChar, portTickType xBlockTime);
+signed portBASE_TYPE uartPutChar (portCHAR pxPort, signed portCHAR cOutChar, portTickType xBlockTime);
+void uartClose (portCHAR xPort);
+void uart0GetRxQueue (xQueueHandle *qh);
+void uart1GetRxQueue (xQueueHandle *qh);
+
+#endif
--- /dev/null
+//
+// Standard includes
+//
+#include <stdlib.h>
+
+//
+// Scheduler includes
+//
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+//
+// Demo application includes
+//
+#include "uart.h"
+#include "uartISR.h"
+
+//
+// Constants to determine the ISR source
+//
+#define serSOURCE_THRE ((unsigned portCHAR) 0x02)
+#define serSOURCE_RX_TIMEOUT ((unsigned portCHAR) 0x0c)
+#define serSOURCE_ERROR ((unsigned portCHAR) 0x06)
+#define serSOURCE_RX ((unsigned portCHAR) 0x04)
+#define serINTERRUPT_SOURCE_MASK ((unsigned portCHAR) 0x0f)
+
+//
+// Queues used to hold received characters, and characters waiting to be transmitted
+//
+static xQueueHandle xRX0Queue;
+static xQueueHandle xTX0Queue;
+static volatile portLONG lTHREEmpty0;
+static xQueueHandle xRX1Queue;
+static xQueueHandle xTX1Queue;
+static volatile portLONG lTHREEmpty1;
+
+//
+//
+//
+void uartISRCreateQueues (portCHAR pxPort, unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRX0Queue, xQueueHandle *pxTX0Queue, portLONG volatile **pplTHREEmptyFlag)
+{
+ switch (pxPort)
+ {
+ case 0:
+ {
+ //
+ // Create the queues used to hold Rx and Tx characters
+ //
+ *pxRX0Queue = xRX0Queue = xQueueCreate (uxQueueLength, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+ *pxTX0Queue = xTX0Queue = xQueueCreate (uxQueueLength + 1, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+
+ //
+ // Initialise the THRE empty flag - and pass back a reference
+ //
+ lTHREEmpty0 = (portLONG) pdTRUE;
+ *pplTHREEmptyFlag = &lTHREEmpty0;
+ }
+ break;
+
+ case 1:
+ {
+ //
+ // Create the queues used to hold Rx and Tx characters
+ //
+ *pxRX0Queue = xRX1Queue = xQueueCreate (uxQueueLength, (unsigned portCHAR) sizeof (signed portCHAR));
+ *pxTX0Queue = xTX1Queue = xQueueCreate (uxQueueLength + 1, (unsigned portCHAR) sizeof (signed portCHAR));
+
+ //
+ // Initialise the THRE empty flag - and pass back a reference
+ //
+ lTHREEmpty1 = (portLONG) pdTRUE;
+ *pplTHREEmptyFlag = &lTHREEmpty1;
+ }
+ break;
+ }
+}
+
+//
+//
+//
+void uartISR0 (void) __attribute__ ((naked));
+void uartISR0 (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ signed portCHAR cChar;
+ portBASE_TYPE xTaskWokenByTx = pdFALSE;
+ portBASE_TYPE xTaskWokenByRx = pdFALSE;
+
+ switch (UART0_IIR & serINTERRUPT_SOURCE_MASK)
+ {
+ //
+ // Not handling this, but clear the interrupt
+ //
+ case serSOURCE_ERROR :
+ {
+ cChar = UART0_LSR;
+ }
+ break;
+
+ //
+ // The THRE is empty. If there is another character in the Tx queue, send it now,
+ // otherwise, no more characters, so indicate THRE is available
+ //
+ case serSOURCE_THRE :
+ {
+ if (xQueueReceiveFromISR (xTX0Queue, &cChar, &xTaskWokenByTx) == pdTRUE)
+ UART0_THR = cChar;
+ else
+ lTHREEmpty0 = pdTRUE;
+ }
+ break;
+
+ //
+ // A character was received. Place it in the queue of received characters
+ //
+ case serSOURCE_RX_TIMEOUT :
+ case serSOURCE_RX :
+ {
+ cChar = UART0_RBR;
+
+ if (xQueueSendFromISR (xRX0Queue, &cChar, (portBASE_TYPE) pdFALSE))
+ xTaskWokenByRx = pdTRUE;
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ portEXIT_SWITCHING_ISR ((xTaskWokenByTx || xTaskWokenByRx));
+}
+
+//
+//
+//
+void uartISR1 (void) __attribute__ ((naked));
+void uartISR1 (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ signed portCHAR cChar;
+ portBASE_TYPE xTaskWokenByTx = pdFALSE;
+ portBASE_TYPE xTaskWokenByRx = pdFALSE;
+
+ switch (UART1_IIR & serINTERRUPT_SOURCE_MASK)
+ {
+ //
+ // Not handling this, but clear the interrupt
+ //
+ case serSOURCE_ERROR :
+ {
+ cChar = UART1_LSR;
+ }
+ break;
+
+ //
+ // The THRE is empty. If there is another character in the Tx queue, send it now,
+ // otherwise, no more characters, so indicate THRE is available
+ //
+ case serSOURCE_THRE :
+ {
+ if (xQueueReceiveFromISR (xTX1Queue, &cChar, &xTaskWokenByTx) == pdTRUE)
+ UART1_THR = cChar;
+ else
+ lTHREEmpty1 = pdTRUE;
+ }
+ break;
+
+ //
+ // A character was received. Place it in the queue of received characters
+ //
+ case serSOURCE_RX_TIMEOUT :
+ case serSOURCE_RX :
+ {
+ cChar = UART1_RBR;
+
+ if (xQueueSendFromISR (xRX1Queue, &cChar, (portBASE_TYPE) pdFALSE))
+ xTaskWokenByRx = pdTRUE;
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ portEXIT_SWITCHING_ISR ((xTaskWokenByTx || xTaskWokenByRx));
+}
--- /dev/null
+#ifndef _UARTISR_H_
+#define _UARTISR_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+//
+//
+//
+void uartISRCreateQueues (portCHAR pxPort, unsigned portBASE_TYPE uxQueueLength, xQueueHandle *pxRX0Queue, xQueueHandle *pxTX0Queue, portLONG volatile **pplTHREEmptyFlag);
+void uartISR0 (void);
+void uartISR1 (void);
+signed portBASE_TYPE uart0PostSpecialFromISR (U8 special);
+signed portBASE_TYPE uart1PostSpecialFromISR (U8 special);
+
+#endif
--- /dev/null
+SRC_FILES=usbISR.c usbcontrol.c usbinit.c usbstdreq.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include "FreeRTOS.h"
+#include "task.h"
+// #include "usb.h"
+#include "usbISR.h"
+#include "usbapi.h"
+
+//
+//
+//
+static TFnDevIntHandler *_pfnDevIntHandler = NULL; /** Installed device interrupt handler */
+static TFnEPIntHandler *_apfnEPIntHandlers [16]; /** Installed endpoint interrupt handlers */
+static TFnFrameHandler *_pfnFrameHandler = NULL; /** Installed frame interrupt handlers */
+
+#define EP2IDX(bEP) ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7)) /** convert from endpoint address to endpoint index */
+#define IDX2EP(idx) ((((idx)<<7)&0x80)|(((idx)>>1)&0xF)) /** convert from endpoint index to endpoint address */
+
+static void usbISR (void) __attribute__ ((naked));
+
+//
+// Local function to wait for a device interrupt (and clear it)
+//
+static void usbWaitForDeviceInterrupt (U32 dwIntr)
+{
+ while ((USB_DevIntSt & dwIntr) != dwIntr)
+ ;
+
+ USB_DevIntClr = dwIntr;
+}
+
+//
+// Local function to send a command to the USB protocol engine
+//
+static void usbHardwareCommand (U8 bCmd)
+{
+ USB_DevIntClr = USB_DevIntClr_CDFULL | USB_DevIntClr_CCEMTY;
+ USB_CmdCode = 0x00000500 | (bCmd << 16);
+ usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
+}
+
+//
+// Local function to send a command + data to the USB protocol engine
+//
+static void usbHardwareCommandWrite (U8 bCmd, U16 bData)
+{
+ usbHardwareCommand (bCmd);
+ USB_CmdCode = 0x00000100 | (bData << 16);
+ usbWaitForDeviceInterrupt (USB_DevIntSt_CCEMTY);
+}
+
+//
+// Local function to send a command to the USB protocol engine and read data
+//
+static U8 usbHardwareCommandRead (U8 bCmd)
+{
+ usbHardwareCommand (bCmd);
+ USB_CmdCode = 0x00000200 | (bCmd << 16);
+ usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
+ return USB_CmdData;
+}
+
+//
+// 'Realizes' an endpoint, meaning that buffer space is reserved for
+// it. An endpoint needs to be realised before it can be used.
+//
+// From experiments, it appears that a USB reset causes USBReEP to
+// re-initialise to 3 (= just the control endpoints).
+// However, a USB bus reset does not disturb the USBMaxPSize settings.
+//
+static void usbHardwareEndpointRealize (int idx, U16 wMaxPSize)
+{
+ USB_ReEP |= (1 << idx);
+ USB_EpInd = idx;
+ USB_MaxPSize = wMaxPSize;
+ usbWaitForDeviceInterrupt (USB_DevIntSt_EPRLZED);
+}
+
+//
+// Enables or disables an endpoint
+//
+static void usbHardwareEndpointEnable (int idx, BOOL fEnable)
+{
+ usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
+}
+
+//
+// Configures an endpoint and enables it
+//
+void usbHardwareEndpointConfig (U8 bEP, U16 wMaxPacketSize)
+{
+ int idx;
+
+ idx = EP2IDX (bEP);
+ usbHardwareEndpointRealize (idx, wMaxPacketSize);
+ usbHardwareEndpointEnable (idx, TRUE);
+}
+
+//
+// Registers an endpoint event callback
+//
+void usbHardwareRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler)
+{
+ int idx;
+
+ idx = EP2IDX (bEP);
+
+ _apfnEPIntHandlers [idx / 2] = pfnHandler;
+ USB_EpIntEn |= (1 << idx);
+ USB_DevIntEn |= USB_DevIntEn_EPSLOW;
+}
+
+//
+// Registers an device status callback
+//
+void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler)
+{
+ _pfnDevIntHandler = pfnHandler;
+ USB_DevIntEn |= USB_DevIntEn_DEVSTAT;
+}
+
+//
+// Registers the frame callback
+//
+void usbHardwareRegisterFrameHandler (TFnFrameHandler *pfnHandler)
+{
+ _pfnFrameHandler = pfnHandler;
+ USB_DevIntEn |= USB_DevIntEn_FRAME;
+}
+
+//
+// Sets the USB address.
+//
+void usbHardwareSetAddress (U8 bAddr)
+{
+ usbHardwareCommandWrite (CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
+}
+
+//
+// Connects or disconnects from the USB bus
+//
+void usbHardwareConnect (BOOL fConnect)
+{
+ usbHardwareCommandWrite (CMD_DEV_STATUS, fConnect ? CON : 0);
+}
+
+//
+// Enables interrupt on NAK condition
+//
+// For IN endpoints a NAK is generated when the host wants to read data
+// from the device, but none is available in the endpoint buffer.
+// For OUT endpoints a NAK is generated when the host wants to write data
+// to the device, but the endpoint buffer is still full.
+//
+// The endpoint interrupt handlers can distinguish regular (ACK) interrupts
+// from NAK interrupt by checking the bits in their bEPStatus argument.
+//
+void usbHardwareNakIntEnable (U8 bIntBits)
+{
+ usbHardwareCommandWrite (CMD_DEV_SET_MODE, bIntBits);
+}
+
+//
+// Gets the stalled property of an endpoint
+//
+BOOL usbHardwareEndpointIsStalled (U8 bEP)
+{
+ int idx = EP2IDX (bEP);
+
+ return (usbHardwareCommandRead (CMD_EP_SELECT | idx) & EP_STATUS_STALLED);
+}
+
+//
+// Sets the stalled property of an endpoint
+//
+void usbHardwareEndpointStall (U8 bEP, BOOL fStall)
+{
+ int idx = EP2IDX (bEP);
+
+ usbHardwareCommandWrite (CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
+}
+
+//
+// Writes data to an endpoint buffer
+//
+int usbHardwareEndpointWrite (U8 bEP, U8 *pbBuf, int iLen)
+{
+ int idx;
+
+ idx = EP2IDX (bEP);
+
+ USB_Ctrl = USB_Ctrl_WREN | ((bEP & 0xF) << 2);
+ USB_TxPLen = iLen;
+
+ while (USB_Ctrl & USB_Ctrl_WREN)
+ {
+ USB_TxData = (pbBuf [3] << 24) | (pbBuf [2] << 16) | (pbBuf [1] << 8) | pbBuf [0];
+ pbBuf += 4;
+ }
+
+ usbHardwareCommand (CMD_EP_SELECT | idx);
+ usbHardwareCommand (CMD_EP_VALIDATE_BUFFER);
+
+ return iLen;
+}
+
+//
+// Reads data from an endpoint buffer
+//
+int usbHardwareEndpointRead (U8 bEP, U8 *pbBuf, int iMaxLen)
+{
+ int i, idx;
+ U32 dwData, dwLen;
+
+ idx = EP2IDX (bEP);
+
+ USB_Ctrl = USB_Ctrl_RDEN | ((bEP & 0xF) << 2);
+
+ do
+ {
+ dwLen = USB_RxPLen;
+ }
+ while ((dwLen & USB_RxPLen_PKTRDY) == 0);
+
+ if ((dwLen & USB_RxPLen_DV) == 0)
+ return -1;
+
+ dwLen &= USB_RxPLen_PKTLENGTH_MASK;
+
+ while (USB_Ctrl & USB_Ctrl_RDEN)
+ {
+ dwData = USB_RxData;
+
+ if (pbBuf != NULL)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ if (iMaxLen-- != 0)
+ *pbBuf++ = dwData & 0xFF;
+
+ dwData >>= 8;
+ }
+ }
+ }
+
+ usbHardwareCommand (CMD_EP_SELECT | idx);
+ usbHardwareCommand (CMD_EP_CLEAR_BUFFER);
+
+ return dwLen;
+}
+
+
+//
+// Sets the 'configured' state.
+//
+void usbHardwareConfigDevice (BOOL fConfigured)
+{
+ usbHardwareCommandWrite (CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
+}
+
+//
+//
+//
+void usbSetupInterruptHandler (void)
+{
+ //
+ // Set up USB interrupt, use highest priority ISR slot
+ //
+ VIC_IntSelect &= ~VIC_IntSelect_USB;
+ VIC_VectAddr1 = (portLONG) usbISR;
+ VIC_VectCntl1 = VIC_VectCntl_ENABLE | VIC_Channel_USB;
+ VIC_IntEnable = VIC_IntEnable_USB;
+}
+
+//
+// USB interrupt handler
+//
+void usbISR (void)
+{
+ portENTER_SWITCHING_ISR ();
+
+ U32 dwStatus;
+ U32 dwIntBit;
+ U8 bEPStat, bDevStat, bStat;
+ int i;
+ portBASE_TYPE xTaskWoken = pdFALSE;
+
+ dwStatus = USB_DevIntSt;
+
+ if (dwStatus & USB_DevIntSt_DEVSTAT)
+ {
+ USB_DevIntClr = USB_DevIntClr_DEVSTAT;
+ bDevStat = usbHardwareCommandRead (CMD_DEV_STATUS);
+
+ if (bDevStat & (CON_CH | SUS_CH | RST))
+ {
+ bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
+ ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
+ ((bDevStat & RST) ? DEV_STATUS_RESET : 0);
+
+ if (_pfnDevIntHandler != NULL)
+ _pfnDevIntHandler (bStat);
+ }
+ }
+
+ if (dwStatus & USB_DevIntSt_EPSLOW)
+ {
+ USB_DevIntClr = USB_DevIntClr_EPSLOW;
+
+ for (i = 0; i < 32; i++)
+ {
+ dwIntBit = (1 << i);
+
+ if (USB_EpIntSt & dwIntBit)
+ {
+ USB_EpIntClr = dwIntBit;
+ usbWaitForDeviceInterrupt (USB_DevIntSt_CDFULL);
+ bEPStat = USB_CmdData;
+
+ bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
+ ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
+ ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
+ ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
+ ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
+
+ if (bEPStat & (1 <<5))
+ {
+ }
+
+ if (bEPStat & (1 <<6))
+ {
+ }
+
+ if (_apfnEPIntHandlers [i / 2] != NULL)
+ xTaskWoken |= _apfnEPIntHandlers [i / 2] (IDX2EP (i), bStat);
+ }
+ }
+ }
+
+ if (dwStatus & USB_DevIntSt_FRAME)
+ {
+ USB_DevIntClr = USB_DevIntClr_FRAME;
+
+ if (_pfnFrameHandler != NULL)
+ _pfnFrameHandler (0);
+ }
+
+ VIC_VectAddr = (unsigned portLONG) 0;
+
+ portEXIT_SWITCHING_ISR (xTaskWoken);
+}
+
+//
+// Initializes the USB hardware
+//
+// This function assumes that the hardware is connected as shown in
+// section 10.1 of the LPC2148 data sheet:
+// * P0.31 controls a switch to connect a 1.5k pull-up to D+ if low.
+// * P0.23 is connected to USB VCC.
+//
+BOOL usbHardwareInit (void)
+{
+ //
+ // Configure P0.23 for Vbus sense, P0.31 as USB connect indicator
+ //
+ PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P023_GPIO) | PCB_PINSEL1_P023_VBUS;
+ GPIO0_IODIR &= ~GPIO_IO_P23;
+ PCB_PINSEL1 = (PCB_PINSEL1 & ~PCB_PINSEL1_P031_GPIO) | PCB_PINSEL1_P031_CONNECT;
+
+ //
+ // Enable PUSB
+ //
+ SCB_PCONP |= SCB_PCONP_PUSB;
+
+ //
+ // Initialize PLL
+ //
+ USB_PLLCON = USB_PLLCON_PLLE;
+ USB_PLLCFG = USB_PLLCFG_DIV2 | USB_PLLCFG_MUL4;
+ USB_PLLFEED = USB_PLLFEED_FEED1;
+ USB_PLLFEED = USB_PLLFEED_FEED2;
+
+ //
+ // Wait for PLL to lock up
+ //
+ while (!(USB_PLLSTAT & USB_PLLSTAT_PLOCK))
+ ;
+
+ USB_PLLCON = USB_PLLCON_PLLC | USB_PLLCON_PLLE;
+ USB_PLLFEED = USB_PLLFEED_FEED1;
+ USB_PLLFEED = USB_PLLFEED_FEED2;
+
+ //
+ // Disable/clear all interrupts for now
+ //
+ USB_DevIntEn = USB_DevIntEn_NONE;
+ USB_EpIntEn = USB_EpIntEn_NONE;
+ USB_DevIntClr = USB_DevIntClr_ALL;
+ USB_EpIntClr = USB_EpIntClr_ALL;
+
+ //
+ // Setup control endpoints
+ //
+ usbHardwareEndpointConfig (0x00, MAX_PACKET_SIZE0);
+ usbHardwareEndpointConfig (0x80, MAX_PACKET_SIZE0);
+
+ //
+ // By default, only ACKs generate interrupts
+ //
+ usbHardwareNakIntEnable (0);
+
+ return TRUE;
+}
--- /dev/null
+//
+// These really need to be normalized to the names in lp210x.h and included there.
+// A #define like "DEV_ADDR" is just too ambiguous when it's unqualified with
+// what sub-system it belongs to.
+//
+
+#ifndef _USBISR_H_
+#define _USBISR_H_
+
+//
+// Protocol engine command codes, device commands
+//
+#define CMD_DEV_SET_ADDRESS 0xD0
+#define CMD_DEV_CONFIG 0xD8
+#define CMD_DEV_SET_MODE 0xF3
+#define CMD_DEV_READ_CUR_FRAME_NR 0xF5
+#define CMD_DEV_READ_TEST_REG 0xFD
+#define CMD_DEV_STATUS 0xFE /* read/write */
+#define CMD_DEV_GET_ERROR_CODE 0xFF
+#define CMD_DEV_READ_ERROR_STATUS 0xFB
+
+//
+// Protocol engine command codes, endpoint commands
+//
+#define CMD_EP_SELECT 0x00
+#define CMD_EP_SELECT_CLEAR 0x40
+#define CMD_EP_SET_STATUS 0x40
+#define CMD_EP_CLEAR_BUFFER 0xF2
+#define CMD_EP_VALIDATE_BUFFER 0xFA
+
+//
+// Set address command
+//
+#define DEV_ADDR (1<<0)
+#define DEV_EN (1<<7)
+
+//
+// Configure device command
+//
+#define CONF_DEVICE (1<<0)
+
+//
+// Set mode command
+//
+#define AP_CLK (1<<0)
+#define INAK_CI (1<<1)
+#define INAK_CO (1<<2)
+#define INAK_II (1<<3)
+#define INAK_IO (1<<4)
+#define INAK_BI (1<<5)
+#define INAK_BO (1<<6)
+
+//
+// Set get device status command
+//
+#define CON (1<<0)
+#define CON_CH (1<<1)
+#define SUS (1<<2)
+#define SUS_CH (1<<3)
+#define RST (1<<4)
+
+//
+// Get error code command
+// ...
+//
+
+//
+// Select Endpoint command read bits
+//
+#define EPSTAT_FE (1<<0)
+#define EPSTAT_ST (1<<1)
+#define EPSTAT_STP (1<<2)
+#define EPSTAT_PO (1<<3)
+#define EPSTAT_EPN (1<<4)
+#define EPSTAT_B1FULL (1<<5)
+#define EPSTAT_B2FULL (1<<6)
+
+//
+// CMD_EP_SET_STATUS command
+//
+#define EP_ST (1<<0)
+#define EP_DA (1<<5)
+#define EP_RF_MO (1<<6)
+#define EP_CND_ST (1<<7)
+
+//
+// Read error status command
+//
+#define PID_ERR (1<<0)
+#define UEPKT (1<<1)
+#define DCRC (1<<2)
+#define TIMEOUT (1<<3)
+#define EOP (1<<4)
+#define B_OVRN (1<<5)
+#define BTSTF (1<<6)
+#define TGL_ERR (1<<7)
+
+#endif
--- /dev/null
+#include "usbstruct.h" // for TSetupPacket
+
+/*************************************************************************
+ USB configuration
+**************************************************************************/
+
+#define MAX_PACKET_SIZE0 64 /**< maximum packet size for EP 0 */
+
+/*************************************************************************
+ USB hardware interface
+**************************************************************************/
+
+// endpoint status sent through callback
+#define EP_STATUS_DATA (1<<0) /**< EP has data */
+#define EP_STATUS_STALLED (1<<1) /**< EP is stalled */
+#define EP_STATUS_SETUP (1<<2) /**< EP received setup packet */
+#define EP_STATUS_ERROR (1<<3) /**< EP data was overwritten by setup packet */
+#define EP_STATUS_NACKED (1<<4) /**< EP sent NAK */
+
+// device status sent through callback
+#define DEV_STATUS_CONNECT (1<<0) /**< device just got connected */
+#define DEV_STATUS_SUSPEND (1<<2) /**< device entered suspend state */
+#define DEV_STATUS_RESET (1<<4) /**< device just got reset */
+
+// interrupt bits for NACK events in usbHardwareNakIntEnable
+// (these bits conveniently coincide with the LPC214x USB controller bit)
+#define INACK_CI (1<<1) /**< interrupt on NACK for control in */
+#define INACK_CO (1<<2) /**< interrupt on NACK for control out */
+#define INACK_II (1<<3) /**< interrupt on NACK for interrupt in */
+#define INACK_IO (1<<4) /**< interrupt on NACK for interrupt out */
+#define INACK_BI (1<<5) /**< interrupt on NACK for bulk in */
+#define INACK_BO (1<<6) /**< interrupt on NACK for bulk out */
+
+BOOL usbHardwareInit (void);
+void usbSetupInterruptHandler (void);
+void usbHardwareNakIntEnable (U8 bIntBits);
+void usbHardwareConnect (BOOL fConnect);
+void usbHardwareSetAddress (U8 bAddr);
+void usbHardwareConfigDevice (BOOL fConfigured);
+
+//
+// Endpoint operations
+//
+void usbHardwareEndpointConfig (U8 bEP, U16 wMaxPacketSize);
+int usbHardwareEndpointRead (U8 bEP, U8 *pbBuf, int iMaxLen);
+int usbHardwareEndpointWrite (U8 bEP, U8 *pbBuf, int iLen);
+void usbHardwareEndpointStall (U8 bEP, BOOL fStall);
+BOOL usbHardwareEndpointIsStalled (U8 bEP);
+
+//
+// Endpoint interrupt handler callback
+//
+typedef int (TFnEPIntHandler) (U8 bEP, U8 bEPStatus);
+void usbHardwareRegisterEPIntHandler (U8 bEP, TFnEPIntHandler *pfnHandler);
+
+//
+// Device status handler callback
+//
+typedef void (TFnDevIntHandler) (U8 bDevStatus);
+void usbHardwareRegisterDevIntHandler (TFnDevIntHandler *pfnHandler);
+
+//
+// Frame event handler callback
+//
+typedef void (TFnFrameHandler)(U16 wFrame);
+void usbHardwareRegisterFrameHandler(TFnFrameHandler *pfnHandler);
+
+
+/*************************************************************************
+ USB application interface
+**************************************************************************/
+
+// initialise the complete stack, including HW
+BOOL usbRegisterHandlers (void);
+
+/** Request handler callback (standard, vendor, class) */
+typedef BOOL (TFnHandleRequest)(TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+void usbRegisterRequestHandler (int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore);
+void usbRegisterCustomReqHandler (TFnHandleRequest *pfnHandler);
+
+/** Descriptor handler callback */
+typedef BOOL (TFnGetDescriptor)(U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
+
+/** Default standard request handler */
+BOOL usbHandleStandardRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData);
+
+/** Default EP0 handler */
+int usbHandleControlTransfer (U8 bEP, U8 bEPStat);
+
+/** Descriptor handling */
+void usbRegisterDescriptors (const U8 *pabDescriptors);
+BOOL usbGetDescriptor (U16 wTypeIndex, U16 wLangID, int *piLen, U8 **ppbData);
--- /dev/null
+/** @file
+ Control transfer handler.
+
+ This module handles control transfers and is normally installed on the
+ endpoint 0 callback.
+
+ Control transfers can be of the following type:
+ 0 Standard;
+ 1 Class;
+ 2 Vendor;
+ 3 Reserved.
+
+ A callback can be installed for each of these control transfers using
+ USBRegisterRequestHandler.
+ When an OUT request arrives, data is collected in the data store provided
+ with the usbRegisterRequestHandler call. When the transfer is done, the
+ callback is called.
+ When an IN request arrives, the callback is called immediately to either
+ put the control transfer data in the data store, or to get a pointer to
+ control transfer data. The data is then packetised and sent to the host.
+*/
+
+#include "FreeRTOS.h"
+
+#include "usbstruct.h"
+#include "usbapi.h"
+
+//
+//
+//
+#define MAX_CONTROL_SIZE 128 /**< maximum total size of control transfer data */
+#define MAX_REQ_HANDLERS 4 /**< standard, class, vendor, reserved */
+
+static TSetupPacket Setup; /**< setup packet */
+
+static U8 *pbData; /**< pointer to data buffer */
+static int iResidue; /**< remaining bytes in buffer */
+static int iLen; /**< total length of control transfer */
+
+static TFnHandleRequest *apfnReqHandlers [4] = { NULL, NULL, NULL, NULL }; // Array of installed request handler callbacks
+static U8 *apbDataStore [4] = { NULL, NULL, NULL, NULL }; // Array of installed request data pointers */
+
+//
+// Local function to handle a request by calling one of the installed
+// request handlers.
+
+// In case of data going from host to device, the data is at *ppbData.
+// In case of data going from device to host, the handler can either
+// choose to write its data at *ppbData or update the data pointer.
+//
+static BOOL _HandleRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ TFnHandleRequest *pfnHandler;
+ int iType;
+
+ iType = REQTYPE_GET_TYPE (pSetup->bmRequestType);
+ pfnHandler = apfnReqHandlers [iType];
+
+ if (pfnHandler == NULL)
+ return FALSE;
+
+ return pfnHandler (pSetup, piLen, ppbData);
+}
+
+//
+// Local function to stall the control endpoint
+//
+static void usbStallControlPipe (U8 bEPStat __attribute__ ((unused)))
+{
+ usbHardwareEndpointStall (0x80, TRUE);
+}
+
+//
+// Sends next chunk of data (possibly 0 bytes) to host
+//
+static void usbDataIn (void)
+{
+ int iChunk;
+
+ iChunk = MIN (MAX_PACKET_SIZE0, iResidue);
+ usbHardwareEndpointWrite (0x80, pbData, iChunk);
+ pbData += iChunk;
+ iResidue -= iChunk;
+}
+
+//
+// Handles IN/OUT transfers on EP0
+//
+int usbHandleControlTransfer (U8 bEP, U8 bEPStat)
+{
+ int iChunk;
+ int iType;
+
+ //
+ // OUT transfer
+ //
+ if (bEP == 0x00)
+ {
+ if (bEPStat & EP_STATUS_SETUP)
+ {
+ //
+ // Setup packet, reset request message state machine
+ //
+ usbHardwareEndpointRead (0x00, (U8 *) &Setup, sizeof (Setup));
+
+ //
+ // Defaults for data pointer and residue
+ //
+ iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
+ pbData = apbDataStore [iType];
+ iResidue = Setup.wLength;
+ iLen = Setup.wLength;
+
+ if ((Setup.wLength == 0) || (REQTYPE_GET_DIR(Setup.bmRequestType) == REQTYPE_DIR_TO_HOST))
+ {
+ if (!_HandleRequest (&Setup, &iLen, &pbData))
+ {
+ usbStallControlPipe (bEPStat);
+ return pdFALSE;
+ }
+
+ iResidue = MIN (iLen, Setup.wLength);
+ usbDataIn ();
+ }
+ }
+ else
+ {
+ if (iResidue > 0)
+ {
+ iChunk = usbHardwareEndpointRead (0x00, pbData, iResidue);
+
+ if (iChunk < 0)
+ {
+ usbStallControlPipe (bEPStat);
+ return pdFALSE;
+ }
+
+ pbData += iChunk;
+ iResidue -= iChunk;
+
+ if (iResidue == 0)
+ {
+ iType = REQTYPE_GET_TYPE (Setup.bmRequestType);
+ pbData = apbDataStore [iType];
+
+ if (!_HandleRequest (&Setup, &iLen, &pbData))
+ {
+ usbStallControlPipe (bEPStat);
+ return pdFALSE;
+ }
+
+ usbDataIn ();
+ }
+ }
+ else
+ iChunk = usbHardwareEndpointRead (0x00, NULL, 0);
+ }
+ }
+ else if (bEP == 0x80)
+ usbDataIn ();
+
+ return pdFALSE;
+}
+
+
+//
+// Registers a callback for handling requests
+//
+void usbRegisterRequestHandler (int iType, TFnHandleRequest *pfnHandler, U8 *pbDataStore)
+{
+ apfnReqHandlers [iType] = pfnHandler;
+ apbDataStore [iType] = pbDataStore;
+}
--- /dev/null
+#include "FreeRTOS.h"
+#include "usbapi.h"
+
+
+//
+// Data storage area for standard requests
+//
+static U8 abStdReqData [8];
+
+
+//
+// USB reset handler
+//
+static void usbHandleReset(U8 bDevStatus __attribute__ ((unused)))
+{
+}
+
+//
+//
+//
+BOOL usbRegisterHandlers (void)
+{
+ usbHardwareInit ();
+ usbHardwareRegisterDevIntHandler (usbHandleReset);
+ usbHardwareRegisterEPIntHandler (0x00, usbHandleControlTransfer);
+ usbHardwareRegisterEPIntHandler (0x80, usbHandleControlTransfer);
+ usbRegisterRequestHandler (REQTYPE_TYPE_STANDARD, usbHandleStandardRequest, abStdReqData);
+
+ return TRUE;
+}
--- /dev/null
+/** @file
+ Standard request handler.
+
+ This modules handles the 'chapter 9' processing, specifically the
+ standard device requests in table 9-3 from the universal serial bus
+ specification revision 2.0
+
+ Specific types of devices may specify additional requests (for example
+ HID devices add a GET_DESCRIPTOR request for interfaces), but they
+ will not be part of this module.
+
+ @todo some requests have to return a request error if device not configured:
+ @todo GET_INTERFACE, GET_STATUS, SET_INTERFACE, SYNCH_FRAME
+ @todo this applies to the following if endpoint != 0:
+ @todo SET_FEATURE, GET_FEATURE
+*/
+
+#include "usbstruct.h"
+#include "usbapi.h"
+
+#define MAX_DESC_HANDLERS 4 /**< device, interface, endpoint, other */
+
+
+//
+// General descriptor field offsets
+//
+#define DESC_bLength 0 /**< length offset */
+#define DESC_bDescriptorType 1 /**< descriptor type offset */
+
+//
+// Config descriptor field offsets
+//
+#define CONF_DESC_wTotalLength 2 /**< total length offset */
+#define CONF_DESC_bConfigurationValue 5 /**< configuration value offset */
+#define CONF_DESC_bmAttributes 7 /**< configuration characteristics */
+
+//
+// Interface descriptor field offsets
+//
+#define INTF_DESC_bAlternateSetting 3 /**< alternate setting offset */
+
+//
+// Endpoint descriptor field offsets
+//
+#define ENDP_DESC_bEndpointAddress 2 /**< endpoint address offset */
+#define ENDP_DESC_wMaxPacketSize 4 /**< maximum packet size offset */
+
+
+static U8 bConfiguration = 0; /** Currently selected configuration */
+static TFnHandleRequest *pfnHandleCustomReq = NULL; /** Installed custom request handler */
+static const U8 *pabDescrip = NULL; /** Pointer to registered descriptors */
+
+
+//
+// Registers a pointer to a descriptor block containing all descriptors for the device.
+//
+void usbRegisterDescriptors (const U8 *pabDescriptors)
+{
+ pabDescrip = pabDescriptors;
+}
+
+//
+// Parses the list of installed USB descriptors and attempts to find the specified USB descriptor.
+//
+BOOL usbGetDescriptor (U16 wTypeIndex, U16 wLangID __attribute__ ((unused)), int *piLen, U8 **ppbData)
+{
+ U8 bType, bIndex;
+ U8 *pab;
+ int iCurIndex;
+
+ bType = GET_DESC_TYPE (wTypeIndex);
+ bIndex = GET_DESC_INDEX (wTypeIndex);
+
+ pab = (U8 *)pabDescrip;
+ iCurIndex = 0;
+
+ while (pab [DESC_bLength] != 0)
+ {
+ if (pab [DESC_bDescriptorType] == bType)
+ {
+ if (iCurIndex == bIndex)
+ {
+ *ppbData = pab;
+
+ if (bType == DESC_CONFIGURATION)
+ *piLen = (pab [CONF_DESC_wTotalLength]) | (pab [CONF_DESC_wTotalLength + 1] << 8);
+ else
+ *piLen = pab [DESC_bLength];
+
+ return TRUE;
+ }
+
+ iCurIndex++;
+ }
+
+ pab += pab [DESC_bLength];
+ }
+
+ return FALSE;
+}
+
+//
+// Configures the device according to the specified configuration index and
+// alternate setting by parsing the installed USB descriptor list.
+// A configuration index of 0 unconfigures the device.
+//
+static BOOL usbSetConfiguration (U8 bConfigIndex, U8 bAltSetting)
+{
+ U8 *pab;
+ U8 bCurConfig, bCurAltSetting;
+ U8 bEP;
+ U16 wMaxPktSize;
+
+ if (bConfigIndex == 0)
+ usbHardwareConfigDevice(FALSE);
+ else
+ {
+ pab = (U8 *) pabDescrip;
+ bCurConfig = 0xFF;
+ bCurAltSetting = 0xFF;
+
+ while (pab [DESC_bLength] != 0)
+ {
+ switch (pab [DESC_bDescriptorType])
+ {
+ case DESC_CONFIGURATION :
+ {
+ bCurConfig = pab [CONF_DESC_bConfigurationValue];
+ }
+ break;
+
+ case DESC_INTERFACE :
+ {
+ bCurAltSetting = pab [INTF_DESC_bAlternateSetting];
+ }
+ break;
+
+ case DESC_ENDPOINT :
+ {
+ if ((bCurConfig == bConfigIndex) && (bCurAltSetting == bAltSetting))
+ {
+ bEP = pab [ENDP_DESC_bEndpointAddress];
+ wMaxPktSize = (pab [ENDP_DESC_wMaxPacketSize]) | (pab [ENDP_DESC_wMaxPacketSize + 1] << 8);
+ usbHardwareEndpointConfig (bEP, wMaxPktSize);
+ }
+ }
+ break;
+
+ default :
+ break;
+ }
+
+ pab += pab [DESC_bLength];
+ }
+
+ usbHardwareConfigDevice (TRUE);
+ }
+
+ return TRUE;
+}
+
+//
+// Local function to handle a standard device request
+//
+static BOOL usbHandleStdDeviceReq (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ U8 *pbData = *ppbData;
+
+ switch (pSetup->bRequest)
+ {
+ case REQ_GET_STATUS :
+ {
+ pbData [0] = 0;
+ pbData [1] = 0;
+ *piLen = 2;
+ }
+ break;
+
+ case REQ_SET_ADDRESS :
+ {
+ usbHardwareSetAddress (pSetup->wValue);
+ }
+ break;
+
+ case REQ_GET_DESCRIPTOR :
+ return usbGetDescriptor (pSetup->wValue, pSetup->wIndex, piLen, ppbData);
+
+ case REQ_GET_CONFIGURATION :
+ {
+ pbData [0] = bConfiguration;
+ *piLen = 1;
+ }
+ break;
+
+ case REQ_SET_CONFIGURATION :
+ {
+ if (!usbSetConfiguration(pSetup->wValue & 0xFF, 0))
+ return FALSE;
+
+ bConfiguration = pSetup->wValue & 0xFF;
+ }
+ break;
+
+ case REQ_CLEAR_FEATURE :
+ case REQ_SET_FEATURE :
+ {
+ if (pSetup->wValue == FEA_REMOTE_WAKEUP) {
+ }
+ if (pSetup->wValue == FEA_TEST_MODE) {
+ }
+ }
+ return FALSE;
+
+ case REQ_SET_DESCRIPTOR :
+ return FALSE;
+
+ default :
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// Local function to handle a standard interface request
+//
+static BOOL usbHandleStdInterfaceReq (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ U8 *pbData = *ppbData;
+
+ switch (pSetup->bRequest)
+ {
+ case REQ_GET_STATUS :
+ {
+ pbData [0] = 0;
+ pbData [1] = 0;
+ *piLen = 2;
+ }
+ break;
+
+ case REQ_CLEAR_FEATURE :
+ case REQ_SET_FEATURE :
+ return FALSE;
+
+ case REQ_GET_INTERFACE :
+ {
+ pbData [0] = 0;
+ *piLen = 1;
+ }
+ break;
+
+ case REQ_SET_INTERFACE :
+ {
+ if (pSetup->wValue != 0)
+ return FALSE;
+
+ *piLen = 0;
+ }
+ break;
+
+ default :
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// Local function to handle a standard endpoint request
+//
+static BOOL usbHandleStdEndPointReq (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ U8 *pbData = *ppbData;
+
+ switch (pSetup->bRequest)
+ {
+ case REQ_GET_STATUS :
+ {
+ pbData [0] = usbHardwareEndpointIsStalled (pSetup->wIndex) ? 1 : 0;
+ pbData [1] = 0;
+ *piLen = 2;
+ }
+ break;
+
+ case REQ_CLEAR_FEATURE :
+ {
+ if (pSetup->wValue == FEA_ENDPOINT_HALT)
+ {
+ usbHardwareEndpointStall(pSetup->wIndex, FALSE);
+ break;
+ }
+ }
+ return FALSE;
+
+ case REQ_SET_FEATURE :
+ {
+ if (pSetup->wValue == FEA_ENDPOINT_HALT)
+ {
+ usbHardwareEndpointStall(pSetup->wIndex, TRUE);
+ break;
+ }
+ }
+ return FALSE;
+
+ case REQ_SYNCH_FRAME :
+ return FALSE;
+
+ default :
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+//
+// Default handler for standard ('chapter 9') requests
+// If a custom request handler was installed, this handler is called first.
+//
+BOOL usbHandleStandardRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ if ((pfnHandleCustomReq != NULL) && pfnHandleCustomReq (pSetup, piLen, ppbData))
+ return TRUE;
+
+ switch (REQTYPE_GET_RECIP(pSetup->bmRequestType))
+ {
+ case REQTYPE_RECIP_DEVICE : return usbHandleStdDeviceReq (pSetup, piLen, ppbData);
+ case REQTYPE_RECIP_INTERFACE : return usbHandleStdInterfaceReq (pSetup, piLen, ppbData);
+ case REQTYPE_RECIP_ENDPOINT : return usbHandleStdEndPointReq (pSetup, piLen, ppbData);
+ default : return FALSE;
+ }
+}
+
+//
+// Registers a callback for custom device requests
+//
+// In usbHandleStandardRequest, the custom request handler gets a first
+// chance at handling the request before it is handed over to the 'chapter 9'
+// request handler.
+//
+// This can be used for example in HID devices, where a REQ_GET_DESCRIPTOR
+// request is sent to an interface, which is not covered by the 'chapter 9'
+// specification.
+//
+void usbRegisterCustomReqHandler (TFnHandleRequest *pfnHandler)
+{
+ pfnHandleCustomReq = pfnHandler;
+}
+
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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.
+*/
+
+
+/**
+ Definitions of structures of standard USB packets
+*/
+
+#ifndef _USBSTRUCT_H_
+#define _USBSTRUCT_H_
+
+#include "sysdefs.h"
+
+//
+// Setup packet definitions
+//
+typedef struct
+{
+ U8 bmRequestType; /**< characteristics of the specific request */
+ U8 bRequest; /**< specific request */
+ U16 wValue; /**< request specific parameter */
+ U16 wIndex; /**< request specific parameter */
+ U16 wLength; /**< length of data transfered in data phase */
+}
+TSetupPacket;
+
+
+#define REQTYPE_GET_DIR(x) (((x)>>7)&0x01)
+#define REQTYPE_GET_TYPE(x) (((x)>>5)&0x03)
+#define REQTYPE_GET_RECIP(x) ((x)&0x1F)
+
+#define REQTYPE_DIR_TO_DEVICE 0
+#define REQTYPE_DIR_TO_HOST 1
+
+#define REQTYPE_TYPE_STANDARD 0
+#define REQTYPE_TYPE_CLASS 1
+#define REQTYPE_TYPE_VENDOR 2
+#define REQTYPE_TYPE_RESERVED 3
+
+#define REQTYPE_RECIP_DEVICE 0
+#define REQTYPE_RECIP_INTERFACE 1
+#define REQTYPE_RECIP_ENDPOINT 2
+#define REQTYPE_RECIP_OTHER 3
+
+//
+// Standard requests
+//
+#define REQ_GET_STATUS 0x00
+#define REQ_CLEAR_FEATURE 0x01
+#define REQ_SET_FEATURE 0x03
+#define REQ_SET_ADDRESS 0x05
+#define REQ_GET_DESCRIPTOR 0x06
+#define REQ_SET_DESCRIPTOR 0x07
+#define REQ_GET_CONFIGURATION 0x08
+#define REQ_SET_CONFIGURATION 0x09
+#define REQ_GET_INTERFACE 0x0A
+#define REQ_SET_INTERFACE 0x0B
+#define REQ_SYNCH_FRAME 0x0C
+
+//
+// Class requests HID
+//
+#define HID_GET_REPORT 0x01
+#define HID_GET_IDLE 0x02
+#define HID_GET_PROTOCOL 0x03
+#define HID_SET_REPORT 0x09
+#define HID_SET_IDLE 0x0A
+#define HID_SET_PROTOCOL 0x0B
+
+//
+// Feature selectors
+//
+#define FEA_ENDPOINT_HALT 0x00
+#define FEA_REMOTE_WAKEUP 0x01
+#define FEA_TEST_MODE 0x02
+
+//
+// USB descriptor header
+//
+typedef struct
+{
+ U8 bLength; /**< descriptor length */
+ U8 bDescriptorType; /**< descriptor type */
+}
+TUSBDescHeader;
+
+#define DESC_DEVICE 1
+#define DESC_CONFIGURATION 2
+#define DESC_STRING 3
+#define DESC_INTERFACE 4
+#define DESC_ENDPOINT 5
+#define DESC_DEVICE_QUALIFIER 6
+#define DESC_OTHER_SPEED 7
+#define DESC_INTERFACE_POWER 8
+
+#define DESC_HID_HID 0x21
+#define DESC_HID_REPORT 0x22
+#define DESC_HID_PHYSICAL 0x23
+
+#define GET_DESC_TYPE(x) (((x)>>8)&0xFF)
+#define GET_DESC_INDEX(x) ((x)&0xFF)
+
+#endif
--- /dev/null
+SRC_FILES=mscblock.c mscbot.c mscscsi.c usbmass.c mscspi.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*****************************************************************************\
+* efs - General purpose Embedded Filesystem library *
+* --------------------- ----------------------------------- *
+* *
+* Filename : sd.c *
+* Revision : Initial developement *
+* Description : This file contains the functions needed to use efs for *
+* accessing files on an SD-card. *
+* *
+* This library is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU Lesser General Public *
+* License as published by the Free Software Foundation; either *
+* version 2.1 of the License, or (at your option) any later version. *
+* *
+* This library 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 *
+* Lesser General Public License for more details. *
+* *
+* (c)2005 Michael De Nil *
+* (c)2005 Lennart Yseboodt *
+\*****************************************************************************/
+
+/*
+ 2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+#include "FreeRTOS.h"
+
+#include <stdio.h>
+
+#include "../fatfs/diskio.h"
+#include "../fatfs/ff.h"
+#include "../fatfs/mmc.h"
+#include "../fatfs/spi.h"
+#include "mscdebug.h"
+#include "mscblock.h"
+#include "mscspi.h"
+
+//
+//
+//
+#define CMD_GOIDLESTATE 0
+#define CMD_SENDOPCOND 1
+#define CMD_READCSD 9
+#define CMD_READCID 10
+#define CMD_SENDSTATUS 13
+#define CMD_READSINGLEBLOCK 17
+#define CMD_WRITE 24
+#define CMD_WRITE_MULTIPLE 25
+
+//
+//
+//
+static void mscblockCommand (U8 cmd, U32 param)
+{
+ U8 abCmd [8];
+
+ abCmd [0] = 0xff;
+ abCmd [1] = 0x40 | cmd;
+ abCmd [2] = (U8)(param >> 24);
+ abCmd [3] = (U8)(param >> 16);
+ abCmd [4] = (U8)(param >> 8);
+ abCmd [5] = (U8)(param);
+ abCmd [6] = 0x95; /* Checksum (should be only valid for first command (0) */
+ abCmd [7] = 0xff; /* eat empty command - response */
+
+ mscspiSendBlock (abCmd, 8);
+}
+
+//
+//
+//
+static U8 mscblockResp8b (void)
+{
+ U8 i;
+ U8 resp;
+
+ /* Respone will come after 1 - 8 pings */
+ for (i = 0; i < 8; i++)
+ if ((resp = mscspiTransferByte (0xff)) != 0xff)
+ return resp;
+
+ return resp;
+}
+
+//
+//
+//
+static void mscblockResp8bError (U8 value)
+{
+ switch (value)
+ {
+ case 0x40 : DBG ("Argument out of bounds.\n"); break;
+ case 0x20 : DBG ("Address out of bounds.\n"); break;
+ case 0x10 : DBG ("Error during erase sequence.\n"); break;
+ case 0x08 : DBG ("CRC failed.\n"); break;
+ case 0x04 : DBG ("Illegal command.\n"); break;
+ case 0x02 : DBG ("Erase reset (see SanDisk docs p5-13).\n"); break;
+ case 0x01 : DBG ("Card is initialising.\n"); break;
+ default : DBG ("Unknown error 0x%x (see SanDisk docs p5-13).\n", value); break;
+ }
+}
+
+//
+// Calculates size of card from CSD
+// (extension by Martin Thomas, inspired by code from Holger Klabunde)
+//
+int mscblockGetSize (U32 *pdwDriveSize)
+{
+ U8 cardresp, i, by;
+ U8 iob [16];
+ U16 c_size, c_size_mult, read_bl_len;
+
+ mscblockCommand (CMD_READCSD, 0);
+
+ do {
+ cardresp = mscblockResp8b ();
+ }
+ while (cardresp != 0xfe);
+
+ DBG ("CSD:");
+
+ for (i = 0; i < 16; i++)
+ {
+ iob [i] = mscspiTransferByte (0xff);
+ DBG (" %02x", iob [i]);
+ }
+
+ DBG("\n");
+
+ mscspiTransferByte (0xff);
+ mscspiTransferByte (0xff);
+
+ c_size = iob [6] & 0x03;
+ c_size <<= 10;
+ c_size += (U16) iob [7] << 2;
+ c_size += iob [8] >> 6;
+
+ by = iob [5] & 0x0f;
+ read_bl_len = 1 << by;
+
+ by = iob [9] & 0x03;
+ by <<= 1;
+ by += iob [10] >> 7;
+
+ c_size_mult = 1 << (2 + by);
+
+ *pdwDriveSize = (U32) (c_size + 1) * (U32) c_size_mult * (U32) read_bl_len;
+
+ return 0;
+}
+
+//
+//
+//
+static U16 mscblockResp16b (void)
+{
+ U16 resp;
+
+ resp = (mscblockResp8b() << 8) & 0xff00;
+ resp |= mscspiTransferByte(0xff);
+
+ return resp;
+}
+
+//
+//
+//
+static int mscblockState (void)
+{
+ U16 value;
+
+ mscblockCommand (CMD_SENDSTATUS, 0);
+ value = mscblockResp16b ();
+
+ switch (value)
+ {
+ case 0x0000 : return 1;
+ case 0x0001 : DBG ("Card is Locked.\n"); break;
+ case 0x0002 : DBG ("WP Erase Skip, Lock/Unlock Cmd Failed.\n"); break;
+ case 0x0004 : DBG ("General / Unknown error -- card broken?.\n"); break;
+ case 0x0008 : DBG ("Internal card controller error.\n"); break;
+ case 0x0010 : DBG ("Card internal ECC was applied, but failed to correct the data.\n"); break;
+ case 0x0020 : DBG ("Write protect violation.\n"); break;
+ case 0x0040 : DBG ("An invalid selection, sectors for erase.\n"); break;
+ case 0x0080 : DBG ("Out of Range, CSD_Overwrite.\n"); break;
+ default : if (value > 0x00ff)
+ mscblockResp8bError ((U8) (value >> 8));
+ else
+ DBG ("Unknown error: 0x%x (see SanDisk docs p5-14).\n", value);
+ break;
+ }
+
+ return -1;
+}
+
+//
+//
+//
+int mscblockInit (void)
+{
+ FRESULT f;
+
+ //
+ // We'll see the error because it means we *must* be using a serial
+ // console, since we can't use USB for MSC and VCOM at the same time.
+ //
+ mscspiInit ();
+
+#if 1
+ if ((f = diskInitialize (0)) != FR_OK)
+ f_printerror (f);
+#endif
+
+#if 0
+ U8 resp;
+ int i;
+
+ //
+ // Try to send reset command up to 100 times
+ //
+ i = 100;
+
+ do
+ {
+ mscblockCommand (CMD_GOIDLESTATE, 0);
+ resp = mscblockResp8b ();
+ }
+ while (resp != 1 && i--);
+
+ if (resp != 1)
+ {
+ if (resp == 0xff)
+ {
+ DBG ("resp=0xff\n");
+ return -1;
+ }
+ else
+ {
+ mscblockResp8bError (resp);
+ DBG ("resp!=0xff\n");
+ return -2;
+ }
+ }
+
+ //
+ // Wait till card is ready initialising (returns 0 on CMD_1)
+ // Try up to 32000 times. */
+ //
+ i = 32000;
+
+ do
+ {
+ mscblockCommand (CMD_SENDOPCOND, 0);
+
+ if ((resp = mscblockResp8b ()) != 0)
+ mscblockResp8bError (resp);
+ }
+ while (resp == 1 && i--);
+
+ if (resp != 0)
+ {
+ mscblockResp8bError (resp);
+ return -3;
+ }
+
+ //
+ // Increase speed after init
+ //
+ // mscspiSetSpeed (SPI_PRESCALE_MIN);
+#endif
+
+ if (mscblockState () < 0)
+ {
+ DBG ("Card didn't return the ready state, breaking up...\n");
+ return -2;
+ }
+
+ DBG ("Init done...\n");
+
+ return 0;
+}
+
+//
+// WAIT ?? -- FIXME
+// CMD_WRITE
+// WAIT
+// CARD RESP
+// WAIT
+// DATA BLOCK OUT
+// START BLOCK
+// DATA
+// CHKS (2B)
+// BUSY...
+//
+int mscblockWrite (U32 dwAddress, U8 * pbBuf)
+{
+ U32 place;
+ U16 t = 0;
+
+ place = 512 * dwAddress;
+ mscblockCommand (CMD_WRITE, place);
+
+ mscblockResp8b (); /* Card response */
+
+ mscspiTransferByte (0xfe); /* Start block */
+ mscspiSendBlock (pbBuf, 512);
+ mscspiTransferByte (0xff); /* Checksum part 1 */
+ mscspiTransferByte (0xff); /* Checksum part 2 */
+
+ mscspiTransferByte (0xff);
+
+ while (spiTransferByte (0xff) != 0xff)
+ t++;
+
+ return 0;
+}
+
+//
+// WAIT ?? -- FIXME
+// CMD_CMD_
+// WAIT
+// CARD RESP
+// WAIT
+// DATA BLOCK IN
+// START BLOCK
+// DATA
+// CHKS (2B)
+//
+int mscblockRead (U32 dwAddress, U8 * pbBuf)
+{
+ U8 cardresp;
+ U8 firstblock;
+ U16 fb_timeout = 0xffff;
+ U32 place;
+
+ place = 512 * dwAddress;
+ mscblockCommand (CMD_READSINGLEBLOCK, place);
+
+ cardresp = mscblockResp8b ();
+
+ //
+ // Wait for startblock
+ //
+ do
+ {
+ firstblock = mscblockResp8b();
+ }
+ while (firstblock == 0xff && fb_timeout--);
+
+ if (cardresp != 0x00 || firstblock != 0xfe)
+ {
+ mscblockResp8bError (firstblock);
+ return -1;
+ }
+
+ mscspiReceiveBlock (pbBuf, 512);
+
+ //
+ // Checksum (2 byte) - ignore for now
+ //
+ mscspiTransferByte (0xff);
+ mscspiTransferByte (0xff);
+
+ return 0;
+}
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 _MSCBLOCK_H_
+#define _MSCBLOCK_H_
+
+#include "sysdefs.h"
+
+int mscblockInit (void);
+int mscblockWrite (U32 dwAddress, U8* pbBuf);
+int mscblockRead (U32 dwAddress, U8* pbBuf);
+int mscblockGetSize (U32 *pdwDriveSize);
+int mscblockGetStatus (void);
+
+#endif
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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.
+*/
+
+/** @file
+
+ Bulk-only-transfer layer for mass storage.
+
+ This layers sits between the generic USB layers and the SCSI layer
+ and performs data transfer according to the BOT protocol.
+*/
+
+#include "FreeRTOS.h"
+
+#include <string.h>
+
+#include "../usb/usbapi.h"
+
+#include "mscdebug.h"
+#include "mscbot.h"
+#include "mscscsi.h"
+
+//
+// Command block wrapper structure
+//
+typedef struct
+{
+ U32 dwCBWSignature;
+ U32 dwCBWTag;
+ U32 dwCBWDataTransferLength;
+ U8 bmCBWFlags;
+ U8 bCBWLun;
+ U8 bCBWCBLength;
+ U8 CBWCB[16];
+}
+TCBW;
+
+//
+// Command status wrapper structure
+//
+typedef struct
+{
+ U32 dwCSWSignature;
+ U32 dwCSWTag;
+ U32 dwCSWDataResidue;
+ U8 bmCSWStatus;
+}
+TCSW;
+
+//
+// States of BOT state machine
+//
+typedef enum
+{
+ eCBW,
+ eDataOut,
+ eDataIn,
+ eCSW,
+ eStalled
+}
+EBotState;
+
+//
+//
+//
+#define CBW_SIGNATURE 0x43425355 /**< magic word in CBW */
+#define CSW_SIGNATURE 0x53425355 /**< magic word in CSW */
+
+#define STATUS_PASSED 0x00 /**< successful transfer */
+#define STATUS_FAILED 0x01 /**< failed transfer */
+#define STATUS_PHASE_ERR 0x02 /**< conflict between host and device */
+
+static U32 dwTransferSize; /**< total size of data transfer */
+static U32 dwOffset; /**< offset in current data transfer */
+static TCBW CBW;
+static TCSW CSW;
+static EBotState eState;
+static U8 *pbData;
+
+//
+// Prepares a CSW, to be sent on next bulk-IN interrupt
+//
+// @param [in] bStatus CSW status
+//
+static void mscbotSendCSW (U8 bStatus)
+{
+ int iResidue;
+
+ iResidue = CBW.dwCBWDataTransferLength - dwTransferSize;
+
+ // construct CSW
+ CSW.dwCSWSignature = CSW_SIGNATURE;
+ CSW.dwCSWTag = CBW.dwCBWTag;
+ CSW.dwCSWDataResidue = MAX (iResidue, 0);
+ CSW.bmCSWStatus = bStatus;
+
+ DBG ("CSW: status=%x, residue=%d\n", bStatus, CSW.dwCSWDataResidue);
+
+ // next state
+ eState = eCSW;
+}
+
+//
+// Checks if CBW is valid and meaningful
+//
+// @param [in] pCBW Command block wrapper
+// @param [in] iLen Length of CBW
+//
+// @return TRUE if valid and meaningful
+//
+static BOOL mscbotCheckCBW (TCBW *pCBW, int iLen)
+{
+ //
+ // CBW valid?
+ //
+ if (iLen != 31)
+ {
+ DBG ("Invalid length (%d)\n", iLen);
+ return FALSE;
+ }
+
+ if (pCBW->dwCBWSignature != CBW_SIGNATURE)
+ {
+ DBG ("Invalid signature %x\n", pCBW->dwCBWSignature);
+ return FALSE;
+ }
+
+ //
+ // CBW meaningful?
+ //
+ if (pCBW->bCBWLun != 0)
+ {
+ DBG ("Invalid LUN %d\n", pCBW->bCBWLun);
+ return FALSE;
+ }
+
+ if ((pCBW->bCBWCBLength < 1) || (pCBW->bCBWCBLength > 16))
+ {
+ DBG ("Invalid CB len %d\n", pCBW->bCBWCBLength);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// mscbotBOTStall
+// Local function to stall ongoing transfer
+//
+// Which endpoint to stall is determined by looking at the transfer
+// direction intended by the host.
+//
+static void mscbotBOTStall (void)
+{
+ if ((CBW.bmCBWFlags & 0x80) || (CBW.dwCBWDataTransferLength == 0))
+ usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+ else
+ usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+}
+
+//
+// mscbotHandleDataIn
+// Handles data from device-to-host
+//
+static void mscbotHandleDataIn (void)
+{
+ int iChunk;
+
+ //
+ // Process data for host in SCSI layer
+ //
+ if ((pbData = mscscsiHandleData (CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset)) == NULL)
+ {
+ mscbotBOTStall ();
+ mscbotSendCSW (STATUS_FAILED);
+ return;
+ }
+
+ //
+ // Send data to host?
+ //
+ if (dwOffset < dwTransferSize)
+ {
+ iChunk = MIN (64, dwTransferSize - dwOffset);
+ usbHardwareEndpointWrite (MSC_BULK_IN_EP, pbData, iChunk);
+ dwOffset += iChunk;
+ }
+
+ //
+ // are we done now?
+ //
+ if (dwOffset == dwTransferSize)
+ {
+ if (dwOffset != CBW.dwCBWDataTransferLength)
+ {
+ DBG ("stalling DIN");
+ mscbotBOTStall ();
+ }
+
+ //
+ // Done
+ //
+ mscbotSendCSW (STATUS_PASSED);
+ }
+}
+
+//
+// mscbotHandleDataOut
+// Handles data from host-to-device
+//
+static void mscbotHandleDataOut (void)
+{
+ int iChunk;
+
+ if (dwOffset < dwTransferSize)
+ {
+ iChunk = usbHardwareEndpointRead (MSC_BULK_OUT_EP, pbData, dwTransferSize - dwOffset);
+ pbData = mscscsiHandleData (CBW.CBWCB, CBW.bCBWCBLength, pbData, dwOffset);
+
+ if (pbData == NULL)
+ {
+ mscbotBOTStall ();
+ mscbotSendCSW (STATUS_FAILED);
+ return;
+ }
+
+ dwOffset += iChunk;
+ }
+
+ //
+ // Are we done now?
+ //
+ if (dwOffset == dwTransferSize)
+ {
+ if (dwOffset != CBW.dwCBWDataTransferLength)
+ {
+ DBG ("stalling DOUT");
+ mscbotBOTStall ();
+ }
+
+ mscbotSendCSW (STATUS_PASSED);
+ }
+}
+
+//
+// Resets the BOT state machine
+//
+void mscbotReset (void)
+{
+ DBG ("BOT reset in state %d\n", eState);
+ eState = eCBW;
+ mscscsiReset ();
+}
+
+//
+// Handles the BOT bulk OUT endpoint
+//
+// @param [in] bEP Endpoint number
+// @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc)
+//
+int mscbotBulkOut (U8 bEP, U8 bEPStatus)
+{
+ unsigned int iLen, iChunk;
+ BOOL fHostIn, fDevIn;
+
+ //
+ // Ignore events on stalled EP
+ //
+ if (bEPStatus & EP_STATUS_STALLED)
+ return 0;
+
+ switch (eState)
+ {
+ case eCBW:
+ {
+ iLen = usbHardwareEndpointRead (bEP, (U8 *)&CBW, sizeof(CBW));
+
+ if (!mscbotCheckCBW(&CBW, iLen))
+ {
+ usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+ usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+ eState = eStalled;
+ break;
+ }
+
+ DBG ("CBW: len=%d, flags=%x, cmd=%x, cmdlen=%d\n", CBW.dwCBWDataTransferLength, CBW.bmCBWFlags, CBW.CBWCB[0], CBW.bCBWCBLength);
+
+ dwOffset = 0;
+ dwTransferSize = 0;
+ fHostIn = ((CBW.bmCBWFlags & 0x80) != 0);
+
+ //
+ // Verify request. Unknown command if NULL
+ //
+ if ((pbData = mscscsiHandleCmd (CBW.CBWCB, CBW.bCBWCBLength, &iLen, &fDevIn)) == NULL)
+ {
+ mscbotBOTStall ();
+ mscbotSendCSW (STATUS_FAILED);
+ break;
+ }
+
+ //
+ // Rule: if device and host disagree on direction, send CSW with status 2
+ //
+ if ((iLen > 0) && ((fHostIn && !fDevIn) || (!fHostIn && fDevIn)))
+ {
+ DBG ("Host and device disagree on direction\n");
+ mscbotBOTStall ();
+ mscbotSendCSW (STATUS_PHASE_ERR);
+ break;
+ }
+
+ //
+ // Rule: if D > H, send CSW with status 2
+ //
+ if (iLen > CBW.dwCBWDataTransferLength)
+ {
+ DBG ("Negative residue\n");
+ mscbotBOTStall ();
+ mscbotSendCSW (STATUS_PHASE_ERR);
+ break;
+ }
+
+ if (((dwTransferSize = iLen) == 0) || fDevIn)
+ {
+ //
+ // Data from device-to-host
+ //
+ eState = eDataIn;
+ mscbotHandleDataIn ();
+ }
+ else
+ {
+ //
+ // Data from host-to-device
+ //
+ eState = eDataOut;
+ }
+ }
+ break;
+
+ case eDataOut:
+ {
+ mscbotHandleDataOut ();
+ }
+ break;
+
+ case eDataIn:
+ case eCSW:
+ {
+ iChunk = usbHardwareEndpointRead (bEP, NULL, 0);
+ DBG ("Phase error in state %d, %d bytes\n", eState, iChunk);
+ eState = eCBW;
+ }
+ break;
+
+ case eStalled:
+ {
+ usbHardwareEndpointStall (MSC_BULK_OUT_EP, TRUE);
+ }
+ break;
+
+ default:
+ {
+ DBG ("Invalid state %d\n", eState);
+ ASSERT (FALSE);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+//
+// Handles the BOT bulk IN endpoint
+//
+// @param [in] bEP Endpoint number
+// @param [in] bEPStatus Endpoint status (indicates NAK, STALL, etc)
+//
+int mscbotBulkIn (U8 bEP __attribute__ ((unused)), U8 bEPStatus)
+{
+ if (bEPStatus & EP_STATUS_STALLED)
+ return 0;
+
+ switch (eState)
+ {
+ //
+ // Ignore possibly old ACKs
+ //
+ case eCBW:
+ case eDataOut:
+ break;
+
+ case eDataIn:
+ mscbotHandleDataIn ();
+ break;
+
+ //
+ // Wait for an IN token, then send the CSW
+ //
+ case eCSW:
+ usbHardwareEndpointWrite (MSC_BULK_IN_EP, (U8 *)&CSW, 13);
+ eState = eCBW;
+ break;
+
+ //
+ // Keep stalling
+ //
+ case eStalled:
+ usbHardwareEndpointStall (MSC_BULK_IN_EP, TRUE);
+ break;
+
+ default:
+ DBG ("Invalid state %d\n", eState);
+ ASSERT (FALSE);
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 _MSCBOT_H_
+#define _MSCBOT_H_
+
+#include "sysdefs.h"
+
+#define MSC_BULK_OUT_EP 0x02
+#define MSC_BULK_IN_EP 0x85
+
+void mscbotReset (void);
+int mscbotBulkOut (U8 bEP, U8 bEPStatus);
+int mscbotBulkIn (U8 bEP, U8 bEPStatus);
+
+#endif
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 _USBDEBUG_H_
+#define _USBDEBUG_H_
+
+#include <stdio.h>
+
+#ifdef USBDEBUG
+#define DBG printf
+#define ASSERT(x) if(!(x)){DBG("\nAssertion '%s' failed in %s:%s#%d!\n",#x,__FILE__,__FUNCTION__,__LINE__);while(1);}
+#else
+#define DBG(x ...) do { } while (0)
+#define ASSERT(x) do { } while (0)
+#endif
+
+#endif
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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.
+*/
+
+/**
+ @file
+
+ This is the SCSI layer of the USB mass storage application example.
+ This layer depends directly on the blockdev layer.
+
+ Windows peculiarities:
+ * Size of REQUEST SENSE CDB is 12 bytes instead of expected 6
+ * Windows requires VERIFY(10) command to do a format.
+ This command is not mandatory in the SBC/SBC-2 specification.
+*/
+
+#include "FreeRTOS.h"
+
+#include <string.h> // memcpy
+
+#include "mscdebug.h"
+#include "mscblock.h"
+#include "mscscsi.h"
+
+//
+//
+//
+#define BLOCKSIZE 512
+
+//
+// SBC2 mandatory SCSI commands
+//
+#define SCSI_CMD_TEST_UNIT_READY 0x00
+#define SCSI_CMD_REQUEST_SENSE 0x03
+#define SCSI_CMD_FORMAT_UNIT 0x04
+#define SCSI_CMD_READ_6 0x08 /* not implemented yet */
+#define SCSI_CMD_INQUIRY 0x12
+#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D /* not implemented yet */
+#define SCSI_CMD_READ_CAPACITY_10 0x25
+#define SCSI_CMD_READ_10 0x28
+#define SCSI_CMD_REPORT_LUNS 0xa0 /* not implemented yet */
+
+//
+// SBC2 optional SCSI commands
+//
+#define SCSI_CMD_WRITE_6 0x0a /* not implemented yet */
+#define SCSI_CMD_WRITE_10 0x2a
+#define SCSI_CMD_VERIFY_10 0x2f /* required for windows format */
+
+//
+// Sense codes
+//
+#define WRITE_ERROR 0x030C00
+#define READ_ERROR 0x031100
+#define INVALID_CMD_OPCODE 0x052000
+#define INVALID_FIELD_IN_CDB 0x052400
+
+//
+// Sense code, which is set on error conditions
+// Hex: 00aabbcc, where aa=KEY, bb=ASC, cc=ASCQ
+//
+static U32 dwSense;
+
+static const U8 abInquiry[] =
+{
+ 0x00, // PDT = direct-access device
+ 0x80, // removeable medium bit = set
+ 0x05, // version = complies to SPC3
+ 0x02, // response data format = SPC3
+ 0x1F, // additional length
+ 0x00,
+ 0x00,
+ 0x00,
+ 'L','P','C','U','S','B',' ',' ', // vendor
+ 'M','a','s','s',' ','s','t','o', // product
+ 'r','a','g','e',' ',' ',' ',' ',
+ '0','.','1',' ' // revision
+};
+
+//
+// Data for "request sense" command. The 0xFF are filled in later
+//
+static const U8 abSense[] = { 0x70, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0A,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+ 0x00, 0x00 };
+
+//
+// Buffer for holding one block of disk data
+//
+static U8 abBlockBuf [512];
+
+typedef struct
+{
+ U8 bOperationCode;
+ U8 abLBA [3];
+ U8 bLength;
+ U8 bControl;
+}
+TCDB6;
+
+//
+//
+//
+void mscscsiReset (void)
+{
+ dwSense = 0;
+}
+
+//
+// SCSIHandleCmd
+// Verifies a SCSI CDB and indicates the direction and amount of data
+// that the device wants to transfer.
+//
+// If this call fails, a sense code is set in dwSense.
+//
+// IN pbCDB - Command data block
+// iCDBLen - Command data block len
+// OUT *piRspLen - Length of intended response data:
+// *pfDevIn - TRUE if data is transferred from device-to-host
+//
+// Returns a pointer to the data exchange buffer if successful,
+// return NULL otherwise.
+//
+U8 *mscscsiHandleCmd (U8 *pbCDB, U8 iCDBLen, unsigned int *piRspLen, BOOL *pfDevIn)
+{
+ static const U8 aiCDBLen [] = {6, 10, 10, 0, 16, 12, 0, 0};
+ int i;
+ TCDB6 *pCDB;
+ U32 dwLen, dwLBA;
+ U8 bGroupCode;
+
+ pCDB = (TCDB6 *) pbCDB;
+
+ // default direction is from device to host
+ *pfDevIn = TRUE;
+
+ // check CDB length
+ bGroupCode = (pCDB->bOperationCode >> 5) & 0x7;
+
+ if (iCDBLen < aiCDBLen[bGroupCode])
+ {
+ DBG("Invalid CBD len (expected %d)!\n", aiCDBLen[bGroupCode]);
+ return NULL;
+ }
+
+ switch (pCDB->bOperationCode)
+ {
+ case SCSI_CMD_TEST_UNIT_READY :
+ DBG ("TEST UNIT READY\n");
+ *piRspLen = 0;
+ break;
+
+ case SCSI_CMD_REQUEST_SENSE :
+ DBG ("REQUEST SENSE (%06X)\n", dwSense);
+ *piRspLen = MIN (18, pCDB->bLength);
+ break;
+
+ case SCSI_CMD_FORMAT_UNIT :
+ DBG ("FORMAT UNIT %02X\n", pbCDB[1]);
+ *piRspLen = 0;
+ break;
+
+ case SCSI_CMD_INQUIRY :
+ DBG ("INQUIRY\n");
+ *piRspLen = MIN (36, pCDB->bLength);
+ break;
+
+ case SCSI_CMD_READ_CAPACITY_10 :
+ DBG ("READ CAPACITY\n");
+ *piRspLen = 8;
+ break;
+
+ case SCSI_CMD_READ_10 :
+ dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+ dwLen = (pbCDB [7] << 8) | pbCDB [8];
+ DBG ("READ10, LBA=%d, len=%d\n", dwLBA, dwLen);
+ *piRspLen = dwLen * BLOCKSIZE;
+ break;
+
+ case SCSI_CMD_WRITE_10 :
+ dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+ dwLen = (pbCDB [7] << 8) | pbCDB [8];
+ DBG ("WRITE10, LBA=%d, len=%d\n", dwLBA, dwLen);
+ *piRspLen = dwLen * BLOCKSIZE;
+ *pfDevIn = FALSE;
+ break;
+
+ case SCSI_CMD_VERIFY_10 :
+ DBG ("VERIFY10\n");
+ if ((pbCDB [1] & (1 << 1)) != 0)
+ {
+ DBG ("BYTCHK not supported\n");
+ return NULL;
+ }
+ *piRspLen = 0;
+ break;
+
+ default :
+ DBG ("Unhandled SCSI: ");
+ for (i = 0; i < iCDBLen; i++)
+ DBG (" %02X", pbCDB[i]);
+ DBG ("\n");
+
+ dwSense = INVALID_CMD_OPCODE;
+ *piRspLen = 0;
+ return NULL;
+ }
+
+ return abBlockBuf;
+}
+
+//
+// SCSIHandleData
+// Handles a block of SCSI data.
+//
+// IN pbCDB . Command data block
+// iCDBLen - Command data block len
+// IN/OUT pbData - Data buffer
+// IN dwOffset - Offset in data
+//
+// Returns a pointer to the next data to be exchanged if successful,
+// returns NULL otherwise.
+//
+U8 *mscscsiHandleData (U8 *pbCDB, U8 iCDBLen __attribute__ ((unused)), U8 *pbData, U32 dwOffset)
+{
+ TCDB6 *pCDB;
+ U32 dwLBA;
+ U32 dwBufPos, dwBlockNr;
+ U32 dwDevSize, dwMaxBlock;
+
+ pCDB = (TCDB6 *)pbCDB;
+
+ switch (pCDB->bOperationCode)
+ {
+ case SCSI_CMD_TEST_UNIT_READY :
+ if (dwSense != 0)
+ return NULL;
+ break;
+
+ case SCSI_CMD_REQUEST_SENSE :
+ memcpy (pbData, abSense, 18);
+ pbData [2] = (dwSense >> 16) & 0xff;
+ pbData [12] = (dwSense >> 8) & 0xff;
+ pbData [13] = (dwSense >> 0) & 0xff;
+ dwSense = 0;
+ break;
+
+ case SCSI_CMD_FORMAT_UNIT :
+ break;
+
+ case SCSI_CMD_INQUIRY :
+ memcpy (pbData, abInquiry, sizeof(abInquiry));
+ break;
+
+ case SCSI_CMD_READ_CAPACITY_10:
+ mscblockGetSize (&dwDevSize);
+ dwMaxBlock = (dwDevSize - 1) / 512;
+ pbData [0] = (dwMaxBlock >> 24) & 0xff;
+ pbData [1] = (dwMaxBlock >> 16) & 0xff;
+ pbData [2] = (dwMaxBlock >> 8) & 0xff;
+ pbData [3] = (dwMaxBlock >> 0) & 0xff;
+ pbData [4] = (BLOCKSIZE >> 24) & 0xff;
+ pbData [5] = (BLOCKSIZE >> 16) & 0xff;
+ pbData [6] = (BLOCKSIZE >> 8) & 0xff;
+ pbData [7] = (BLOCKSIZE >> 0) & 0xff;
+ break;
+
+ case SCSI_CMD_READ_10 :
+ dwLBA = (pbCDB [2] << 24) | (pbCDB [3] << 16) | (pbCDB [4] << 8) | (pbCDB [5]);
+ dwBufPos = (dwOffset & (BLOCKSIZE - 1));
+ if (dwBufPos == 0)
+ {
+ dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+ DBG ("R");
+ if (mscblockRead(dwBlockNr, abBlockBuf) < 0)
+ {
+ dwSense = READ_ERROR;
+ DBG ("mscblockRead failed\n");
+ return NULL;
+ }
+ }
+
+ return abBlockBuf + dwBufPos ;
+
+ case SCSI_CMD_WRITE_10:
+ dwLBA = (pbCDB[2] << 24) | (pbCDB[3] << 16) | (pbCDB[4] << 8) | (pbCDB[5]);
+
+ dwBufPos = ((dwOffset + 64) & (BLOCKSIZE - 1));
+ if (dwBufPos == 0)
+ {
+ dwBlockNr = dwLBA + (dwOffset / BLOCKSIZE);
+ DBG ("W");
+ if (mscblockWrite (dwBlockNr, abBlockBuf) < 0)
+ {
+ dwSense = WRITE_ERROR;
+ DBG ("mscblockWrite failed\n");
+ return NULL;
+ }
+ }
+ return abBlockBuf + dwBufPos;
+
+ case SCSI_CMD_VERIFY_10 :
+ break;
+
+ default :
+ dwSense = INVALID_CMD_OPCODE;
+ return NULL;
+ }
+
+ return abBlockBuf;
+}
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 _MSCSCSI_H_
+#define _MSCSCSI_H_
+
+#include "sysdefs.h"
+
+void mscscsiReset (void);
+U8 *mscscsiHandleCmd (U8 *pbCDB, U8 bCDBLen, unsigned int *piRspLen, BOOL *pfDevIn);
+U8 *mscscsiHandleData (U8 *pbCDB, U8 bCDBLen, U8 *pbData, U32 dwOffset);
+
+#endif
--- /dev/null
+/*****************************************************************************\
+* efs - General purpose Embedded Filesystem library *
+* --------------------- ----------------------------------- *
+* *
+* Filename : lpc2000_spi.c *
+* Description : This contains the functions needed to use efs for *
+* accessing files on an SD-card connected to an LPC2xxx. *
+* *
+* This library is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU Lesser General Public *
+* License as published by the Free Software Foundation; either *
+* version 2.1 of the License, or (at your option) any later version. *
+* *
+* This library 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 *
+* Lesser General Public License for more details. *
+* *
+* (c)2005 Martin Thomas *
+* *
+\*****************************************************************************/
+
+/*
+ 2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+//
+//
+//
+#include "FreeRTOS.h"
+
+#include "../fatfs/spi.h"
+
+#include "mscspi.h"
+
+//
+//
+//
+#define SELECT_CARD() do { GPIO0_IOCLR = GPIO_IO_P20; } while (0)
+#define UNSELECT_CARD() do { GPIO0_IOSET = GPIO_IO_P20; } while (0)
+
+//
+//
+//
+void mscspiInit (void)
+{
+ spiInit ();
+}
+
+//
+//
+//
+U8 mscspiTransferByte (U8 outgoing)
+{
+ U8 r;
+
+ spiChipSelect (1);
+ r = spiTransferByte (outgoing);
+ spiChipSelect (0);
+
+ return r;
+}
+
+//
+//
+//
+void mscspiSendBlock (U8 *pbBuf, int iLen)
+{
+ spiChipSelect (1);
+ spiSendBlock (pbBuf, iLen);
+ spiChipSelect (0);
+}
+
+//
+//
+//
+void mscspiReceiveBlock (U8 *pbBuf, int iLen)
+{
+ spiChipSelect (1);
+ spiReceiveBlock (pbBuf, iLen);
+ spiChipSelect (0);
+}
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 _MSCSPI_H_
+#define _MSCSPI_H_
+
+//
+//
+//
+#include "sysdefs.h"
+
+//
+//
+//
+#define SPI_PRESCALE_MIN 8
+
+//
+//
+//
+void mscspiInit (void);
+U8 mscspiTransferByte (U8 outgoing);
+void mscspiSendBlock (U8 *pbBuf, int iLen);
+void mscspiReceiveBlock (U8 *pbBuf, int iLen);
+
+#endif
--- /dev/null
+/*****************************************************************************\
+* efs - General purpose Embedded Filesystem library *
+* --------------------- ----------------------------------- *
+* *
+* Filename : lpc2000_spi.c *
+* Description : This contains the functions needed to use efs for *
+* accessing files on an SD-card connected to an LPC2xxx. *
+* *
+* This library is free software; you can redistribute it and/or *
+* modify it under the terms of the GNU Lesser General Public *
+* License as published by the Free Software Foundation; either *
+* version 2.1 of the License, or (at your option) any later version. *
+* *
+* This library 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 *
+* Lesser General Public License for more details. *
+* *
+* (c)2005 Martin Thomas *
+* *
+\*****************************************************************************/
+
+/*
+ 2006, Bertrik Sikken, modified for LPCUSB
+*/
+
+//
+//
+//
+#include "FreeRTOS.h"
+
+#include "../fatfs/spi.h"
+
+#include "mscspi.h"
+
+//
+//
+//
+#define SELECT_CARD() do { GPIO0_IOCLR = GPIO_IO_P20; } while (0)
+#define UNSELECT_CARD() do { GPIO0_IOSET = GPIO_IO_P20; } while (0)
+
+//
+//
+//
+void mscspiInit (void)
+{
+ spiInit ();
+}
+
+//
+//
+//
+U8 mscspiTransferByte (U8 outgoing)
+{
+ U8 r;
+
+ SELECT_CARD ();
+ r = spiTransferByte (outgoing);
+ UNSELECT_CARD ();
+
+ return r;
+}
+
+//
+//
+//
+void mscspiSendBlock (U8 *pbBuf, int iLen)
+{
+ SELECT_CARD ();
+ spiSendBlock (pbBuf, iLen);
+ UNSELECT_CARD ();
+}
+
+//
+//
+//
+void mscspiReceiveBlock (U8 *pbBuf, int iLen)
+{
+ SELECT_CARD ();
+ spiReceiveBlock (pbBuf, iLen);
+ UNSELECT_CARD ();
+}
--- /dev/null
+/*
+ LPCUSB, an USB device driver for LPC microcontrollers
+ Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR 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 "FreeRTOS.h"
+
+#include "../usb/usbapi.h"
+
+#include "mscdebug.h"
+#include "mscbot.h"
+#include "mscblock.h"
+#include "usbmass.h"
+
+//
+//
+//
+#define MAX_PACKET_SIZE 64
+#define LE_WORD(x) ((x)&0xff),((x)>>8)
+
+//
+//
+//
+static U8 abClassReqData [4];
+
+static const U8 abDescriptors [] =
+{
+ //
+ // Device descriptor
+ //
+ 0x12,
+ DESC_DEVICE,
+ LE_WORD(0x0200), // bcdUSB
+ 0x00, // bDeviceClass
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ MAX_PACKET_SIZE0, // bMaxPacketSize
+ LE_WORD(0xFFFF), // idVendor
+ LE_WORD(0x0003), // idProduct
+ LE_WORD(0x0100), // bcdDevice
+ 0x01, // iManufacturer
+ 0x02, // iProduct
+ 0x03, // iSerialNumber
+ 0x01, // bNumConfigurations
+
+ //
+ // Configuration descriptor
+ //
+ 0x09,
+ DESC_CONFIGURATION,
+ LE_WORD(32), // wTotalLength
+ 0x01, // bNumInterfaces
+ 0x01, // bConfigurationValue
+ 0x00, // iConfiguration
+ 0xC0, // bmAttributes
+ 0x32, // bMaxPower
+
+ //
+ // Interface
+ //
+ 0x09,
+ DESC_INTERFACE,
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndPoints
+ 0x08, // bInterfaceClass = mass storage
+ 0x06, // bInterfaceSubClass = transparent SCSI
+ 0x50, // bInterfaceProtocol = BOT
+ 0x00, // iInterface
+
+ //
+ // EP
+ //
+ 0x07,
+ DESC_ENDPOINT,
+ MSC_BULK_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+
+ //
+ // EP
+ //
+ 0x07,
+ DESC_ENDPOINT,
+ MSC_BULK_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+
+ //
+ // String descriptors
+ //
+ 0x04,
+ DESC_STRING,
+ LE_WORD(0x0409),
+
+ 0x0E,
+ DESC_STRING,
+ 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+ 0x12,
+ DESC_STRING,
+ 'P', 0, 'r', 0, 'o', 0, 'd', 0, 'u', 0, 'c', 0, 't', 0, 'X', 0,
+
+ 0x1A,
+ DESC_STRING,
+ 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0, 'C', 0, 'A', 0, 'F', 0, 'E', 0,
+
+ // terminating zero
+ 0
+};
+
+
+//
+//
+//
+static BOOL HandleClassRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ if (pSetup->wIndex != 0)
+ {
+ DBG ("Invalid idx %X\n", pSetup->wIndex);
+ return FALSE;
+ }
+
+ if (pSetup->wValue != 0)
+ {
+ DBG ("Invalid val %X\n", pSetup->wValue);
+ return FALSE;
+ }
+
+ switch (pSetup->bRequest)
+ {
+ //
+ // Get max LUN (always return no LUNs)
+ //
+ case 0xfe:
+ {
+ *ppbData [0] = 0;
+ *piLen = 1;
+ }
+ break;
+
+ //
+ // MSC reset
+ //
+ case 0xff:
+ {
+ if (pSetup->wLength > 0)
+ return FALSE;
+
+ mscbotReset ();
+ }
+ break;
+
+ default:
+ {
+ DBG ("Unhandled class\n");
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+//
+//
+void usbmassInit (void)
+{
+ portENTER_CRITICAL ();
+ mscblockInit ();
+ usbRegisterHandlers ();
+ usbRegisterDescriptors (abDescriptors);
+ usbRegisterRequestHandler (REQTYPE_TYPE_CLASS, HandleClassRequest, abClassReqData);
+ usbHardwareRegisterEPIntHandler (MSC_BULK_IN_EP, mscbotBulkIn);
+ usbHardwareRegisterEPIntHandler (MSC_BULK_OUT_EP, mscbotBulkOut);
+ usbHardwareNakIntEnable (INACK_BI);
+ usbSetupInterruptHandler ();
+ portEXIT_CRITICAL ();
+
+ usbHardwareConnect (TRUE);
+}
--- /dev/null
+#ifndef _USBMASS_H_
+#define _USBMASS_H_
+
+void usbmassInit (void);
+
+#endif
--- /dev/null
+SRC_FILES=usbser.c
+
+#
+# Define all object files.
+#
+ARM_OBJ = $(SRC_FILES:.c=.o)
+
+.PHONY: all
+all: $(ARM_OBJ)
+
+$(ARM_OBJ) : %.o : %.c Makefile .depend
+ $(CC) -c $(CFLAGS) $< -o $@
+ $(AR) r $(COMMON)/common.a $@
+
+#
+# The .depend files contains the list of header files that the
+# various source files depend on. By doing this, we'll only
+# rebuild the .o's that are affected by header files changing.
+#
+.depend:
+ $(CC) $(CFLAGS) -M $(SRC_FILES) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+#include "../usb/usbapi.h"
+#include "usbser.h"
+
+//
+//
+//
+#define EOF (-1)
+
+#define INT_IN_EP 0x81
+#define BULK_OUT_EP 0x05
+#define BULK_IN_EP 0x82
+
+#define MAX_PACKET_SIZE 64
+
+#define LE_WORD(x) ((x)&0xFF),((x)>>8)
+
+// CDC definitions
+#define CS_INTERFACE 0x24
+#define CS_ENDPOINT 0x25
+
+#define SET_LINE_CODING 0x20
+#define GET_LINE_CODING 0x21
+#define SET_CONTROL_LINE_STATE 0x22
+
+//
+// Data structure for GET_LINE_CODING / SET_LINE_CODING class requests
+//
+typedef struct
+{
+ U32 dwDTERate;
+ U8 bCharFormat;
+ U8 bParityType;
+ U8 bDataBits;
+}
+TLineCoding;
+
+static TLineCoding LineCoding = {115200, 0, 0, 8};
+static U8 abBulkBuf [64];
+static U8 abClassReqData [8];
+static xQueueHandle xRXQueue = NULL;
+static xQueueHandle xTXQueue = NULL;
+static int usbSerialInitialized = FALSE;
+
+//
+//
+//
+static const U8 abDescriptors [] =
+{
+ //
+ // Device descriptor
+ //
+ 0x12,
+ DESC_DEVICE,
+ LE_WORD(0x0200), // bcdUSB
+ 0x02, // bDeviceClass
+ 0x00, // bDeviceSubClass
+ 0x00, // bDeviceProtocol
+ MAX_PACKET_SIZE0, // bMaxPacketSize
+ LE_WORD(0xFFFF), // idVendor
+ LE_WORD(0x0005), // idProduct
+ LE_WORD(0x0100), // bcdDevice
+ 0x01, // iManufacturer
+ 0x02, // iProduct
+ 0x03, // iSerialNumber
+ 0x01, // bNumConfigurations
+
+ //
+ // Configuration descriptor
+ //
+ 0x09,
+ DESC_CONFIGURATION,
+ LE_WORD(67), // wTotalLength
+ 0x02, // bNumInterfaces
+ 0x01, // bConfigurationValue
+ 0x00, // iConfiguration
+ 0xC0, // bmAttributes
+ 0x32, // bMaxPower
+
+ //
+ // Control class interface
+ //
+ 0x09,
+ DESC_INTERFACE,
+ 0x00, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x01, // bNumEndPoints
+ 0x02, // bInterfaceClass
+ 0x02, // bInterfaceSubClass
+ 0x01, // bInterfaceProtocol, linux requires value of 1 for the cdc_acm module
+ 0x00, // iInterface
+
+ //
+ // Header functional descriptor
+ //
+ 0x05,
+ CS_INTERFACE,
+ 0x00,
+ LE_WORD(0x0110),
+
+ //
+ // Call management functional descriptor
+ //
+ 0x05,
+ CS_INTERFACE,
+ 0x01,
+ 0x01, // bmCapabilities = device handles call management
+ 0x01, // bDataInterface
+
+ //
+ // ACM functional descriptor
+ //
+ 0x04,
+ CS_INTERFACE,
+ 0x02,
+ 0x02, // bmCapabilities
+
+ //
+ // Union functional descriptor
+ //
+ 0x05,
+ CS_INTERFACE,
+ 0x06,
+ 0x00, // bMasterInterface
+ 0x01, // bSlaveInterface0
+
+ //
+ // Notification EP
+ //
+ 0x07,
+ DESC_ENDPOINT,
+ INT_IN_EP, // bEndpointAddress
+ 0x03, // bmAttributes = intr
+ LE_WORD(8), // wMaxPacketSize
+ 0x0A, // bInterval
+
+ //
+ // Data class interface descriptor
+ //
+ 0x09,
+ DESC_INTERFACE,
+ 0x01, // bInterfaceNumber
+ 0x00, // bAlternateSetting
+ 0x02, // bNumEndPoints
+ 0x0A, // bInterfaceClass = data
+ 0x00, // bInterfaceSubClass
+ 0x00, // bInterfaceProtocol
+ 0x00, // iInterface
+
+ //
+ // Data EP OUT
+ //
+ 0x07,
+ DESC_ENDPOINT,
+ BULK_OUT_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+
+ //
+ // Data EP in
+ //
+ 0x07,
+ DESC_ENDPOINT,
+ BULK_IN_EP, // bEndpointAddress
+ 0x02, // bmAttributes = bulk
+ LE_WORD(MAX_PACKET_SIZE), // wMaxPacketSize
+ 0x00, // bInterval
+
+ //
+ // String descriptors
+ //
+ 0x04,
+ DESC_STRING,
+ LE_WORD(0x0409),
+
+ 0x0E,
+ DESC_STRING,
+ 'L', 0, 'P', 0, 'C', 0, 'U', 0, 'S', 0, 'B', 0,
+
+ 0x14,
+ DESC_STRING,
+ 'U', 0, 'S', 0, 'B', 0, 'S', 0, 'e', 0, 'r', 0, 'i', 0, 'a', 0, 'l', 0,
+
+ 0x12,
+ DESC_STRING,
+ 'D', 0, 'E', 0, 'A', 0, 'D', 0, 'C', 0, '0', 0, 'D', 0, 'E', 0,
+
+ //
+ // Terminating zero
+ //
+ 0
+};
+
+//
+// Local function to handle incoming bulk data. This needs to copy the incoming data to the VCOM RX queue.
+//
+static int usbserBulkOut (U8 bEP, U8 bEPStatus __attribute__ ((unused)))
+{
+ int i;
+ int iLen;
+ portBASE_TYPE xTaskWokenByPost = pdFALSE;
+
+ iLen = usbHardwareEndpointRead (bEP, abBulkBuf, sizeof (abBulkBuf));
+
+ for (i = 0; i < iLen; i++)
+ xTaskWokenByPost = xQueueSendFromISR (xRXQueue, &abBulkBuf [i], xTaskWokenByPost);
+
+ return xTaskWokenByPost;
+}
+
+//
+// Local function to handle outgoing bulk data. This needs to copy any user data in the VCOM TX queue to the bulk endpoint.
+//
+static int usbserBulkIn (U8 bEP, U8 bEPStatus __attribute__ ((unused)))
+{
+ int i;
+ portBASE_TYPE xTaskWoken = pdFALSE;
+
+ for (i = 0; i < MAX_PACKET_SIZE; i++)
+ if (!xQueueReceiveFromISR (xTXQueue, &abBulkBuf [i], &xTaskWoken))
+ break;
+
+ if (i > 0)
+ usbHardwareEndpointWrite (bEP, abBulkBuf, i);
+
+ return xTaskWoken;
+}
+
+//
+// Local function to handle the USB-CDC class requests
+//
+static BOOL usbserHandleClassRequest (TSetupPacket *pSetup, int *piLen, U8 **ppbData)
+{
+ switch (pSetup->bRequest)
+ {
+ case SET_LINE_CODING:
+ {
+ memcpy ((U8 *) &LineCoding, *ppbData, 7);
+ *piLen = 7;
+ }
+ break;
+
+ case GET_LINE_CODING:
+ {
+ *ppbData = (U8 *) &LineCoding;
+ *piLen = 7;
+ }
+ break;
+
+ case SET_CONTROL_LINE_STATE:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// Writes one character to VCOM port
+//
+signed portBASE_TYPE usbserPutChar (signed portCHAR cOutChar, portTickType xBlockTime)
+{
+ if (!usbSerialInitialized)
+ return pdFALSE;
+
+ return xQueueSend (xTXQueue, &cOutChar, xBlockTime);
+}
+
+signed portBASE_TYPE usbserPutString (const signed portCHAR * const pcString, portTickType xBlockTime)
+{
+ signed portCHAR *pxNext;
+
+ if (!usbSerialInitialized)
+ return pdFALSE;
+
+ pxNext = (signed portCHAR *) pcString;
+
+ while (*pxNext)
+ {
+ if (!usbserPutChar (*pxNext, xBlockTime))
+ return pdFALSE;
+
+ pxNext++;
+ }
+
+ return pdTRUE;
+}
+
+//
+// Reads one character from VCOM port
+//
+signed portBASE_TYPE usbserGetChar (signed portCHAR *pcRxedChar, portTickType xBlockTime)
+{
+ if (!usbSerialInitialized)
+ return pdFALSE;
+
+ if (xQueueReceive (xRXQueue, pcRxedChar, xBlockTime))
+ return pdTRUE;
+ else
+ return pdFALSE;
+}
+
+void usbserGetRxQueue (xQueueHandle *qh)
+{
+ *qh = xRXQueue;
+}
+
+//
+//
+//
+void usbserInit (void)
+{
+ portENTER_CRITICAL ();
+ usbRegisterHandlers ();
+ usbRegisterDescriptors (abDescriptors);
+ usbRegisterRequestHandler (REQTYPE_TYPE_CLASS, usbserHandleClassRequest, abClassReqData);
+ usbHardwareRegisterEPIntHandler (INT_IN_EP, NULL);
+ usbHardwareRegisterEPIntHandler (BULK_IN_EP, usbserBulkIn);
+ usbHardwareRegisterEPIntHandler (BULK_OUT_EP, usbserBulkOut);
+ usbHardwareNakIntEnable (INACK_BI);
+ usbSetupInterruptHandler ();
+ xRXQueue = xQueueCreate (256, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+ xTXQueue = xQueueCreate (256, (unsigned portBASE_TYPE) sizeof (signed portCHAR));
+ usbSerialInitialized = TRUE;
+ portEXIT_CRITICAL ();
+
+ usbHardwareConnect (TRUE);
+}
--- /dev/null
+#ifndef _USBSER_H_
+#define _USBSER_H_
+
+#include "FreeRTOS.h"
+#include "queue.h"
+
+//
+//
+//
+signed portBASE_TYPE usbserPutChar (signed portCHAR cOutChar, portTickType xBlockTime);
+signed portBASE_TYPE usbserPutString (const signed portCHAR * const pcString, portTickType xBlockTime);
+signed portBASE_TYPE usbserGetChar (signed portCHAR *pcRxedChar, portTickType xBlockTime);
+void usbserInit (void);
+void usbserGetRxQueue (xQueueHandle *qh);
+
+#endif