/**
 * \ingroup freertos_uart_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte write operation on a
 * UART peripheral.
 *
 * freertos_uart_write_packet_async() is an ASF specific FreeRTOS driver
 * function.  It configures the UART peripheral DMA controller (PDC) to
 * transmit data on the UART port, then returns.
 * freertos_uart_write_packet_async() does not wait for the transmission to
 * complete before returning.
 *
 * The FreeRTOS UART driver is initialized using a call to
 * freertos_uart_serial_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_uart_write_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_TX_COMPLETE bit clear.
 *
 * freertos_uart_write_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_uart_write_packet() is a
 * version that does not exit until the PDC transfer is complete, but still
 * allows other RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the UART PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_uart    The handle to the UART peripheral returned by the
 *     freertos_uart_serial_init() call used to initialise the peripheral.
 * \param data    A pointer to the data to be transmitted.
 * \param len    The number of bytes to transmit.
 * \param block_time_ticks    The FreeRTOS ASF UART driver is initialized using
 *     a call to freertos_uart_serial_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit
 *     set, then the driver will only write to the UART peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the write operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the transmit
 *     function exits the transmit function as soon as the transmission starts.
 *     The data being transmitted by the PDC must not be modified until after
 *     the transmission has completed.  The PDC interrupt (handled internally by
 *     the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has finished accessing the data.
 *     The calling task can call standard FreeRTOS functions to block on the
 *     semaphore until the PDC interrupt occurs.  Other RTOS tasks will execute
 *     while the the calling task is in the Blocked state.  The semaphore must
 *     be created using the FreeRTOS vSemaphoreCreateBinary() API function
 *     before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the UART peripheral could be obtained.  STATUS_OK is returned
 *     if the PDC was successfully configured to perform the UART write
 *     operation.
 */
status_code_t freertos_uart_write_packet_async(freertos_uart_if p_uart,
		const uint8_t *data, size_t len, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE uart_index;
	Uart *uart_base;

	uart_base = (Uart *) p_uart;
	uart_index = get_pdc_peripheral_details(all_uart_definitions,
			MAX_UARTS,
			(void *) uart_base);

	/* Don't do anything unless a valid UART pointer was used. */
	if (uart_index < MAX_UARTS) {
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[uart_index]),
				&block_time_ticks);

		if (return_value == STATUS_OK) {
			freertos_start_pdc_tx(&(tx_dma_control[uart_index]),
					data, len,
					all_uart_definitions[uart_index].pdc_base_address,
					notification_semaphore);

			/* Catch the end of transmission so the access mutex can be
			returned, and the task notified (if it supplied a notification
			semaphore).  The interrupt can be enabled here because the ENDTX
			signal from the PDC to the UART will have been de-asserted when
			the next transfer was configured. */
			uart_enable_interrupt(uart_base, UART_IER_ENDTX);

			return_value = freertos_optionally_wait_transfer_completion(
					&(tx_dma_control[uart_index]),
					notification_semaphore,
					block_time_ticks);
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 2
0
/**
 * \ingroup freertos_spi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte read operation on an SPI
 * peripheral.
 *
 * freertos_spi_read_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the SPI peripheral DMA controller (PDC) to read data from the
 * SPI port, then returns.  freertos_spi_read_packet_async() does not wait for
 * the reception to complete before returning.
 *
 * The FreeRTOS ASF SPI driver is initialized using a call to
 * freertos_spi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_spi_read_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_RX_COMPLETE bit clear.
 *
 * freertos_spi_read_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_spi_read_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the SPI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_spi    The handle to the SPI port returned by the
 *     freertos_spi_master_init() call used to initialise the port.
 * \param data    A pointer to the buffer into which received data is to be
 *     written.
 * \param len    The number of bytes to receive.
 * \param block_time_ticks    The FreeRTOS ASF SPI driver is initialized using a
 *     call to freertos_spi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the SPI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the receive
 *     function exits the receive function as soon as the reception starts.
 *     The data being received by the PDC cannot normally be processed until
 *     after the reception has completed.  The PDC interrupt (handled internally
 *     by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has read the requested number of
 *     bytes.  The calling task can call standard FreeRTOS functions to block on
 *     the semaphore until the PDC interrupt occurs.  Other RTOS tasks will
 *     execute while the the calling task is in the Blocked state.  The
 *     semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API
 *     function before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the SPI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the SPI read operation.
 */
status_code_t freertos_spi_read_packet_async(freertos_spi_if p_spi,
		uint8_t *data, uint32_t len, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	pdc_packet_t pdc_tx_packet;
	portBASE_TYPE spi_index;
	Spi *spi_base;
	volatile uint16_t junk_value;

	spi_base = (Spi *) p_spi;
	spi_index = get_pdc_peripheral_details(all_spi_definitions, MAX_SPIS,
			(void *) spi_base);

	/* Don't do anything unless a valid SPI pointer was used. */
	if (spi_index < MAX_SPIS) {
		/* Because the peripheral is half duplex, there is only one access mutex
		and the rx uses the tx mutex. */
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[spi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Data must be sent for data to be received.  Set the receive
			buffer to all 0xffs so it can also be used as the send buffer. */
			memset((void *)data, 0xff, (size_t)len);

			/* Ensure Rx is already empty. */
			while(spi_is_rx_full(all_spi_definitions[spi_index].peripheral_base_address) != 0) {
				junk_value = ((Spi*) all_spi_definitions[spi_index].peripheral_base_address)->SPI_RDR;
				(void) junk_value;
			}

			/* Start the PDC reception, although nothing is received until the
			SPI is also transmitting. */
			freertos_start_pdc_rx(&(rx_dma_control[spi_index]),
					data, len,
					all_spi_definitions[spi_index].pdc_base_address,
					notification_semaphore);

			/* Start the transmit so data is also received. */
			pdc_tx_packet.ul_addr = (uint32_t)data;
			pdc_tx_packet.ul_size = (uint32_t)len;
			pdc_disable_transfer(
					all_spi_definitions[spi_index].pdc_base_address,
					PERIPH_PTCR_TXTDIS);
			pdc_tx_init(
					all_spi_definitions[spi_index].pdc_base_address, &pdc_tx_packet,
					NULL);
			pdc_enable_transfer(
					all_spi_definitions[spi_index].pdc_base_address,
					PERIPH_PTCR_TXTEN);

			/* Catch the end of reception so the access mutex can be returned,
			and the task notified (if it supplied a notification semaphore).
			The interrupt can be enabled here because the ENDRX	signal from the
			PDC to the peripheral will have been de-asserted when the next
			transfer was configured. */
			spi_enable_interrupt(spi_base, SPI_IER_ENDRX);

			return_value = freertos_optionally_wait_transfer_completion(
					&(rx_dma_control[spi_index]),
					notification_semaphore,
					block_time_ticks);
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 3
0
/**
 * \ingroup freertos_spi_peripheral_control_group
 * \brief Initializes the FreeRTOS ASF SPI master driver for the specified SPI port.
 *
 * freertos_spi_master_init() is an ASF specific FreeRTOS driver function.  It
 * must be called before any other ASF specific FreeRTOS driver functions
 * attempt to access the same SPI port.
 *
 * If freertos_driver_parameters->operation_mode equals SPI_MASTER then
 * freertos_spi_master_init() will configure the SPI port for master mode
 * operation and enable the peripheral.  If
 * freertos_driver_parameters->operation_mode equals any other value then
 * freertos_spi_master_init() will not take any action.
 *
 * Other ASF SPI functions, such as those to set the SPI clock rate and other
 * bus parameters, can be called after freertos_spi_master_init() has completed
 * successfully.
 *
 * The FreeRTOS ASF driver both installs and handles the SPI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * This driver is provided with an application note, and an example project that
 * demonstrates the use of this function.
 *
 * \param p_spi    The SPI peripheral being initialized.
 * \param freertos_driver_parameters    Defines the driver behavior.  See the
 *    freertos_peripheral_options_t documentation, and the application note that
 *    accompanies the ASF specific FreeRTOS functions.
 *
 * \return If the initialization completes successfully then a handle that can
 *     be used with FreeRTOS SPI read and write functions is returned.  If
 *     the initialisation fails then NULL is returned.
 */
freertos_spi_if freertos_spi_master_init(Spi *p_spi,
		const freertos_peripheral_options_t *const freertos_driver_parameters)
{
	portBASE_TYPE spi_index;
	bool is_valid_operating_mode;
	freertos_spi_if return_value;
	const enum peripheral_operation_mode valid_operating_modes[] = {SPI_MASTER};

	/* Find the index into the all_spi_definitions array that holds details of
	the p_spi peripheral. */
	spi_index = get_pdc_peripheral_details(all_spi_definitions, MAX_SPIS,
			(void *) p_spi);

	/* Check the requested operating mode is valid for the peripheral. */
	is_valid_operating_mode = check_requested_operating_mode(
			freertos_driver_parameters->operation_mode,
			valid_operating_modes,
			sizeof(valid_operating_modes) /
			sizeof(enum peripheral_operation_mode));

	/* Don't do anything unless a valid p_spi pointer was used, and a valid
	operating mode was requested. */
	if ((spi_index < MAX_SPIS) && (is_valid_operating_mode == true)) {
		/* This function must be called exactly once per supported spi.  Check it
		has not been called	before. */
		configASSERT(memcmp((void *) &(tx_dma_control[spi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);
		configASSERT(memcmp((void *) &(rx_dma_control[spi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);

		/* Ensure everything is disabled before configuration. */
		spi_disable(all_spi_definitions[spi_index].peripheral_base_address);
		pdc_disable_transfer(
				all_spi_definitions[spi_index].pdc_base_address,
				(PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS));
		spi_disable_interrupt(
				all_spi_definitions[spi_index].peripheral_base_address,
				MASK_ALL_INTERRUPTS);

		switch (freertos_driver_parameters->operation_mode) {
		case SPI_MASTER:
			/* Call the standard ASF init function. */
			spi_master_init(
					all_spi_definitions[spi_index].peripheral_base_address);
			break;

		default:
			/* No other modes are currently supported. */
			break;
		}

		/* Create any required peripheral access mutexes and transaction complete
		semaphores.  This peripheral is half duplex so only a single access
		mutex is required. */
		create_peripheral_control_semaphores(
				freertos_driver_parameters->options_flags,
				&(tx_dma_control[spi_index]),
				&(rx_dma_control[spi_index]));

		/* Configure and enable the SPI interrupt in the interrupt controller. */
		configure_interrupt_controller(
				all_spi_definitions[spi_index].peripheral_irq,
				freertos_driver_parameters->interrupt_priority);

		/* Error interrupts are always enabled. */
		spi_enable_interrupt(
				all_spi_definitions[spi_index].peripheral_base_address,
				IER_ERROR_INTERRUPTS);

		/* Finally, enable the peripheral. */
		spi_enable(all_spi_definitions[spi_index].peripheral_base_address);

		return_value = (freertos_spi_if)p_spi;
	} else {
		return_value = NULL;
	}

	return return_value;
}
/**
 * \ingroup freertos_uart_peripheral_control_group
 * \brief Initiate a completely multi-byte read operation on a UART peripheral.
 *
 * The FreeRTOS ASF UART driver uses the PDC to transfer data from a peripheral
 * to a circular buffer.  Reception happens in the background, while the
 * microcontroller is executing application code.* freertos_uart_read_packet()
 * copies bytes from the DMA buffer into the buffer passed as a
 * freertos_uart_read_packet() parameter.
 *
 * Readers are recommended to also reference the application note and examples
 * that accompany the FreeRTOS ASF drivers.
 *
 * The FreeRTOS ASF driver both installs and handles the UART PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_uart    The handle to the UART port returned by the
 *     freertos_uart_serial_init() call used to initialise the port.
 * \param data    A pointer to the buffer into which received data is to be
 *     copied.
 * \param len    The number of bytes to copy.
 * \param block_time_ticks    Defines the maximum combined time the function
 *     will wait to get exclusive access to the peripheral and receive the
 *     requested number of bytes.  Other tasks will execute during any waiting
 *     time.
 *
 *     The FreeRTOS ASF UART driver is initialized using a
 *     call to freertos_uart_serial_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the UART buffer if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.
 *
 *     If the number of bytes available is less than the number requested then
 *     freertos_uart_serial_read_packet() will wait for more bytes to become
 *     available.  block_time_ticks specifies the maximum amount of time the
 *     driver will wait before returning fewer bytes than were requested.
 *
 *     block_time_ticks is specified in RTOS tick periods.  To specify a block
 *     time in milliseconds, divide the milliseconds value by portTICK_RATE_MS,
 *     and pass the result in  block_time_ticks.  portTICK_RATE_MS is defined by
 *     FreeRTOS.
 *
 * \return     The number of bytes that were copied into data.  This will be
 *     less than the requested number of bytes if a time out occurred.
 */
uint32_t freertos_uart_serial_read_packet(freertos_uart_if p_uart,
		uint8_t *data, uint32_t len, portTickType block_time_ticks)
{
	portBASE_TYPE uart_index, attempt_read;
	Uart *uart_base;
	xTimeOutType time_out_definition;
	uint32_t bytes_read = 0;

	uart_base = (Uart *) p_uart;
	uart_index = get_pdc_peripheral_details(all_uart_definitions,
			MAX_UARTS,
			(void *) uart_base);

	/* It is possible to initialise the peripheral to only use Tx and not Rx.
	Check that Rx has been initialised. */
	configASSERT(rx_buffer_definitions[uart_index].next_byte_to_read);
	configASSERT(rx_buffer_definitions[uart_index].next_byte_to_read !=
			RX_NOT_USED);

	/* Only do anything if the UART is valid. */
	if (uart_index < MAX_UARTS) {
		/* Must not request more bytes than will fit in the buffer. */
		if (len <=
				(rx_buffer_definitions[uart_index].past_rx_buffer_end_address
				- rx_buffer_definitions[uart_index].rx_buffer_start_address)) {
			/* Remember the time on entry. */
			vTaskSetTimeOutState(&time_out_definition);

			/* If an Rx mutex is in use, attempt to obtain it. */
			if (rx_buffer_definitions[uart_index].rx_access_mutex != NULL) {
				/* Attempt to obtain the mutex. */
				attempt_read = xSemaphoreTake(
						rx_buffer_definitions[uart_index].rx_access_mutex,
						block_time_ticks);

				if (attempt_read == pdTRUE) {
					/* The semaphore was obtained, adjust the block_time_ticks to take
					into account the time taken to obtain the semaphore. */
					if (xTaskCheckForTimeOut(&time_out_definition,
							&block_time_ticks) == pdTRUE) {
						attempt_read = pdFALSE;

						/* The port is not going to be used, so return the
						mutex now. */
						xSemaphoreGive(rx_buffer_definitions[uart_index].rx_access_mutex);
					}
				}
			} else {
				attempt_read = pdTRUE;
			}

			if (attempt_read == pdTRUE) {
				do {
					/* Wait until data is available. */
					xSemaphoreTake(rx_buffer_definitions[uart_index].rx_event_semaphore,
							block_time_ticks);

					/* Copy as much data as is available, up to however much
					a maximum of the total number of requested bytes. */
					bytes_read += freertos_copy_bytes_from_pdc_circular_buffer(
							&(rx_buffer_definitions[uart_index]),
							all_uart_definitions[uart_index].pdc_base_address->PERIPH_RPR,
							&(data[bytes_read]),
							(len - bytes_read));

					/* The Rx DMA will have stopped if the Rx buffer had become
					full before this read operation.  If bytes were removed by
					this read then there is guaranteed to be space in the Rx
					buffer and the Rx DMA can be restarted. */
					if (bytes_read > 0) {
						taskENTER_CRITICAL();
						{
							if(rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_size == 0UL) {
								configure_rx_dma(uart_index, data_removed);
							}
						}
						taskEXIT_CRITICAL();
					}

				  /* Until all the requested bytes are received, or the function
				  runs out of time. */
				} while ((bytes_read < len) && (xTaskCheckForTimeOut(
						&time_out_definition,
						&block_time_ticks) == pdFALSE));

				if (rx_buffer_definitions[uart_index].rx_access_mutex != NULL) {
					/* Return the mutex. */
					xSemaphoreGive(rx_buffer_definitions[uart_index].rx_access_mutex);
				}
			}
		}
	}

	return bytes_read;
}
/**
 * \ingroup freertos_uart_peripheral_control_group
 * \brief Initializes the FreeRTOS ASF UART driver for the specified UART
 * port.
 *
 * freertos_uart_serial_init() is an ASF specific FreeRTOS driver function.  It
 * must be called before any other ASF specific FreeRTOS driver functions
 * attempt to access the same UART port.
 *
 * If freertos_driver_parameters->operation_mode equals UART_RS232 then
 * freertos_uart_serial_init() will configure the UART port for standard RS232
 * operation.  If freertos_driver_parameters->operation_mode equals any other
 * value then freertos_uart_serial_init() will not take any action.
 *
 * Other ASF UART functions can be called after freertos_uart_serial_init()
 * has completed successfully.
 *
 * The FreeRTOS ASF driver both installs and handles the UART PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * This driver is provided with an application note, and an example project that
 * demonstrates the use of this function.
 *
 * \param p_uart    The UART peripheral being initialized.
 * \param uart_parameters    Structure that defines the UART bus and transfer
 *     parameters, such the baud rate and the number of data bits.
 *     sam_uart_opt_t is a standard ASF type (it is not FreeRTOS specific).
 * \param freertos_driver_parameters    Defines the driver behavior.  See the
 *    freertos_peripheral_options_t documentation, and the application note that
 *    accompanies the ASF specific FreeRTOS functions.
 *
 * \return If the initialization completes successfully then a handle that can
 *     be used with FreeRTOS UART read and write functions is returned.  If
 *     the initialisation fails then NULL is returned.
 */
freertos_uart_if freertos_uart_serial_init(Uart *p_uart,
		const sam_uart_opt_t *const uart_parameters,
		const freertos_peripheral_options_t *const freertos_driver_parameters)
{
	portBASE_TYPE uart_index;
	bool is_valid_operating_mode;
	freertos_uart_if return_value;
	const enum peripheral_operation_mode valid_operating_modes[] = {UART_RS232};

	/* Find the index into the all_uart_definitions array that holds details of
	the p_uart peripheral. */
	uart_index = get_pdc_peripheral_details(all_uart_definitions,
			MAX_UARTS,
			(void *) p_uart);

	/* Check the requested operating mode is valid for the peripheral. */
	is_valid_operating_mode = check_requested_operating_mode(
			freertos_driver_parameters->operation_mode,
			valid_operating_modes,
			sizeof(valid_operating_modes) /
			sizeof(enum peripheral_operation_mode));

	/* Don't do anything unless a valid p_uart pointer was used, and a valid
	operating mode was requested. */
	if ((uart_index < MAX_UARTS) && (is_valid_operating_mode == true)) {
		/* This function must be called exactly once per supported UART.  Check it
		has not been called	before. */
		configASSERT(rx_buffer_definitions[uart_index].next_byte_to_read == NULL);

		/* Disable everything before enabling the clock. */
		uart_disable_tx(p_uart);
		uart_disable_rx(p_uart);
		pdc_disable_transfer(all_uart_definitions[uart_index].pdc_base_address,
				(PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS));

		/* Enable the peripheral clock in the PMC. */
		pmc_enable_periph_clk(
				all_uart_definitions[uart_index].peripheral_id);

		switch (freertos_driver_parameters->operation_mode) {
		case UART_RS232:
			/* Call the standard ASF init function. */
			uart_init(p_uart, uart_parameters);
			break;

		default:
			/* Other modes are not currently supported. */
			break;
		}

		/* Disable all the interrupts. */
		uart_disable_interrupt(p_uart, MASK_ALL_INTERRUPTS);

		/* Create any required peripheral access mutexes and transaction complete
		semaphores.  This peripheral is full duplex so only the Tx semaphores
		are created in the following function.  The the Rx semaphores are
		created	separately. */
		create_peripheral_control_semaphores(
				freertos_driver_parameters->options_flags,
				&(tx_dma_control[uart_index]),
				NULL /* The rx structures are not created in this function. */);

		/* Is the driver also going to receive? */
		if (freertos_driver_parameters->receive_buffer != NULL) {
			/* rx_event_semaphore is used to signal the arival of new data.  It
			must be a counting semaphore for the following reason:  If the Rx
			DMA places data at the end of its circular buffer it will give the
			semaphore to indicate the presence of unread data.  If it then
			receives more data, it will write this to the start of the circular
			buffer, then give the semaphore again.  Now, if a task reads data
			out of the same circular buffer, and requests less data than is
			available, but more than is available between the next read pointer
			and the end of the buffer, the actual amount returned will be
			capped to that available up to the end of the buffer only.  If this
			semaphore was a binary semaphore, it would then be 'taken' even
			though, unknown to the reading task, unread and therefore available
			data remained at the beginning of the buffer. */
			rx_buffer_definitions[uart_index].rx_event_semaphore =
					xSemaphoreCreateCounting(portMAX_DELAY, 0);
			configASSERT(rx_buffer_definitions[uart_index].rx_event_semaphore);

			/* The receive buffer is currently empty, so the DMA has control
			over the entire buffer. */
			rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_addr =
					(uint32_t)freertos_driver_parameters->receive_buffer;
			rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_size =
					freertos_driver_parameters->receive_buffer_size;
			pdc_rx_init(
					all_uart_definitions[uart_index].pdc_base_address,
					&(rx_buffer_definitions[uart_index].rx_pdc_parameters),
					NULL);

			/* Set the next byte to read to the start of the buffer as no data
			has yet been read. */
			rx_buffer_definitions[uart_index].next_byte_to_read =
					freertos_driver_parameters->receive_buffer;

			/* Remember the limits of entire buffer. */
			rx_buffer_definitions[uart_index].rx_buffer_start_address =
					rx_buffer_definitions[uart_index].rx_pdc_parameters.ul_addr;
			rx_buffer_definitions[uart_index].past_rx_buffer_end_address =
					rx_buffer_definitions[uart_index].rx_buffer_start_address +
					freertos_driver_parameters->receive_buffer_size;

			/* If the rx driver is to be thread aware, create an access control
			mutex. */
			if ((freertos_driver_parameters->options_flags &
					USE_RX_ACCESS_MUTEX) != 0) {
				rx_buffer_definitions[uart_index].rx_access_mutex =
					xSemaphoreCreateMutex();
				configASSERT(rx_buffer_definitions[uart_index].rx_access_mutex);
			}

			/* Catch the DMA running out of Rx space, and gaps in the
			reception.  These events are both used to signal that there is
			data available in the Rx buffer. */
			uart_enable_interrupt(p_uart, UART_IER_ENDRX | UART_IER_RXRDY);

			/* The Rx DMA is running all the time, so enable it now. */
			pdc_enable_transfer(
					all_uart_definitions[uart_index].pdc_base_address,
					PERIPH_PTCR_RXTEN);
		} else {
			/* next_byte_to_read is used to check to see if this function
			has been called before, so it must be set to something, even if
			it is not going to be used.  The value it is set to is not
			important, provided it is not zero (NULL). */
			rx_buffer_definitions[uart_index].next_byte_to_read = RX_NOT_USED;
		}

		/* Configure and enable the UART interrupt in the interrupt controller. */
		configure_interrupt_controller(all_uart_definitions[uart_index].peripheral_irq,
				freertos_driver_parameters->interrupt_priority);

		/* Error interrupts are always enabled. */
		uart_enable_interrupt(
				all_uart_definitions[uart_index].peripheral_base_address,
				IER_ERROR_INTERRUPTS);

		/* Finally, enable the receiver and transmitter. */
		uart_enable_tx(p_uart);
		uart_enable_rx(p_uart);

		return_value = (freertos_uart_if) p_uart;
	} else {
		return_value = NULL;
	}

	return return_value;
}
Ejemplo n.º 6
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte read operation on an TWI
 * peripheral.
 *
 * freertos_twi_read_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to read data from the
 * TWI port, then returns.  freertos_twi_read_packet_async() does not wait for
 * the reception to complete before returning.
 *
 * The FreeRTOS ASF TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_read_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_RX_COMPLETE bit clear. The function can also only be used
 * if the length of the packet is more that two. If less, it will block until the
 * transfer is done.
 *
 * freertos_twi_read_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_read_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI port returned by the
 *     freertos_twi_master_init() call used to initialise the port.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the destination for the data being read,
 *     and the number of bytes to read.  twi_packet_t is a standard ASF type (it
 *     is not FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the receive
 *     function exits the receive function as soon as the reception starts.
 *     The data being received by the PDC cannot normally be processed until
 *     after the reception has completed.  The PDC interrupt (handled internally
 *     by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has read the requested number of
 *     bytes.  The calling task can call standard FreeRTOS functions to block on
 *     the semaphore until the PDC interrupt occurs.  Other RTOS tasks will
 *     execute while the the calling task is in the Blocked state.  The
 *     semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API
 *     function before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI read operation.
 */
status_code_t freertos_twi_read_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		/* Because the peripheral is half duplex, there is only one access mutex
		and the rx uses the tx mutex. */
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Ensure Rx is already empty. */
			twi_read_byte(twi_base);

			/* Set read mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(
					p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length) {
				internal_address = p_packet->addr [0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length <= 2) {
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);

				/* Cannot use PDC transfer, use normal transfer */
				uint8_t stop_sent = 0;
				uint32_t cnt = p_packet->length;
				uint32_t status;
				uint8_t *buffer = p_packet->buffer;
				uint32_t timeout_counter = 0;

				/* Start the transfer. */
				if (cnt == 1) {
					twi_base->TWI_CR = TWI_CR_START | TWI_CR_STOP;
					stop_sent = 1;
				} else {
					twi_base->TWI_CR = TWI_CR_START;
				}

				while (cnt > 0) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					/* Last byte ? */
					if (cnt == 1 && !stop_sent) {
						twi_base->TWI_CR = TWI_CR_STOP;
						stop_sent = 1;
					}
					if (!(status & TWI_SR_RXRDY)) {
						if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
							return_value = ERR_TIMEOUT;
							break;
						}
						continue;
					}
					*buffer++ = twi_base->TWI_RHR;
					cnt--;
					timeout_counter = 0;
				}

				timeout_counter = 0;
				/* Wait for stop to be sent */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (rx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(rx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}
			} else {
				/* Start the PDC reception. */
				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;
				freertos_start_pdc_rx(&(rx_dma_control[twi_index]),
						p_packet->buffer, (p_packet->length)-2,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Start the transfer. */
				twi_base->TWI_CR = TWI_CR_START;

				/* Catch the end of reception so the access mutex can be returned,
				and the task notified (if it supplied a notification semaphore).
				The interrupt can be enabled here because the ENDRX	signal from the
				PDC to the peripheral will have been de-asserted when the next
				transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDRX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(rx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 7
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte write operation on a TWI
 * peripheral.
 *
 * freertos_twi_write_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to transmit data on the
 * TWI port, then returns.  freertos_twi_write_packet_async() does not wait for
 * the transmission to complete before returning.
 *
 * The FreeRTOS TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_write_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_TX_COMPLETE bit clear. It can also only be used if packet
 * length is more than 1.
 *
 * freertos_twi_write_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_write_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI peripheral returned by the
 *     freertos_twi_master_init() call used to initialise the peripheral.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the source data location, and the number
 *     of bytes to transmit.  twi_packet_t is a standard ASF type (it is not
 *     FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit
 *     set, then the driver will only write to the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the write operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the transmit
 *     function exits the transmit function as soon as the transmission starts.
 *     The data being transmitted by the PDC must not be modified until after
 *     the transmission has completed.  The PDC interrupt (handled internally by
 *     the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has finished accessing the data.
 *     The calling task can call standard FreeRTOS functions to block on the
 *     semaphore until the PDC interrupt occurs.  Other RTOS tasks will execute
 *     while the the calling task is in the Blocked state.  The semaphore must
 *     be created using the FreeRTOS vSemaphoreCreateBinary() API function
 *     before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI write operation.
 */
status_code_t freertos_twi_write_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Set write mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length > 0) {
				internal_address = p_packet->addr[0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length == 1) {
				uint32_t status;
				uint32_t timeout_counter = 0;
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Send start condition */
				twi_base->TWI_THR = *((uint8_t*)(p_packet->buffer));
				while (1) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					if (status & TWI_SR_TXRDY) {
						break;
					}
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				twi_base->TWI_CR = TWI_CR_STOP;
				/* Wait for TX complete */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}

				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (tx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(tx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}

			} else {

				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;

				freertos_start_pdc_tx(&(tx_dma_control[twi_index]),
						p_packet->buffer, p_packet->length - 1,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Catch the end of transmission so the access mutex can be
				returned, and the task notified (if it supplied a notification
				semaphore).  The interrupt can be enabled here because the ENDTX
				signal from the PDC to the peripheral will have been de-asserted when
				the next transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDTX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(tx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
Ejemplo n.º 8
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initializes the FreeRTOS ASF TWI (I2C) master driver for the specified
 * TWI port.
 *
 * freertos_twi_master_init() is an ASF specific FreeRTOS driver function.  It
 * must be called before any other ASF specific FreeRTOS driver functions
 * attempt to access the same TWI port.
 *
 * If freertos_driver_parameters->operation_mode equals TWI_I2C_MASTER then
 * freertos_twi_master_init() will configure the TWI port for master mode
 * operation and enable the peripheral.  If
 * freertos_driver_parameters->operation_mode equals any other value then
 * freertos_twi_master_init() will not take any action.
 *
 * Other ASF TWI functions can be called after freertos_twi_master_init() has
 * completed successfully.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * This driver is provided with an application note, and an example project that
 * demonstrates the use of this function.
 *
 * \param p_twi    The twi peripheral being initialized.
 * \param freertos_driver_parameters    Defines the driver behavior.  See the
 *    freertos_peripheral_options_t documentation, and the application note that
 *    accompanies the ASF specific FreeRTOS functions.
 *
 * \return If the initialization completes successfully then a handle that can
 *     be used with FreeRTOS TWI read and write functions is returned.  If
 *     the initialisation fails then NULL is returned.
 */
freertos_twi_if freertos_twi_master_init(Twi *p_twi,
		const freertos_peripheral_options_t *const freertos_driver_parameters)
{
	portBASE_TYPE twi_index;
	bool is_valid_operating_mode;
	freertos_twi_if return_value;
	const enum peripheral_operation_mode valid_operating_modes[] = {TWI_I2C_MASTER};

	/* Find the index into the all_twi_definitions array that holds details of
	the p_twi peripheral. */
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) p_twi);

	/* Check the requested operating mode is valid for the peripheral. */
	is_valid_operating_mode = check_requested_operating_mode(
			freertos_driver_parameters->operation_mode,
			valid_operating_modes,
			sizeof(valid_operating_modes) /
			sizeof(enum peripheral_operation_mode));

	/* Don't do anything unless a valid p_twi pointer was used, and a valid
	operating mode was requested. */
	if ((twi_index < MAX_TWIS) && (is_valid_operating_mode == true)) {
		/* This function must be called exactly once per supported twi.  Check
		it has not been called	before. */
		configASSERT(memcmp((void *)&(tx_dma_control[twi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);
		configASSERT(memcmp((void *)&(rx_dma_control[twi_index]),
				&null_dma_control,
				sizeof(null_dma_control)) == 0);

		/* Enable the peripheral's clock. */
#if (SAMG55)
		/* Enable the peripheral and set TWI mode. */
		uint32_t temp = (uint32_t)(all_twi_definitions[twi_index].peripheral_base_address - 0x600);
		Flexcom *p_flexcom = (Flexcom *)temp;
		flexcom_enable(p_flexcom);
		flexcom_set_opmode(p_flexcom, FLEXCOM_TWI);
#else
		pmc_enable_periph_clk(
				all_twi_definitions[twi_index].peripheral_id);
#endif
		/* Ensure everything is disabled before configuration. */
		pdc_disable_transfer(
				all_twi_definitions[twi_index].pdc_base_address,
				(PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS));
		twi_disable_interrupt(
				all_twi_definitions[twi_index].peripheral_base_address,
				MASK_ALL_INTERRUPTS);
		twi_reset(
				all_twi_definitions[twi_index].peripheral_base_address);

		switch (freertos_driver_parameters->operation_mode) {
		case TWI_I2C_MASTER:
			/* Call the standard ASF init function. */
			twi_enable_master_mode(
					all_twi_definitions[twi_index].peripheral_base_address);
			break;

		default:
			/* No other modes are currently supported. */
			break;
		}

		/* Create any required peripheral access mutexes and transaction complete
		semaphores.  This peripheral is half duplex so only a single access
		mutex is required. */
		create_peripheral_control_semaphores(
				freertos_driver_parameters->options_flags,
				&(tx_dma_control[twi_index]),
				&(rx_dma_control[twi_index]));

		/* Error interrupts are always enabled. */
		twi_enable_interrupt(
				all_twi_definitions[twi_index].peripheral_base_address,
				IER_ERROR_INTERRUPTS);

		/* Configure and enable the TWI interrupt in the interrupt controller. */
		configure_interrupt_controller(
				all_twi_definitions[twi_index].peripheral_irq,
				freertos_driver_parameters->interrupt_priority);

		return_value = (freertos_twi_if) p_twi;
	} else {
		return_value = NULL;
	}

	return return_value;
}