Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Thread

SPI delay

SPI delay

2005-01-18 by teunvandeberg

Hello all,

I have written a SPI driver for use with FreeRTOS (www.freertos.org). 
I am using a LPC2292.
Using this driver I have observed some strange behavior. The driver 
is interrupt driven, so I write to the SPI data register again after 
the interrupt flag goes hi. Sometimes however, nothing happens on the 
SPI pins. If I add a small delay, no problems occur, however this 
should not be necessary. When debugging, this problem doesn't occur 
so that also suggests timing problems. Is anyone familiar with this 
problem? For more details I attached my code below.
Thank you in advance,

Teun

--------------------------------------------------------------------
Here's the calling code:
--------------------------------------------------------------------
unsigned portCHAR cBatmanPing()
{
	unsigned portCHAR ucPingReturn;

        int i;
	
	/* Setup the spi bus for the BATMAN */
	prvInitBus();
		
	/* Now we can give our ping command. */
	if( cSpiPutChar( BATMANspiDEV, BATMANPing, BATMANBlockTime ) !
= pdTRUE ) //Send the write command and the adress.
	{
		prvFreeBus();
		return pdFALSE;
	}
		
	/* Give the data */
	if( cSpiPutChar( BATMANspiDEV, BATMANpingData, 
BATMANBlockTime ) != pdTRUE ) //Send the write command and the adress.
	{
		prvFreeBus();
		return pdFALSE;
	}

        for( i = 0 ; i < 60 ; i++ )
          ; // This is the delay. Whithout this the read the comes 
next will not drive the clock.

	/* Read the data */
	if( cSpiGetChar( BATMANspiDEV, &ucPingReturn, 
BATMANBlockTime ) != pdTRUE )
	{
		prvFreeBus();
		return pdFALSE;
	}
		
	/* Free the spi bus */
	prvFreeBus();
	
	/* Check if we received the correct data */
	if(~ucPingReturn != BATMANpingData)
		return pdFALSE;
	
	return pdTRUE;
}
--------------------------------------------------------------------
spi.c:
--------------------------------------------------------------------
/*	
	Description:	BASIC INTERRUPT DRIVER SPI BUS DRIVER FOR THE 
LPC2114.
					
					This file contains all the 
SPI driver components that can be
					compiled to either ARM or 
THUMB mode. Components the must be
					compiled to ARM mode are 
contained in spiisr.c. This driver
					is designed for use with 
FreeRTOS v2.5.0.
	
	Date:			18-11-2004
	
	Author:			Teun van de Berg
	
	Version:		0.5
	
	Todo:			Debugging.
	
	Note: 			The bus must always be initialized 
when calling the iReserveSpiBus function.
					There are more of these 
logical dependencies, one example is that you should not free the bus
					if you haven't reserved it.
		
	Revision history:
        0.6                             Fixed the reserve and free 
bus functions.
	0.4A                            Change SPI so that it sends 
dummy date when trying to read.
					Some comment updates.
	0.4				Todo comment update.
	0.3				Changed the vFreeSpiBus so 
that the calling task will block until the bus is really free.
	0.2				Resolved some signed / 
unsigned inconsistencies.	
	0.1				Added the functionality to 
synchronize the bus over different
					tasks.
*/

/* Standard includes. */
#include <stdlib.h>

/* Scheduler includes. */
#include "projdefs.h"
#include "portable.h"
#include "queue.h"
#include "task.h"

#include "semphr.h"

/* Demo application includes. */
#include "spi.h"
#include "interrupt_priority.h"

/* Constants to setup and access the SPI device. */
#define spiINTERRUPT_ENABLE				( ( unsigned 
portCHAR ) 0x80 )
#define spiINTERRUPT_NOT_ENABLE			( ( unsigned 
portCHAR ) 0x00 )

#define spiDUMMY_DATA					( ( unsigned 
portCHAR ) 0x00 )

/* Constants to setup and access the VIC. */
#define spiDEV0_VIC_CHANNEL			( ( unsigned 
portLONG ) 0x000A )
#define spiDEV0_VIC_CHANNEL_BIT		( ( unsigned portLONG ) 
0x0400 )
#define spiDEV1_VIC_CHANNEL			( ( unsigned 
portLONG ) 0x000B )
#define spiDEV1_VIC_CHANNEL_BIT		( ( unsigned portLONG ) 
0x0800 )
#define spiVIC_ENABLE				( ( unsigned 
portLONG ) 0x0020 )
#define spiCLEAR_VIC_INTERRUPT		( ( unsigned portLONG ) 0 )

/*-----------------------------------------------------------*/

/* Constants to setup and reset the UART. */
#define SPI_SPCCR_RESET					( ( unsigned 
portCHAR ) 0x00)
#define SPI_SPCR_RESET					( ( unsigned 
portCHAR ) 0x00)
#define SPI_DATA_RESET					( ( unsigned 
portCHAR ) 0x00)
#define SPI_INT_RESET					( ( unsigned 
portCHAR ) 0x01)

/* Constants to setup and reset the VIC. */
#define SPIDEV_VIC_A_AND_C_RESET			( ( unsigned 
portLONG ) 0x0000 )

/*-----------------------------------------------------------*/

/* Queues used to hold received characters, and characters waiting to 
be
transmitted. */
static xQueueHandle xRxedChars_SPIDEV0; 
static xQueueHandle xCharsForTx_SPIDEV0; 
static xQueueHandle xRxedChars_SPIDEV1; 
static xQueueHandle xCharsForTx_SPIDEV1;

static xSemaphoreHandle xBusFreeSemaphore_SPIDEV0;
static xSemaphoreHandle xBusFreeSemaphore_SPIDEV1;


/* Variables to synchronize the SPI bus between the different tasks */
/* static */ unsigned portCHAR busAVAILABLE_SPIDEV0; //Indicates that 
the buffers are empty and that the bus can be reserved.
/* static */ unsigned portCHAR busRESERVED_SPIDEV0; //Indicates that 
the bus is currently reserved by a task.
/* static */ unsigned portCHAR busAVAILABLE_SPIDEV1; //Indicates that 
the buffers are empty and that the bus can be reserved.
/* static */ unsigned portCHAR busRESERVED_SPIDEV1; //Indicates that 
the bus is currently reserved by a task.

#define spiNO_BLOCK						( ( 
portTickType ) 0 )

/*-----------------------------------------------------------*/
extern void vSpiISRCreateQueues_SPIDEVx( xSpiHandle pxSPIDEV, 
unsigned portCHAR ucQueueLength, xQueueHandle *pxRxedChars_SPIDEVx, 
xQueueHandle *pxCharsForTx_SPIDEVx, portLONG volatile 
**pplDataRegEmptyFlag_SPIDEVx, xSemaphoreHandle 
*pxBusFreeSemaphore_SPIDEVx );
/*-----------------------------------------------------------*/

/* Communication flag between the interrupt service routine and 
serial API. */
static volatile portLONG *plDataRegEmptyFlag_SPIDEV0;
static volatile portLONG *plDataRegEmptyFlag_SPIDEV1;

extern /* static */ unsigned portCHAR isrMode_SPIDEV0;
extern /* static */ unsigned portCHAR isrMode_SPIDEV1;

/*-----------------------------------------------------------*/
xSpiHandle xSpiInit( xSpiHandle spiDEV, unsigned portCHAR 
cClockPhase, unsigned portCHAR cClockParity, unsigned portCHAR 
cMasterMode, unsigned portCHAR cWhoisSignificantByte, unsigned 
portLONG ulWantedClock, unsigned portCHAR ucQueueLength )
{
unsigned portCHAR ucClockCount;
xSpiHandle xReturn;
extern void ( vSPI_ISR_SPIDEV0 )( void );
extern void ( vSPI_ISR_SPIDEV1 )( void );

switch( (int)spiDEV )
	{
		case (int)spiDEV0 : /* init SPI dev 0 */
			
			/* The queues are used in the serial ISR 
routine, so are created from
			serialISR.c (which is always compiled to ARM 
mode. */
			vSpiISRCreateQueues_SPIDEVx( (xSpiHandle)
spiDEV0, ucQueueLength, &xRxedChars_SPIDEV0, &xCharsForTx_SPIDEV0, 
&plDataRegEmptyFlag_SPIDEV0, &xBusFreeSemaphore_SPIDEV0 );

			/* Calculate the Clock Counter value */
			ucClockCount = (portCHAR)(portCPU_CLOCK_HZ / 
ulWantedClock);
                        ucClockCount &= 0xFE;
			
			/* Initialize the flags for intertask 
synchronization */
			busAVAILABLE_SPIDEV0 = 1;
			busRESERVED_SPIDEV0 = 0;
			
			/* Initialize the flag for synchronization 
with the ISR */
			isrMode_SPIDEV0 = spiModeIDLE;
			
			if( 
				( xRxedChars_SPIDEV0 != 
spiINVALID_QUEUE ) && 
				( xCharsForTx_SPIDEV0 != 
spiINVALID_QUEUE ) && 
				( ucClockCount >= (portCHAR)8 ) &&
				( ucClockCount % (portCHAR)2 != 1) 
	  		)
			{
				portENTER_CRITICAL();
				{
					/* Setup the bitrate. */
					SPI0_SPCCR = 
ucClockCount; //Correct ?

					/* Setup the control 
register. */
					SPI0_SPCR = cClockPhase | 
cMasterMode | cClockParity | cWhoisSignificantByte | 
spiINTERRUPT_ENABLE;

					/* Setup the VIC for the SPI. 
*/
					VICIntSelect &= ~( 
spiDEV0_VIC_CHANNEL_BIT );
					VICIntEnable |= 
spiDEV0_VIC_CHANNEL_BIT;
					SPIDEV0_INTERRUPT_VICvectAddr 
= ( portLONG ) vSPI_ISR_SPIDEV0;
					SPIDEV0_INTERRUPT_VICvectCntl 
= spiDEV0_VIC_CHANNEL | spiVIC_ENABLE;
				}
				portEXIT_CRITICAL();
		
				xReturn = ( xSpiHandle ) spiDEV0;
			}
			else
			{
				xReturn = ( xSpiHandle ) spiFAULT;
			}
			break;
			
		case (int)spiDEV1 : /* init SPI dev 1 */
			
			/* The queues are used in the serial ISR 
routine, so are created from
			serialISR.c (which is always compiled to ARM 
mode. */
			vSpiISRCreateQueues_SPIDEVx( (xSpiHandle)
spiDEV1, ucQueueLength, &xRxedChars_SPIDEV1, &xCharsForTx_SPIDEV1, 
&plDataRegEmptyFlag_SPIDEV1, &xBusFreeSemaphore_SPIDEV1 );

			if( 
				( xRxedChars_SPIDEV1 != 
spiINVALID_QUEUE ) && 
				( xCharsForTx_SPIDEV1 != 
spiINVALID_QUEUE ) && 
				( ucClockCount >= (portCHAR)8 ) &&
				( ucClockCount % (portCHAR)2 != 1) 
	  		)
			{
				portENTER_CRITICAL();
				{
					/* Setup the bitrate. */
					SPI1_SPCCR = 
ucClockCount; //Correct ?

					/* Setup the control 
register. */
					SPI1_SPCR = cClockPhase | 
cMasterMode | cClockParity | cWhoisSignificantByte | 
spiINTERRUPT_ENABLE;

					/* Setup the VIC for the SPI. 
*/
					VICIntSelect &= ~( 
spiDEV1_VIC_CHANNEL_BIT );
					VICIntEnable |= 
spiDEV1_VIC_CHANNEL_BIT;
					SPIDEV1_INTERRUPT_VICvectAddr 
= ( portLONG ) vSPI_ISR_SPIDEV1;
					SPIDEV1_INTERRUPT_VICvectCntl 
= spiDEV1_VIC_CHANNEL | spiVIC_ENABLE;
				}
				portEXIT_CRITICAL();
		
				xReturn = ( xSpiHandle ) spiDEV1;
			}
			else
			{
				xReturn = ( xSpiHandle ) spiFAULT;
			}
			break;
			
		default: /* If a non existing SPI device is selecter 
*/
			xReturn = ( xSpiHandle ) spiFAULT;
			break;
	}
	return xReturn;
}
/*-----------------------------------------------------------*/
/** Function that reads a char from the selected SPI device(s 
buffer). 
* This function blocks the task for xBlockTime if no char is received.
*/
unsigned portCHAR cSpiGetChar( xSpiHandle pxSPIDEV, unsigned portCHAR 
*pcRxedChar, portTickType xBlockTime )
{
	xQueueHandle xRxedChars_SPIDEVx;
	static unsigned portCHAR *pucIsrMode_SPIDEVx;
	
	/* Select the appropriate queue for this SPIDEV. */
	switch( (int)pxSPIDEV )
	{
		case spiDEV0	:	/* Select the SPIDEV0 queue 
for SPIDEV0 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV0;
						
	pucIsrMode_SPIDEVx = &isrMode_SPIDEV0;
							break;
						
		case spiDEV1	:	/* Select the SPIDEV1 queue 
for SPIDEV1 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV1;
						
	pucIsrMode_SPIDEVx = &isrMode_SPIDEV1;
							break;
						
		default			:	/* If a different 
SPIDEV was selected then return error */
							return ( 
unsigned portCHAR ) pdFALSE;
	}
	
	/* Wait until no write is active */
	while( *pucIsrMode_SPIDEVx != spiModeIDLE )
		vTaskDelay( xBlockTime );
	
	/* Setup the ISR so that the interrupt will cause a read of 
the SPDR */
	*pucIsrMode_SPIDEVx = spiModeREAD;	
	
	/* Drive the clock */
	vWriteSPIDEVx_DATA( pxSPIDEV, spiDUMMY_DATA );

	/* Get the next character from the buffer.  Return false if 
no characters
	are available, or arrive before xBlockTime expires. */
	if( cQueueReceive( xRxedChars_SPIDEVx, pcRxedChar, 
xBlockTime ) )
	{
		return ( unsigned portCHAR ) pdTRUE;
	}
	else
	{
		return ( unsigned portCHAR ) pdFALSE;
	}
}
/*-----------------------------------------------------------*/
/** Function that writes a char to the selected UART(s buffer). 
* This function blocks the task for xBlockTime if there's no space in 
the buffer.
*/
unsigned portCHAR cSpiPutChar( xSpiHandle pxSPIDEV, unsigned portCHAR 
cOutChar, portTickType xBlockTime )
{
unsigned portCHAR cReturn;

	volatile portLONG *plDataRegEmptyFlag_SPIDEVx;
	xQueueHandle xRxedChars_SPIDEVx;
	xQueueHandle xCharsForTx_SPIDEVx;
	static unsigned portCHAR *pucIsrMode_SPIDEVx;

	/* Select the appropriate queue, handles, etc for this 
SPIDEV. */
	switch( (int)pxSPIDEV )
	{
		case spiDEV0	:	/* Select the SPIDEV0 queue 
for SPIDEV0 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV0;
						
	xCharsForTx_SPIDEVx = xCharsForTx_SPIDEV0;
						
	plDataRegEmptyFlag_SPIDEVx = plDataRegEmptyFlag_SPIDEV0;
						
	pucIsrMode_SPIDEVx = &isrMode_SPIDEV0;
							break;
						
		case spiDEV1	:	/* Select the SPIDEV1 queue 
for SPIDEV1 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV1;
						
	xCharsForTx_SPIDEVx = xCharsForTx_SPIDEV1;
						
	plDataRegEmptyFlag_SPIDEVx = plDataRegEmptyFlag_SPIDEV1;
						
	pucIsrMode_SPIDEVx = &isrMode_SPIDEV1;
							break;
						
		default			:	/* If a different 
SPIDEV was selected then return error */
							return ( 
signed portCHAR ) pdFALSE;
	}

	/* Wait until no read is active */
	while( *pucIsrMode_SPIDEVx == spiModeREAD )
		vTaskDelay( xBlockTime );

	portENTER_CRITICAL();
	{
		/* Is there space to write directly to the SPI 
device? */
		if( *plDataRegEmptyFlag_SPIDEVx == ( portLONG ) 
pdTRUE )
		{
			/* We wrote the character directly to the SPI 
device, so was 
			successful. */
			*plDataRegEmptyFlag_SPIDEVx = pdFALSE;
			*pucIsrMode_SPIDEVx = spiModeWRITE;
			vWriteSPIDEVx_DATA( pxSPIDEV, cOutChar );
			cReturn = ( unsigned portCHAR ) pdPASS;
		}
		else 
		{
			/* We cannot write directly to the SPI 
device, so queue the character.
			Block for a maximum of xBlockTime if there is 
no space in the
			queue. */
			cReturn = cQueueSend( xCharsForTx_SPIDEVx, 
&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( *plDataRegEmptyFlag_SPIDEVx == ( 
portLONG ) pdTRUE )
			{
				cQueueReceive( xCharsForTx_SPIDEVx, 
&cOutChar, spiNO_BLOCK );
				*plDataRegEmptyFlag_SPIDEVx = pdFALSE;
				*pucIsrMode_SPIDEVx = spiModeWRITE;
				vWriteSPIDEVx_DATA( pxSPIDEV, 
cOutChar );
			}
		}
	}
	portEXIT_CRITICAL();

	return cReturn;
}
/*-----------------------------------------------------------*/
/** Function that writes to a SPI device's DATA register. */
inline void vWriteSPIDEVx_DATA( xSpiHandle spiDEV, unsigned portCHAR 
cToWrite )
{
	switch( (int)spiDEV )
	{
		case spiDEV0	:	/* Write to SPIDEV0_DATA. */
							SPI0_SPDR = 
cToWrite;
							break;
		case spiDEV1	:	/* Write to SPIDEV1_DATA. */
							SPI1_SPDR = 
cToWrite;
							break;
		default			:	/* Don't do anyting 
since no valid UART is selected. */
							break;
	}
}
/*-----------------------------------------------------------*/
/** Function that reads from a SPI device's DATA register. */
inline unsigned portCHAR vReadSPIDEVx_DATA( xSpiHandle spiDEV )
{
	signed portCHAR cRead = 0;
	
	switch( (int)spiDEV )
	{
		case spiDEV0	:	/* Read from to SPIDEV0_DATA. 
*/
							cRead = 
SPI0_SPDR;
							break;
		case spiDEV1	:	/* Read from to SPIDEV1_DATA. 
*/
							cRead = 
SPI1_SPDR;
							break;
		default			:	/* Don't do anyting 
since no valid UART is selected. */
							break;
	}
	return cRead;
}
/*-----------------------------------------------------------*/
/** Waits until the last char from the buffer is send.
* Then resets all the SPI hardware and related ISR registers.
* Finally destroys the queues and makes the pointers invalid.
*/
void vSpiClose( xSpiHandle spiDEV )
{
	xQueueHandle xRxedChars_SPIDEVx;
	xQueueHandle xCharsForTx_SPIDEVx;

	/* Select the appropriate queues, handles, etc for this 
SPIDEV. */
	switch( (int)spiDEV )
	{
		case spiDEV0	:	/* Select the SPIDEV0 queues 
for SPIDEV0 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV0;
						
	xCharsForTx_SPIDEVx = xCharsForTx_SPIDEV0;
							break;
						
		case spiDEV1	:	/* Select the SPIDEV1 queues 
for SPIDEV1 */
						
	xRxedChars_SPIDEVx = xRxedChars_SPIDEV1;
						
	xCharsForTx_SPIDEVx = xCharsForTx_SPIDEV1;
							break;
						
		default			:	/* If a different SPI 
device was selected then do nothing */
							return;
	}

	/* Wait until the send queue is empty. */
	/* We do not need to wait until the receive queue is empty 
because the application cannot and should not read from the SPI 
device once it is closed anyway. */
		while( ucQueueMessagesWaiting( xRxedChars_SPIDEVx ) )
		vTaskDelay( ( portTickType ) 0x32 );
	
	/* Reset all registers set for the selected SPI device */
	
	switch( (int)spiDEV )
	{
		case spiDEV0	:	
							/* Reset all 
registers set for SPIDEV0 */
						
	portENTER_CRITICAL();
							{
								/* 
Reset the divisor. */
							
	SPI0_SPCCR = SPI_SPCCR_RESET;
								
								/* 
Reset the control register. */
							
	SPI0_SPCR = SPI_SPCR_RESET;
								
								/* 
Reset the data register */
							
	SPI0_SPDR = SPI_DATA_RESET;
								
								/* 
Clear any pending interrupts */
							
	SPI0_SPINT = SPI_INT_RESET;

								/* 
Clear the VIC for the UART. */
							
	VICIntSelect &= ~( spiDEV0_VIC_CHANNEL_BIT );
							
	VICIntEnClear |= spiDEV0_VIC_CHANNEL_BIT;
							
	SPIDEV0_INTERRUPT_VICvectAddr = SPIDEV_VIC_A_AND_C_RESET;
							
	SPIDEV0_INTERRUPT_VICvectCntl = SPIDEV_VIC_A_AND_C_RESET;
							}
						
	portEXIT_CRITICAL();
							break;
				
		case spiDEV1	:	
							/* Reset all 
registers set for SPIDEV0 */
						
	portENTER_CRITICAL();
							{
								/* 
Reset the divisor. */
							
	SPI1_SPCCR = SPI_SPCCR_RESET;
								
								/* 
Reset the control register. */
							
	SPI1_SPCR = SPI_SPCR_RESET;
								
								/* 
Reset the data register */
							
	SPI1_SPDR = SPI_DATA_RESET;
								
								/* 
Clear any pending interrupts */
							
	SPI1_SPINT = SPI_INT_RESET;

								/* 
Clear the VIC for the UART. */
							
	VICIntSelect &= ~( spiDEV1_VIC_CHANNEL_BIT );
							
	VICIntEnClear |= spiDEV1_VIC_CHANNEL_BIT;
							
	SPIDEV1_INTERRUPT_VICvectAddr = SPIDEV_VIC_A_AND_C_RESET;
							
	SPIDEV1_INTERRUPT_VICvectCntl = SPIDEV_VIC_A_AND_C_RESET;
							}
						
	portEXIT_CRITICAL();
							break;
	}
	
	/* Delete the queues */
	vQueueDelete( xRxedChars_SPIDEVx ); 
	vQueueDelete( xCharsForTx_SPIDEVx );
	
	/* Make the queue handles invalid. */
	switch( (int)spiDEV )
	{
		case spiDEV0	:	/* Make the queue handles for 
SPIDEV0 invalid. */
						
	xRxedChars_SPIDEV0 = spiINVALID_QUEUE;
						
	xCharsForTx_SPIDEV0 = spiINVALID_QUEUE;
							break;
						
		case spiDEV1	:	/* Make the queue handles for 
SPIDEV1 invalid. */
						
	xRxedChars_SPIDEV1 = spiINVALID_QUEUE;
						
	xCharsForTx_SPIDEV1 = spiINVALID_QUEUE;
							break;
	}
}
/*-----------------------------------------------------------*/
/** Function that reserves the SPI bus if it is available.
*	Returns: pdTRUE on success or pdFALSE on failure.
*/
signed portCHAR cReserveSpiBus( xSpiHandle spiDEV )
{
signed portCHAR returnValue;

switch( (int)spiDEV )
	{
		case spiDEV0	:	/*	Prevent context 
switches from occurring while we are reserving the bus.
							This in order 
to prevent 2 different tasks from reserving the bus 
						
	simultaneously. */
						
	portENTER_CRITICAL();
							{
								if
(busAVAILABLE_SPIDEV0 == pdTRUE)
								{
								
	busAVAILABLE_SPIDEV0 = pdFALSE;
								
	busRESERVED_SPIDEV0 = pdTRUE;
								
	returnValue = ( signed portCHAR ) pdTRUE;
								}
								else
								{
								
	returnValue = ( signed portCHAR ) pdFALSE;
								}
							}
						
	portEXIT_CRITICAL();
							break;
								
		case spiDEV1	:	/*	Prevent context 
switches from occurring while we are reserving the bus.
							This in order 
to prevent 2 different tasks from reserving the bus 
						
	simultaneously. */
						
	portENTER_CRITICAL();
							{
								if
(busAVAILABLE_SPIDEV1 == pdTRUE)
								{
								
	busAVAILABLE_SPIDEV1 = pdFALSE;
								
	busRESERVED_SPIDEV1 = pdTRUE;
								
	returnValue = ( signed portCHAR ) pdTRUE;
								}
								else
								{
								
	returnValue = ( signed portCHAR ) pdFALSE;
								
	}
							}
						
	portEXIT_CRITICAL();
							break;
							
		default			:	/* If a wrong SPI 
device is selected */
							returnValue 
=  ( signed portCHAR ) pdFALSE;
							break;	
		}	
								
								
						
return returnValue;
}
/*-----------------------------------------------------------*/
/** Function that frees the SPI bus. */
void vFreeSpiBus( xSpiHandle spiDEV, portTickType xBlockTime )
{

switch( (int)spiDEV )
	{
		case spiDEV0	:	/*	Prevent context 
switches from occurring while we are freeing the bus.*/
						
	portENTER_CRITICAL();
							{
                                                                /* 
Release our reservation of the bus */
							
	busRESERVED_SPIDEV0 = pdFALSE;
                                                                /* If 
there are no more messages waiting in the queue the ISR might not be 
called again
                                                                and 
thus we need to set the bus to AVAILABLE here */
                                                                if( 
ucQueueMessagesWaiting( xBusFreeSemaphore_SPIDEV0 ) == 0 );
                                                                  
busAVAILABLE_SPIDEV0 = pdTRUE;
							}
						
	portEXIT_CRITICAL();
							cSemaphoreTake
( xBusFreeSemaphore_SPIDEV0, xBlockTime ); //Wait until the bus is 
really free.
							break;
								
		case spiDEV1	:	/*	Prevent context 
switches from occurring while we are freeing the bus.
							Just set it 
to be unreserved and it will become available again from the ISR */
						
	portENTER_CRITICAL();
							{
                                                                /* 
Release our reservation of the bus */
							
	busRESERVED_SPIDEV1 = pdFALSE;
                                                                /* If 
there are no more messages waiting in the queue the ISR might not be 
called again
                                                                and 
thus we need to set the bus to AVAILABLE here */
                                                                if( 
ucQueueMessagesWaiting( xBusFreeSemaphore_SPIDEV1 ) == 0 );
                                                                  
busAVAILABLE_SPIDEV1 = pdTRUE;
							}
						
	portEXIT_CRITICAL();
							cSemaphoreTake
( xBusFreeSemaphore_SPIDEV1, xBlockTime ); //Wait until the bus is 
really free.
							break;
							
		default			:	/* If a wrong SPI 
device is selected */
							break;
	}
}
--------------------------------------------------------------------
spi.h:
--------------------------------------------------------------------
/*	
	Description:	BASIC INTERRUPT DRIVEN SPI BUS DRIVER FOR THE 
LPC2114.
					
					This driver is designed for 
use with FreeRTOS v2.5.0.
	
	Date:			6-12-2004
	
	Author:			Teun van de Berg
	
	Version:		0.6
	
	Todo:			Debugging.
	
	Revision history:
	0.5				Changed spiMSB_FISRT to 
spiMSB_FIRST
	0.4				Added the I/O enable for SPI 
DEV 1.
	0.3				Changes to support 
vFreeSpiBus blocking (interrupt driven) until the bus is really free.
	0.2				Resolved some signed / 
unsigned inconsistencies.
	0.1				Added the functionality to 
synchronize the bus over different
					tasks.
*/

#ifndef SPI_H
#define SPI_H

typedef void * xSpiHandle;

typedef enum
{ 
	spiFAULT,
	spiDEV0, 
	spiDEV1 
} eSpiDEV;

xSpiHandle xSpiInit( xSpiHandle spiDEV, unsigned portCHAR 
cClockPhase, unsigned portCHAR cClockParity, unsigned portCHAR 
cMasterMode, unsigned portCHAR cWhoisSignificantByte, unsigned 
portLONG ulWantedClock, unsigned portCHAR ucQueueLength );
unsigned portCHAR cSpiGetChar( xSpiHandle pxSPIDEV, unsigned portCHAR 
*pcRxedChar, portTickType xBlockTime );
unsigned portCHAR cSpiPutChar( xSpiHandle pxSPIDEV, unsigned portCHAR 
cOutChar, portTickType xBlockTime );
inline void vWriteSPIDEVx_DATA( xSpiHandle spiDEV, unsigned portCHAR 
cToWrite );
inline unsigned portCHAR vReadSPIDEVx_DATA( xSpiHandle spiDEV );
void vSpiClose( xSpiHandle spiDEV );
signed portCHAR cReserveSpiBus( xSpiHandle spiDEV );
void vFreeSpiBus( xSpiHandle spiDEV, portTickType xBlockTime );

/* Constants to setup and access the SPI device. */
#define spiCLOCK_PHASE_ON_FIST_EDGE		( ( unsigned 
portCHAR ) 0x00 )
#define spiCLOCK_PHASE_ON_SECOND_EDGE	( ( unsigned portCHAR ) 0x08 )
#define spiCLOCK_ACTIVE_LOW				( ( unsigned 
portCHAR ) 0x10 )
#define spiCLOCK_ACTIVE_HIGH			( ( unsigned 
portCHAR ) 0x00 )
#define spiMASTER_MODE					( ( unsigned 
portCHAR ) 0x20 )
#define spiSLAVE_MODE					( ( unsigned 
portCHAR ) 0x00 )
#define spiLSB_FIRST					( ( unsigned 
portCHAR ) 0x40 )
#define spiMSB_FIRST					( ( unsigned 
portCHAR ) 0x00 )

/* Constants to use the queues. */
#define spiINVALID_QUEUE				( ( 
xQueueHandle ) 0 )

/* Constants to setup I/O. */
#define SCK_ENABLE_SPIDEV0	( ( unsigned portLONG ) 
0x100 ) //PINSEL0 REG
#define MISO_ENABLE_SPIDEV0	( ( unsigned portLONG ) 0x400 )
#define MOSI_ENABLE_SPIDEV0 ( ( unsigned portLONG ) 0x1000 )
#define SSEL_ENABLE_SPIDEV0 ( ( unsigned portLONG ) 0x4000 ) 

#define SCK_ENABLE_SPIDEV1	( ( unsigned portLONG ) 
0x0004 ) //PINSEL1 REG
#define MISO_ENABLE_SPIDEV1	( ( unsigned portLONG ) 0x0010 )
#define MOSI_ENABLE_SPIDEV1 ( ( unsigned portLONG ) 0x0040 )
#define SSEL_ENABLE_SPIDEV1 ( ( unsigned portLONG ) 0x0100 ) 

/* Constants to setup the ISR internal status */
#define spiModeREAD						( ( 
unsigned portCHAR ) 0 )
#define spiModeWRITE					( ( unsigned 
portCHAR ) 1 )
#define spiModeIDLE						( ( 
unsigned portCHAR ) 2 )

#define spiNO_BLOCK						( ( 
portTickType ) 0 )

#endif

--------------------------------------------------------------------
spiisr.c:
--------------------------------------------------------------------
/*	
	Description:	BASIC INTERRUPT DRIVEN SPI BUS DRIVER FOR THE 
LPC2114.
					
					This file contains all the 
SPI driver components that must be
					compiled to ARM mode. 
Components that can be compiled to either
					ARM or THUMB mode are 
contained in spi.c. This driver is
					designed for use with 
FreeRTOS v2.5.0.
	
	Date:			24-11-2004
	
	Author:			Teun van de Berg
	
	Version:		0.6
	
	Todo:			Debugging.
					Add LED error code.
		
	Revision history:
	0.5				Fixed some compiler warnings.
	0.4				Change SPI so that it sends 
dummy date when trying to read.
	0.3				Fixed the way the interrupts 
are handled and cleared.
	0.2				Changes to support 
vFreeSpiBus blocking (interrupt driven) until the bus is really free.
	0.1				Added the functionality to 
synchronize the bus over different
					tasks.
					Filled the ISRs.
*/

/* Standard includes. */
#include <stdlib.h>

/* Scheduler includes. */
#include "projdefs.h"
#include "portable.h"
#include "queue.h"
#include "task.h"

#include "semphr.h"


/* Demo application includes. */
#include "spi.h"

/* Constant to access the VIC. */
#define spiCLEAR_VIC_INTERRUPT			( ( unsigned 
portCHAR ) 0x01 )

/* Constants to setup and access the SPI device. */
#define spiCLEAR_INTERRUPT				/*( ( 
unsigned portLONG )*/ 0x01//)

#define spiRX_BUFFER_LENGTH				( ( unsigned 
portCHAR ) 0x01 )

/* Constants to determine the ISR source. */
#define spiSOURCE_ABRT					( ( unsigned 
portCHAR ) 0x08 )
#define spiSOURCE_MODF					( ( unsigned 
portCHAR ) 0x10 )
#define spiSOURCE_ROVR					( ( unsigned 
portCHAR ) 0x20 )
#define spiSOURCE_WCOL					( ( unsigned 
portCHAR ) 0x40 )
#define spiSOURCE_SPIF					( ( unsigned 
portCHAR ) 0x80 )

/* Queues used to hold received characters, and characters waiting to 
be
transmitted. */
static xQueueHandle xRxedChars_SPIDEV0; 
static xQueueHandle xCharsForTx_SPIDEV0; 
static xQueueHandle xRxedChars_SPIDEV1; 
static xQueueHandle xCharsForTx_SPIDEV1; 

static xSemaphoreHandle xBusFreeSemaphore_SPIDEV0;
static xSemaphoreHandle xBusFreeSemaphore_SPIDEV1;

/* Variables to synchronize the SPI bus between the different tasks */
extern /* static */ unsigned portCHAR  
busAVAILABLE_SPIDEV0; //Indicates that the buffers are empty and that 
the bus can be reserved.
extern /* static */ unsigned portCHAR 
busRESERVED_SPIDEV0; //Indicates that the bus is currently reserved 
by a task.
extern /* static */ unsigned portCHAR 
busAVAILABLE_SPIDEV1; //Indicates that the buffers are empty and that 
the bus can be reserved.
extern /* static */ unsigned portCHAR 
busRESERVED_SPIDEV1; //Indicates that the bus is currently reserved 
by a task.

/* static */ unsigned portCHAR isrMode_SPIDEV0;
/* static */ unsigned portCHAR isrMode_SPIDEV1;

/*-----------------------------------------------------------*/

/* Communication flag between the interrupt service routine and 
serial API. */
static volatile portLONG lDataRegEmptyFlag_SPIDEV0;
static volatile portLONG lDataRegEmptyFlag_SPIDEV1;

/*-----------------------------------------------------------*/

/* UART interrupt service routines.  These can cause a context switch 
so MUST
be declared "naked". */
void vSPI_ISR_SPIDEV0( void ) __attribute__ ((naked));
void vSPI_ISR_SPIDEV1( void ) __attribute__ ((naked));

/*-----------------------------------------------------------*/
/** Function that creates the queues and passes back a reference to 
them. */
void vSpiISRCreateQueues_SPIDEVx( xSpiHandle pxSPIDEV, unsigned 
portCHAR ucQueueLength, xQueueHandle *pxRxedChars_SPIDEVx, 
							
	xQueueHandle *pxCharsForTx_SPIDEVx, portLONG volatile 
**pplDataRegEmptyFlag_SPIDEVx, xSemaphoreHandle 
*pxBusFreeSemaphore_SPIDEVx )
{
xQueueHandle xRxedChars_SPIDEVx;
xQueueHandle xCharsForTx_SPIDEVx;
xSemaphoreHandle xBusFreeSemaphore_SPIDEVx;

	/* Error handling if a bad DEV is selected */
	if( ( (int)pxSPIDEV != (int)spiDEV0 ) && ( (int)pxSPIDEV != 
(int)spiDEV1 ) )
	{
		*pxRxedChars_SPIDEVx = spiINVALID_QUEUE;
		*pxCharsForTx_SPIDEVx = spiINVALID_QUEUE;
		return;
	}
	
	/* Create the queues used to hold Rx and Tx characters. */
	xRxedChars_SPIDEVx = xQueueCreate( spiRX_BUFFER_LENGTH, ( 
unsigned portCHAR ) sizeof( signed portCHAR ) );
	xCharsForTx_SPIDEVx = xQueueCreate( ucQueueLength + 1, ( 
unsigned portCHAR ) sizeof( signed portCHAR ) );
	
	vSemaphoreCreateBinary( xBusFreeSemaphore_SPIDEVx );

	/* Pass back a reference to the queues so the serial API file 
can 
	post/receive characters. */
	*pxRxedChars_SPIDEVx = xRxedChars_SPIDEVx;
	*pxCharsForTx_SPIDEVx = xCharsForTx_SPIDEVx;
	
	*pxBusFreeSemaphore_SPIDEVx =xBusFreeSemaphore_SPIDEVx;

	/* Store the pointers to the queues & THRE in the appropriate 
globals. */
	switch( (int)pxSPIDEV )
	{
		case spiDEV0	:	/* Set the UART0 queue for 
UART0 */
						
	xRxedChars_SPIDEV0 = xRxedChars_SPIDEVx;
						
	xCharsForTx_SPIDEV0 = xCharsForTx_SPIDEVx;
							/* Initialise 
the THRE empty flag - and pass back a reference. */
						
	lDataRegEmptyFlag_SPIDEV0 = ( portLONG ) pdTRUE;
						
	*pplDataRegEmptyFlag_SPIDEVx = &lDataRegEmptyFlag_SPIDEV0;
							/* Set the 
local semaphore */
						
	xBusFreeSemaphore_SPIDEV0 = xBusFreeSemaphore_SPIDEVx;
							break;
						
		case spiDEV1	:	/* Set the UART1 queues for 
UART1 */
						
	xRxedChars_SPIDEV1 = xRxedChars_SPIDEVx;
						
	xCharsForTx_SPIDEV1 = xCharsForTx_SPIDEVx;
							/* Initialise 
the THRE empty flag - and pass back a reference. */
						
	lDataRegEmptyFlag_SPIDEV1 = ( portLONG ) pdTRUE;
						
	*pplDataRegEmptyFlag_SPIDEVx = &lDataRegEmptyFlag_SPIDEV1;
							/* Set the 
local semaphore */
						
	xBusFreeSemaphore_SPIDEV1 = xBusFreeSemaphore_SPIDEVx;
							break;
	}
}
/*-----------------------------------------------------------*/
/** Function that handles the SPI0 interrupts.
* See the comment in the code for more detailed information.
*/
void vSPI_ISR_SPIDEV0( void )
{
	/* This ISR can cause a context switch, so the first 
statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be 
BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	/* Now we can declare the local variables. */
	signed portCHAR cTaskWokenByTx = ( signed portCHAR ) pdFALSE;
	portLONG lTaskWokenByRx = ( portLONG ) pdFALSE;
	unsigned portCHAR cChar;
	unsigned portLONG lLocalSPI0_SPSR = SPI0_SPSR; //Some data in 
this reg is cleared on read but we use it multiple times.
	
	/* Just to stop compiler warnings. */
	( void ) lLocalSPI0_SPSR;

	/* Clear the interrupt flag */
	SPI0_SPINT = spiCLEAR_VIC_INTERRUPT;

	/* Clear the ISR in the VIC. */
	VICVectAddr = spiCLEAR_VIC_INTERRUPT;
	
	/* All the error below should actually be handled of course
	but we don't check these because there is a bug in the chip. 
*/
	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI0_SPSR & spiSOURCE_ABRT ) == spiSOURCE_ABRT )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!		
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI0_SPSR & spiSOURCE_MODF ) == spiSOURCE_MODF )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!
// 	}	
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI0_SPSR & spiSOURCE_ROVR ) == spiSOURCE_ROVR )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!		
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI0_SPSR & spiSOURCE_WCOL ) == spiSOURCE_WCOL )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!		
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI0_SPSR & spiSOURCE_SPIF ) == spiSOURCE_SPIF )
// 	{
		switch( isrMode_SPIDEV0 )
		{
			case spiModeWRITE :
	       		/* If the transmission queue is empty than 
the next interrupt
				must be caused by a character being 
received unless a new 
				write was defined before. */
				if (cQueueReceiveFromISR( 
xCharsForTx_SPIDEV0, &cChar, &cTaskWokenByTx ) == ( signed portCHAR ) 
pdFALSE )
				{
					/* There are no more 
characters */
					isrMode_SPIDEV0 = spiModeIDLE;
					lDataRegEmptyFlag_SPIDEV0 = 
pdTRUE;
					if(busRESERVED_SPIDEV0 == 
pdFALSE)
					{
						busAVAILABLE_SPIDEV0 
= pdTRUE;
						cSemaphoreGiveFromISR
( xBusFreeSemaphore_SPIDEV0, pdFALSE );
						lTaskWokenByRx = ( 
portLONG ) pdTRUE;
	                    //We do not use the SPI data register 
here but we just read it because
	                    //this is required to clear the interrupt.
	                    {
	                        int temp;
	                        temp = (int)SPI0_SPDR;
	                    }
					}
				}
				else
				{
					/* Send the next character */
					SPI0_SPDR = cChar;
				}
				break;
			
			case spiModeREAD :
				{
					/* Read the character */
 					cChar = SPI0_SPDR;
 					cQueueSendFromISR( 
xRxedChars_SPIDEV0, ( void * ) &cChar, pdFALSE );
				}
 				lTaskWokenByRx = ( portLONG ) pdTRUE;
	 			isrMode_SPIDEV0 = spiModeIDLE;
				break;
			
			default :
				/* You should never reach here */
				break;
		}
		
// 	}

	/* Exit the ISR.  If a task was woken by either a character 
being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR( ( cTaskWokenByTx || 
lTaskWokenByRx ) );
}

/*-----------------------------------------------------------*/
/** Function that handles the SPI0 interrupts.
* See the comment in the code for more detailed information.
*/
void vSPI_ISR_SPIDEV1( void )
{
	/* This ISR can cause a context switch, so the first 
statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be 
BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	/* Now we can declare the local variables. */
	signed portCHAR cTaskWokenByTx = ( signed portCHAR ) pdFALSE;
	portLONG lTaskWokenByRx = ( portLONG ) pdFALSE;
	unsigned portCHAR cChar;
	unsigned portLONG lLocalSPI1_SPSR = SPI1_SPSR; //Some data in 
this reg is cleared on read but we use it multiple times.
	
	/* Just to stop compiler warnings. */
	( void ) lLocalSPI1_SPSR;
	
	/* All the error below should actually be handled of course
	but we don't check these because there is a bug in the chip. 
*/
	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI1_SPSR & spiSOURCE_ABRT ) == spiSOURCE_ABRT )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!	
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI1_SPSR & spiSOURCE_MODF ) == spiSOURCE_MODF )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!	
// 	}	
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI1_SPSR & spiSOURCE_ROVR ) == spiSOURCE_ROVR )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!	
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI1_SPSR & spiSOURCE_WCOL ) == spiSOURCE_WCOL )
// 	{
// 		// Should not occur.
// 		// Turn on error LEDs!	
// 	}
// 	
// 	/* Handle all the interrupts */
// 	if( ( lLocalSPI1_SPSR & spiSOURCE_SPIF ) == spiSOURCE_SPIF )
// 	{
		if(isrMode_SPIDEV1 == spiModeWRITE)
		{
			/* If the transmission queue is empty than 
the next interrupt
			must be caused by a character being received 
unless a new 
			write was defined before. */
			if (cQueueReceiveFromISR( 
xCharsForTx_SPIDEV1, &cChar, &cTaskWokenByTx ) == ( signed portCHAR ) 
pdFALSE )
			{
				/* There are no more characters */
				isrMode_SPIDEV1 = spiModeREAD;
				lDataRegEmptyFlag_SPIDEV1 = pdTRUE;
				if(busRESERVED_SPIDEV1 == pdFALSE)
				{
					busAVAILABLE_SPIDEV1 = pdTRUE;
					cSemaphoreGiveFromISR( 
xBusFreeSemaphore_SPIDEV1, pdFALSE );
					lTaskWokenByRx = ( portLONG ) 
pdTRUE;
                    //We do not use the SPI data register here but we 
just read it because
                    //this is required to clear the interrupt.
                    {
                        int temp;
                        temp = (int)SPI0_SPDR;
                    }
				}
			}
			else
			{
				/* Send the next character */
				SPI1_SPDR = cChar;
			}
		}
		else
		{
			/* recieve char and place it in recieved 
queue */
			cChar = SPI1_SPDR;
			cQueueSendFromISR( xRxedChars_SPIDEV1, ( void 
* ) &cChar, pdFALSE );
			lTaskWokenByRx = ( portLONG ) pdTRUE;
		}
// 	}

	/* Clear the interrupt flag */
	SPI1_SPINT = spiCLEAR_VIC_INTERRUPT;

	/* Clear the ISR in the VIC. */
	VICVectAddr = spiCLEAR_VIC_INTERRUPT;

	/* Exit the ISR.  If a task was woken by either a character 
being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR( ( cTaskWokenByTx || 
lTaskWokenByRx ) );
}

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.