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