Files
base/drivers/source/uart/sdrv_uart.c
2025-11-07 09:57:14 +08:00

3163 lines
110 KiB
C

/**
* @file sdrv_uart.c
* @brief sdrv uart driver source.
*
* @copyright Copyright (c) 2020 Semidrive Semiconductor.
* All rights reserved.
*/
#include <debug.h>
#include <string.h>
#include <types.h>
#include "sdrv_uart.h"
#if CONFIG_UART_ENABLE_DMA
#include "armv7-r/cache.h"
#endif
#include "common.h"
#include "irq.h"
/**************************Static Functions Start******************************/
/**
* brief Srdv UART Initialization.
*
* This function brief initializes sdrv uart module with user-defined settings
*
* param [in] cfg sdrv uart config
* return The result of initializing uart module
*/
static sdrv_uart_error_status_e sdrv_uart_init(const sdrv_uart_config_t *cfg);
/**
* brief Srdv UART set flow control mode.
*
* param [in] base sdrv uart register base
* param [in] fcm_cfg The configurations of fcm
*/
static void sdrv_uart_set_fcm(sdrv_uart_regs_t *base,
sdrv_uart_fcm_config_t *fcm_cfg);
/**
* brief Srdv UART initializes interrupt register.
*
* This function initializes sdrv uart module interrupt to disable.
*
* param [in] base sdrv uart register base
*/
static void sdrv_uart_intr_init(sdrv_uart_regs_t *base);
/**
* brief Srdv UART initializes interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] base sdrv uart register base
*/
static void sdrv_uart_intr_status_init(sdrv_uart_regs_t *base);
/**
* brief Srdv UART initializes rx interrupt status register.
*
* This function initializes sdrv uart module rx interrupt.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_rx_intr_ctrl(sdrv_uart_t *ctrl, bool enable);
/**
* brief Srdv UART initializes tx interrupt status register.
*
* This function initializes sdrv uart module tx interrupt.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_tx_intr_ctrl(sdrv_uart_t *ctrl, bool enable);
/**
* brief Srdv UART initializes rx interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_rx_intrstatus_clear(sdrv_uart_t *ctrl);
/**
* brief Srdv UART initializes tx interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] ctrl sdrv uart controller
*/
static void sdrv_uart_tx_intrstatus_clear(sdrv_uart_t *ctrl);
/**
* brief Disable uart module.
*
* param [in] base sdrv uart register base
*/
static inline void sdrv_uart_disable(sdrv_uart_regs_t *base);
/**
* brief Sdrv uart baudrate round-off.
*
* param [in] dividend The clock frequency.
* param [in] divisor The value of baud.
* return The result of the baudrate after rounded off.
*/
static uint32_t sdrv_uart_baudrate_roundoff(uint32_t dividend,
uint32_t divisor);
/**
* brief Sdrv uart get char from rx fifo.
*
* param [in] base Sdrv uart register base
* param [in] c The character to be received
* param [in] timeout The max times of query fifo empty register
* return The result of getting a character from rx fifo
*/
static inline bool sdrv_uart_getc(sdrv_uart_regs_t *base, uint8_t *c,
uint32_t timeout);
/**
* brief Sdrv uart put char in tx fifo.
*
* param [in] base sdrv uart register base
* param [in] c The character to be transmitted
* param [in] timeout The max times of query fifo full register
* return The result of writting a character from tx fifo
*/
static inline bool sdrv_uart_putc(sdrv_uart_regs_t *base, uint8_t c,
uint32_t timeout);
/**
* brief Sdrv uart async read data from fifo
*
* param [in] base Sdrv uart register base
* param [in] data Data buff
* param [in] size The size of data expected
* return The count of received characters
*/
static inline uint32_t sdrv_uart_read_async(sdrv_uart_regs_t *base,
uint8_t *data, uint32_t size);
/**
* brief Sdrv uart async write data to fifo
*
* param [in] base Sdrv uart register base
* param [in] data Data buff
* param [in] size The size of data expected
* return The count of transmitted characters
*/
static inline uint32_t sdrv_uart_send_async(sdrv_uart_regs_t *base,
const uint8_t *data, uint32_t size);
/**
* brief Sdrv uart get the length of data in rx fifo.
*
* param [in] base sdrv uart register base
* return The length of data in rx fifo
*/
static inline uint32_t sdrv_uart_get_rxfifolen(sdrv_uart_regs_t *base);
/**
* brief Sdrv uart module reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart module.
*/
static bool sdrv_uart_module_reset(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Sdrv uart clear tx fifo.
*
* param[in] base The address of uart's register.
*
* return The result of clearing tx fifo.
*/
static bool sdrv_uart_txfifo_clear(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Sdrv uart clear rx fifo.
*
* param[in] base The address of uart's register.
*
* return The result of clearing rx fifo.
*/
static bool sdrv_uart_rxfifo_clear(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Sdrv uart rx dma reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart dma rx.
*/
static bool sdrv_uart_rxdma_reset(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Sdrv uart tx dma reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart dma tx.
*/
static bool sdrv_uart_txdma_reset(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Waitting until sdrv uart tx io state changing to idle.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_txio_idle(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Waitting until sdrv uart rx io state changing to idle.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_rxio_idle(sdrv_uart_regs_t *base, uint32_t timeout);
/**
* brief Waitting until auto baudrate detect completed or timeout.
*
* param[in] ctrl The uart controller entity.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_abr_ready(sdrv_uart_t *ctrl, uint32_t timeout);
/**
* brief Handle error interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_err_irq_handler(sdrv_uart_t *ctrl);
/**
* brief Handle receive interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_rx_irq_handler(sdrv_uart_t *ctrl);
/**
* brief Handle transmit interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_tx_irq_handler(sdrv_uart_t *ctrl);
/**
* brief Handle auto baudrate detect interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_abr_irq_handler(sdrv_uart_t *ctrl);
#if CONFIG_UART_ENABLE_DMA
/**
* brief Handle rx idle interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_rx_idle_irq_handler(sdrv_uart_t *ctrl);
/**
* brief Control uart rx dma interface.
*
* param[in] ctrl The uart controller entity.
* param[in] enable Enable or disable uart rx dma.
* param[in] timeout Timeout value.
*/
static bool sdrv_uart_dma_rx_ctrl(sdrv_uart_t *ctrl, bool enable,
uint32_t timeout);
/**
* brief Control uart tx dma interface.
*
* param[in] ctrl The uart controller entity.
* param[in] enable Enable or disable uart tx dma.
* param[in] timeout Timeout value.
*/
static bool sdrv_uart_dma_tx_ctrl(sdrv_uart_t *ctrl, bool enable,
uint32_t timeout);
/**
* brief UART receive data with dma single mode.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [in] dma_ctrl sdrv dma controller entity
* param [out] xfer_config the configuration of the dma channel
* param [in] channel_id the number of dma channel
* param [in] xfer_type the type of the dma transfer
* param [in] xfer_mode the mode of the dma transfer
* param [in] burst_len the port burst length
* param [in] data receive data buffer
* param [in] size the size of receive data
*/
static void sdrv_uart_dma_config_creat(sdrv_uart_t *ctrl, sdrv_dma_t *dma_ctrl,
sdrv_dma_channel_config_t *xfer_config,
sdrv_dma_channel_id_e channel_id,
sdrv_dma_xfer_type_e xfer_type,
sdrv_dma_xfer_mode_e xfer_mode,
uint32_t burst_len, uint8_t *data,
uint32_t size);
/**
* brief Handle uart rx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_rx_realtime_handler(uint32_t status, uint32_t param,
void *context);
/**
* brief UART receive data with dma single mode.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [out] data receive data
* param [in] size the size of receive data
* param [in] rx_cb the callback function of receive
* param [in] rx_userparam the param of callback function
* param [in] dma_ctrl sdrv dma controller entity
* param [in] dma_channel sdrv dma channel controller entity
* param [in] channel_id The number of dma channel
* return The result of uart dma receive function
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart rx dma interface timeout.
* Status_Success : Starting the uart to receive with dma success.
*/
static sdrv_uart_error_status_e sdrv_uart_dma_receive_single(
sdrv_uart_t *ctrl, uint8_t *data, uint32_t size, uart_callback_t rx_cb,
void *rx_userparam, sdrv_dma_t *dma_ctrl, sdrv_dma_channel_t *dma_channel,
sdrv_dma_channel_id_e channel_id);
/**
* brief UART transmit data with dma single mode.
*
* This function transmit data with dma module.
* User should initializes dma module before use this function.
* User's data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [out] data transmit data
* param [in] size the size of transmit data
* param [in] tx_cb the callback function of transmit
* param [in] tx_userparam the param of callback function
* param [in] dma_ctrl sdrv dma controller entity
* param [in] dma_channel sdrv dma channel controller entity
* param [in] channel_id The number of dma channel
* return The result of uart dma transmit function
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart tx dma interface timeout.
* Status_Success : Starting the uart to transmit with dma success.
*/
static sdrv_uart_error_status_e sdrv_uart_dma_transmit_single(
sdrv_uart_t *ctrl, const uint8_t *data, uint32_t size,
uart_callback_t tx_cb, void *tx_userparam, sdrv_dma_t *dma_ctrl,
sdrv_dma_channel_t *dma_channel, sdrv_dma_channel_id_e channel_id);
/**
* brief Handle uart rx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_rx_handler(uint32_t status, uint32_t param,
void *context);
/**
* brief Handle uart tx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_tx_handler(uint32_t status, uint32_t param,
void *context);
#endif
/**************************Static Functions End******************************/
/**
* @brief Sdrv UART controller initialization.
*
* This function initializes:
* 1) The uart module;
* 2) The uart controller entity.
*
* This function attach irq handler and transfer callback function.
*
* @param [in] ctrl sdrv uart controller.
* @param [in] cfg sdrv uart configurations.
* @param [in] callback sdrv uart transfer callback function.
* @param [in] userData sdrv uart transfer callback function param.
* @return The result of initilalizing uart.
*/
sdrv_uart_error_status_e
sdrv_uart_controller_init(sdrv_uart_t *ctrl, const sdrv_uart_config_t *cfg,
uart_callback_t callback, void *userData)
{
ASSERT(cfg != NULL);
ASSERT(ctrl != NULL);
ASSERT((cfg->baud > 0U) || (1U == cfg->abr_en));
ASSERT(cfg->clk_freq > 0U);
ASSERT(cfg->base > 0U);
/* Initializes uart module. */
sdrv_uart_error_status_e ret = sdrv_uart_init(cfg);
if (Status_Success != ret) {
return ret;
}
/* Initializes the controller. */
(void)memset(ctrl, 0, sizeof(sdrv_uart_t));
ctrl->base = cfg->base;
ctrl->irq = cfg->irq;
ctrl->clk_freq = cfg->clk_freq;
#if CONFIG_UART_ENABLE_DMA
ctrl->rx_idle = cfg->rx_idle;
#endif
/* Set abr and tx/rx status */
ctrl->tx_state = Transfer_TxIdle;
ctrl->rx_state = Transfer_RxIdle;
/* Set auto baudrate state as Transfer_RxAbrBusy if uart need detect
* baudrate. */
if (cfg->abr_en) {
ctrl->abr_count = 0U;
ctrl->abr_state = Transfer_RxAbrBusy;
} else {
ctrl->baud = cfg->baud;
ctrl->abr_state = Transfer_RxAbrReady;
}
/* Set transfer callback function and user param */
ctrl->callback = callback;
ctrl->userData = userData;
/* Enable uart irq and attach handler */
if (ctrl->irq > 0U) {
ssdk_printf(SSDK_NOTICE, "uart3 irq\r\n");
irq_attach(ctrl->irq, sdrv_uart_irq_handler, ctrl);
irq_enable(ctrl->irq);
}
return ret;
}
/**
* @brief Srdv UART Deinitializes.
*
* This function deinitializes:
* 1) The uart controller entity
* 2) The uart module;
*
* This function dettach irq handler and transfer callback function.
*
* @param [in] ctrl sdrv uart ctrl
* @return The result of deinitilalizing uart.
*/
sdrv_uart_error_status_e sdrv_uart_deinit(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Make sure pre operation was complete */
sdrv_uart_wait_txio_idle(uart_base, SDRV_UART_OPERATION_TIMEOUT);
sdrv_uart_wait_rxio_idle(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable uart module */
sdrv_uart_disable(uart_base);
/* Disable uart irq and dettach handler */
if (ctrl->irq > 0U) {
irq_disable(ctrl->irq);
irq_detach(ctrl->irq);
}
/* Deinitializes the controller. */
(void)memset(ctrl, 0, sizeof(sdrv_uart_t));
return Status_Success;
}
/**
* @brief Configure uart baud rate.
*
*This function configures the uart module baud rate.
*This function is used to update the uart module baud rate.
*after the uart module is initialized by the sdrv_uart_controller_init.
*
* @param [in] ctrl sdrv uart controller
* @param [in] baud baud
* @return The result of setting baudrate.
*/
sdrv_uart_error_status_e sdrv_uart_set_baudrate(sdrv_uart_t *ctrl,
uint32_t baud)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
if (0U == baud) {
return Status_Invalid_Param;
}
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Disable auto baudrate detect. */
uart_base->PCR0.ABREN = 0U;
uart_base->INTEN0.ABRPASS = 0U;
uart_base->INTEN0.ABRFAIL = 0U;
/* Set baud in controller and configurate baudrate in register. */
ctrl->baud = baud;
ctrl->abr_state = Transfer_RxAbrReady;
uart_base->PCR1.BAUDRATE =
sdrv_uart_baudrate_roundoff(ctrl->clk_freq, baud);
return Status_Success;
}
/**
* @brief Start auto baudrate detect.
*
*This function start auto baudrate detect.
*
* @param [in] ctrl sdrv uart controller
* @param [in] num The character number that abr expect to recv and match
* @return The result of starting abr.
*/
sdrv_uart_error_status_e sdrv_uart_abr_start(sdrv_uart_t *ctrl,
sdrv_abr_max_e num)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)ctrl->base;
ctrl->abr_count = 0U;
ctrl->abr_state = Transfer_RxAbrBusy;
if (!sdrv_uart_module_reset(uart_base, SDRV_UART_OPERATION_TIMEOUT)) {
return Status_Timeout;
}
uart_base->PCR0.ABRCTL0 = UART_ABR_PATTERN;
uart_base->PCR0.ABRCTL1 = num;
uart_base->INTEN0.ABRPASS = 1U;
uart_base->INTEN0.ABRFAIL = 1U;
uart_base->PCR0.ABREN = 1U;
return Status_Success;
}
/**
* @brief Get the data in rx fifo.
*
* This function is used to get data in rx fifo.
* If user use sdrv_uart_start_realtime_receive function, this function is
* used in user's callback function to get rx fifo data.
* Users could call sdrv_uart_get_rxfifodata() to clear fifo.
*
* @param [in] ctrl sdrv uart controller
* @param [in] data the first address of user data buffer
* @param [in] maxlen the max length of user's data buffer
* @return the count of received byte
*/
uint32_t sdrv_uart_get_rxfifodata(sdrv_uart_t *ctrl, uint8_t *data,
uint32_t maxlen)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)ctrl->base;
/* Get the length of data in RX FIFO. */
uint32_t size = sdrv_uart_get_rxfifolen(uart_base);
/* Read data from RX FIFO.*/
size = (size <= maxlen) ? size : maxlen;
for (uint32_t i = 0U; i < size; ++i) {
sdrv_uart_getc(uart_base, &data[i], SDRV_UART_OPERATION_TIMEOUT);
}
return size;
}
/**
* @brief Synchronous UART receive.
*
* This function receive RX data with a blocking method.
* This function will wait until data received successfully when times set
* as WaitForever.
*
* @param [in] ctrl sdrv uart controller
* @param [out] data receive data
* @param [in] size the size of receive data
* @param [in] received_bytes the size of data has been received
* @param [in] times the max times of query fifo empty register
* @return the result of transfer.
*/
sdrv_uart_error_status_e sdrv_uart_sync_receive(sdrv_uart_t *ctrl,
uint8_t *data, uint32_t size,
uint32_t *received_bytes,
uint32_t times)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_uart_error_status_e ret = Status_Success;
uint32_t index = 0U;
if (Transfer_RxIdle != ctrl->rx_state) {
return Status_Busy;
} else {
ctrl->rx_state = Transfer_RxBusy;
ctrl->rxtransfer_type = SDRV_TRANSFER_SYNC_MODE;
if (NULL != received_bytes)
*received_bytes = 0U;
/* Read data from RX FIFO. */
for (index = 0U; index < size; index++) {
/* Wait for receiving data until timeout. */
if ((!sdrv_uart_wait_abr_ready(ctrl, times)) ||
(!sdrv_uart_getc(uart_base, &data[index], times))) {
if (Transfer_RxAbrReady != ctrl->abr_state) {
ret = Status_Abr_Not_Ready;
break;
} else {
ret = Status_Timeout;
break;
}
}
if (NULL != received_bytes)
++(*received_bytes);
/* Transmission occurs error. */
if (SDRV_UART_INTR_RX_ERROR & sdrv_uart_intr_status_get(ctrl)) {
/* Check error type. */
if (SDRV_UART_INTR_RX_FOVF & sdrv_uart_intr_status_get(ctrl)) {
if ((index + 1U) != size) {
ret = Status_Rxfovf;
break;
}
}
if (SDRV_UART_INTR_PARITYERR &
sdrv_uart_intr_status_get(ctrl)) {
ret = Status_Parity_Err;
break;
}
#if (CONFIG_E3 || CONFIG_D3)
if (SDRV_UART_INTR_BAUDRATEERR &
sdrv_uart_intr_status_get(ctrl)) {
ret = Status_Baudrate_Err;
break;
}
#endif
#if CONFIG_E3L
if (IS_P0) {
if (SDRV_UART_INTR_BAUDRATEERR &
sdrv_uart_intr_status_get(ctrl)) {
ret = Status_Baudrate_Err;
break;
}
}
#endif
if (SDRV_UART_INTR_NOISERERR &
sdrv_uart_intr_status_get(ctrl)) {
ret = Status_Noise_Err;
break;
}
if (SDRV_UART_INTR_FRAMEERR & sdrv_uart_intr_status_get(ctrl)) {
ret = Status_Frame_Err;
break;
}
}
}
if (Status_Success != ret) {
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
}
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->rx_state = Transfer_RxIdle;
}
return ret;
}
/**
* @brief Get empty status of tx fifo.
*
* This function is used to get empty status of tx fifo.
*
* @param [in] ctrl sdrv uart controller
* @return the empty status of tx fifo
*/
bool sdrv_uart_txfifo_empty(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)ctrl->base;
return uart_base->FSR0.EMPTY > 0U;
}
/**
* @brief Synchronous UART transmit.
*
* This function transmit TX data with a blocking method.
*
* @param [in] ctrl sdrv uart controller
* @param [in] data transmit data
* @param [in] size the size of transmit data
* @param [in] transmitted_bytes the size of data has been tansmitted
* @param [in] times the max times of query fifo full register
* @return the result of transfer
*/
sdrv_uart_error_status_e
sdrv_uart_sync_transmit(sdrv_uart_t *ctrl, const uint8_t *data, uint32_t size,
uint32_t *transmitted_bytes, uint32_t times)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
if (Transfer_TxIdle != ctrl->tx_state) {
return Status_Busy;
} else {
ctrl->tx_state = Transfer_TxBusy;
ctrl->txtransfer_type = SDRV_TRANSFER_SYNC_MODE;
if (NULL != transmitted_bytes)
*transmitted_bytes = 0U;
/* Wait for transmitting data untill timeout. */
for (uint32_t index = 0U; index < size; index++) {
if (!sdrv_uart_putc(uart_base, data[index], times)) {
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->tx_state = Transfer_TxIdle;
return Status_Timeout;
}
if (NULL != transmitted_bytes)
++(*transmitted_bytes);
}
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->tx_state = Transfer_TxIdle;
}
return Status_Success;
}
/**
* @brief Start UART realtime receive.
*
* This function start the feature of continuous receive RX data with a
* interrupt method.
*
* @param [in] ctrl sdrv uart controller
* @return the result of starting recv
*/
sdrv_uart_error_status_e sdrv_uart_start_realtime_receive(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
if (Transfer_RxIdle != ctrl->rx_state) {
return Status_Busy;
} else {
/* Update rx status and type. */
ctrl->rx_state = Transfer_RxBusy;
ctrl->rxtransfer_type = SDRV_TRANSFER_REALTIME_MODE;
/* Clear RX Fifo */
if ((!sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT))) {
/* Update rx status and type. */
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_Timeout;
}
/* Enable rx related interrupt and clear interrupt status. */
sdrv_uart_rx_intrstatus_clear(ctrl);
sdrv_uart_rx_intr_ctrl(ctrl, true);
}
return Status_Success;
}
/**
* @brief Stop UART realtime receive.
*
* This function stop the feature of continuous receive RX data with a
* interrupt method.
*
* @param [in] ctrl sdrv uart controller
* @return The result of stopping realtime receive.
*/
sdrv_uart_error_status_e sdrv_uart_stop_realtime_receive(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Clear RX Fifo */
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable rx related interrupt. */
sdrv_uart_rx_intr_ctrl(ctrl, false);
sdrv_uart_rx_intrstatus_clear(ctrl);
/* Update rx status and type. */
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->rx_state = Transfer_RxIdle;
return Status_Success;
}
/**
* @brief Asynchronous UART receive.
*
* This function receive RX data with an interrupt method.
*
* @param [in] ctrl sdrv uart controller
* @param [out] data receive data
* @param [in] size the size of receive data
* @param [in] rx_cb the callback function of receive
* @param [in] rx_userparam the param of callback function
* @return the result of uart async receive function
*/
sdrv_uart_error_status_e sdrv_uart_async_receive(sdrv_uart_t *ctrl,
uint8_t *data, uint32_t size,
uart_callback_t rx_cb,
void *rx_userparam)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
if (Transfer_RxIdle != ctrl->rx_state) {
return Status_Busy;
} else {
/* Update rx status and type. */
ctrl->rx_state = Transfer_RxBusy;
ctrl->rxtransfer_type = SDRV_TRANSFER_ASYNC_MODE;
/* Update rx frame information. */
ctrl->rx_ptr = data;
ctrl->rx_remain = size;
/* Update rx callback function. */
ctrl->rx_async_cb = rx_cb;
ctrl->rx_userparam = rx_userparam;
/* Enable rx related interrupt and clear interrupt status. */
sdrv_uart_rx_intr_ctrl(ctrl, true);
}
return Status_Success;
}
/**
* @brief Asynchronous UART receive abort.
*
* This function abort the transfer of receive RX data with an interrupt
* method.
*
* @param [in] ctrl sdrv uart controller
*/
sdrv_uart_error_status_e sdrv_uart_async_receive_abort(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Clear RX Fifo */
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable rx related interrupt. */
sdrv_uart_rx_intr_ctrl(ctrl, false);
sdrv_uart_rx_intrstatus_clear(ctrl);
/* Update rx status and type. */
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->rx_state = Transfer_RxIdle;
return Status_Success;
}
/**
* @brief Asynchronous UART transmit.
*
* This function transmit TX data with an interrupt method.
*
* @param [in] ctrl sdrv uart controller
* @param [in] data transmit data
* @param [in] size the size of transmit data
* @param [in] tx_cb the callback function of transmit
* @param [in] tx_userparam the param of callback function
* @return the result of uart async transmit function
*/
sdrv_uart_error_status_e
sdrv_uart_async_transmit(sdrv_uart_t *ctrl, const uint8_t *data, uint32_t size,
uart_callback_t tx_cb, void *tx_userparam)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
if (Transfer_TxIdle != ctrl->tx_state) {
return Status_Busy;
} else {
/* Update tx status and type. */
ctrl->tx_state = Transfer_TxBusy;
ctrl->txtransfer_type = SDRV_TRANSFER_ASYNC_MODE;
/* Update tx frame information. */
ctrl->tx_ptr = data;
ctrl->tx_remain = size;
/* Update tx callback function. */
ctrl->tx_async_cb = tx_cb;
ctrl->tx_userparam = tx_userparam;
/* Get transmitted bytes. */
uint32_t transmitted = sdrv_uart_send_async(uart_base, data, size);
if (transmitted > 0U) {
ctrl->tx_ptr += transmitted;
ctrl->tx_remain -= transmitted;
}
/* Enable tx related interrupt and clear interrupt status. */
sdrv_uart_tx_intr_ctrl(ctrl, true);
}
return Status_Success;
}
/**
* @brief Asynchronous UART transmit abort.
*
* This function abort the transfer of transmit TX data with an interrupt
* method.
*
* @param [in] ctrl sdrv uart controller
* @return The result of aborting transmit.
*/
sdrv_uart_error_status_e sdrv_uart_async_transmit_abort(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Clear tx fifo */
sdrv_uart_txfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable tx related interrupt. */
sdrv_uart_tx_intr_ctrl(ctrl, false);
sdrv_uart_tx_intrstatus_clear(ctrl);
/* Update tx status and type. */
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->tx_state = Transfer_TxIdle;
return Status_Success;
}
#if CONFIG_UART_ENABLE_DMA
/**
* @brief UART receive data with dma.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
* This function can receive the fixed length data.
*
* @param [in] ctrl sdrv uart controller
* @param [out] data receive data
* @param [in] size the size of receive data
* @param [in] rx_cb the callback function of receive
* @param [in] rx_userparam the param of callback function
* @param [in] dma_ctrl sdrv dma controller entity
* @param [in] dma_channel sdrv dma channel controller entity
* @param [in] channel_id The number of dma channel
* @return The result of uart dma receive function
* Status_Busy : The uart receiver is busy.
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart rx dma interface timeout.
* Status_Success : Starting the uart to receive with dma success.
*/
sdrv_uart_error_status_e
sdrv_uart_dma_receive(sdrv_uart_t *ctrl, uint8_t *data, uint32_t size,
uart_callback_t rx_cb, void *rx_userparam,
sdrv_dma_t *dma_ctrl, sdrv_dma_channel_t *dma_channel,
sdrv_dma_channel_id_e channel_id)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
ASSERT(dma_ctrl != NULL);
ASSERT(dma_channel != NULL);
ASSERT(0 == (((uint32_t)data)) % CONFIG_ARCH_CACHE_LINE);
if (size > NUM_LINKLIST_ITEMS * DMA_BURST16_MAD_SIZE_MAX) {
return Status_Invalid_Param;
}
uint8_t *data_ptr = data;
uint32_t data_size = size;
uint32_t index = 0;
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_dma_channel_config_t xfer_config;
if (Transfer_RxIdle != ctrl->rx_state) {
return Status_Busy;
} else {
ctrl->rx_state = Transfer_RxBusy;
ctrl->rxtransfer_type = SDRV_TRANSFER_DMA_ASYNC_MODE;
memset(&ctrl->rx_dma_linklist[0U], 0, sizeof(ctrl->rx_dma_linklist));
if (size >= CONFIG_ARCH_CACHE_LINE) {
/* Get the configuration of the dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_DEV2MEM,
SDRV_DMA_TRANSFER_MODE_LINKLIST, 16U, data, size);
/* Initialize receive linklist. */
while ((data_size / DMA_BURST16_MAD_SIZE_MAX) > 0U) {
/* Decrease size. */
data_size -= DMA_BURST16_MAD_SIZE_MAX;
/* set destination address */
xfer_config.dst_addr = (paddr_t)data_ptr;
/* Increase data pointer. */
data_ptr += DMA_BURST16_MAD_SIZE_MAX;
/* Set the next mad's linklist address. */
xfer_config.linklist_addr =
(paddr_t)&ctrl
->rx_dma_linklist[(index + 1) % NUM_LINKLIST_ITEMS];
/* Set transfer bytes */
xfer_config.xfer_bytes = DMA_BURST16_MAD_SIZE_MAX;
/* Set the mad's type. */
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_NORMAL_MAD;
if (0U == index) {
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_FIRST_MAD;
}
if (0U == data_size) {
xfer_config.linklist_addr = 0U;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
}
/* Initialize the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->rx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config);
/* Initialize dma channel. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
++index;
}
if (data_size > 0U) {
/* set destination address */
xfer_config.dst_addr = (paddr_t)data_ptr;
xfer_config.linklist_addr = 0U;
/* Set transfer bytes, should aligned with
* CONFIG_ARCH_CACHE_LINE.
*/
xfer_config.xfer_bytes =
data_size - (data_size % CONFIG_ARCH_CACHE_LINE);
/* Decrease size. */
data_size -= xfer_config.xfer_bytes;
/* Increase data pointer. */
data_ptr += xfer_config.xfer_bytes;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
/* Initialize the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->rx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config); /* init linklst */
/* Initialize dma channel. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
}
/* Must invalidate rx linklist and dst_data cache */
arch_clean_cache_range((uint32_t)&ctrl->rx_dma_linklist[0U],
sizeof(ctrl->rx_dma_linklist));
arch_invalidate_cache_range((addr_t)data, size);
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 15U;
ctrl->rx_ptr = data_ptr;
ctrl->rx_remain = data_size;
ctrl->rx_async_cb = rx_cb;
} else {
/* Get configuration of the rx dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_DEV2MEM,
SDRV_DMA_TRANSFER_MODE_SINGLE, 1U, data, size);
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
/* Must invalidate dst_data cache */
arch_invalidate_cache_range((addr_t)data, size);
/* Increase data buffer pointer. */
data += size;
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 0U;
ctrl->rx_ptr = data;
ctrl->rx_remain = 0U;
ctrl->rx_async_cb = rx_cb;
}
/* Set interrupt callback */
dma_channel->irq_callback = sdrv_uart_dma_rx_handler;
dma_channel->irq_context = (void *)ctrl;
/* Update uart tranfer params. */
ctrl->dma_instance = dma_ctrl;
ctrl->rx_dmachannel = dma_channel;
ctrl->rx_userparam = rx_userparam;
ctrl->bytes_rxcarried = 0U;
/* Start dma channel. */
sdrv_dma_clear_channel_xfer_bytes(dma_channel);
sdrv_dma_start_channel_xfer(dma_channel);
/* Enable rx dma interface. */
if (!sdrv_uart_dma_rx_ctrl(ctrl, true, SDRV_UART_OPERATION_TIMEOUT)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_Timeout;
}
return Status_Success;
}
}
/**
* @brief Abort the process of uart to receive data with dma.
*
* This function stop the dma channel and disable uart rx dma interface and
* clear tranfer status.
*
* @param [in] ctrl sdrv uart controller
* @return The result of aborting receive.
* Status_Success : Abort the transfer success.
*/
sdrv_uart_error_status_e sdrv_uart_dma_receive_abort(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(ctrl->rx_dmachannel != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Clear RX Fifo */
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable rx dma interface. */
sdrv_uart_dma_rx_ctrl(ctrl, false, SDRV_UART_OPERATION_TIMEOUT);
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 0U;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
/* Disable rx dma channel. */
sdrv_dma_stop_channel_xfer(ctrl->rx_dmachannel);
/* Clear dma transfer byte register. */
sdrv_dma_clear_channel_xfer_bytes(ctrl->rx_dmachannel);
ctrl->rx_state = Transfer_RxIdle;
return Status_Success;
}
/**
* @brief UART transmit data with dma.
*
* This function transmit data with dma linklist mode.
* User should initializes dma module before use this function.
* User's data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
* This function can receive the indefinite length data.
*
* @param [in] ctrl sdrv uart controller
* @param [out] data transmit data
* @param [in] size the size of transmit data
* @param [in] tx_cb the callback function of transmit
* @param [in] tx_userparam the param of callback function
* @param [in] dma_ctrl sdrv dma controller entity
* @param [in] dma_channel sdrv dma channel controller entity
* @param [in] channel_id The number of dma channel
* @return The result of uart dma transmit function
* Status_Busy : The uart transmitter is busy.
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart tx dma interface timeout.
* Status_Success : Starting the uart to transmit with dma success.
*/
sdrv_uart_error_status_e
sdrv_uart_dma_transmit(sdrv_uart_t *ctrl, const uint8_t *data, uint32_t size,
uart_callback_t tx_cb, void *tx_userparam,
sdrv_dma_t *dma_ctrl, sdrv_dma_channel_t *dma_channel,
sdrv_dma_channel_id_e channel_id)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
ASSERT(dma_ctrl != NULL);
ASSERT(dma_channel != NULL);
ASSERT(0 == (((uint32_t)data)) % CONFIG_ARCH_CACHE_LINE);
uint8_t *data_ptr = (uint8_t *)data;
uint32_t data_size = size;
uint32_t index = 0;
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_dma_channel_config_t xfer_config;
if (Transfer_TxIdle != ctrl->tx_state) {
return Status_Busy;
} else {
ctrl->tx_state = Transfer_TxBusy;
ctrl->txtransfer_type = SDRV_TRANSFER_DMA_ASYNC_MODE;
memset(&ctrl->tx_dma_linklist[0U], 0, sizeof(ctrl->tx_dma_linklist));
if (size >= CONFIG_ARCH_CACHE_LINE) {
/* Get configuration of the tx dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_MEM2DEV,
SDRV_DMA_TRANSFER_MODE_LINKLIST, 16U, data_ptr, size);
/* Initialize transmit linklist. */
while (((data_size / DMA_BURST16_MAD_SIZE_MAX) > 0U)) {
/* Decrease size. */
data_size -= DMA_BURST16_MAD_SIZE_MAX;
/* set source address */
xfer_config.src_addr = (paddr_t)data_ptr;
/* Increase data pointer. */
data_ptr += DMA_BURST16_MAD_SIZE_MAX;
/* Set the next mad's linklist address. */
xfer_config.linklist_addr =
(paddr_t)&ctrl
->tx_dma_linklist[(index + 1) % NUM_LINKLIST_ITEMS];
/* Set transfer bytes */
xfer_config.xfer_bytes = DMA_BURST16_MAD_SIZE_MAX;
/* Set linklist mad type. */
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_NORMAL_MAD;
if (0U == index) {
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_FIRST_MAD;
}
if (0U == data_size) {
xfer_config.linklist_addr = 0U;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
}
/* Configurate the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->tx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config); /* init linklst */
/* Initialize channal. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->tx_state = Transfer_TxIdle;
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
++index;
}
if (data_size > 0U) {
/* Set source address */
xfer_config.src_addr = (paddr_t)data_ptr;
xfer_config.linklist_addr = 0U;
/* Set transfer bytes, should aligned with
* CONFIG_ARCH_CACHE_LINE.
*/
xfer_config.xfer_bytes =
data_size - (data_size % CONFIG_ARCH_CACHE_LINE);
/* Decrease size. */
data_size -= xfer_config.xfer_bytes;
/* Increase data pointer. */
data_ptr += xfer_config.xfer_bytes;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
/* Configurate the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->tx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config);
/* Initialize channal. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->tx_state = Transfer_TxIdle;
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
}
/* Must clean linklist and dst_data cache */
arch_clean_cache_range((uint32_t)&ctrl->tx_dma_linklist[0U],
sizeof(ctrl->tx_dma_linklist));
arch_clean_cache_range((addr_t)data, size);
/* Configurate Tx water level. */
uart_base->FCR0.WMLVL = 15U;
ctrl->tx_ptr = data_ptr;
ctrl->tx_remain = data_size;
} else {
/* Get configuration of the tx dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_MEM2DEV,
SDRV_DMA_TRANSFER_MODE_SINGLE, 1U, (uint8_t *)data, size);
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
return Status_dma_channel_config_Err;
}
/* Must clean dst_data cache */
arch_clean_cache_range((addr_t)data, size);
/* Increase data buffer pointer. */
data += size;
/* Configurate tx water level. */
uart_base->FCR0.WMLVL = 0U;
ctrl->tx_ptr = data;
ctrl->tx_remain = 0U;
}
/* Set interrupt callback */
dma_channel->irq_callback = sdrv_uart_dma_tx_handler;
dma_channel->irq_context = (void *)ctrl;
/* Update uart transfer params. */
ctrl->dma_instance = dma_ctrl;
ctrl->tx_dmachannel = dma_channel;
ctrl->tx_async_cb = tx_cb;
ctrl->tx_userparam = tx_userparam;
/* Start the channel. */
sdrv_dma_clear_channel_xfer_bytes(dma_channel);
sdrv_dma_start_channel_xfer(dma_channel);
/* Enable rx dma interface. */
if (!sdrv_uart_dma_tx_ctrl(ctrl, true, SDRV_UART_OPERATION_TIMEOUT)) {
ctrl->tx_state = Transfer_TxIdle;
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_Timeout;
}
return Status_Success;
}
}
/**
* @brief Abort the process of uart to transmit data with dma.
*
* This function stop the dma channel and disable uart tx dma interface and
* clear transfer status.
*
* @param [in] ctrl sdrv uart controller
* @return The result of aborting transmit.
* Status_Timeout : Reset uart tx dma interface or clear tx fifo timeout
* Status_Success : Abort the transfer success.
*/
sdrv_uart_error_status_e sdrv_uart_dma_transmit_abort(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(ctrl->tx_dmachannel != NULL);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* Clear TX Fifo */
sdrv_uart_txfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Disable tx dma interface. */
sdrv_uart_dma_tx_ctrl(ctrl, false, SDRV_UART_OPERATION_TIMEOUT);
/* Configurate tx water level. */
uart_base->FCR0.WMLVL = 0U;
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
/* Disable tx dma channel. */
sdrv_dma_stop_channel_xfer(ctrl->tx_dmachannel);
sdrv_dma_clear_channel_xfer_bytes(ctrl->tx_dmachannel);
ctrl->tx_state = Transfer_TxIdle;
return Status_Success;
}
/**
* @brief UART receive data with dma.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
* The size of the user's buffer should be larger than the size of the data
* that excepted received.
*
* @param [in] ctrl sdrv uart controller
* @param [out] data receive data
* @param [in] size the max size of data buffer
* @param [in] rx_cb the callback function of receive
* @param [in] rx_userparam the param of callback function
* @param [in] dma_ctrl sdrv dma controller entity
* @param [in] dma_channel sdrv dma channel controller entity
* @param [in] channel_id The number of dma channel
* @return The result of uart dma receive function
* Status_Busy : The uart receiver is busy.
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart rx dma interface timeout.
* Status_Success : Starting the uart to receive with dma success.
*/
sdrv_uart_error_status_e sdrv_uart_dma_receive_start(
sdrv_uart_t *ctrl, uint8_t *data, uint32_t size, uart_callback_t rx_cb,
void *rx_userparam, sdrv_dma_t *dma_ctrl, sdrv_dma_channel_t *dma_channel,
sdrv_dma_channel_id_e channel_id)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
ASSERT(dma_ctrl != NULL);
ASSERT(dma_channel != NULL);
ASSERT(0 == (((uint32_t)data)) % CONFIG_ARCH_CACHE_LINE);
if (size > NUM_LINKLIST_ITEMS * DMA_BURST1_MAD_SIZE_MAX) {
return Status_Invalid_Param;
}
uint8_t *data_ptr = data;
uint32_t data_size = size;
uint32_t index = 0;
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_dma_channel_config_t xfer_config;
if (Transfer_RxIdle != ctrl->rx_state) {
return Status_Busy;
} else {
ctrl->rx_state = Transfer_RxBusy;
ctrl->rxtransfer_type = SDRV_TRANSFER_DMA_REALTIME_MODE;
memset(&ctrl->rx_dma_linklist[0U], 0, sizeof(ctrl->rx_dma_linklist));
/* Get configuration of the rx dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_DEV2MEM,
SDRV_DMA_TRANSFER_MODE_LINKLIST, 1U, data, size);
/* Initialize receive linklist. */
while ((data_size / DMA_BURST1_MAD_SIZE_MAX) > 0U) {
/* Decrease size. */
data_size -= DMA_BURST1_MAD_SIZE_MAX;
/* set destination address */
xfer_config.dst_addr = (paddr_t)data_ptr;
/* Increase data pointer. */
data_ptr += DMA_BURST1_MAD_SIZE_MAX;
/* Set the next mad's linklist address. */
xfer_config.linklist_addr =
(paddr_t)&ctrl
->rx_dma_linklist[(index + 1) % NUM_LINKLIST_ITEMS];
/* Set transfer bytes */
xfer_config.xfer_bytes = DMA_BURST1_MAD_SIZE_MAX;
/* Set the mad's type. */
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_NORMAL_MAD;
if (0U == index) {
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_FIRST_MAD;
}
if (0U == data_size) {
xfer_config.linklist_addr = 0U;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
}
/* Initialize the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->rx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config);
/* Initialize dma channel. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
++index;
}
if (data_size > 0U) {
/* set destination address */
xfer_config.dst_addr = (paddr_t)data_ptr;
xfer_config.linklist_addr = 0U;
/* Set transfer bytes, should aligned with
* CONFIG_ARCH_CACHE_LINE.
*/
xfer_config.xfer_bytes = data_size;
/* Decrease size. */
data_size = 0U;
/* Increase data pointer. */
data_ptr += xfer_config.xfer_bytes;
xfer_config.linklist_mad_type = SDRV_DMA_LINKLIST_LAST_MAD;
/* Initialize the linklist of this mad. */
sdrv_dma_init_linklist_entry(
&ctrl->rx_dma_linklist[index % NUM_LINKLIST_ITEMS],
&xfer_config); /* init linklst */
/* Initialize dma channel. */
if (0U == index) {
/* Init channel config */
if (SDRV_STATUS_OK !=
sdrv_dma_init_channel(dma_channel, &xfer_config)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_dma_channel_config_Err;
}
}
}
/* Must invalidate rx linklist and dst_data cache */
arch_clean_cache_range((uint32_t)&ctrl->rx_dma_linklist[0U],
sizeof(ctrl->rx_dma_linklist));
arch_invalidate_cache_range((addr_t)data, size);
/* Set interrupt callback */
dma_channel->irq_callback = sdrv_uart_dma_rx_realtime_handler;
dma_channel->irq_context = (void *)ctrl;
/* Update uart tranfer params. */
ctrl->dma_instance = dma_ctrl;
ctrl->rx_dmachannel = dma_channel;
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 0U;
ctrl->rx_ptr = data;
ctrl->rx_remain = size;
ctrl->rx_async_cb = rx_cb;
ctrl->rx_userparam = rx_userparam;
ctrl->bytes_rxcarried = 0U;
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Enable rx dma interface. */
if (!sdrv_uart_dma_rx_ctrl(ctrl, true, SDRV_UART_OPERATION_TIMEOUT)) {
ctrl->rx_state = Transfer_RxIdle;
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
return Status_Timeout;
}
sdrv_dma_clear_channel_xfer_bytes(dma_channel);
sdrv_dma_start_channel_xfer(dma_channel);
}
return Status_Success;
}
/**
* @brief Get the count of data carried by dma.
*
* This function only for dma mode.
*
* @param [in] ctrl sdrv uart controller
* @return the count of received byte
*/
uint32_t sdrv_uart_dma_bytes_received(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
/* The number of the data carried by dma. */
return ctrl->bytes_rxcarried;
}
#endif
/**
* @brief Enable/Disable Sdrv UART Interrupt.
*
* This function enable/disable sdrv uart interrupt with the provided mask.
*
* @param [in] ctrl sdrv uart controller
* @param [in] mask the interrupts to enable
* @param [in] value enable or disable
* @return The result of setting interrupt register.
*/
sdrv_uart_error_status_e sdrv_uart_intr_ctrl(sdrv_uart_t *ctrl, uint32_t mask,
bool value)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t intr_ctrl = uart_base->INTEN0.v;
intr_ctrl = value ? (intr_ctrl | mask) : (intr_ctrl & (~mask));
uart_base->INTEN0.v = intr_ctrl;
return Status_Success;
}
/**
* @brief Get Sdrv UART Interrupt enable/disable status.
*
* This function get sdrv uart interrupt enable/disable status with the
* provided mask.
*
* @param [in] ctrl sdrv uart controller
* @return Sdrv UART Interrupt enable/disable status
*/
uint32_t sdrv_uart_intr_get(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
return uart_base->INTEN0.v;
}
/**
* @brief Get Sdrv UART Interrupt flag status.
*
* This function get Sdrv UART Interrupt flag status.
*
* @param [in] ctrl sdrv uart controller
* @return all sdrv UART Interrupt status
*/
uint32_t sdrv_uart_intr_status_get(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
return uart_base->INTR0.v;
}
/**
* @brief Clear Sdrv UART Interrupt flag status.
*
* This function clear Sdrv UART Interrupt flag status with the provided
* mask.
*
* @param [in] ctrl sdrv uart controller
* @param [in] mask the interrupts status to clear
* @return The result of clearing interrupt status.
*/
sdrv_uart_error_status_e sdrv_uart_intr_status_clear(sdrv_uart_t *ctrl,
uint32_t mask)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uart_base->INTR0.v = mask;
return Status_Success;
}
/**
* @brief Sdrv UART default IRQ handle function.
*
* This function handles the sdrv uart transmit and receive
* and error IRQ request.
*
* @param [in] irq the irq number of uartx
* @param [in] ctrl sdrv uart controller
*/
int sdrv_uart_irq_handler(uint32_t irq, void *ctrl)
{
ASSERT(ctrl != NULL);
sdrv_uart_t *irq_ctrl = (sdrv_uart_t *)ctrl;
ASSERT(irq_ctrl->base > 0U);
/* Handle error interrupt during transfer. */
if ((SDRV_UART_INTR_RX_ERROR | SDRV_UART_INTR_TX_ERROR) &
sdrv_uart_intr_get(irq_ctrl)) {
if ((SDRV_UART_INTR_RX_ERROR | SDRV_UART_INTR_TX_ERROR) &
sdrv_uart_intr_status_get(irq_ctrl)) {
sdrv_uart_err_irq_handler(irq_ctrl);
}
}
/* Handle receive interrupt. */
if ((Transfer_RxAbrReady == irq_ctrl->abr_state) &&
(Transfer_RxBusy == irq_ctrl->rx_state)) {
if (SDRV_UART_INTR_RX_FWF & sdrv_uart_intr_get(irq_ctrl)) {
if (SDRV_UART_INTR_RX_FWF & sdrv_uart_intr_status_get(irq_ctrl)) {
sdrv_uart_rx_irq_handler(irq_ctrl);
}
}
}
#if CONFIG_UART_ENABLE_DMA
/* Handle rx idle interrupt. */
if ((Transfer_RxAbrReady == irq_ctrl->abr_state) &&
(Transfer_RxBusy == irq_ctrl->rx_state)) {
if (SDRV_UART_INTR_RXIDLE & sdrv_uart_intr_get(irq_ctrl)) {
if (SDRV_UART_INTR_RXIDLE & sdrv_uart_intr_status_get(irq_ctrl)) {
sdrv_uart_rx_idle_irq_handler(irq_ctrl);
}
}
}
#endif
/* Handle transmit interrupt. */
if ((Transfer_TxBusy == irq_ctrl->tx_state)) {
if (SDRV_UART_INTR_TX_COMPLETED & sdrv_uart_intr_get(irq_ctrl)) {
if (SDRV_UART_INTR_TX_COMPLETED &
sdrv_uart_intr_status_get(irq_ctrl)) {
sdrv_uart_tx_irq_handler(irq_ctrl);
}
}
}
/* Handle auto baudrate detect interrupt. */
if (SDRV_UART_INTR_ABR & sdrv_uart_intr_get(irq_ctrl)) {
if (SDRV_UART_INTR_ABR & sdrv_uart_intr_status_get(irq_ctrl)) {
sdrv_uart_abr_irq_handler(irq_ctrl);
}
}
return 0;
}
/*************************Static Functions Start******************************/
/**
* brief Disable uart module.
*
* param [in] base sdrv uart register base
*/
static inline void sdrv_uart_disable(sdrv_uart_regs_t *base)
{
base->PCR0.TXEN = 0U;
base->PCR0.RXEN = 0U;
base->MCR0.MODEN = 0U;
}
/**
* brief Srdv UART set flow control mode.
*
* param [in] base sdrv uart register base
* param [in] fcm_cfg The configurations of fcm
*/
static void sdrv_uart_set_fcm(sdrv_uart_regs_t *base,
sdrv_uart_fcm_config_t *fcm_cfg)
{
ASSERT(fcm_cfg != NULL);
base->PCR0.FCM = fcm_cfg->fcm_type;
}
/**
* brief Srdv UART Initialization.
*
* This function brief initializes sdrv uart module with user-defined
* settings
*
* param [in] cfg sdrv uart config
* return The result of initializing uart module
*/
static sdrv_uart_error_status_e sdrv_uart_init(const sdrv_uart_config_t *cfg)
{
ASSERT(cfg != NULL);
ASSERT(cfg->base > 0U);
ASSERT((cfg->baud > 0U) || (1U == cfg->abr_en));
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(cfg->base);
/* Initializes sdrv uart module */
/* Disable uart module */
sdrv_uart_disable(uart_base);
/* Configurate uart as serial mode and full duplex. */
uart_base->MCR0.OPMOD = SDRV_UART_SERIAL_MODE;
uart_base->PCR0.TRANSFERMODE = SDRV_UART_FULL_DUPLEX;
/* Configurate sdrv uart flow control mode */
sdrv_uart_set_fcm(uart_base, (sdrv_uart_fcm_config_t *)&cfg->fcm);
/* Configurate uart data frame. */
uart_base->PCR0.DATABIT = cfg->data_bits;
uart_base->PCR0.STOPBIT = cfg->stop_bits;
uart_base->PCR0.PARITYBIT = cfg->parity;
/* Configurate uart fifo. */
uart_base->FCR0.WMLVL = cfg->txwmlvl;
uart_base->FCR1.WMLVL = cfg->rxwmlvl;
if ((!sdrv_uart_txfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT)) ||
(!sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT))) {
return Status_Timeout;
}
/* Initializes uart interrupt. */
sdrv_uart_intr_init(uart_base);
sdrv_uart_intr_status_init(uart_base);
/* Configurate uart dma interface. */
if (cfg->dma_en) {
if ((!sdrv_uart_txdma_reset(uart_base, SDRV_UART_OPERATION_TIMEOUT)) ||
(!sdrv_uart_rxdma_reset(uart_base, SDRV_UART_OPERATION_TIMEOUT))) {
return Status_Timeout;
}
uart_base->DMACR.TXDMAE = 1U;
uart_base->DMACR.RXDMAE = 1U;
} else {
uart_base->DMACR.TXDMAE = 0U;
uart_base->DMACR.RXDMAE = 0U;
}
/* Configurate filter. */
uart_base->PCR8.RXFILTCTL = 3U;
uart_base->PCR8.RXSYNCEN = 1U;
/* Reset uart module. */
if (!sdrv_uart_module_reset(uart_base, SDRV_UART_OPERATION_TIMEOUT)) {
return Status_Timeout;
}
/* Enable TX line. */
uart_base->PCR0.TXEN = 1U;
/* Enable RX line. */
uart_base->PCR0.RXEN = 1U;
/* Enable uart module. */
uart_base->MCR0.MODEN = 1U;
/* Configurate auto baudrate detect. */
if (1U == cfg->abr_en) {
uart_base->PCR0.ABRCTL0 = UART_ABR_PATTERN;
uart_base->PCR0.ABRCTL1 = cfg->match_num;
uart_base->PCR1.BAUDRATE = 0U;
uart_base->INTEN0.ABRPASS = 1U;
uart_base->INTEN0.ABRFAIL = 1U;
uart_base->PCR0.ABREN = 1U;
} else {
uart_base->INTEN0.ABRPASS = 0U;
uart_base->INTEN0.ABRFAIL = 0U;
uart_base->PCR0.ABREN = 0U;
uart_base->PCR1.BAUDRATE =
sdrv_uart_baudrate_roundoff(cfg->clk_freq, cfg->baud);
}
return Status_Success;
}
/**
* brief Srdv UART initializes interrupt register.
*
* This function initializes sdrv uart module interrupt to disable.
*
* param [in] base sdrv uart register base
*/
static void sdrv_uart_intr_init(sdrv_uart_regs_t *base) { base->INTEN0.v = 0; }
/**
* brief Srdv UART initializes interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] base sdrv uart register base
*/
static void sdrv_uart_intr_status_init(sdrv_uart_regs_t *base)
{
base->INTR0.v = 0xFFFFFFFFU;
}
/**
* brief Srdv UART initializes rx interrupt status register.
*
* This function initializes sdrv uart module interrupt.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_rx_intr_ctrl(sdrv_uart_t *ctrl, bool enable)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t intr_ctrl = uart_base->INTEN0.v;
uint32_t mask = SDRV_UART_INTR_RX_ERROR;
#if CONFIG_E3L
if (IS_P1) {
mask = mask & (~SDRV_UART_INTR_BAUDRATEERR);
}
#endif
if ((SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) ||
(SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type)) {
mask = mask | SDRV_UART_INTR_RX_FWF;
}
intr_ctrl = enable ? (intr_ctrl | mask) : (intr_ctrl & (~mask));
uart_base->INTEN0.v = intr_ctrl;
}
/**
* brief Srdv UART initializes tx interrupt status register.
*
* This function initializes sdrv uart module interrupt.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_tx_intr_ctrl(sdrv_uart_t *ctrl, bool enable)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t intr_ctrl = uart_base->INTEN0.v;
uint32_t mask = SDRV_UART_INTR_TX_ERROR;
if ((SDRV_TRANSFER_REALTIME_MODE == ctrl->txtransfer_type) ||
(SDRV_TRANSFER_ASYNC_MODE == ctrl->txtransfer_type)) {
mask = mask | SDRV_UART_INTR_TX_COMPLETED;
}
intr_ctrl = enable ? (intr_ctrl | mask) : (intr_ctrl & (~mask));
uart_base->INTEN0.v = intr_ctrl;
}
/**
* brief Srdv UART initializes rx interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] ctrl sdrv uart controller
* param [in] value enable or disable
*/
static void sdrv_uart_rx_intrstatus_clear(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t mask = SDRV_UART_INTR_RX_ERROR;
#if CONFIG_E3L
if (IS_P1) {
mask = mask & (~SDRV_UART_INTR_BAUDRATEERR);
}
#endif
if ((SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) ||
(SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type)) {
mask = mask | SDRV_UART_INTR_RX_FWF;
}
uart_base->INTR0.v = mask;
}
/**
* brief Srdv UART initializes tx interrupt status register.
*
* This function initializes sdrv uart module interrupt status.
*
* param [in] ctrl sdrv uart controller
*/
static void sdrv_uart_tx_intrstatus_clear(sdrv_uart_t *ctrl)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t mask = SDRV_UART_INTR_TX_ERROR;
if ((SDRV_TRANSFER_REALTIME_MODE == ctrl->txtransfer_type) ||
(SDRV_TRANSFER_ASYNC_MODE == ctrl->txtransfer_type)) {
mask = mask | SDRV_UART_INTR_TX_COMPLETED;
}
uart_base->INTR0.v = mask;
}
/**
* brief Sdrv uart baudrate round-off.
*
* param [in] dividend The clock frequency.
* param [in] divisor The value of baud.
* return The result of the baudrate after rounded off.
*/
static uint32_t sdrv_uart_baudrate_roundoff(uint32_t dividend, uint32_t divisor)
{
uint32_t temp = dividend * 10U / divisor;
return ((temp % 10U) < 5U) ? (temp / 10U) : (temp / 10U + 1U);
}
/**
* brief Sdrv uart get char from rx fifo.
*
* param [in] base Sdrv uart register base
* param [in] c The character to be received
* param [in] timeout The max times of query fifo empty register
* return The result of getting a character from rx fifo
*/
static inline bool sdrv_uart_getc(sdrv_uart_regs_t *base, uint8_t *c,
uint32_t timeout)
{
/* Wait for receiving data until timeout. */
while (base->FSR1.EMPTY) {
if (WaitForever != timeout) {
if (0U == timeout) {
return false;
}
--timeout;
}
}
/* Read one character from rx fifo. */
*c = base->RXDR;
return true;
}
/**
* brief Sdrv uart put char in tx fifo.
*
* param [in] base sdrv uart register base
* param [in] c The character to be transmitted
* param [in] timeout The max times of query fifo full register
* return The result of writting a character from tx fifo
*/
static inline bool sdrv_uart_putc(sdrv_uart_regs_t *base, uint8_t c,
uint32_t timeout)
{
/* Wait for transmitting data until timeout. */
while (base->FSR0.FULL) {
if (WaitForever != timeout) {
if (0U == timeout) {
return false;
}
--timeout;
}
}
/* Write one character to tx fifo. */
base->TXDR = c;
return true;
}
/**
* brief Sdrv uart async read data from rx fifo
*
* param [in] base Sdrv uart register base
* param [in] data Data buff
* param [in] size The size of data expected
* return The count of received characters
*/
static inline uint32_t sdrv_uart_read_async(sdrv_uart_regs_t *base,
uint8_t *data, uint32_t size)
{
uint32_t received = 0U;
/* Keep reading when there's character in RBR or Rx FIFO. */
while ((received < size) && (1U != (base->FSR1.EMPTY))) {
*data++ = base->RXDR;
received++;
}
return received;
}
/**
* brief Sdrv uart async write data to tx fifo
*
* param [in] base Sdrv uart register base
* param [in] data Data buff
* param [in] size The size of data expected
* return The count of transmitted characters
*/
static inline uint32_t sdrv_uart_send_async(sdrv_uart_regs_t *base,
const uint8_t *data, uint32_t size)
{
uint32_t transmitted = 0U;
while ((1U != (base->FSR0.FULL)) && (transmitted < size)) {
/* Fill the FIFO from the buffer */
base->TXDR = *data++;
/* Increment the send count. */
transmitted++;
}
return transmitted;
}
/**
* brief Sdrv uart get the length of data in rx fifo.
*
* param [in] base sdrv uart register base
* return The length of data in rx fifo
*/
static inline uint32_t sdrv_uart_get_rxfifolen(sdrv_uart_regs_t *base)
{
return base->FSR1.FILLLVL;
}
/**
* brief Sdrv uart clear rx fifo.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of clearing rx fifo.
*/
static bool sdrv_uart_rxfifo_clear(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Clear RX Fifo */
base->FCR1.CLR = 1U;
while (base->FCR1.CLR) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Sdrv uart clear tx fifo.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of clearing tx fifo.
*/
static bool sdrv_uart_txfifo_clear(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Clear RX Fifo */
base->FCR0.CLR = 1U;
while (base->FCR0.CLR) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Sdrv uart module reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart module.
*/
static bool sdrv_uart_module_reset(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Clear RX Fifo */
base->MCR0.MODRST = 1U;
while (base->MCR0.MODRST) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Sdrv uart rx dma reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart dma rx.
*/
static bool sdrv_uart_rxdma_reset(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Reset dma rx. */
base->DMACR.RXDMARST = 1U;
while (base->DMACR.RXDMARST) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Sdrv uart tx dma reset.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of resetting uart dma tx.
*/
static bool sdrv_uart_txdma_reset(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Reset dma tx. */
base->DMACR.TXDMARST = 1U;
while (base->DMACR.TXDMARST) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Waitting until sdrv uart tx io state changing to idle.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_txio_idle(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Wait for tx io idle. */
while (base->PSR0.IOTX_STATE) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Waitting until sdrv uart rx io state changing to idle.
*
* param[in] base The address of uart's register.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_rxio_idle(sdrv_uart_regs_t *base, uint32_t timeout)
{
/* Wait for rx io idle. */
while (base->PSR0.IORX_STATE) {
if (0U == timeout) {
return false;
}
--timeout;
}
return true;
}
/**
* brief Waitting until auto baudrate detect completed or timeout.
*
* param[in] ctrl The uart controller entity.
* param[in] timeout The value of timeout.
* return The result of Waitting.
*/
static bool sdrv_uart_wait_abr_ready(sdrv_uart_t *ctrl, uint32_t timeout)
{
/* Wait for rx io idle. */
while (Transfer_RxAbrReady != ctrl->abr_state) {
if (WaitForever != timeout) {
if (0U == timeout) {
return false;
}
--timeout;
}
}
return true;
}
/**
* brief Handle error interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_err_irq_handler(sdrv_uart_t *ctrl)
{
/* Transmission occurs rx fifo overflow error. */
if ((SDRV_UART_INTR_RX_FOVF & sdrv_uart_intr_status_get(ctrl)) &&
(SDRV_UART_INTR_RX_FOVF & sdrv_uart_intr_get(ctrl))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_RxFifoOverFlow, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoOverFlow,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoOverFlow,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoOverFlow,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs rx fifo underflow error. */
if ((SDRV_UART_INTR_RX_FUDF & sdrv_uart_intr_status_get(ctrl)) &&
((SDRV_UART_INTR_RX_FUDF & sdrv_uart_intr_get(ctrl)))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_RxFifoUnderFlow, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoUnderFlow,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoUnderFlow,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxFifoUnderFlow,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs parity error. */
if ((SDRV_UART_INTR_PARITYERR & sdrv_uart_intr_status_get(ctrl)) &&
(SDRV_UART_INTR_PARITYERR & sdrv_uart_intr_get(ctrl))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_ParityError, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_ParityError,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_ParityError,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_ParityError,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs baudrate error. */
if ((SDRV_UART_INTR_BAUDRATEERR & sdrv_uart_intr_status_get(ctrl)) &&
((SDRV_UART_INTR_BAUDRATEERR & sdrv_uart_intr_get(ctrl)))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_BaudrateError, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_BaudrateError,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_BaudrateError,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_BaudrateError,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs noise error. */
if ((SDRV_UART_INTR_NOISERERR & sdrv_uart_intr_status_get(ctrl)) &&
(SDRV_UART_INTR_NOISERERR & sdrv_uart_intr_get(ctrl))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_NoiseError, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_NoiseError,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_NoiseError,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_NoiseError,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs frame error. */
if ((SDRV_UART_INTR_FRAMEERR & sdrv_uart_intr_status_get(ctrl)) &&
(SDRV_UART_INTR_FRAMEERR & sdrv_uart_intr_get(ctrl))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_FramingError, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_FramingError,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_FramingError,
ctrl->rx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_FramingError,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_ERROR);
}
/* Transmission occurs tx fifo overflow error. */
if ((SDRV_UART_INTR_TX_FOVF & sdrv_uart_intr_status_get(ctrl)) &&
(SDRV_UART_INTR_TX_FOVF & sdrv_uart_intr_get(ctrl))) {
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->txtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_TxFifoOverFlow, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->txtransfer_type) {
sdrv_uart_async_transmit_abort(ctrl);
if (ctrl->tx_async_cb != NULL) {
ctrl->tx_async_cb(ctrl, SDRV_UART_TxFifoOverFlow,
ctrl->tx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) {
/* Abort this transfer. */
sdrv_uart_dma_transmit_abort(ctrl);
if (ctrl->tx_async_cb != NULL) {
ctrl->tx_async_cb(ctrl, SDRV_UART_TxFifoOverFlow,
ctrl->tx_userparam);
}
} else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_TxFifoOverFlow,
ctrl->rx_userparam);
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_TX_ERROR);
}
}
/**
* brief Handle receive interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_rx_irq_handler(sdrv_uart_t *ctrl)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* UART receive data. */
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_RxFWF, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_remain > 0U) {
uint32_t transfer_size =
sdrv_uart_read_async(uart_base, ctrl->rx_ptr, ctrl->rx_remain);
ctrl->rx_ptr += transfer_size;
ctrl->rx_remain -= transfer_size;
}
if (ctrl->rx_remain == 0U) {
sdrv_uart_rx_intr_ctrl(ctrl, false);
ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->rx_state = Transfer_RxIdle;
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxCompleted,
ctrl->rx_userparam);
}
}
}
#if CONFIG_UART_ENABLE_DMA
else if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
if (0U != ctrl->rx_idle) {
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RXIDLE);
/* Enable uart rx idle interrupt. */
uart_base->INTEN0.RXIDLE = 1U;
uart_base->PCR1.RXIDLECTL = ctrl->rx_idle & 0x07U;
/* Disable RX interrupt */
uart_base->INTEN0.RXFWF = 0U;
}
}
#endif
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_FWF);
}
#if CONFIG_UART_ENABLE_DMA
/**
* brief Handle rx idle interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_rx_idle_irq_handler(sdrv_uart_t *ctrl)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* UART receive data. */
if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
/* Enable uart rx idle interrupt. */
uart_base->PCR1.RXIDLECTL = 0U;
uart_base->INTEN0.RXIDLE = 0U;
sdrv_dma_stop_channel_xfer(ctrl->rx_dmachannel);
ctrl->bytes_rxcarried =
sdrv_dma_get_channel_xfer_bytes(ctrl->rx_dmachannel);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_RxIdle, ctrl->rx_userparam);
}
ctrl->bytes_rxcarried = 0U;
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RX_FWF);
uart_base->INTEN0.RXFWF = true;
/* Must invalidate rx linklist and dst_data cache */
arch_invalidate_cache_range((addr_t)ctrl->rx_ptr, ctrl->rx_remain);
sdrv_dma_clear_channel_xfer_bytes(ctrl->rx_dmachannel);
sdrv_dma_start_channel_xfer(ctrl->rx_dmachannel);
}
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_RXIDLE);
}
#endif
/**
* brief Handle transmit interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_tx_irq_handler(sdrv_uart_t *ctrl)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* UART transmit data. */
if (SDRV_TRANSFER_ASYNC_MODE == ctrl->txtransfer_type) {
if (ctrl->tx_remain > 0U) {
uint32_t transfer_size =
sdrv_uart_send_async(uart_base, ctrl->tx_ptr, ctrl->tx_remain);
ctrl->tx_ptr += transfer_size;
ctrl->tx_remain -= transfer_size;
}
if (ctrl->tx_remain == 0U) {
/* Disable TX interrupt */
uart_base->INTEN0.TC = 0U;
/* Update tx status. */
ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
ctrl->tx_state = Transfer_TxIdle;
if (ctrl->tx_async_cb != NULL) {
ctrl->tx_async_cb(ctrl, SDRV_UART_TxCompleted,
ctrl->tx_userparam);
}
}
}
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_TX_COMPLETED);
}
/**
* brief Handle auto baudrate detect interrupt during transfer.
*
* param[in] ctrl The uart controller entity.
*/
static void sdrv_uart_abr_irq_handler(sdrv_uart_t *ctrl)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
/* UART auto baudrate detect pass. */
if (SDRV_UART_INTR_ABRPASS & sdrv_uart_intr_status_get(ctrl)) {
/* Disable abr pass interrupt */
uart_base->INTEN0.ABRPASS = 0U;
uart_base->INTEN0.ABRFAIL = 0U;
if (0U == uart_base->PSR1.AUTOBAUDRATE) {
ctrl->abr_state = Transfer_RxAbrFail;
/* Stop auto baudrate detect */
uart_base->PCR0.ABREN = 0U;
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
sdrv_uart_stop_realtime_receive(ctrl);
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_AbrFail, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrFail,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if ((SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) ||
(SDRV_TRANSFER_DMA_REALTIME_MODE ==
ctrl->rxtransfer_type)) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrFail,
ctrl->rx_userparam);
}
}
#endif
} else {
sdrv_uart_rxfifo_clear(uart_base, SDRV_UART_OPERATION_TIMEOUT);
/* Get abr result and calculate baud */
ctrl->baud = sdrv_uart_baudrate_roundoff(
ctrl->clk_freq, uart_base->PSR1.AUTOBAUDRATE);
ctrl->abr_state = Transfer_RxAbrReady;
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_AbrPass, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrPass,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if ((SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) ||
(SDRV_TRANSFER_DMA_REALTIME_MODE ==
ctrl->rxtransfer_type)) {
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrPass,
ctrl->rx_userparam);
}
}
#endif
}
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_ABRPASS);
}
/* UART auto baudrate detect fail. */
if (SDRV_UART_INTR_ABRFAIL & sdrv_uart_intr_status_get(ctrl)) {
if (ctrl->abr_count < SDRV_UART_MAX_ABR_NUM) {
uart_base->PCR0.ABREN = 0U;
++ctrl->abr_count;
/* enable auto baudrate detect */
uart_base->PCR0.ABREN = 1U;
} else {
ctrl->abr_state = Transfer_RxAbrFail;
/* Disable abr pass interrupt */
uart_base->INTEN0.ABRPASS = 0U;
uart_base->INTEN0.ABRFAIL = 0U;
/* Stop auto baudrate detect */
uart_base->PCR0.ABREN = 0U;
if (SDRV_TRANSFER_REALTIME_MODE == ctrl->rxtransfer_type) {
sdrv_uart_stop_realtime_receive(ctrl);
if (ctrl->callback != NULL) {
ctrl->callback(ctrl, SDRV_UART_AbrFail, ctrl->userData);
}
} else if (SDRV_TRANSFER_ASYNC_MODE == ctrl->rxtransfer_type) {
sdrv_uart_async_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrFail,
ctrl->rx_userparam);
}
}
#if CONFIG_UART_ENABLE_DMA
else if ((SDRV_TRANSFER_DMA_ASYNC_MODE == ctrl->rxtransfer_type) ||
(SDRV_TRANSFER_DMA_REALTIME_MODE ==
ctrl->rxtransfer_type)) {
sdrv_uart_dma_receive_abort(ctrl);
if (ctrl->rx_async_cb != NULL) {
ctrl->rx_async_cb(ctrl, SDRV_UART_AbrFail,
ctrl->rx_userparam);
}
}
#endif
}
/* Clear uart interrupt status. */
sdrv_uart_intr_status_clear(ctrl, SDRV_UART_INTR_ABRFAIL);
}
}
#if CONFIG_UART_ENABLE_DMA
/**
* brief Control uart rx dma interface.
*
* param[in] ctrl The uart controller entity.
* param[in] enable Enable or disable uart rx dma.
* param[in] timeout Timeout value.
*/
static bool sdrv_uart_dma_rx_ctrl(sdrv_uart_t *ctrl, bool enable,
uint32_t timeout)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t value = enable ? 1U : 0U;
sdrv_uart_rx_intr_ctrl(ctrl, enable);
sdrv_uart_rx_intrstatus_clear(ctrl);
if (SDRV_TRANSFER_DMA_REALTIME_MODE == ctrl->rxtransfer_type) {
/* Disable uart rx idle interrupt. */
uart_base->PCR1.RXIDLECTL = 0U;
uart_base->INTEN0.RXIDLE = 0U;
uart_base->INTR0.RXIDLE = 1U;
/* Enable/Disable RX fifo underflow interrupt. */
uart_base->INTEN0.RXFWF = value;
}
/* Enable/Disable rx dma. */
uart_base->DMACR.RXDMAE = value;
return true;
}
/**
* brief Control uart tx dma interface.
*
* param[in] ctrl The uart controller entity.
* param[in] enable Enable or disable uart tx dma.
* param[in] timeout Timeout value.
*/
static bool sdrv_uart_dma_tx_ctrl(sdrv_uart_t *ctrl, bool enable,
uint32_t timeout)
{
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
uint32_t value = enable ? 1U : 0U;
/* Enable/Disable TX fifo overflow interrupt. */
sdrv_uart_tx_intr_ctrl(ctrl, enable);
sdrv_uart_tx_intrstatus_clear(ctrl);
/* Enable/Disable tx dma. */
uart_base->DMACR.TXDMAE = value;
return true;
}
/**
* brief UART receive data with dma single mode.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [in] dma_ctrl sdrv dma controller entity
* param [out] xfer_config the configuration of the dma channel
* param [in] channel_id the number of dma channel
* param [in] xfer_type the type of the dma transfer
* param [in] xfer_mode the mode of the dma transfer
* param [in] burst_len the port burst length
* param [in] data receive data buffer
* param [in] size the size of receive data
*/
static void sdrv_uart_dma_config_creat(sdrv_uart_t *ctrl, sdrv_dma_t *dma_ctrl,
sdrv_dma_channel_config_t *xfer_config,
sdrv_dma_channel_id_e channel_id,
sdrv_dma_xfer_type_e xfer_type,
sdrv_dma_xfer_mode_e xfer_mode,
uint32_t burst_len, uint8_t *data,
uint32_t size)
{
/* Get default config. */
sdrv_dma_init_channel_config(xfer_config, dma_ctrl);
/* Modify dma config param */
xfer_config->channel_id = channel_id; /* select channel */
xfer_config->xfer_type = xfer_type; /* mem2mem or mem2dev or dev2mem */
xfer_config->xfer_mode = xfer_mode; /* single or continuous or
linklist*/
if (SDRV_DMA_DIR_DEV2MEM == xfer_type) {
xfer_config->src_inc =
SDRV_DMA_ADDR_NO_INC; /* source address increase or not */
xfer_config->dst_inc =
SDRV_DMA_ADDR_INC; /* destination address increase or not */
xfer_config->src_port_sel =
SDRV_DMA_PORT_AHB32; /* periph -> SDRV_DMA_PORT_AHB32 */
xfer_config->dst_port_sel =
SDRV_DMA_PORT_AXI64; /* memory -> SDRV_DMA_PORT_AXI64 */
xfer_config->src_addr =
ctrl->base + SDRV_UART_RX_FIFO_OFFSET; /* set source address
(uart_rx_fifo address)*/
xfer_config->dst_addr = (paddr_t)data;
} else if (SDRV_DMA_DIR_MEM2DEV == xfer_type) {
xfer_config->src_inc =
SDRV_DMA_ADDR_INC; /* source address increase or not */
xfer_config->dst_inc =
SDRV_DMA_ADDR_NO_INC; /* destination address increase or not */
xfer_config->src_port_sel =
SDRV_DMA_PORT_AXI64; /* periph -> SDRV_DMA_PORT_AXI64 */
xfer_config->dst_port_sel =
SDRV_DMA_PORT_AHB32; /* memory -> SDRV_DMA_PORT_AHB32 */
xfer_config->src_addr = (paddr_t)data;
xfer_config->dst_addr =
ctrl->base + SDRV_UART_TX_FIFO_OFFSET; /* set source address
(uart_tx_fifo address)*/
}
xfer_config->src_width =
SDRV_DMA_BUSWIDTH_1_BYTE; /* source address width */
xfer_config->dst_width =
SDRV_DMA_BUSWIDTH_1_BYTE; /* destination address width */
xfer_config->src_burst_len = burst_len; /* source burst_length (transfer
level), max value is 4096. */
xfer_config->dst_burst_len =
burst_len; /* destination burst_length, max value is 4096. */
xfer_config->loop_mode =
SDRV_DMA_LOOP_MODE_1; /* mem2mem(MODE_0) mem2dev/dev2mem(MODE_1) */
xfer_config->interrupt_type =
SDRV_DMA_LAST_MAD_DONE; /* set interrupt type */
xfer_config->trig_mode =
SDRV_DMA_TRIGGER_BY_HARDWARE; /* by hardware trig */
xfer_config->xfer_bytes = size;
}
/**
* brief UART receive data with dma.
*
* This function receive data with dma module.
* User should initializes dma module before use this function.
* User data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [out] data receive data
* param [in] size the size of receive data
* param [in] rx_cb the callback function of receive
* param [in] rx_userparam the param of callback function
* param [in] dma_ctrl sdrv dma controller entity
* param [in] dma_channel sdrv dma channel controller entity
* param [in] channel_id The number of dma channel
* return The result of uart dma receive function
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart rx dma interface timeout.
* Status_Success : Starting the uart to receive with dma success.
*/
static sdrv_uart_error_status_e sdrv_uart_dma_receive_single(
sdrv_uart_t *ctrl, uint8_t *data, uint32_t size, uart_callback_t rx_cb,
void *rx_userparam, sdrv_dma_t *dma_ctrl, sdrv_dma_channel_t *dma_channel,
sdrv_dma_channel_id_e channel_id)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
ASSERT(0 == (((uint32_t)data)) % CONFIG_ARCH_CACHE_LINE);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_dma_channel_config_t xfer_config;
/* Get configuration of the rx dma channel. */
sdrv_uart_dma_config_creat(ctrl, dma_ctrl, &xfer_config, channel_id,
SDRV_DMA_DIR_DEV2MEM,
SDRV_DMA_TRANSFER_MODE_SINGLE, 1U, data, size);
/* Init channel config */
if (SDRV_STATUS_OK != sdrv_dma_init_channel(dma_channel, &xfer_config)) {
return Status_dma_channel_config_Err;
}
/* Must invalidate dst_data cache */
arch_invalidate_cache_range((addr_t)data, size);
/* Increase data buffer pointer. */
data += size;
/* Set interrupt callback */
dma_channel->irq_callback = sdrv_uart_dma_rx_handler;
dma_channel->irq_context = (void *)ctrl;
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 0U;
/* Update uart tranfer params. */
ctrl->dma_instance = dma_ctrl;
ctrl->rx_dmachannel = dma_channel;
ctrl->rx_ptr = data;
ctrl->rx_remain = 0U;
ctrl->rx_async_cb = rx_cb;
ctrl->rx_userparam = rx_userparam;
sdrv_dma_start_channel_xfer(dma_channel);
/* Enable rx dma interface. */
if (!sdrv_uart_dma_rx_ctrl(ctrl, true, SDRV_UART_OPERATION_TIMEOUT)) {
return Status_Timeout;
}
return Status_Success;
}
/**
* brief UART transmit data with dma.
*
* This function transmit data with dma module.
* User should initializes dma module before use this function.
* User's data buffer must be __aligned(CONFIG_ARCH_CACHE_LINE).
*
* param [in] ctrl sdrv uart controller
* param [out] data transmit data
* param [in] size the size of transmit data
* param [in] tx_cb the callback function of transmit
* param [in] tx_userparam the param of callback function
* param [in] dma_ctrl sdrv dma controller entity
* param [in] dma_channel sdrv dma channel controller entity
* param [in] channel_id The number of dma channel
* return The result of uart dma transmit function
* Status_dma_channel_config_Err : The dma channel config error.
* Status_Timeout : Reset uart tx dma interface timeout.
* Status_Success : Starting the uart to transmit with dma success.
*/
static sdrv_uart_error_status_e sdrv_uart_dma_transmit_single(
sdrv_uart_t *ctrl, const uint8_t *data, uint32_t size,
uart_callback_t tx_cb, void *tx_userparam, sdrv_dma_t *dma_ctrl,
sdrv_dma_channel_t *dma_channel, sdrv_dma_channel_id_e channel_id)
{
ASSERT(ctrl != NULL);
ASSERT(ctrl->base > 0U);
ASSERT(data != NULL);
ASSERT(0 == (((uint32_t)data)) % CONFIG_ARCH_CACHE_LINE);
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(ctrl->base);
sdrv_dma_channel_config_t xfer_config;
/* Get configuration of the tx dma channel. */
sdrv_uart_dma_config_creat(
ctrl, dma_ctrl, &xfer_config, channel_id, SDRV_DMA_DIR_MEM2DEV,
SDRV_DMA_TRANSFER_MODE_SINGLE, 1U, (uint8_t *)data, size);
/* Init channel config */
if (SDRV_STATUS_OK != sdrv_dma_init_channel(dma_channel, &xfer_config)) {
return Status_dma_channel_config_Err;
}
/* Must clean dst_data cache */
arch_clean_cache_range((addr_t)data, size);
/* Increase data buffer pointer. */
data += size;
/* Set interrupt callback */
dma_channel->irq_callback = sdrv_uart_dma_tx_handler;
dma_channel->irq_context = (void *)ctrl;
/* Configurate tx water level. */
uart_base->FCR0.WMLVL = 0U;
/* Update uart tranfer params. */
ctrl->dma_instance = dma_ctrl;
ctrl->tx_dmachannel = dma_channel;
ctrl->tx_ptr = data;
ctrl->tx_remain = 0U;
ctrl->tx_async_cb = tx_cb;
ctrl->tx_userparam = tx_userparam;
sdrv_dma_start_channel_xfer(dma_channel);
/* Enable rx dma interface. */
if (!sdrv_uart_dma_tx_ctrl(ctrl, true, SDRV_UART_OPERATION_TIMEOUT)) {
return Status_Timeout;
}
return Status_Success;
}
/**
* brief Handle uart rx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_rx_handler(uint32_t status, uint32_t param,
void *context)
{
sdrv_uart_t *uart_ctrl = (sdrv_uart_t *)context;
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(uart_ctrl->base);
if ((SDRV_DMA_ERR == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_ASYNC_MODE == uart_ctrl->rxtransfer_type)) {
/* Stop uart rx dma channel transfer */
sdrv_dma_stop_channel_xfer(uart_ctrl->rx_dmachannel);
uart_ctrl->bytes_rxcarried =
sdrv_dma_get_channel_xfer_bytes(uart_ctrl->rx_dmachannel);
sdrv_uart_dma_receive_abort(uart_ctrl);
if (uart_ctrl->rx_async_cb) {
uart_ctrl->rx_async_cb(uart_ctrl, SDRV_UART_RxDmaError,
uart_ctrl->rx_userparam);
}
}
if ((SDRV_DMA_COMPLETED == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_ASYNC_MODE == uart_ctrl->rxtransfer_type)) {
/* Stop uart rx dma channel transfer */
sdrv_dma_stop_channel_xfer(uart_ctrl->rx_dmachannel);
if (uart_ctrl->rx_remain > 0U) {
sdrv_uart_dma_receive_single(
uart_ctrl, uart_ctrl->rx_ptr, uart_ctrl->rx_remain,
uart_ctrl->rx_async_cb, uart_ctrl->rx_userparam,
uart_ctrl->dma_instance, uart_ctrl->rx_dmachannel,
uart_ctrl->rx_dmachannel->channel_id);
} else {
uart_ctrl->bytes_rxcarried =
sdrv_dma_get_channel_xfer_bytes(uart_ctrl->rx_dmachannel);
sdrv_dma_clear_channel_xfer_bytes(uart_ctrl->rx_dmachannel);
/* Disable uart rx dma interface. */
sdrv_uart_dma_rx_ctrl(uart_ctrl, false,
SDRV_UART_OPERATION_TIMEOUT);
uart_ctrl->rx_state = Transfer_RxIdle;
uart_ctrl->rxtransfer_type = SDRV_TRANSFER_NO_MODE;
/* Configurate rx water level. */
uart_base->FCR1.WMLVL = 0U;
if (uart_ctrl->rx_async_cb) {
uart_ctrl->rx_async_cb(uart_ctrl, SDRV_UART_RxDmaDone,
uart_ctrl->rx_userparam);
}
}
}
}
/**
* brief Handle uart tx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_tx_handler(uint32_t status, uint32_t param,
void *context)
{
sdrv_uart_t *uart_ctrl = (sdrv_uart_t *)context;
sdrv_uart_regs_t *uart_base = (sdrv_uart_regs_t *)(uart_ctrl->base);
if ((SDRV_DMA_ERR == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_ASYNC_MODE == uart_ctrl->txtransfer_type)) {
sdrv_uart_dma_transmit_abort(uart_ctrl);
if (uart_ctrl->tx_async_cb) {
uart_ctrl->tx_async_cb(uart_ctrl, SDRV_UART_TxDmaError,
uart_ctrl->tx_userparam);
}
} else if ((SDRV_DMA_COMPLETED == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_ASYNC_MODE == uart_ctrl->txtransfer_type)) {
/* Stop uart tx dma channel transfer */
sdrv_dma_stop_channel_xfer(uart_ctrl->tx_dmachannel);
if (uart_ctrl->tx_remain > 0U) {
sdrv_uart_dma_transmit_single(
uart_ctrl, uart_ctrl->tx_ptr, uart_ctrl->tx_remain,
uart_ctrl->tx_async_cb, uart_ctrl->tx_userparam,
uart_ctrl->dma_instance, uart_ctrl->tx_dmachannel,
uart_ctrl->tx_dmachannel->channel_id);
} else {
/* Disable uart tx dma interface. */
sdrv_uart_dma_tx_ctrl(uart_ctrl, false,
SDRV_UART_OPERATION_TIMEOUT);
uart_ctrl->tx_state = Transfer_TxIdle;
uart_ctrl->txtransfer_type = SDRV_TRANSFER_NO_MODE;
/* Configurate Tx water level. */
uart_base->FCR0.WMLVL = 0U;
if (uart_ctrl->tx_async_cb) {
uart_ctrl->tx_async_cb(uart_ctrl, SDRV_UART_TxDmaDone,
uart_ctrl->tx_userparam);
}
}
}
}
/**
* brief Handle uart rx dma interrupt during transfer.
*
* param[in] status Dma event status.
* param[in] param User param.
* param[in] context The uart controller entity.
*/
static void sdrv_uart_dma_rx_realtime_handler(uint32_t status, uint32_t param,
void *context)
{
sdrv_uart_t *uart_ctrl = (sdrv_uart_t *)context;
uart_ctrl->bytes_rxcarried =
sdrv_dma_get_channel_xfer_bytes(uart_ctrl->rx_dmachannel);
if ((SDRV_DMA_ERR == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_REALTIME_MODE == uart_ctrl->rxtransfer_type)) {
/* Abort uart rx dma channel transfer */
sdrv_uart_dma_receive_abort(uart_ctrl);
if (uart_ctrl->rx_async_cb) {
uart_ctrl->rx_async_cb(uart_ctrl, SDRV_UART_RxDmaError,
uart_ctrl->rx_userparam);
}
}
if ((SDRV_DMA_COMPLETED == (sdrv_dma_status_e)status) &&
(SDRV_TRANSFER_DMA_REALTIME_MODE == uart_ctrl->rxtransfer_type)) {
/* The user's buffer is full. */
if (uart_ctrl->rx_remain <= uart_ctrl->bytes_rxcarried) {
sdrv_uart_dma_receive_abort(uart_ctrl);
if (uart_ctrl->rx_async_cb) {
uart_ctrl->rx_async_cb(uart_ctrl, SDRV_UART_RxBufferFull,
uart_ctrl->rx_userparam);
}
}
}
}
#endif
/*************************Static Functions End*****************************/