//
//
//
//lecture - UART - specific uart open method invoked from vFreeRTOS_lpc17xx_PopulateFunctionPointers()
//                 in FreeRTOS_lpc17xx_DriverInterface.c - refer to that file, if needed !!!
//
//
portBASE_TYPE FreeRTOS_UART_open( Peripheral_Control_t * const pxPeripheralControl )
{
//
//
//lecture - UART - refer to respective header for typedef of objects - for instance LPC17xx.h
//                 refer to that LPC17xx.h file if needed
//
//
PINSEL_CFG_Type xPinConfig;
UART_CFG_Type xUARTConfig;
UART_FIFO_CFG_Type xUARTFIFOConfig;
LPC_UART_TypeDef * const pxUART = ( LPC_UART_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( pxPeripheralControl );
portBASE_TYPE xReturn;
const uint8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( pxPeripheralControl );
    //
    //lecture - UART - we are initializing the specific driver methods for UART
    //
    //lecture - UART - these methods are described in this file !!!
    //
	/* Sanity check the peripheral number. */
	if( cPeripheralNumber < boardNUM_UARTS )
	{
		pxPeripheralControl->read = FreeRTOS_UART_read;
		pxPeripheralControl->write = FreeRTOS_UART_write;
		pxPeripheralControl->ioctl = FreeRTOS_UART_ioctl;

		/* Setup the pins for the UART being used. */
		taskENTER_CRITICAL();
		{
			//
			//
			//lecture - refer to LPCXpresso17xx-base-board.h
			//          used to configure the pin selection to enable UART3 pins
			//
			//
			boardCONFIGURE_UART_PINS( cPeripheralNumber, xPinConfig );
            //
			//
			//lecture - refer to cmsis firmware lib. file lpc17xx_uart.c
			//
			//lecture - refer to LPCXpresso17xx-base-board.h
			//
			//lecture - refer to lpc17xx user-manual for hw specific details - chapter 14 and further,
			//          relevant sections ???
			//
			//
			/* Set up the default UART configuration. */
			xUARTConfig.Baud_rate = boardDEFAULT_UART_BAUD;
			xUARTConfig.Databits = UART_DATABIT_8;
			xUARTConfig.Parity = UART_PARITY_NONE;
			xUARTConfig.Stopbits = UART_STOPBIT_1;
			UART_Init( pxUART, &xUARTConfig );

			/* Enable the FIFO. */
			xUARTFIFOConfig.FIFO_ResetRxBuf = ENABLE;
			xUARTFIFOConfig.FIFO_ResetTxBuf = ENABLE;
			xUARTFIFOConfig.FIFO_DMAMode = DISABLE;
			xUARTFIFOConfig.FIFO_Level = UART_FIFO_TRGLEV2;
			UART_FIFOConfig( pxUART, &xUARTFIFOConfig );

			/* Enable Tx. */
			UART_TxCmd( pxUART, ENABLE );
		}
		taskEXIT_CRITICAL();

		xReturn = pdPASS;
	}
	else
	{
		xReturn = pdFAIL;
	}

	return xReturn;
}
size_t FreeRTOS_UART_read( Peripheral_Descriptor_t const pxPeripheral, void * const pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_UART_TypeDef * const pxUART = ( LPC_UART_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
//
//lecture - UART - rx transfer structure is NULL for rx polling mode
//                 in the case of i2c, this is different - refer to i2c related code
//
	if( diGET_RX_TRANSFER_STRUCT( pxPeripheralControl ) == NULL )
	{
		#if ioconfigUSE_UART_POLLED_RX == 1
		{
			/* No FreeRTOS objects exist to allow reception without blocking
			the task, so just receive by polling.  No semaphore or queue is
			used here, so the application must ensure only one task attempts
			to make a polling read at a time. */
			xReturn = UART_Receive( pxUART, pvBuffer, xBytes, NONE_BLOCKING );
		}
		#endif /* ioconfigUSE_UART_POLLED_RX */
	}
	else
	{
		/* Sanity check the array index. */
		configASSERT( diGET_PERIPHERAL_NUMBER( pxPeripheralControl ) < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );

		switch( diGET_RX_TRANSFER_TYPE( pxPeripheralControl ) )
		{
			case ioctlUSE_CIRCULAR_BUFFER_RX :

				#if ioconfigUSE_UART_CIRCULAR_BUFFER_RX == 1
				{
					/* There is nothing to prevent multiple tasks attempting to
					read the circular buffer at any one time.  The implementation
					of the circular buffer uses a semaphore to indicate when new
					data is available, and the semaphore will ensure that only the
					highest priority task that is attempting a read will actually
					receive bytes. */
					ioutilsRECEIVE_CHARS_FROM_CIRCULAR_BUFFER
						(
							pxPeripheralControl,
							UART_IntConfig( pxUART, UART_INTCFG_RBR, DISABLE ),	/* Disable peripheral. */
							UART_IntConfig( pxUART, UART_INTCFG_RBR, ENABLE ), 	/* Enable peripheral. */
							( ( uint8_t * ) pvBuffer ),							/* Data destination. */
							xBytes,												/* Bytes to read. */
							xReturn												/* Number of bytes read. */
						);
				}
				#endif /* ioconfigUSE_UART_CIRCULAR_BUFFER_RX */
				break;


			case ioctlUSE_CHARACTER_QUEUE_RX :

				#if ioconfigUSE_UART_RX_CHAR_QUEUE == 1
				{
					/* The queue allows multiple tasks to attempt to read
					bytes, but ensures only the highest priority of these
					tasks will actually receive bytes.  If two tasks of equal
					priority attempt to read simultaneously, then the
					application must ensure mutual exclusion, as time slicing
					could result in the string being received being partially
					received by each task. */
					xReturn = xIOUtilsReceiveCharsFromRxQueue( pxPeripheralControl, ( uint8_t * ) pvBuffer, xBytes );
				}
				#endif /* ioconfigUSE_UART_RX_CHAR_QUEUE */
				break;


			default :

				/* Other methods can be implemented here. */
				configASSERT( xReturn );

				/* Prevent compiler warnings when the configuration is set such
				that the following parameters are not used. */
				( void ) pvBuffer;
				( void ) xBytes;
				( void ) pxUART;
				break;
		}
	}

	return xReturn;
}
//
//
//lecture - UART - uart specific ioctl commands are processed by this method - for instance,
//                 for using hw interrupts or changing speed of operation
//
//
//
portBASE_TYPE FreeRTOS_UART_ioctl( Peripheral_Descriptor_t pxPeripheral, uint32_t ulRequest, void *pvValue )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
UART_CFG_Type xUARTConfig;
uint32_t ulValue = ( uint32_t ) pvValue;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
LPC_UART_TypeDef * pxUART = ( LPC_UART_TypeDef * ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
portBASE_TYPE xReturn = pdPASS;

	/* Sanity check the array index. */
	configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );

	taskENTER_CRITICAL();
	{
		switch( ulRequest )
		{
		    //
		    //
		    //
		    //lecture - UART - for hw specific details, refer to chapter 14
		    //                 lpc17xx user-manual for UART3 specific settings
		    //          UART - Tx interrupts and Rx interrupts are enabled here
		    //          UART - we may introduce another set of IOCTL commands that will enable Tx and Rx
		    //                 interrupts separately ??
		    //          UART - some parts of ioctl commands' implementations are incomplete - ??
		    //
		    //
			case ioctlUSE_INTERRUPTS :

				if( ulValue == pdFALSE )
				{
					NVIC_DisableIRQ( xIRQ[ cPeripheralNumber ] );
				}
				else
				{
					/* Enable the Rx and Tx interrupt. */
					UART_IntConfig( pxUART, UART_INTCFG_RBR, ENABLE );
					UART_IntConfig( pxUART, UART_INTCFG_THRE, ENABLE );

					/* Enable the interrupt and set its priority to the minimum
					interrupt priority.  A separate command can be issued to raise
					the priority if desired. */
					NVIC_SetPriority( xIRQ[ cPeripheralNumber ], configMIN_LIBRARY_INTERRUPT_PRIORITY );
					NVIC_EnableIRQ( xIRQ[ cPeripheralNumber ] );

					/* If the Rx is configured to use interrupts, remember the
					transfer control structure that should be used.  A reference
					to the Tx transfer control structure is taken when a write()
					operation is actually performed. */
					pxRxTransferControlStructs[ cPeripheralNumber ] = pxPeripheralControl->pxRxControl;
				}
				break;


			case ioctlSET_SPEED :

				/* Set up the default UART configuration. */
				xUARTConfig.Baud_rate = ulValue;
				xUARTConfig.Databits = UART_DATABIT_8;
				xUARTConfig.Parity = UART_PARITY_NONE;
				xUARTConfig.Stopbits = UART_STOPBIT_1;
				UART_Init( pxUART, &xUARTConfig );
				break;
			//
            //
            //lecture - UART - need to follow the rules of interrupt management and interrupt safe
		    //                 methods / apis
			//
			case ioctlSET_INTERRUPT_PRIORITY :

				/* The ISR uses ISR safe FreeRTOS API functions, so the priority
				being set must be lower than (ie numerically larger than)
				configMAX_LIBRARY_INTERRUPT_PRIORITY. */
				configASSERT( ulValue >= configMAX_LIBRARY_INTERRUPT_PRIORITY );
				NVIC_SetPriority( xIRQ[ cPeripheralNumber ], ulValue );
				break;


			default :

				xReturn = pdFAIL;
				break;
		}
	}
	taskEXIT_CRITICAL();

	return xReturn;
}
Beispiel #4
0
portBASE_TYPE FreeRTOS_SSP_ioctl( Peripheral_Descriptor_t const pxPeripheral, uint32_t ulRequest, void *pvValue )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
uint32_t ulValue = ( uint32_t ) pvValue, ulInitSSP = pdFALSE;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
LPC_SSP_TypeDef * pxSSP = ( LPC_SSP_TypeDef * ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	taskENTER_CRITICAL();
	{
		switch( ulRequest )
		{
			case ioctlUSE_INTERRUPTS :

				/* Sanity check the array index. */
				configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );

				if( ulValue == pdFALSE )
				{
					NVIC_DisableIRQ( xIRQ[ cPeripheralNumber ] );
				}
				else
				{
					/* Enable the Rx interrupts only.  New data is sent if an
					Rx interrupt makes space in the FIFO, so Tx interrupts are
					not required. */
					SSP_IntConfig( LPC_SSP1, SSP_INTCFG_TX, DISABLE );
					SSP_IntConfig( pxSSP, sspALL_SSP_RX_INTERRUPTS, ENABLE );

					/* Enable the interrupt and set its priority to the minimum
					interrupt priority.  A separate command can be issued to raise
					the priority if desired. */
					NVIC_SetPriority( xIRQ[ cPeripheralNumber ], configSPI_INTERRUPT_PRIORITY );
					NVIC_EnableIRQ( xIRQ[ cPeripheralNumber ] );

					/* If the Rx is configured to use interrupts, remember the
					transfer control structure that should be used.  A reference
					to the Tx transfer control structure is taken when a write()
					operation is actually performed. */
					pxRxTransferControlStructs[ cPeripheralNumber ] = pxPeripheralControl->pxRxControl;
				}
				break;


			case ioctlSET_INTERRUPT_PRIORITY :

				/* The ISR uses ISR safe FreeRTOS API functions, so the priority
				being set must be lower than (ie numerically larger than)
				configMAX_LIBRARY_INTERRUPT_PRIORITY. */
				configASSERT( ulValue < configMAX_LIBRARY_INTERRUPT_PRIORITY );
				NVIC_SetPriority( xIRQ[ cPeripheralNumber ], ulValue );
				break;


			case ioctlSET_SPEED : /* In Hz. */

				xSSPConfigurations[ cPeripheralNumber ].ClockRate = ulValue;
				ulInitSSP = pdTRUE;
				break;


			case ioctlSET_SPI_DATA_BITS	: /* 4 to 16. */

				xSSPConfigurations[ cPeripheralNumber ].Databit = ulValue;
				ulInitSSP = pdTRUE;
				break;


			case ioctlSET_SPI_CLOCK_PHASE : /* SSP_CPHA_FIRST or SSPCPHA_SECOND */
				xSSPConfigurations[ cPeripheralNumber ].CPHA = ulValue;
				ulInitSSP = pdTRUE;
				break;


			case ioctlSET_SPI_CLOCK_POLARITY : /* SSP_CPOL_HI or SSP_CPOL_LO. */

				xSSPConfigurations[ cPeripheralNumber ].CPOL = ulValue;
				break;


			case ioctlSET_SPI_MODE : /* SSP_MASTER_MODE or SSP_SLAVE_MODE. */

				xSSPConfigurations[ cPeripheralNumber ].Mode = ulValue;
				break;


			case ioctlSET_SSP_FRAME_FORMAT : /* SSP_FRAME_SPI or SSP_FRAME_TI or SSP_FRAME_MICROWIRE. */

				xSSPConfigurations[ cPeripheralNumber ].FrameFormat = ulValue;
				break;
		}

		if( ulInitSSP == pdTRUE )
		{
			SSP_Cmd( pxSSP, DISABLE );
			SSP_DeInit( pxSSP );
			SSP_Init( pxSSP, &( xSSPConfigurations[ cPeripheralNumber ] ) );
			SSP_Cmd( pxSSP, ENABLE );
		}
	}
	taskEXIT_CRITICAL();

	return pdPASS;
}
size_t FreeRTOS_UART_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_UART_TypeDef * const pxUART = ( LPC_UART_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
int8_t cPeripheralNumber;
//
//lecture - UART - tx transfer control structure is NULL for tx polling mode -
//                 in the case of i2c, this is not NULL - refer to i2c code more details !!!
//
//
	if( diGET_TX_TRANSFER_STRUCT( pxPeripheralControl ) == NULL )
	{
		#if ioconfigUSE_UART_POLLED_TX == 1
		{
			/* No FreeRTOS objects exist to allow transmission without blocking
			the	task, so just send out by polling.  No semaphore or queue is
			used here, so the application must ensure only one task attempts to
			make a polling write at a time. */
			xReturn = UART_Send( pxUART, ( uint8_t * ) pvBuffer, ( size_t ) xBytes, BLOCKING );

			/* The UART is set to polling mode, so may as well poll the busy bit
			too.  Change to interrupt driven mode to avoid wasting CPU time here. */
			while( UART_CheckBusy( pxUART ) != RESET );
		}
		#endif /* ioconfigUSE_UART_POLLED_TX */
	}
	else
	{
		/* Remember which transfer control structure is being used.
		The Tx interrupt will use this to continue to write data to the
		Tx FIFO/UART until the length member of the structure reaches
		zero. */
		cPeripheralNumber = diGET_PERIPHERAL_NUMBER( pxPeripheralControl );
		pxTxTransferControlStructs[ cPeripheralNumber  ] = diGET_TX_TRANSFER_STRUCT( pxPeripheralControl );

		switch( diGET_TX_TRANSFER_TYPE( pxPeripheralControl ) )
		{
			case ioctlUSE_ZERO_COPY_TX :

				#if ioconfigUSE_UART_ZERO_COPY_TX == 1
				{
					/* The implementation of the zero copy write uses a semaphore
					to indicate whether a write is complete (and so the buffer
					being written free again) or not.  The semantics of using a
					zero copy write dictate that a zero copy write can only be
					attempted by a task, once the semaphore has been successfully
					obtained by that task.  This ensure that only one task can
					perform a zero copy write at any one time.  Ensure the semaphore
					is not currently available, if this function has been called
					without it being obtained first then it is an error. */
					configASSERT( xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, 0U ) == 0 );
					xReturn = xBytes;
					ioutilsINITIATE_ZERO_COPY_TX
						(
							pxPeripheralControl,
							UART_TxCmd( pxUART, DISABLE ),	/* Disable peripheral function. */
							UART_TxCmd( pxUART, ENABLE ), 	/* Enable peripheral function. */
							prvFillFifoFromBuffer( pxUART, ( uint8_t ** ) &( pvBuffer ), xBytes ), /* Write to peripheral function. */
							pvBuffer, 						/* Data source. */
							xReturn							/* Number of bytes to be written. This will get set to zero if the write mutex is not held. */
						);
				}
				#endif /* ioconfigUSE_UART_ZERO_COPY_TX */
				break;


			case ioctlUSE_CHARACTER_QUEUE_TX :

				#if ioconfigUSE_UART_TX_CHAR_QUEUE == 1
				{
					/* The queue allows multiple tasks to attempt to write
					bytes, but ensures only the highest priority of these tasks
					will actually succeed.  If two tasks of equal priority
					attempt to write simultaneously, then the application must
					ensure mutual exclusion, as time slicing could result in
					the strings being sent to the queue being interleaved. */
					ioutilsBLOCKING_SEND_CHARS_TO_TX_QUEUE
						(
							pxPeripheralControl,
							( pxUART->LSR & uartTX_BUSY_MASK ) == uartTX_BUSY_MASK,  /* Peripheral busy condition. */
							pxUART->THR = ucChar,				/* Peripheral write function. */
							( ( uint8_t * ) pvBuffer ),			/* Data source. */
							xBytes, 							/* Number of bytes to be written. */
							xReturn );
				}
				#endif /* ioconfigUSE_UART_TX_CHAR_QUEUE */
				break;


			default :

				/* Other methods can be implemented here.  For now set the
				stored transfer structure back to NULL as nothing is being
				sent. */
				configASSERT( xReturn );
				pxTxTransferControlStructs[ cPeripheralNumber ] = NULL;

				/* Prevent compiler warnings when the configuration is set such
				that the following parameters are not used. */
				( void ) pvBuffer;
				( void ) xBytes;
				( void ) pxUART;
				break;
		}
	}

	return xReturn;
}
Beispiel #6
0
size_t FreeRTOS_SSP_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_SSP_TypeDef * const pxSSP = ( LPC_SSP_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
SSP_DATA_SETUP_Type *pxSSPTransferDefinition;
const uint32_t ulPeripheralNumber = ( uint32_t ) diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	/* Remember which transfer control structure is being used, so if
	an interrupt is being used, it can continue the same transfer until
	all data has been transmitted. */
	pxTxTransferControlStructs[ ulPeripheralNumber ] = diGET_TX_TRANSFER_STRUCT( pxPeripheralControl );

	switch( diGET_TX_TRANSFER_TYPE( pxPeripheralControl ) )
	{
		case ioctlUSE_POLLED_TX :

			#if ioconfigUSE_SSP_POLLED_TX == 1
			{
				/* Configure the transfer data.  No semaphore or queue is used
				here, so the application must ensure only one task attempts to
				make a polling write at a time. */
				pxSSPTransferDefinition = ( SSP_DATA_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl );
				configASSERT( pxSSPTransferDefinition );
				pxSSPTransferDefinition->tx_data = ( void * ) pvBuffer;
				pxSSPTransferDefinition->rx_data = NULL;
				pxSSPTransferDefinition->length  = ( uint32_t ) xBytes;
				xReturn = SSP_ReadWrite( pxSSP, pxSSPTransferDefinition, SSP_TRANSFER_POLLING );
			}
			#endif /* ioconfigUSE_SSP_POLLED_TX */

			/* The transfer struct is set back to NULL as the Tx is complete
			before the above call to SSP_ReadWrite() completes. */
			pxTxTransferControlStructs[ ulPeripheralNumber ] = NULL;
			break;


		case ioctlUSE_ZERO_COPY_TX :

			#if ioconfigUSE_SSP_ZERO_COPY_TX == 1
			{
				/* The implementation of the zero copy write uses a semaphore
				to indicate whether a write is complete (and so the buffer
				being written free again) or not.  The semantics of using a
				zero copy write dictate that a zero copy write can only be
				attempted by a task, once the semaphore has been successfully
				obtained by that task.  This ensure that only one task can
				perform a zero copy write at any one time.  Ensure the semaphore
				is not currently available, if this function has been called
				without it being obtained first then it is an error. */
				configASSERT( xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, 0U ) == 0 );
				xReturn = xBytes;
				ioutilsINITIATE_ZERO_COPY_TX
					(
						pxPeripheralControl,
						SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ),		/* Disable interrupt. */
						SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), 		/* Enable interrupt. */
						prvFillFifoFromBuffer( pxSSP, ( uint8_t ** ) &( pvBuffer ), xBytes ), 	/* Write to peripheral function.  The buffer is passed in by address as the pointer is incremented. */
						pvBuffer, 																/* Data source. */
						xReturn																	/* Number of bytes to be written.  This will get set to zero if the write mutex is not held. */
					);
			}
			#endif /* ioconfigUSE_SSP_ZERO_COPY_TX */

			/* Remove compiler warnings in case the above is #defined out. */
			( void ) prvFillFifoFromBuffer;
			break;


		case ioctlUSE_CHARACTER_QUEUE_TX :

			#if ioconfigUSE_SSP_TX_CHAR_QUEUE == 1
			{
				/* The queue allows multiple tasks to attempt to write bytes,
				but ensures only the highest priority of these tasks will
				actually succeed.  If two tasks of equal priority attempt to
				write simultaneously, then the application must ensure mutual
				exclusion, as time slicing could result in the strings being
				sent to the queue becoming interleaved. */
				xReturn = xIOUtilsSendCharsToTxQueue( pxPeripheralControl, ( ( uint8_t * ) pvBuffer ), xBytes );

				ioutilsFILL_FIFO_FROM_TX_QUEUE(
						pxPeripheralControl,
						SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ),	/* Disable Rx interrupt. */
						SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), 	/* Enable Rx interrupt. */
						sspMAX_FIFO_DEPTH, 													/* Bytes to write to the FIFO. */
						( pxSSP->SR & SSP_STAT_TXFIFO_NOTFULL ) != 0UL,						/* FIFO not full. */
						pxSSP->DR = SSP_DR_BITMASK( ucChar ) );							  	/* Tx function. */
			}
			#endif /* ioconfigUSE_SSP_RX_CHAR_QUEUE */
			break;


		default :

			/* Other methods can be implemented here.  For now, set the stored
			Tx structure back to NULL as nothing is being sent. */
			pxTxTransferControlStructs[ ulPeripheralNumber ] = NULL;
			configASSERT( xReturn );

			/* Prevent compiler warnings when the configuration is set such
			that the following parameters are not used. */
			( void ) pvBuffer;
			( void ) xBytes;
			( void ) pxSSP;
			( void ) pxSSPTransferDefinition;
			break;
	}

	return xReturn;
}
Beispiel #7
0
size_t FreeRTOS_SSP_read( Peripheral_Descriptor_t const pxPeripheral, void * const pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_SSP_TypeDef * const pxSSP = ( LPC_SSP_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
SSP_DATA_SETUP_Type *pxSSPTransferDefinition;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	/* Sanity check the array index. */
	configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );

	switch( diGET_RX_TRANSFER_TYPE( pxPeripheralControl ) )
	{
		case ioctlUSE_POLLED_RX :

			#if ioconfigUSE_SSP_POLLED_RX == 1
			{
				/* Configure the transfer data.  No semaphore or queue is used
				here, so the application must ensure only one task attempts to
				make a polling read at a time.  *NOTE* the Tx transfer state
				is used, as the SSP requires a Tx to occur for any data to be
				received. */
				pxSSPTransferDefinition = ( SSP_DATA_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl );
				configASSERT( pxSSPTransferDefinition );
				pxSSPTransferDefinition->tx_data = NULL;
				pxSSPTransferDefinition->rx_data = ( void * ) pvBuffer;
				pxSSPTransferDefinition->length  = ( uint32_t ) xBytes;
				xReturn = SSP_ReadWrite( pxSSP, pxSSPTransferDefinition, SSP_TRANSFER_POLLING );
			}
			#endif /* ioconfigUSE_SSP_POLLED_RX */
			break;


		case ioctlUSE_CIRCULAR_BUFFER_RX :
			/* _RB_ This relies on Tx being configured to zero copy mode. */
			#if ioconfigUSE_SSP_CIRCULAR_BUFFER_RX == 1
			{
				/* There is nothing to prevent multiple tasks attempting to
				read the circular buffer at any one time.  The implementation
				of the circular buffer uses a semaphore to indicate when new
				data is available, and the semaphore will ensure that only the
				highest priority task that is attempting a read will actually
				receive bytes. */

				/* A write is performed first, to generate the clock required
				to clock the data in.  NULL is passed as the source buffer as
				there isn't actually any data to send, and NULL will just
				result in 0xff being sent.  When the data written to the FIFO
				has been transmitted an Rx interrupt will copy the received
				data into the circular buffer, and check to see if there is
				more data to be written. */

				/* Ensure the last Tx has completed. */
				xReturn = xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, ioutilsDEFAULT_ZERO_COPY_TX_MUTEX_BLOCK_TIME );
				configASSERT( xReturn );

				if( xReturn == pdPASS )
				{
					/* Empty whatever is lingering in the Rx buffer (there
					shouldn't be any. */
					vIOUtilsClearRxCircularBuffer( pxPeripheralControl );

					/* Data should be received during the following write. */
					ulReceiveActive[ cPeripheralNumber ] = pdTRUE;

					/* Write to solicit received data. */
					FreeRTOS_SSP_write( pxPeripheralControl, NULL, xBytes );

					/* This macro will continuously wait on the new data mutex,
					reading bytes from the circular buffer each time it
					receives it, until the desired number of bytes have been
					read. */
					ioutilsRECEIVE_CHARS_FROM_CIRCULAR_BUFFER
						(
							pxPeripheralControl,
							SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, DISABLE ), /* Disable interrupt. */
							SSP_IntConfig( pxSSP, sspRX_DATA_AVAILABLE_INTERRUPTS, ENABLE ), /* Enable interrupt. */
							( ( uint8_t * ) pvBuffer ),	/* Data destination. */
							xBytes,						/* Bytes to read. */
							xReturn						/* Number of bytes read. */
						);

					/* Not expecting any more Rx data now, so just junk anything
					that is received until the next explicit read is performed. */
					ulReceiveActive[ cPeripheralNumber ] = pdFALSE;
				}
			}
			#endif
			break;


		case ioctlUSE_CHARACTER_QUEUE_RX :

			/* The queue allows multiple tasks to attempt to read bytes,
			but ensures only the highest priority of these tasks will
			actually receive bytes.  If two tasks of equal priority attempt
			to read simultaneously, then the application must ensure mutual
			exclusion, as time slicing could result in the string being
			received being partially received by each task. */
			#if ioconfigUSE_SSP_RX_CHAR_QUEUE == 1
			{
				/* Ensure the last Tx has completed. */
				xIOUtilsWaitTxQueueEmpty( pxPeripheralControl, boardDEFAULT_READ_MUTEX_TIMEOUT );

				/* Clear any residual data - there shouldn't be any! */
				xIOUtilsClearRxCharQueue( pxPeripheralControl );

				/* Data should be received during the following write. */
				ulReceiveActive[ cPeripheralNumber ] = pdTRUE;

				/* Write to solicit received data. */
				FreeRTOS_SSP_write( pxPeripheralControl, NULL, xBytes );

				/* Read the received data placed in the Rx queue by the
				interrupt. */
				xReturn = xIOUtilsReceiveCharsFromRxQueue( pxPeripheralControl, ( uint8_t * ) pvBuffer, xBytes );

				/* Not expecting any more Rx data now, so just junk anything
				that is received until the next explicit read is performed. */
				ulReceiveActive[ cPeripheralNumber ] = pdFALSE;
			}
			#endif
			break;


		default :

			/* Other methods can be implemented here. */
			configASSERT( xReturn );

			/* Prevent compiler warnings when the configuration is set such
			that the following parameters are not used. */
			( void ) pvBuffer;
			( void ) xBytes;
			( void ) pxSSP;
			( void ) pxSSPTransferDefinition;
			( void ) cPeripheralNumber;
			break;
	}

	return xReturn;
}
Beispiel #8
0
portBASE_TYPE FreeRTOS_SSP_open( Peripheral_Control_t * const pxPeripheralControl )
{
PINSEL_CFG_Type xPinConfig;
portBASE_TYPE xReturn = pdFAIL;
LPC_SSP_TypeDef * const pxSSP = ( LPC_SSP_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( pxPeripheralControl );
SSP_DATA_SETUP_Type *pxSSPTransferDefinition;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( pxPeripheralControl );
volatile uint16_t usJunkIt;

	/* Sanity check the peripheral number. */
	if( cPeripheralNumber < boardNUM_SSPS )
	{
		/* Polled mode is used by default.  Create the structure used to
		transfer SSP data in polled mode. */
		pxSSPTransferDefinition = ( SSP_DATA_SETUP_Type * ) pvPortMalloc( sizeof( SSP_DATA_SETUP_Type ) );

		if( pxSSPTransferDefinition != NULL )
		{
			/* Create the transfer control structures in which references to
			pxSSPTransferDefinition will be stored. */
			vIOUtilsCreateTransferControlStructure( &( pxPeripheralControl->pxTxControl ) );
			vIOUtilsCreateTransferControlStructure( &( pxPeripheralControl->pxRxControl ) );

			if( ( pxPeripheralControl->pxTxControl != NULL ) && ( pxPeripheralControl->pxTxControl != NULL ) )
			{
				pxPeripheralControl->read = FreeRTOS_SSP_read;
				pxPeripheralControl->write = FreeRTOS_SSP_write;
				pxPeripheralControl->ioctl = FreeRTOS_SSP_ioctl;
				pxPeripheralControl->pxTxControl->pvTransferState = pxSSPTransferDefinition;
				pxPeripheralControl->pxTxControl->ucType = ioctlUSE_POLLED_TX;
				pxPeripheralControl->pxRxControl->pvTransferState = NULL;
				pxPeripheralControl->pxRxControl->ucType = ioctlUSE_POLLED_RX;

				taskENTER_CRITICAL();
				{
					/* Setup the pins for the SSP being used. */
					boardCONFIGURE_SSP_PINS( cPeripheralNumber, xPinConfig );

					/* Set up the default SSP configuration. */
					SSP_ConfigStructInit( &( xSSPConfigurations[ cPeripheralNumber ] ) );
					SSP_Init( pxSSP, &( xSSPConfigurations[ cPeripheralNumber ] ) );
					SSP_Cmd( pxSSP, ENABLE );

					/* Clear data in Rx Fifo. */
					while( ( pxSSP->SR & SSP_SR_RNE ) != 0 )
					{
						usJunkIt = pxSSP->DR;
					}
				}
				taskEXIT_CRITICAL();

				xReturn = pdPASS;
			}
			else
			{
				/* Could not create one of other transfer control structure,
				so free	the created LPC_SSP_TypeDef typedef structures and any
				transfer control structures that were created before
				exiting. */
				if( pxPeripheralControl->pxTxControl != NULL )
				{
					vPortFree( pxPeripheralControl->pxTxControl );
					pxPeripheralControl->pxTxControl = NULL;
				}

				if( pxPeripheralControl->pxRxControl != NULL )
				{
					vPortFree( pxPeripheralControl->pxRxControl );
					pxPeripheralControl->pxRxControl = NULL;
				}

				vPortFree( pxSSPTransferDefinition );
			}
		}
	}

	return xReturn;
}
portBASE_TYPE FreeRTOS_I2C_open( Peripheral_Control_t * const pxPeripheralControl )
{
PINSEL_CFG_Type xPinConfig;
LPC_I2C_TypeDef * const pxI2C = ( LPC_I2C_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( pxPeripheralControl );
portBASE_TYPE xReturn = pdFAIL;
const uint8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( pxPeripheralControl );
I2C_M_SETUP_Type *pxI2CTxTransferDefinition = NULL, *pxI2CRxTransferDefinition = NULL;

	/* Sanity check the peripheral number. */
	if( cPeripheralNumber < boardNUM_I2CS )
	{
		/* Polled mode is used by default.  This can be changed using an
		ioctl() call.  Create the structures used to transfer I2C data in
		polled mode. */
		pxI2CTxTransferDefinition = ( I2C_M_SETUP_Type * ) pvPortMalloc( sizeof( I2C_M_SETUP_Type ) );
		pxI2CRxTransferDefinition = ( I2C_M_SETUP_Type * ) pvPortMalloc( sizeof( I2C_M_SETUP_Type ) );

		if( ( pxI2CTxTransferDefinition != NULL ) && ( pxI2CRxTransferDefinition != NULL ) )
		{
			/* Create the transfer control structures in which references to
			pxI2CNxTransferDefinitions will be stored. */
			vIOUtilsCreateTransferControlStructure( &( pxPeripheralControl->pxTxControl ) );
			vIOUtilsCreateTransferControlStructure( &( pxPeripheralControl->pxRxControl ) );

			if( ( pxPeripheralControl->pxTxControl != NULL ) && ( pxPeripheralControl->pxRxControl != NULL ) )
			{
				pxPeripheralControl->read = FreeRTOS_I2C_read;
				pxPeripheralControl->write = FreeRTOS_I2C_write;
				pxPeripheralControl->ioctl = FreeRTOS_I2C_ioctl;
				pxPeripheralControl->pxTxControl->pvTransferState = pxI2CTxTransferDefinition;
				pxPeripheralControl->pxTxControl->ucType = ioctlUSE_POLLED_TX;
				pxPeripheralControl->pxRxControl->pvTransferState = pxI2CRxTransferDefinition;
				pxPeripheralControl->pxRxControl->ucType = ioctlUSE_POLLED_RX;

				taskENTER_CRITICAL();
				{
					/* Setup the pins for the I2C being used. */
					boardCONFIGURE_I2C_PINS( cPeripheralNumber, xPinConfig );

					/* Set up the default I2C configuration. */
					I2C_Init( pxI2C, boardDEFAULT_I2C_SPEED );
					I2C_Cmd( pxI2C, ENABLE );
				}
				taskEXIT_CRITICAL();

				xReturn = pdPASS;
			}
		}

		if( xReturn != pdPASS )
		{
			/* The open operation could not complete because something could
			not be created.  Delete anything that was created. */
			if( pxI2CTxTransferDefinition != NULL )
			{
				vPortFree( pxI2CTxTransferDefinition );
			}

			if( pxI2CRxTransferDefinition != NULL )
			{
				vPortFree( pxI2CRxTransferDefinition );
			}

			if( pxPeripheralControl->pxTxControl != NULL )
			{
				vPortFree( pxPeripheralControl->pxTxControl );
				pxPeripheralControl->pxTxControl = NULL;
			}

			if( pxPeripheralControl->pxRxControl != NULL )
			{
				vPortFree( pxPeripheralControl->pxRxControl );
				pxPeripheralControl->pxRxControl = NULL;
			}
		}
	}

	/* Just to prevent compiler warnings when FreeRTIOSIOConfig.h is configured
	such that the variable is not used. */
	( void ) pxRxTransferControlStructs;

	return xReturn;
}
portBASE_TYPE FreeRTOS_I2C_ioctl( Peripheral_Descriptor_t const pxPeripheral, uint32_t ulRequest, void *pvValue )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
uint32_t ulValue = ( uint32_t ) pvValue;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
portBASE_TYPE xReturn = pdPASS;
LPC_I2C_TypeDef * pxI2C = ( LPC_I2C_TypeDef * ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	/* Sanity check the array index. */
	configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );

	taskENTER_CRITICAL();
	{
		switch( ulRequest )
		{
			case ioctlSET_I2C_SLAVE_ADDRESS :

				ucSlaveAddresses[ cPeripheralNumber ] = ( uint8_t ) ulValue;
				break;


			case ioctlUSE_INTERRUPTS :

				if( ulValue == pdFALSE )
				{
					NVIC_DisableIRQ( xIRQ[ cPeripheralNumber ] );
				}
				else
				{
					/* Ensure the interrupt is not already enabled. */
					I2C_IntCmd( pxI2C, DISABLE );

					/* Clear any pending interrupts in the peripheral and
					NVIC. */
					pxI2C->I2CONCLR = I2C_I2CONCLR_SIC;
					NVIC_ClearPendingIRQ( xIRQ[ cPeripheralNumber ] );

					/* Set the priority of the interrupt to the minimum
					interrupt priority.  A separate command can be issued to
					raise the priority if desired.  The interrupt is only
					enabled when a transfer is started. */
					NVIC_SetPriority( xIRQ[ cPeripheralNumber ], configMIN_LIBRARY_INTERRUPT_PRIORITY );

					/* Remember the	transfer control structure that should
					be used for Rx.  A reference to the Tx transfer control
					structure is taken when a write() operation is actually
					performed. */
					pxRxTransferControlStructs[ cPeripheralNumber ] = pxPeripheralControl->pxRxControl;
				}
				break;


			case ioctlSET_SPEED :

				/* Set up the default I2C configuration. */
				I2C_SetClock( pxI2C, ulValue );
				break;


			case ioctlSET_INTERRUPT_PRIORITY :

				/* The ISR uses ISR safe FreeRTOS API functions, so the priority
				being set must be lower than or equal to (ie numerically larger
				than or equal to) configMAX_LIBRARY_INTERRUPT_PRIORITY. */
				configASSERT( ulValue >= configMAX_LIBRARY_INTERRUPT_PRIORITY );
				NVIC_SetPriority( xIRQ[ cPeripheralNumber ], ulValue );
				break;


			default :

				xReturn = pdFAIL;
				break;
		}
	}
	taskEXIT_CRITICAL();

	return xReturn;
}
size_t FreeRTOS_I2C_read( Peripheral_Descriptor_t const pxPeripheral, void * const pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_I2C_TypeDef * const pxI2C = ( LPC_I2C_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
I2C_M_SETUP_Type *pxI2CTransferDefinition;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	/* Sanity check the array index. */
	configASSERT( cPeripheralNumber < ( int8_t ) ( sizeof( xIRQ ) / sizeof( IRQn_Type ) ) );
	configASSERT( xBytes > 0U );

	/* Remove compiler warnings when configASSERT() is not defined. */
	( void ) xBytes;

	switch( diGET_RX_TRANSFER_TYPE( pxPeripheralControl ) )
	{
		case ioctlUSE_POLLED_RX :

			#if ioconfigUSE_I2C_POLLED_RX == 1
			{
				/* Configure the transfer data.  No semaphore or queue is used
				here, so the application must ensure only one task attempts to
				make a polling write at a time. */
				pxI2CTransferDefinition = ( I2C_M_SETUP_Type * ) diGET_RX_TRANSFER_STATE( pxPeripheralControl );
				configASSERT( pxI2CTransferDefinition );
				pxI2CTransferDefinition->sl_addr7bit = ucSlaveAddresses[ cPeripheralNumber ];
				pxI2CTransferDefinition->tx_data = NULL;
				pxI2CTransferDefinition->tx_length = 0;
				pxI2CTransferDefinition->rx_data = ( uint8_t * ) pvBuffer;;
				pxI2CTransferDefinition->rx_length = xBytes;
				pxI2CTransferDefinition->retransmissions_max = boardI2C_MAX_RETRANSMISSIONS;

				if( I2C_MasterTransferData( pxI2C, pxI2CTransferDefinition, I2C_TRANSFER_POLLING ) == SUCCESS )
				{
					xReturn = xBytes;
				}
			}
			#endif /* ioconfigUSE_I2C_POLLED_RX */

			break;


		case ioctlUSE_CIRCULAR_BUFFER_RX :

			#if ioconfigUSE_I2C_CIRCULAR_BUFFER_RX == 1
			{
				/* There is nothing to prevent multiple tasks attempting to
				read the circular buffer at any one time.  The implementation
				of the circular buffer uses a semaphore to indicate when new
				data is available, and the semaphore will ensure that only the
				highest priority task that is attempting a read will actually
				receive bytes. */

				if( xDataDirection[ cPeripheralNumber ] == i2cIdle )
				{
					/* This is the first time read() has been called for this
					transfer.  Start the transfer by setting the start
					bit, then mark the read transfer as in progress. */
					pxI2C->I2CONSET = I2C_I2CONSET_STA;
					xDataDirection[ cPeripheralNumber ] = i2cReading;
					xBytesOutstanding[ cPeripheralNumber ] = xBytes;
					I2C_IntCmd( pxI2C, ENABLE );
				}

				ioutilsRECEIVE_CHARS_FROM_CIRCULAR_BUFFER
					(
						pxPeripheralControl,
						I2C_IntCmd( pxI2C, DISABLE ),	/* Disable peripheral. */
						I2C_IntCmd( pxI2C, ENABLE ), 	/* Enable peripheral. */
						( ( uint8_t * ) pvBuffer ),		/* Data destination. */
						xBytes,							/* Bytes to read. */
						xReturn							/* Number of bytes read. */
					);
			}
			#endif /* ioconfigUSE_I2C_CIRCULAR_BUFFER_RX */
			break;


		case ioctlUSE_CHARACTER_QUEUE_RX :
			/* Not (yet?) implemented for I2C. */
			configASSERT( xReturn );
			break;


		default :

			/* Other methods can be implemented here. */
			configASSERT( xReturn );

			/* Prevent compiler warnings when the configuration is set such
			that the following parameters are not used. */
			( void ) pvBuffer;
			( void ) pxI2C;
			( void ) pxI2CTransferDefinition;
			( void ) cPeripheralNumber;
			break;
	}

	return xReturn;
}
size_t FreeRTOS_I2C_write( Peripheral_Descriptor_t const pxPeripheral, const void *pvBuffer, const size_t xBytes )
{
Peripheral_Control_t * const pxPeripheralControl = ( Peripheral_Control_t * const ) pxPeripheral;
size_t xReturn = 0U;
LPC_I2C_TypeDef * const pxI2C = ( LPC_I2C_TypeDef * const ) diGET_PERIPHERAL_BASE_ADDRESS( ( ( Peripheral_Control_t * const ) pxPeripheral ) );
I2C_M_SETUP_Type *pxI2CTransferDefinition;
const int8_t cPeripheralNumber = diGET_PERIPHERAL_NUMBER( ( ( Peripheral_Control_t * const ) pxPeripheral ) );

	/* Remember which transfer control structure is being used, so if
	an interrupt is being used, it can continue the same transfer until
	all data has been transmitted. */
	pxTxTransferControlStructs[ cPeripheralNumber ] = diGET_TX_TRANSFER_STRUCT( pxPeripheralControl );
	xDataDirection[ cPeripheralNumber ] = i2cWriting;

	switch( diGET_TX_TRANSFER_TYPE( pxPeripheralControl ) )
	{
		case ioctlUSE_POLLED_TX :

			#if ioconfigUSE_I2C_POLLED_TX == 1
			{
				/* Configure the transfer data.  No semaphore or queue is used
				here, so the application must ensure only one task attempts to
				make a polling write at a time. */
				pxI2CTransferDefinition = ( I2C_M_SETUP_Type * ) diGET_TX_TRANSFER_STATE( pxPeripheralControl );
				configASSERT( pxI2CTransferDefinition );
				pxI2CTransferDefinition->sl_addr7bit = ucSlaveAddresses[ cPeripheralNumber ];
				pxI2CTransferDefinition->tx_data = ( uint8_t * ) pvBuffer;
				pxI2CTransferDefinition->tx_length = xBytes;
				pxI2CTransferDefinition->rx_data = NULL;
				pxI2CTransferDefinition->rx_length = 0;
				pxI2CTransferDefinition->retransmissions_max = boardI2C_MAX_RETRANSMISSIONS;

				if( I2C_MasterTransferData( pxI2C, pxI2CTransferDefinition, I2C_TRANSFER_POLLING ) == SUCCESS )
				{
					xReturn = xBytes;
				}
			}
			#endif /* ioconfigUSE_I2C_POLLED_TX_RX */

			/* The transfer struct is set back to NULL as the Tx is complete
			before the above call to I2C_ReadWrite() completes. */
			pxTxTransferControlStructs[ cPeripheralNumber ] = NULL;
			break;


		case ioctlUSE_ZERO_COPY_TX :

			#if ioconfigUSE_I2C_ZERO_COPY_TX == 1
			{
				/* The implementation of the zero copy write uses a semaphore
				to indicate whether a write is complete (and so the buffer
				being written free again) or not.  The semantics of using a
				zero copy write dictate that a zero copy write can only be
				attempted by a task, once the semaphore has been successfully
				obtained by that task.  This ensure that only one task can
				perform a zero copy write at any one time.  Ensure the semaphore
				is not currently available, if this function has been called
				without it being obtained first then it is an error. */
				configASSERT( xIOUtilsGetZeroCopyWriteMutex( pxPeripheralControl, ioctlOBTAIN_WRITE_MUTEX, 0U ) == 0 );
				xReturn = xBytes;
				ioutilsINITIATE_ZERO_COPY_TX
					(
						pxPeripheralControl,
						I2C_IntCmd( pxI2C, DISABLE ),	/* Disable interrupt.  Not really necessary in this case as it should not be enabled anyway. */
						( void ) 0, 					/* As the start condition has not been sent, the interrupt is not enabled yet. */
						0,  							/* In this case no write is attempted and all that should happen is the buffer gets set up ready. */
						pvBuffer, 						/* Data source. */
						xReturn							/* Number of bytes to be written.  This will get set to zero if the write mutex is not held. */
					);

				/* Ensure there are not already interrupt pending. */
				pxI2C->I2CONCLR = ( I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_AAC | I2C_I2CONCLR_STAC );

				/* Set start flag. */
				pxI2C->I2CONSET = I2C_I2CONSET_STA;

				/* Now enable interrupts. */
				I2C_IntCmd( pxI2C, ENABLE );
			}
			#endif /* ioconfigUSE_I2C_ZERO_COPY_TX */
			break;


		case ioctlUSE_CHARACTER_QUEUE_TX :

			/* Not (yet?) implemented for I2C. */
			configASSERT( xReturn );
			break;


		default :

			/* Other methods can be implemented here.  For now, set the stored
			Tx structure back to NULL as nothing is being sent. */
			pxTxTransferControlStructs[ cPeripheralNumber ] = NULL;
			configASSERT( xReturn );

			/* Prevent compiler warnings when the configuration is set such
			that the following parameters are not used. */
			( void ) pvBuffer;
			( void ) xBytes;
			( void ) pxI2C;
			( void ) pxI2CTransferDefinition;
			break;
	}

	return xReturn;
}