blob: ea885332084f6a5c04f444a6a4a7a8d5f445c111 [file] [log] [blame]
/**
* \addtogroup BSP
* \{
* \addtogroup DEVICES
* \{
* \addtogroup UART
* \{
* \brief UART Controller
*/
/**
*****************************************************************************************
*
* @file hw_uart.h
*
* @brief Definition of API for the UART Low Level Driver.
*
* Copyright (c) 2016, Dialog Semiconductor
* All rights reserved.
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*****************************************************************************************
*/
#ifndef HW_UART_H_
#define HW_UART_H_
#if dg_configUSE_HW_UART
#include <stdbool.h>
#include <stdint.h>
#include <sdk_defs.h>
#include "hw_dma.h"
#ifndef HW_UART_USE_DMA_SUPPORT
# define HW_UART_USE_DMA_SUPPORT 1
#endif
#define UBA(id) ((UART2_Type *)id)
#define HW_UART1 ((uint16_t *)UART_BASE)
#define HW_UART2 ((uint16_t *)UART2_BASE)
typedef uint16_t * HW_UART_ID;
/**
* \brief Get the mask of a field of a UART register.
*
* \param [in] instance identifies the UART instance to use (empty: UART, 2: UART2)
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
* \note The stripped register name should be provided, e.g.:
* - to get UART_UART_USR_REG_UART_BUSY_Msk, use
* HW_UART_REG_FIELD_MASK(, USR, UART_BUSY)
* - to get UART2_UART2_SFE_REG_UART_SHADOW_FIFO_ENABLE_Msk, use
* HW_UART_REG_FIELD_MASK(2, SFE, UART_SHADOW_FIFO_ENABLE)
*
*/
#define HW_UART_REG_FIELD_MASK(instance, reg, field) \
(UART##instance##_UART##instance##_##reg##_REG_##field##_Msk)
/**
* \brief Get the bit position of a field of a UART register.
*
* \param [in] instance identifies the UART instance to use (empty: UART, 2: UART2)
* \param [in] reg is the register to access
* \param [in] field is the register field to access
*
* \note The stripped register name should be provided, e.g.:
* - to get UART_UART_USR_REG_UART_BUSY_Pos, use
* HW_UART_REG_FIELD_POS(, USR, UART_BUSY)
* - to get UART2_UART2_SFE_REG_UART_SHADOW_FIFO_ENABLE_Pos, use
* HW_UART_REG_FIELD_POS(2, SFE, UART_SHADOW_FIFO_ENABLE)
*
*/
#define HW_UART_REG_FIELD_POS(instance, reg, field) \
(UART##instance##_UART##instance##_##reg##_REG_##field##_Pos)
/**
* \brief Get the value of a field of a UART register.
*
* \param [in] id identifies UART to use
* \param [in] reg is the register to access
* \param [in] field is the register field to write
*
* \return the value of the register field
*
*/
#define HW_UART_REG_GETF(id, reg, field) \
((UBA(id)->UART2_##reg##_REG & (UART2_UART2_##reg##_REG_##field##_Msk)) >> (UART2_UART2_##reg##_REG_##field##_Pos))
/**
* \brief Set the value of a field of a UART register.
*
* \param [in] id identifies UART to use
* \param [in] reg is the register to access
* \param [in] field is the register field to write
* \param [in] new_val is the value to write
*
*/
#define HW_UART_REG_SETF(id, reg, field, new_val) \
UBA(id)->UART2_##reg##_REG = ((UBA(id)->UART2_##reg##_REG & ~(UART2_UART2_##reg##_REG_##field##_Msk)) | \
((UART2_UART2_##reg##_REG_##field##_Msk) & ((new_val) << (UART2_UART2_##reg##_REG_##field##_Pos))))
/*
* ENUMERATION DEFINITIONS
*****************************************************************************************
*/
/**
* \brief Interrupt Identification codes
*
*/
typedef enum {
HW_UART_INT_MODEM_STAT = 0,
HW_UART_INT_NO_INT_PEND = 1,
HW_UART_INT_THR_EMPTY = 2,
HW_UART_INT_RECEIVED_AVAILABLE = 4,
HW_UART_INT_RECEIVE_LINE_STAT = 6,
HW_UART_INT_BUSY_DETECTED = 7,
HW_UART_INT_TIMEOUT = 12,
} HW_UART_INT;
/**
* \brief Baud rates dividers
*
* The defined values comprise the values of 3 registers: DLH, DLL, DLF.
* The encoding of the values for each register is:
*
* +--------+--------+--------+--------+
* | unused | DLH | DLL | DLF |
* +--------+--------+--------+--------+
*
*/
typedef enum {
HW_UART_BAUDRATE_1000000 = 0x00000100,
HW_UART_BAUDRATE_500000 = 0x00000200,
HW_UART_BAUDRATE_230400 = 0x00000405,
HW_UART_BAUDRATE_115200 = 0x0000080b,
HW_UART_BAUDRATE_57600 = 0x00001106,
HW_UART_BAUDRATE_38400 = 0x00001a01,
HW_UART_BAUDRATE_28800 = 0x0000220c,
HW_UART_BAUDRATE_19200 = 0x00003401,
HW_UART_BAUDRATE_14400 = 0x00004507,
HW_UART_BAUDRATE_9600 = 0x00006803,
HW_UART_BAUDRATE_4800 = 0x0000d005,
} HW_UART_BAUDRATE;
/**
* \brief Character format
*
*/
typedef enum {
HW_UART_DATABITS_5 = 0,
HW_UART_DATABITS_6 = 1,
HW_UART_DATABITS_7 = 2,
HW_UART_DATABITS_8 = 3,
} HW_UART_DATABITS;
/**
* \brief Parity
*
*/
typedef enum {
HW_UART_PARITY_NONE = 0,
HW_UART_PARITY_ODD = 1,
HW_UART_PARITY_EVEN = 3,
} HW_UART_PARITY;
/**
* \brief Stop bits
*
*/
typedef enum {
HW_UART_STOPBITS_1 = 0,
/**< The number of stop bits is 1.5 if a character format with 5 bit is chosen */
HW_UART_STOPBITS_2 = 1, /**< Stop bit 2 */
} HW_UART_STOPBITS;
/**
* \brief UART configuration structure definition
*
*/
typedef struct {
// Baud rate divisor
HW_UART_BAUDRATE baud_rate;
HW_UART_DATABITS data:2;
HW_UART_PARITY parity:2;
HW_UART_STOPBITS stop:1;
uint8_t auto_flow_control:1;
uint8_t use_dma:1;
uint8_t use_fifo:1;
HW_DMA_CHANNEL tx_dma_channel:4;
HW_DMA_CHANNEL rx_dma_channel:4;
} uart_config;
/**
* \brief UART configuration structure definition (extended version)
*
*/
typedef struct {
// Baud rate divisor
HW_UART_BAUDRATE baud_rate;
HW_UART_DATABITS data:2;
HW_UART_PARITY parity:2;
HW_UART_STOPBITS stop:1;
uint8_t auto_flow_control:1;
uint8_t use_dma:1;
uint8_t use_fifo:1;
uint8_t tx_fifo_tr_lvl:2;
uint8_t rx_fifo_tr_lvl:2;
HW_DMA_CHANNEL tx_dma_channel:4;
HW_DMA_CHANNEL rx_dma_channel:4;
} uart_config_ex;
#ifdef HW_UART_ENABLE_USER_ISR
/**
* \brief User defined interrupt function
*
* User code does not need to handle interrupts. Interrupts are handled by the driver.
* If for some reason the user need to handle interrupts differently it is possible to
* set a different ISR via hw_uart_set_isr(uart_id, user_isr).
* In that case, the user-defined ISR must handle all UART interrupts as required.
*
* \sa hw_uart_set_isr
*
*/
typedef void (*hw_uart_interrupt_isr)(void);
/**
* \brief Setup user defined interrupt function for uart
*
* \param [in] uart identifies UART
* \param [in] isr user defined interrupt handler
*
*/
void hw_uart_set_isr(HW_UART_ID uart, hw_uart_interrupt_isr isr);
#endif
typedef void (*hw_uart_tx_callback)(void *user_data, uint16_t written);
typedef void (*hw_uart_rx_callback)(void *user_data, uint16_t read);
//======================= Status functions ====================================
/**
* \brief Check if a serial transfer is inprogress
*
* \return true or false
*/
static inline bool hw_uart_is_busy(HW_UART_ID uart)
{
return HW_UART_REG_GETF(uart, USR, UART_BUSY);
}
//===================== Read/Write functions ===================================
/**
* \brief Read one byte from UART
*
* This is blocking function to read single byte from UART.
* UART must be enabled before.
*
* \param [in] uart identifies UART to use
*
* \return the received byte
*
*/
uint8_t hw_uart_read(HW_UART_ID uart);
/**
* \brief Write one byte to UART
*
* Function wait till output FIFO has empty space according to
* threshold level, and puts byte to be transmitted.
*
* \param [in] uart identifies UART to use
* \param [in] data byte to be written
*
*/
void hw_uart_write(HW_UART_ID uart, uint8_t data);
/**
* \brief Stop asynchronous read from UART
*
* If there is outstanding read on given UART it will be stopped.
* Callback will be fired with data already present in buffer.
* Callback may be called from interrupt in the meantime but will be called
* only once.
*
* \param [in] uart identifies UART to use
*
* \return number of bytes actually received
*
*/
uint16_t hw_uart_abort_receive(HW_UART_ID uart);
/**
* \brief Get number of bytes currently received by asynchronous read
*
* If there is outstanding read on given UART function returns number of
* byte currently received.
*
* \param [in] uart identifies UART to use
*
*/
uint16_t hw_uart_peek_received(HW_UART_ID uart);
/**
* \brief Read receive buffer register
*
* \param [in] uart identifies UART to use
*
* \return the read byte
*
*/
static inline uint8_t hw_uart_rxdata_getf(HW_UART_ID uart)
{
// Read element from the receive FIFO
return UBA(uart)->UART2_RBR_THR_DLL_REG;
}
/**
* \brief Write byte to the transmit holding register
*
* \param [in] uart identifies UART to use
* \param [in] data byte to be written
*
*/
static inline void hw_uart_txdata_setf(HW_UART_ID uart, uint8_t data)
{
// Write data to the transmit FIFO
UBA(uart)->UART2_RBR_THR_DLL_REG = data;
}
/**
* \brief Writes number of bytes to UART synchronously
*
* This function finishes when all data is put in FIFO. It does not wait for data to be transmitted
* out from UART. Call \sa hw_uart_is_tx_fifo_empty() to wait for transmission to finish.
* This function does not use interrupts nor DMA.
*
* \param [in] uart identifies UART to use
* \param [in] data data to be written
* \param [in] len length of to be written
*
*/
void hw_uart_write_buffer(HW_UART_ID uart, const void *data, uint16_t len);
/**
* \brief Writes number of bytes to UART
*
* \param [in] uart identifies UART to use
* \param [in] data data to be written
* \param [in] len length of to be written
* \param [in] cb function to call from interrupt when transmission ends
* \param [in] user_data parameter passed to cb function
*
*/
void hw_uart_send(HW_UART_ID uart, const void *data, uint16_t len, hw_uart_tx_callback cb,
void *user_data);
/**
* \brief Read number of bytes from UART synchronously
*
* This function waits to receive \p len bytes from UART.
* This function does not use interrupts not DMA, it just waits for all data to arive.
*
* \param [in] uart identifies UART to use
* \param [out] data buffer for incoming data
* \param [in] len number of bytes to read
*
*/
void hw_uart_read_buffer(HW_UART_ID uart, void *data, uint16_t len);
/**
* \brief Read number of bytes from UART
*
* Function initializes UART for receiving data.
* When \p len data is received or timeout occurs user provided callback will be fired with
* number of bytes read so far.
*
* \param [in] uart identifies UART to use
* \param [out] data buffer for incoming data
* \param [in] len max number of bytes to read
* \param [in] cb function to call from interrupt when data is received
* \param [in] user_data parameter passed to cb function
*
*/
void hw_uart_receive(HW_UART_ID uart, void *data, uint16_t len, hw_uart_rx_callback cb,
void *user_data);
#if HW_UART_USE_DMA_SUPPORT
/**
* \brief Assign DMA channel to UART rx and tx
*
* Function specifies DMA channel to use for specified UART rx and tx FIFO.
* It will setup channel only if there is no transmission in progress.
*
* \param [in] uart identifies UART to use
* \param [in] channel id of DMA channel to use for rx,
* tx will use next channel,
* -1 if DMA should not be used
* \param [in] pri priority DMA_PRIO_0 (lowest),
* .....
* DMA_PRIO_7 (highest)
*
*/
void hw_uart_set_dma_channels(HW_UART_ID uart, int8_t channel, HW_DMA_PRIO pri);
/**
* \brief Assign DMA channel to UART rx and tx
*
* Function specifies DMA channel to use for specified UART rx and tx FIFO.
* It will setup channel only if there is no transmission in progress.
*
* \param [in] uart identifies UART to use
* \param [in] tx_channel id of DMA channel to use for tx:
* HW_DMA_CHANNEL_0..HW_DMA_CHANNEL_INVALID
* \param [in] rx_channel id of DMA channel to use for rx:
* HW_DMA_CHANNEL_0..HW_DMA_CHANNEL_INVALID
* \param [in] pri priority DMA_PRIO_0 (lowest),
* .....
* DMA_PRIO_7 (highest)
*
*/
void hw_uart_set_dma_channels_ex(HW_UART_ID uart, int8_t tx_channel, int8_t rx_channel, HW_DMA_PRIO pri);
#endif
//============== Interrupt handling ============================================
/**
* \brief Set the Received Data Available interrupt
*
* \param [in] uart identifies UART to use
* \param [in] recdataavail should be 0 to disable and 1 to enable
*
*/
static inline void hw_uart_rec_data_int_set(HW_UART_ID uart, uint8_t recdataavail)
{
// Set ERBFI bit in Interrupt Enable Register
HW_UART_REG_SETF(uart, IER_DLH, ERBFI_dlh0, recdataavail);
}
/**
* \brief Set the Transmit Holding Register empty interrupt
*
* \param [in] uart identifies UART to use
* \param [in] txempty should be 0 to disable and 1 to enable
*
*/
static inline void hw_uart_tx_empty_int_set(HW_UART_ID uart, uint8_t txempty)
{
// Set ETBEI bit in Interrupt Enable Register
HW_UART_REG_SETF(uart, IER_DLH, ETBEI_dlh1, txempty);
}
/**
* \brief Set the Line Status interrupt
*
* \param [in] uart identifies UART to use
* \param [in] linestat should be 0 to disable and 1 to enable
*
*/
static inline void hw_uart_linestat_int_set(HW_UART_ID uart, uint8_t linestat)
{
// Set ELSI bit in Interrupt Enable Register
HW_UART_REG_SETF(uart, IER_DLH, ELSI_dhl2, linestat);
}
/**
* \brief Set the Programmable THRE interrupt
*
* \param [in] uart identifies UART to use
* \param [in] pthre should be 0 to disable and 1 to enable
*
*/
static inline void hw_uart_pthre_int_set(HW_UART_ID uart, uint8_t pthre)
{
// Set PTIME bit in Interrupt Enable Register
HW_UART_REG_SETF(uart, IER_DLH, PTIME_dlh7, pthre);
}
/**
* \brief Get the Interrupt ID
*
* \param [in] uart identifies UART to use
*
* \return interrupt type
*
*/
static inline HW_UART_INT hw_uart_get_interrupt_id(HW_UART_ID uart)
{
return (HW_UART_INT) (UBA(uart)->UART2_IIR_FCR_REG & 0xF);
}
/**
* \brief Write Scratch pad register
*
* \param [in] uart identifies UART to use
* \param [in] value the value to be written
*
* /warning Reserved when retarget is used else it is free to use.
*
*/
static inline void hw_uart_write_scr(HW_UART_ID uart, uint8_t value)
{
UBA(uart)->UART2_SCR_REG = value;
}
/**
* \brief Read Scratch pad register
*
* \param [in] uart identifies UART to use
*
* \return register value
*
* \warning Reserved when retarget is used else it is free to use.
*
*/
static inline uint8_t hw_uart_read_scr(HW_UART_ID uart)
{
return UBA(uart)->UART2_SCR_REG;
}
//==================== Configuration functions =================================
/**
* \brief Get the baud rate setting
*
* \param [in] uart identifies UART to use
*
* \return baud rate of specified uart
*
*/
HW_UART_BAUDRATE hw_uart_baudrate_get(HW_UART_ID uart);
/**
* \brief Set the baud rate
*
* \param [in] uart identifies UART to use
* \param [in] baud_rate uart baud rate
*
*/
void hw_uart_baudrate_set(HW_UART_ID uart, HW_UART_BAUDRATE baud_rate);
//=========================== FIFO control functions ===========================
/**
* \brief Check if there is data available for read
*
* \param [in] uart identifies UART to use
*
* \return true if there is data to receive
*
*/
static inline bool hw_uart_is_data_ready(HW_UART_ID uart)
{
return (UBA(uart)->UART2_LSR_REG & 1) != 0;
}
/**
* \brief Get the FIFO mode setting
*
* \param [in] uart identifies UART to use
*
* \return true if FIFO is enabled (both transmitter and receiver)
*
*/
static inline bool hw_uart_is_fifo_enabled(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return UART2->UART2_SFE_REG != 0;
}
/**
* \brief Disable both FIFOs
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_disable_fifo(HW_UART_ID uart)
{
uint16_t iir_fcr_reg = UBA(uart)->UART2_IIR_FCR_REG;
iir_fcr_reg &= 0xfffe;
UBA(uart)->UART2_IIR_FCR_REG = iir_fcr_reg;
}
/**
* \brief Enable both FIFOs
*
* Thresholds should be set before for predictable results.
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_enable_fifo(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
UART2->UART2_SFE_REG = 1 << HW_UART_REG_FIELD_POS(2, SFE, UART_SHADOW_FIFO_ENABLE);
}
/**
* \brief Check if receive FIFO is not empty
*
* \param [in] uart identifies UART to use
*
* \return true if FIFO is not empty
*
*/
static inline bool hw_uart_receive_fifo_not_empty(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return HW_UART_REG_GETF(uart, USR, UART_RFNE) != 0;
}
/**
* \brief Check if transmit FIFO is not full
*
* \param [in] uart identifies UART to use
*
* \return true if FIFO is full
*
*/
static inline bool hw_uart_transmit_fifo_not_full(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return HW_UART_REG_GETF(uart, USR, UART_TFNF) != 0;
}
/**
* \brief Check if transmit FIFO is empty
*
* \param [in] uart identifies UART to use
*
* \return true if FIFO empty
*
*/
static inline bool hw_uart_transmit_fifo_empty(HW_UART_ID uart)
{
return HW_UART_REG_GETF(uart, USR, UART_TFE) != 0;
}
/**
* \brief Read number of byte in receive FIFO
*
* \param [in] uart identifies UART to use
*
* \return number of byte in receive FIFO
*
*/
static inline uint16_t hw_uart_receive_fifo_count(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return UART2->UART2_RFL_REG;
}
/**
* \brief Read number of byte in transmit FIFO
*
* \param [in] uart identifies UART to use
*
* \return number of byte in transmit FIFO
*
*/
static inline uint16_t hw_uart_transmit_fifo_count(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return UART2->UART2_TFL_REG;
}
/**
* \brief Enable loopback
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_enable_loopback(HW_UART_ID uart)
{
HW_UART_REG_SETF(uart, MCR, UART_LB, 1);
}
/**
* \brief Disable loopback
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_disable_loopback(HW_UART_ID uart)
{
HW_UART_REG_SETF(uart, MCR, UART_LB, 0);
}
/**
* \brief Get the FIFO mode setting
*
* \param [in] uart identifies UART to use
*
* \return the FIFO mode that has been set in the FIFO Control Register:
* 0 = FIFO mode disabled,
* 1 = FIFO mode enabled
*
*/
uint8_t hw_uart_fifo_en_getf(HW_UART_ID uart);
/**
* \brief Enable or disable the UART FIFO mode
*
* \param [in] uart identifies UART to use
* \param [in] en should be 0 to disable and 1 to enable FIFO mode
*
*/
static inline void hw_uart_fifo_en_setf(HW_UART_ID uart, uint8_t en)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
// Write FIFO Enable (FIFOE) bit in FIFO Control Register
uint16_t iir_fcr_reg = UBA(uart)->UART2_IIR_FCR_REG;
iir_fcr_reg &= ~0x1;
iir_fcr_reg |= (en & 0x1);
UBA(uart)->UART2_IIR_FCR_REG = iir_fcr_reg;
}
/**
* \brief Get the receive FIFO trigger level at which the
* Received Data Available Interrupt is generated
*
* \param [in] uart identifies UART to use
*
* \return the receive FIFO trigger level:
* 0 = 1 character in the FIFO,
* 1 = FIFO 1/4 full,
* 2 = FIFO 1/2 full,
* 3 = FIFO 2 less than full
*
*/
static inline uint8_t hw_uart_rx_fifo_tr_lvl_getf(HW_UART_ID uart)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
return UART2->UART2_SRT_REG & UART2_UART2_SRT_REG_UART_SHADOW_RCVR_TRIGGER_Msk;
}
/**
* \brief Set the receive FIFO trigger level at which the
* Received Data Available Interrupt is generated
*
* \param [in] uart identifies UART to use
* \param [in] tr_lvl The receive FIFO trigger level:
* 0 = 1 character in the FIFO,
* 1 = FIFO 1/4 full,
* 2 = FIFO 1/2 full,
* 3 = FIFO 2 less than full
*
*/
static inline void hw_uart_rx_fifo_tr_lvl_setf(HW_UART_ID uart, uint8_t tr_lvl)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
UART2->UART2_SRT_REG = tr_lvl;
}
/**
* \brief Get the transmit FIFO trigger level at which the
* Transmit Holding Register Empty (THRE) Interrupt is generated
*
* \param [in] uart identifies UART to use
*
* \return the transmit FIFO trigger level:
* 0 = FIFO empty,
* 1 = 2 characters in the FIFO,
* 2 = FIFO 1/4 full,
* 3 = FIFO 1/2 full
*
*/
uint8_t hw_uart_tx_fifo_tr_lvl_getf(HW_UART_ID uart);
/**
* \brief Set the transmit FIFO trigger level at which the
* Transmit Holding Register Empty (THRE) Interrupt is generated
*
* \param [in] uart identifies UART to use
* \param [in] tr_lvl the transmit FIFO trigger level:
* 0 = FIFO empty,
* 1 = 2 characters in the FIFO,
* 2 = FIFO 1/4 full,
* 3 = FIFO 1/2 full
*
*/
static inline void hw_uart_tx_fifo_tr_lvl_setf(HW_UART_ID uart, uint8_t tr_lvl)
{
/* Only UART2 has a FIFO */
ASSERT_ERROR(uart == HW_UART2);
UART2->UART2_STET_REG = tr_lvl;
}
/**
* \brief Reset UART transmit FIFO
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_tx_fifo_flush(HW_UART_ID uart)
{
HW_UART_REG_SETF(uart, SRR, UART_XFR, 1);
}
/**
* \brief Reset UART receive FIFO
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_rx_fifo_flush(HW_UART_ID uart)
{
HW_UART_REG_SETF(uart, SRR, UART_RFR, 1);
}
/**
* \brief Check whether reading buffer is empty
*
* Works for both when Rx FIFO is enabled or not.
*
* \param [in] uart identifies UART to use
*
* \return true if there is no data available for reading
*
*/
static inline bool hw_uart_read_buf_empty(HW_UART_ID uart)
{
return !HW_UART_REG_GETF(uart, LSR, UART_DR);
}
/**
* \brief Check whether writing buffer is full
*
* Works for both when Tx FIFO is enabled or not.
*
* \param [in] uart identifies UART to use
*
* \return true if transmit buffer is full
*
*/
static inline bool hw_uart_write_buf_full(HW_UART_ID uart)
{
return !HW_UART_REG_GETF(uart, LSR, UART_THRE);
}
#if dg_configUART_SOFTWARE_FIFO
/**
* \brief Set buffer that will be use for incoming data when there is no read in progress
*
* \param [in] uart identifies UART to use
* \param [in] buf buffer to use as software FIFO
* \param [in] size size of \p buf
*
*/
void hw_uart_set_soft_fifo(HW_UART_ID uart, uint8_t *buf, uint8_t size);
#endif
//=========================== DMA control functions ============================
/**
* \brief Set UART DMA mode
*
* \param [in] uart identifies UART to use
* \param [in] dma_mode DMA mode 0 or 1
*
*/
static inline void hw_uart_dma_mode_setf(HW_UART_ID uart, uint8_t dma_mode)
{
/* Only UART2 has the SDMAM register */
ASSERT_ERROR(uart == HW_UART2);
UART2->UART2_SDMAM_REG = ((dma_mode & 1) << UART2_UART2_SDMAM_REG_UART_SHADOW_DMA_MODE_Pos)
<< UART2_UART2_SDMAM_REG_UART_SHADOW_DMA_MODE_Msk;
}
/**
* \brief Clear DMA request
*
* \param [in] uart identifies UART to use
*
*/
static inline void hw_uart_clear_dma_request(HW_UART_ID uart)
{
UBA(uart)->UART2_DMASA_REG = 1;
}
//=========================== Line control functions ============================
/**
* \brief Set UART line settings
*
* This function initialize UART registers with given configuration.
* It also initializes all internal software variables for buffered transmissions.
*
* \param [in] uart identifies UART to use
* \param [in] cfg pointer to the UART configuration structure
*
*/
void hw_uart_init(HW_UART_ID uart, const uart_config *cfg);
/**
* \brief Set UART line settings
*
* This function initialize UART registers with given configuration,
* including tx and rx fifo trigger levels
* It also initializes all internal software variables for buffered transmissions.
*
* \param [in] uart identifies UART to use
* \param [in] cfg pointer to the UART configuration structure
*
*/
void hw_uart_init_ex(HW_UART_ID uart, const uart_config_ex *cfg);
/**
* \brief Re-initialize UART registers
*
* Call this function with configuration that should be re-applied, this function should be
* called after platform exits power sleep mode.
* This function is similar to uart_init, but it does not initialize software variables
* used for transmission control it just re-applies hardware configuration.
* It will turn on interrupts if transmission was in progress.
*
* \param [in] uart identifies UART to use
* \param [in] cfg pointer to the UART configuration structure
*
*/
void hw_uart_reinit(HW_UART_ID uart, const uart_config *cfg);
/**
* \brief Re-initialize UART registers
*
* Call this function with configuration that should be re-applied, this function should be
* called after platform exits power sleep mode.
* This function is similar to uart_init_ex, but it does not initialize software variables
* used for transmission control it just re-applies hardware configuration.
* It will turn on interrupts if transmission was in progress.
*
* \param [in] uart identifies UART to use
* \param [in] cfg pointer to the UART configuration structure
*
*/
void hw_uart_reinit_ex(HW_UART_ID uart, const uart_config_ex *cfg);
/**
* \brief Get UART line settings
*
* \param [in] uart identifies UART to use
* \param [in] cfg pointer to the UART configuration structure
*/
void hw_uart_cfg_get(HW_UART_ID uart, uart_config *cfg);
//=========================== Modem control functions ==========================
/**
* \brief Get the IrDA SIR mode setting
*
* \param [in] uart identifies UART to use
*
* \return IrDA SIR mode:
* 0 = IrDA SIR mode disabled,
* 1 = IrDA SIR mode enabled
*
*/
uint8_t hw_uart_sire_getf(HW_UART_ID uart);
/**
* \brief Set the IrDA SIR mode
*
* \param [in] uart identifies UART to use
* \param [in] sire 0 = disable IrDA SIR mode,
* 1 = enable IrDA SIR mode
*
*/
void hw_uart_sire_setf(HW_UART_ID uart, uint8_t sire);
/**
* \brief Get the Auto Flow Control Enable (AFCE) setting
*
* \param [in] uart identifies UART to use
*
* \return Auto Flow Control Enable (AFCE):
* 0 = Auto Flow Control Mode disabled,
* 1 = Auto Flow Control Mode enabled
*
*/
uint8_t hw_uart_afce_getf(HW_UART_ID uart);
/**
* \brief Enable or disable Auto Flow Control
*
* \param [in] uart identifies UART to use
* \param [in] afce Auto Flow Control Enable (AFCE):
* 0 = disable Auto Flow Control Mode,
* 1 = enable Auto Flow Control Mode
*
*/
void hw_uart_afce_setf(HW_UART_ID uart, uint8_t afce);
/**
* \brief Get UART diagnostic mode status
*
* \param [in] uart identifies UART to use
*
* \return the value of the loop back bit
*
*/
uint8_t hw_uart_loopback_getf(HW_UART_ID uart);
/**
* \brief Set UART in diagnostic mode
*
* \param [in] uart identifies UART to use
* \param [in] lb loop back bit value
*
*/
void hw_uart_loopback_setf(HW_UART_ID uart, uint8_t lb);
/**
* \brief Get RTS output value
*
* \param [in] uart identifies UART to use
*
* \return RTS output value
*
*/
uint8_t hw_uart_rts_getf(HW_UART_ID uart);
/**
* \brief Set RTS output value
*
* \param [in] uart identifies UART to use
* \param [in] rtsn Value for the RTS output (asserted low)
*
*/
void hw_uart_rts_setf(HW_UART_ID uart, uint8_t rtsn);
//=========================== Line status functions ============================
/**
* \brief Get the value of the Receiver FIFO Error bit
*
* \param [in] uart identifies UART to use
*
* \return receiver FIFO Error bit value:
* 0 = no error in RX FIFO,
* 1 = error in RX FIFO
*
*/
uint8_t hw_uart_rx_fifo_err_getf(HW_UART_ID uart);
/**
* \brief Get the value of the Transmitter Empty bit
*
* \param [in] uart identifies UART to use
*
* \return 1 if transmitter FIFO is empty
*
*/
uint8_t hw_uart_is_tx_fifo_empty(HW_UART_ID uart);
/**
* \brief Get the value of the Transmit Holding Register Empty bit
*
* \param [in] uart identifies UART to use
*
* \return the Transmit Holding Register Empty bit value
*
*/
uint8_t hw_uart_thr_empty_getf(HW_UART_ID uart);
/**
* \brief Get the value of the Break Interrupt bit
*
* \param [in] uart identifies UART to use
*
* \return break interrupt bit value: This is used to indicate the detection of a
* break sequence on the serial input data
*
*/
uint8_t hw_uart_break_int_getf(HW_UART_ID uart);
/**
* \brief Get the value of the Framing Error bit
*
* \param [in] uart identifies UART to use
*
* \return framing error bit value:
* 0 = no framing error,
* 1 = framing error
*
*
*/
uint8_t hw_uart_frame_err_getf(HW_UART_ID uart);
/**
* \brief Get the value of the Parity Error bit
*
* \param [in] uart identifies UART to use
*
* \return parity error bit value:
* 0 = no parity error,
* 1 = parity error
*
*/
uint8_t hw_uart_parity_err_getf(HW_UART_ID uart);
/**
* \brief Get the value of the Overrun Error bit
*
* \param [in] uart identifies UART to use
*
* \return overrun error bit value:
* 0 = no overrun error,
* 1 = overrun error
*
*/
uint8_t hw_uart_overrun_err_getf(HW_UART_ID uart);
//=========================== Modem status functions ===========================
/**
* \brief Get CTS input status
*
* \param [in] uart identifies UART to use
*
* \return status of CTS input:
* 0 = CTSn input is de-asserted (logic 1),
* 1 = CTSn input is asserted (logic 0),
* In loopback mode, CTS is the same as RTS
*
*/
uint8_t hw_uart_cts_getf(HW_UART_ID uart);
/**
* \brief Get Delta CTS
*
* \param [in] uart identifies UART to use
*
* \return DCTS:
* 0 = No change on CTS since last read of Modem Control Register,
* 1 = Change on CTS since last read of Modem Control Register,
* Note that calling this function will clear the DCTS bit,
* In loopback mode, DCTS reflects changes on RTS
*
*/
uint8_t hw_uart_delta_cts_getf(HW_UART_ID uart);
/**
* \brief Check if buffered write is in progress
*
* \param [in] uart identifies UART to use
*
* \return true if there is TX transmission in progress
*
*/
bool hw_uart_tx_in_progress(HW_UART_ID uart);
/**
* \brief Check if buffered read is in progress
*
* \param [in] uart identifies UART to use
*
* \return true if there is RX transmission in progress
*
*/
bool hw_uart_rx_in_progress(HW_UART_ID uart);
#if dg_configUART_RX_CIRCULAR_DMA
/**
* \brief Enable circular RX DMA for UART
*
* This reconfigures RX DMA channel to use circular buffer for incoming data and enabled it
* immediately. Incoming data will be read by DMA to intermediate buffer. Subsequent calls to
* hw_uart_receive() will fire callback as soon as enough data are available in buffer to be read,
* but the actual read from intermediate buffer has to be done using hw_uart_copy_rx_circular_dma_buffer().
*
* Recommended way to move between DMA buffer and user buffer is to call hw_uart_abort_receive()
* that will copy the amount specified on read or the actual number of received bytes if
* hw_uart_abort_receive() was called before requested the amount was received.
*
* \note
* This can be only called for an UART which is configured using \p dg_configUARTx_RX_CIRCULAR_DMA_BUF_SIZE.
*
* \param [in] uart identifies UART to use
*
*/
void hw_uart_enable_rx_circular_dma(HW_UART_ID uart);
/**
* \brief Copy data from circular RX DMA buffer to user buffer
*
* \param [in] uart identifies UART to use
* \param [in] buf buffer to copy data to
* \param [in] len length of data to copy to buffer
*
*/
void hw_uart_copy_rx_circular_dma_buffer(HW_UART_ID uart, uint8_t *buf, uint16_t len);
#endif /* dg_configUART_RX_CIRCULAR_DMA */
#endif /* dg_configUSE_HW_UART */
#endif /* HW_UART_H_ */
/**
* \}
* \}
* \}
*/