/** * @file sdrv_uart.c * @brief sdrv uart driver source. * * @copyright Copyright (c) 2020 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #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*****************************/