/***************************************************************************//**
* \file cyhal_uart.h
*
* \brief
* Provides a high level interface for interacting with the Infineon UART.
* This interface abstracts out the chip specific details. If any chip specific
* functionality is necessary, or performance is critical the low level functions
* can be used directly.
*
********************************************************************************
* \copyright
* Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
/**
* \addtogroup group_hal_uart UART (Universal Asynchronous Receiver-Transmitter)
* \ingroup group_hal
* \{
* High level interface for interacting with the Universal Asynchronous Receiver-Transmitter (UART).
*
* The Universal Asynchronous Receiver/Transmitter (UART) protocol is an
* asynchronous serial interface protocol. UART communication is typically
* point-to-point. The UART interface consists of two signals:
* * TX: Transmitter output
* * RX: Receiver input
*
* Additionally, two side-band signals are used to implement flow control in
* UART. Note that the flow control applies only to TX functionality.
* * Clear to Send (CTS): This is an input signal to the transmitter.
* When active, it indicates that the slave is ready for the master to
* transmit data.
* * Ready to Send (RTS): This is an output signal from the receiver. When
* active, it indicates that the receiver is ready to receive data
*
* Flow control can be configured by providing cts / rts pins to cyhal_uart_init() and this will activate the feature in
* driver. In case flow control enablement status needs to be changed, cyhal_uart_enable_flow_control() function
* can be used.
*
* The data frame size, STOP bits and parity can be configured via \ref cyhal_uart_cfg_t.
* The UART contains dedicated hardware buffers for transmit and receive. Optionally,
* either of these can be augmented with a software buffer. This is done in scope of \ref cyhal_uart_init (if appropriate
* configuration was selected) and \ref cyhal_uart_config_software_buffer functions.
*
* \note For applications that require printing messages on a UART terminal using printf(),
* the retarget-io utility library can be used directly.
*
* \section subsection_uart_features Features
* * Configurable UART baud rate - \ref cyhal_uart_set_baud
* * Configurable data frame size, STOP bits and parity - \ref cyhal_uart_cfg_t
* * Configurable interrupts and callback on UART events - \ref cyhal_uart_event_t
* \section subsection_uart_interrupts Interrupts and callbacks
* Interrupts are handled by callbacks based on events \ref cyhal_uart_event_t
* If an event is disabled, the underlying interrupt is still enabled. Enabling or disabling
* an event only enables or disables the callback.
* \note Care must be exercised when using the \ref CYHAL_UART_IRQ_RX_NOT_EMPTY event.
* The callback must read all available received data or the interrupt will not be cleared
* leading to the callback being immediately retriggered.
* \section subsection_uart_quickstart Quick Start
* \ref cyhal_uart_init is used for UART initialization
*
* \section subsection_uart_sample_snippets Code Snippets
*
* \subsection subsection_uart_snippet_1 Snippet 1: Initialization and Configuration
* The following snippet initializes the UART block and assigns the **tx**, **rx** pins and sets the baudrate.
*
* The snippet also shows how to use \ref cyhal_uart_write, \ref cyhal_uart_putc, \ref cyhal_uart_read API.
*
* \snippet hal_uart.c snippet_cyhal_uart_init
*
* \subsection subsection_uart_snippet_2 Snippet 2: Interrupts on UART events
*
* In the following snippet, UART events are handled in a callback function.
* The callback function has to be registered and then the events have to be enabled.
*
* \snippet hal_uart.c snippet_cyhal_uart_event
*
*/
#pragma once
#include
#include
#include "cy_result.h"
#include "cyhal_hw_types.h"
#if defined(__cplusplus)
extern "C" {
#endif
/****************************************************************
* Defines
*****************************************************************/
/** \addtogroup group_hal_results_uart UART HAL Results
* UART specific return codes
* \ingroup group_hal_results
* \{ *//**
*/
/** The requested resource type is invalid */
#define CYHAL_UART_RSLT_ERR_INVALID_PIN \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 0))
/** Failed to configure power management callback */
#define CYHAL_UART_RSLT_ERR_PM_CALLBACK \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 1))
/** The getc call timed out with no received data */
#define CY_RSLT_ERR_CSP_UART_GETC_TIMEOUT \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 2))
/** The actual baud rate is greater than 10% off the requested baud rate */
#define CY_RSLT_WRN_CSP_UART_BAUD_TOLERANCE \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_WARNING, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 3))
/** The requested configuration is not supported on the current hardware */
#define CYHAL_UART_RSLT_ERR_UNSUPPORTED_CONFIG \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 4))
/** The requested operation is not supported on the current hardware */
#define CYHAL_UART_RSLT_ERR_UNSUPPORTED_OPERATION \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 5))
/** Can't make changes in user-provided clock */
#define CYHAL_UART_RSLT_CLOCK_ERROR \
(CY_RSLT_CREATE_EX(CY_RSLT_TYPE_ERROR, CY_RSLT_MODULE_ABSTRACTION_HAL, CYHAL_RSLT_MODULE_UART, 6))
/**
* \}
*/
/** The baud rate to set to if no clock is specified in the init function */
#define CYHAL_UART_DEFAULT_BAUD 115200
/** The maximum allowable difference between baud requested and actual baud **/
#define CYHAL_UART_MAX_BAUD_PERCENT_DIFFERENCE 10
/****************************************************************
* Enumerations
*****************************************************************/
/** UART Parity */
typedef enum
{
CYHAL_UART_PARITY_NONE, /**< UART has no parity check */
CYHAL_UART_PARITY_EVEN, /**< UART has even parity check */
CYHAL_UART_PARITY_ODD, /**< UART has odd parity check */
} cyhal_uart_parity_t;
/** Enum to enable/disable/report interrupt cause flags. */
typedef enum
{
CYHAL_UART_IRQ_NONE = 0, //!< No interrupt
CYHAL_UART_IRQ_TX_TRANSMIT_IN_FIFO = 1 << 1, //!< All TX data from transmit has been moved to the HW TX FIFO buffer
CYHAL_UART_IRQ_TX_DONE = 1 << 2, //!< All TX data has been transmitted (applicable only for cyhal_uart_write_async)
CYHAL_UART_IRQ_TX_ERROR = 1 << 3, //!< An error occurred during TX
CYHAL_UART_IRQ_RX_FULL = 1 << 4, //!< The SW RX buffer (if used) is full. Additional data will be stored in the HW RX FIFO buffer
CYHAL_UART_IRQ_RX_DONE = 1 << 5, //!< All RX data has been received (applicable only for cyhal_uart_read_async)
CYHAL_UART_IRQ_RX_ERROR = 1 << 6, //!< An error occurred during RX
CYHAL_UART_IRQ_RX_NOT_EMPTY = 1 << 7, //!< The HW RX FIFO buffer is not empty
CYHAL_UART_IRQ_TX_EMPTY = 1 << 8, //!< The HW TX FIFO buffer is empty
CYHAL_UART_IRQ_TX_FIFO = 1 << 9, //!< Number of entries in the HW TX FIFO is less than the TX FIFO trigger level
CYHAL_UART_IRQ_RX_FIFO = 1 << 10, //!< Number of entries in the HW RX FIFO is more than the RX FIFO trigger level
} cyhal_uart_event_t;
/** UART FIFO type */
typedef enum
{
CYHAL_UART_FIFO_RX, //!< Set RX FIFO level
CYHAL_UART_FIFO_TX, //!< Set TX FIFO level
} cyhal_uart_fifo_type_t;
/** Enum of possible output signals from a UART */
typedef enum
{
CYHAL_UART_OUTPUT_TRIGGER_RX_FIFO_LEVEL_REACHED, //!< Output the RX FIFO signal which is triggered when the receive FIFO has more entries than the configured level.
CYHAL_UART_OUTPUT_TRIGGER_TX_FIFO_LEVEL_REACHED, //!< Output the TX FIFO signal which is triggered when the transmit FIFO has less entries than the configured level.
} cyhal_uart_output_t;
/****************************************************************
* Typedef
*****************************************************************/
/** @brief Initial UART configuration */
typedef struct
{
uint32_t data_bits; //!< The number of data bits (generally 8 or 9)
uint32_t stop_bits; //!< The number of stop bits (generally 0 or 1)
cyhal_uart_parity_t parity; //!< The parity
uint8_t *rx_buffer; //!< The rx software buffer pointer, if NULL, no rx software buffer will be used
uint32_t rx_buffer_size; //!< The number of bytes in the rx software buffer
} cyhal_uart_cfg_t;
/** UART callback function type */
typedef void (*cyhal_uart_event_callback_t)(void *callback_arg, cyhal_uart_event_t event);
/*******************************************************************************
* Functions
*******************************************************************************/
/** Initialize the UART peripheral.
*
* \note This will set the baud rate to a default of \ref CYHAL_UART_DEFAULT_BAUD. This can
* be changed by calling \ref cyhal_uart_set_baud.
* \note Function activates the flow control feature if CTS / RTS pins are provided.
*
* @param[out] obj Pointer to a UART object. The caller must allocate the memory
* for this object but the init function will initialize its contents.
* @param[in] tx The TX pin name, if no TX pin use NC
* @param[in] rx The RX pin name, if no RX pin use NC
* @param[in] cts The CTS pin name, if no CTS pin use NC
* @param[in] rts The RTS pin name, if no RTS pin use NC
* @param[in] clk The clock to use can be shared. If not provided, a new clock will be
* allocated and the default baud rate will be set
* @param[in] cfg The UART configuration data for data bits, stop bits and parity.
* If not provided, default values of (8, 1, none) will be used
* @return The status of the init request
*/
cy_rslt_t cyhal_uart_init(cyhal_uart_t *obj, cyhal_gpio_t tx, cyhal_gpio_t rx, cyhal_gpio_t cts, cyhal_gpio_t rts, const cyhal_clock_t *clk, const cyhal_uart_cfg_t *cfg);
/** Release the UART peripheral.
*
* @param[in,out] obj The UART object
*/
void cyhal_uart_free(cyhal_uart_t *obj);
/** Configure the baud rate
*
* @note This function should only be called if a shared clock divider is not used i.e. the clock
* parameter is set to NULL when calling \ref cyhal_uart_init.
*
* @param[in,out] obj The UART object
* @param[in] baudrate The baud rate to be configured
* @param[out] actualbaud The actual baud rate achieved by the HAL
* Specify NULL if you do not want this information.
* @return The status of the set_baud request
*/
cy_rslt_t cyhal_uart_set_baud(cyhal_uart_t *obj, uint32_t baudrate, uint32_t *actualbaud);
/** Configure the data bits, stop bits, and parity
*
* @param[in,out] obj The UART object
* @param[in] cfg The UART configuration data for data bits, stop bits and parity.
* rx_buffer and rx_buffer_size are ignored.
* @return The status of the configure request
*/
cy_rslt_t cyhal_uart_configure(cyhal_uart_t *obj, const cyhal_uart_cfg_t *cfg);
/** Get a character. This is a blocking call which waits till a character is received.
*
* @param[in] obj The UART object
* @param[out] value The value read from the serial port
* @param[in] timeout The time in ms to spend attempting to receive from serial port.
* Zero is wait forever
* @return The status of the getc request
*/
cy_rslt_t cyhal_uart_getc(cyhal_uart_t *obj, uint8_t *value, uint32_t timeout);
/** Send a character. This is a blocking call which waits till the character is sent out from the UART completely.
*
* @param[in] obj The UART object
* @param[in] value The character to be sent
* @return The status of the putc request
*/
cy_rslt_t cyhal_uart_putc(cyhal_uart_t *obj, uint32_t value);
/** Check the number of bytes available to read from the receive buffers
*
* @param[in] obj The UART object
* @return The number of readable bytes
*/
uint32_t cyhal_uart_readable(cyhal_uart_t *obj);
/** Check the number of bytes than can be written to the transmit buffer
*
* @param[in] obj The UART object
* @return The number of bytes that can be written
*/
uint32_t cyhal_uart_writable(cyhal_uart_t *obj);
/** Clear the UART buffers
*
* @param[in] obj The UART object
* @return The status of the clear request
*/
cy_rslt_t cyhal_uart_clear(cyhal_uart_t *obj);
/** Configure the UART for flow control. It sets flow control in the hardware
* if a UART peripheral supports it, otherwise software emulation is used.
*
* @param[in,out] obj The UART object
* @param[in] enable_cts Enable or disable CTS functionality
* @param[in] enable_rts Enable or disable RTS functionality
* @return The status of the enable_flow_control request
*/
cy_rslt_t cyhal_uart_enable_flow_control(cyhal_uart_t *obj, bool enable_cts, bool enable_rts);
/** Begin synchronous TX transfer.
*
* This will write either `length` bytes or until the write buffer is full, whichever is less,
* then return. The value pointed to by `length` will be updated to reflect the number of bytes
* that was actually written.
*
* @param[in] obj The UART object
* @param[in] tx The transmit buffer
* @param[in,out] tx_length [in] The number of bytes to transmit, [out] number actually transmitted
* @return The status of the tx request
*/
cy_rslt_t cyhal_uart_write(cyhal_uart_t *obj, void *tx, size_t *tx_length);
/** Begin synchronous RX transfer (enable interrupt for data collecting)
*
* This will read either `length` bytes or the number of bytes that are currently available in the
* receive buffer, whichever is less, then return. The value pointed to by `length` will be updated
* to reflect the number of bytes that was actually read.
*
* @param[in] obj The UART object
* @param[in] rx The receive buffer
* @param[in,out] rx_length [in] The number of bytes to receive, [out] number actually received
* @return The status of the rx request
*/
cy_rslt_t cyhal_uart_read(cyhal_uart_t *obj, void *rx, size_t *rx_length);
/** Set the mechanism that is used to perform UART asynchronous transfers. The default is SW.
* @warning The effect of calling this function while an async transfer is pending is undefined.
*
* @param[in] obj The UART object
* @param[in] mode The transfer mode
* @param[in] dma_priority The priority, if DMA is used. Valid values are the same as for @ref cyhal_dma_init.
* If DMA is not selected, the only valid value is CYHAL_DMA_PRIORITY_DEFAULT, and no
guarantees are made about prioritization.
* @return The status of the set mode request
*/
cy_rslt_t cyhal_uart_set_async_mode(cyhal_uart_t *obj, cyhal_async_mode_t mode, uint8_t dma_priority);
/** Begin asynchronous TX transfer.
*
* This will transfer `length` bytes into the buffer pointed to by `tx` in the background. When the
* requested quantity of data has been transferred, the @ref CYHAL_UART_IRQ_TX_TRANSMIT_IN_FIFO event will
* be raised. The transmit buffer is a user defined buffer that will be sent on the UART. The user
* must register a callback with \ref cyhal_uart_register_callback. If desired, TX callback
* events can be enabled using \ref cyhal_uart_enable_event with the appropriate events.
*
* If D-cache is enabled and data Cache line is 32 bytes,
* the user needs to make sure that the tx pointer passed to the cyhal_uart_write_async
* function points to a 32 byte aligned array of words that contains the buffer data.
* The size of buffer data must be a multiple of 32 bytes to ensure cache coherency.
* CY_ALIGN(__SCB_DCACHE_LINE_SIZE) macro can be used for 32 byte alignment.
*
* Refer to \ref DCACHE_Management for more information.
*
* @param[in] obj The UART object
* @param[in] tx The transmit buffer
* @param[in] length The number of bytes to transmit
* @return The status of the tx_async request
*/
cy_rslt_t cyhal_uart_write_async(cyhal_uart_t *obj, void *tx, size_t length);
/** Begin asynchronous RX transfer.
*
* This will transfer `length` bytes into the buffer pointed to by `rx` in the background. When the
* requested quantity of data has been transferred, the @ref CYHAL_UART_IRQ_RX_DONE event will be raised.
* Received data is placed in the user specified buffer. The user must register a callback with
* \ref cyhal_uart_register_callback. RX callback events can be enabled using \ref
* cyhal_uart_enable_event with the appropriate events.
*
* If D-cache is enabled and data Cache line is 32 bytes,
* the user needs to make sure that the tx pointer passed to the cyhal_uart_read_async
* function points to a 32 byte aligned array of words that contains the buffer data.
* The size of buffer data must be a multiple of 32 bytes to ensure cache coherency.
* CY_ALIGN(__SCB_DCACHE_LINE_SIZE) macro can be used for 32 byte alignment.
*
* Refer to \ref DCACHE_Management for more information.
*
* @param[in] obj The UART object
* @param[out] rx The user specified receive buffer
* @param[in] length The number of bytes to receive
* @return The status of the rx_async request
*/
cy_rslt_t cyhal_uart_read_async(cyhal_uart_t *obj, void *rx, size_t length);
/** Determines if the UART peripheral is currently in use for TX
*
* @param[in] obj The UART object
* @return TX channel active status (active=true)
*/
bool cyhal_uart_is_tx_active(cyhal_uart_t *obj);
/** Determines if the UART peripheral is currently in use for RX
*
* @param[in] obj The UART object
* @return RX channel active status (active=true)
*/
bool cyhal_uart_is_rx_active(cyhal_uart_t *obj);
/** Abort the ongoing TX transaction.
*
* Disables the TX interrupt and flushes the TX hardware buffer if TX FIFO is used.
*
* @param[in] obj The UART object
* @return The status of the tx_abort request
*/
cy_rslt_t cyhal_uart_write_abort(cyhal_uart_t *obj);
/** Abort the ongoing read transaction.
*
* Disables the RX interrupt and flushes the RX hardware buffer if RX FIFO is used.
*
* @param[in] obj The UART object
* @return The status of the read_abort request
*/
cy_rslt_t cyhal_uart_read_abort(cyhal_uart_t *obj);
/** Register a uart callback handler
*
* This function will be called when one of the events enabled by \ref cyhal_uart_enable_event occurs.
*
* @param[in] obj The UART object
* @param[in] callback The callback handler which will be invoked when the interrupt fires
* @param[in] callback_arg Generic argument that will be provided to the callback when called
*/
void cyhal_uart_register_callback(cyhal_uart_t *obj, cyhal_uart_event_callback_t callback, void *callback_arg);
/** Enable or disable specified UART events.
*
* When an enabled event occurs, the function specified by \ref cyhal_uart_register_callback will be called.
*
* @param[in] obj The UART object
* @param[in] event The uart event type, this argument supports the bitwise-or of multiple enum flag values
* @param[in] intr_priority The priority for NVIC interrupt events
* @param[in] enable True to turn on interrupts, False to turn off
*/
void cyhal_uart_enable_event(cyhal_uart_t *obj, cyhal_uart_event_t event, uint8_t intr_priority, bool enable);
/** Sets a threshold level for a FIFO that will generate an interrupt and a
* trigger output.
*
* The RX FIFO interrupt and trigger will be activated when
* the receive FIFO has more entries than the threshold. The TX FIFO interrupt
* and trigger will be activated when the transmit FIFO has less entries than
* the threshold.
*
* @param[in] obj The UART object
* @param[in] type FIFO type to set level for
* @param[in] level Level threshold to set
* @return The status of the level set
* */
cy_rslt_t cyhal_uart_set_fifo_level(cyhal_uart_t *obj, cyhal_uart_fifo_type_t type, uint16_t level);
/** Enables the specified output signal from a UART.
*
* @param[in] obj The UART object
* @param[in] output Which output signal to enable
* @param[out] source Pointer to user-allocated source signal object
* which will be initialized by enable_output. \p source should be passed to
* (dis)connect_digital functions to (dis)connect the associated endpoints.
* @return The status of the output enable
* */
cy_rslt_t cyhal_uart_enable_output(cyhal_uart_t *obj, cyhal_uart_output_t output, cyhal_source_t *source);
/** Disables the specified output signal from a UART
*
* @param[in] obj The UART object
* @param[in] output Which output signal to disable
* @return The status of the output disable
* */
cy_rslt_t cyhal_uart_disable_output(cyhal_uart_t *obj, cyhal_uart_output_t output);
/** Initialize the UART peripheral using a configurator generated configuration struct.
*
* @param[in] obj The UART peripheral to configure
* @param[in] cfg Configuration structure generated by a configurator.
* @return The status of the operation
*/
cy_rslt_t cyhal_uart_init_cfg(cyhal_uart_t *obj, const cyhal_uart_configurator_t *cfg);
/** Configure UART RX software buffer, which will extend the hardware RX FIFO buffer only
* for SW async mode. \ref cyhal_uart_init function does
* not require this function call if a non-null value was provided for `rx_buffer`.
*
* @param[in] obj The UART peripheral to configure
* @param[in] rx_buffer The RX software buffer pointer
* @param[in] rx_buffer_size The number of bytes in the RX software buffer
* @return The status of the operation
*/
cy_rslt_t cyhal_uart_config_software_buffer(cyhal_uart_t *obj, uint8_t *rx_buffer, uint32_t rx_buffer_size);
#if defined(__cplusplus)
}
#endif
#ifdef CYHAL_UART_IMPL_HEADER
#include CYHAL_UART_IMPL_HEADER
#endif /* CYHAL_UART_IMPL_HEADER */
/** \} group_hal_uart */