/**
 * \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_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;
}