PSOC E8XXGP Device Support Library

| PSOC E8XXGP Device Support Library

API Reference
UART (SCB)
PDL API Reference » SCB (Serial Communication Block)

## General Description

Driver API for UART.

The functions and other declarations used in this part of the driver are in cy_scb_uart.h. You can also include cy_pdl.h to get access to all functions and declarations in the PDL.

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

Features:

- Supports UART protocol
  - Standard UART
  - Multi-processor mode
- SmartCard (ISO7816) reader
- IrDA
- Data frame size programmable from 4 to 16 bits
- Programmable number of STOP bits, which can be set in terms of half bit periods between 1 and 4
- Parity support (odd and even parity)
- Median filter on Rx input
- Programmable oversampling
- Start skipping

# Configuration Considerations

The UART driver configuration can be divided to number of sequential steps listed below:

- Configure UART
- Assign and Configure Pins
- Assign Clock Divider
- Configure Baud Rate
- Configure Interrupt
- Enable UART

Note
  UART driver is built on top of the SCB hardware block. The SCB5 instance is used as an example for all code snippets. Modify the code to match your design.

## Configure UART

To set up the UART driver, provide the configuration parameters in the cy_stc_scb_uart_config_t structure. For example: provide uartMode, oversample, dataWidth, enableMsbFirst, parity, and stopBits. The other parameters are optional. To initialize the driver, call Cy_SCB_UART_Init function providing a pointer to the populated cy_stc_scb_uart_config_t structure and the allocated cy_stc_scb_uart_context_t structure.

/* Allocate context for UART operation */
cy_stc_scb_uart_context_t uartContext;
/* Populate configuration structure */
const cy_stc_scb_uart_config_t uartConfig =
{
.uartMode = CY_SCB_UART_STANDARD,
.enableMultiProcessorMode = false,
.smartCardRetryOnNack = false,
.irdaInvertRx = false,
.irdaEnableLowPowerReceiver = false,
.oversample = 12UL,
.enableMsbFirst = false,
.dataWidth = 8UL,
.parity = CY_SCB_UART_PARITY_NONE,
.stopBits = CY_SCB_UART_STOP_BITS_1,
.enableInputFilter = false,
.breakWidth = 11UL,
.dropOnFrameError = false,
.dropOnParityError = false,
.receiverAddress = 0UL,
.receiverAddressMask = 0UL,
.acceptAddrInFifo = false,
.enableCts = false,
.ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
.rtsRxFifoLevel = 0UL,
.rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
.rxFifoTriggerLevel = 0UL,
.rxFifoIntEnableMask = 0UL,
.txFifoTriggerLevel = 0UL,
.txFifoIntEnableMask = 0UL,
};
/* Configure UART to operate */
(void) Cy_SCB_UART_Init(SCB5, &uartConfig, &uartContext);
cy_stc_scb_uart_config_t::uartMode
cy_en_scb_uart_mode_t uartMode
Specifies the UART's mode of operation.
Definition: cy_scb_uart.h:392
cy_stc_scb_uart_config_t
UART configuration structure.
Definition: cy_scb_uart.h:390
cy_stc_scb_uart_context_t
UART context structure.
Definition: cy_scb_uart.h:555
CY_SCB_UART_PARITY_NONE
@ CY_SCB_UART_PARITY_NONE
UART has no parity check
Definition: cy_scb_uart.h:358
CY_SCB_UART_STOP_BITS_1
@ CY_SCB_UART_STOP_BITS_1
UART looks for 1 Stop Bit
Definition: cy_scb_uart.h:346
CY_SCB_UART_ACTIVE_LOW
@ CY_SCB_UART_ACTIVE_LOW
Signal is active low.
Definition: cy_scb_uart.h:366
CY_SCB_UART_STANDARD
@ CY_SCB_UART_STANDARD
Configures the SCB for Standard UART operation.
Definition: cy_scb_uart.h:338
Cy_SCB_UART_Init
cy_en_scb_uart_status_t Cy_SCB_UART_Init(CySCB_Type *base, cy_stc_scb_uart_config_t const *config, cy_stc_scb_uart_context_t *context)
Initializes the SCB for UART operation.
Definition: cy_scb_uart.c:267

## Assign and Configure Pins

Only dedicated SCB pins can be used for UART operation. The HSIOM register must be configured to connect dedicated SCB UART pins to the SCB block. Also, the UART output pins must be configured in Strong Drive Input Off mode and UART input pins in Digital High-Z:

/* Assign pins for UART on SCB5: P17[0], P17[1] */
#define UART_PORT P17_0_PORT
#define UART_RX_NUM P17_0_NUM
#define UART_TX_NUM P17_1_NUM
/* Connect SCB5 UART function to pins */
Cy_GPIO_SetHSIOM(UART_PORT, UART_RX_NUM, P17_0_SCB5_UART_RX);
Cy_GPIO_SetHSIOM(UART_PORT, UART_TX_NUM, P17_1_SCB5_UART_TX);
/* Configure pins for UART operation */
Cy_GPIO_SetDrivemode(UART_PORT, UART_RX_NUM, CY_GPIO_DM_HIGHZ);
Cy_GPIO_SetDrivemode(UART_PORT, UART_TX_NUM, CY_GPIO_DM_STRONG_IN_OFF);
CY_GPIO_DM_STRONG_IN_OFF
#define CY_GPIO_DM_STRONG_IN_OFF
Strong Drive.
Definition: cy_gpio.h:514
CY_GPIO_DM_HIGHZ
#define CY_GPIO_DM_HIGHZ
Digital High-Z.
Definition: cy_gpio.h:516
Cy_GPIO_SetDrivemode
__STATIC_INLINE void Cy_GPIO_SetDrivemode(GPIO_PRT_Type *base, uint32_t pinNum, uint32_t value)
Configures the pin output buffer drive mode and input buffer enable.
Definition: cy_gpio.h:1286
Cy_GPIO_SetHSIOM
__STATIC_INLINE void Cy_GPIO_SetHSIOM(GPIO_PRT_Type *base, uint32_t pinNum, en_hsiom_sel_t value)
Configures the HSIOM connection to the pin.
Definition: cy_gpio.h:925

## Assign Clock Divider

A clock source must be connected to the SCB block to oversample input and output signals, in this document this clock will be referred as clk_scb. You must use one of available integer or fractional dividers. Use the SysClk (System Clock) driver API to do this.

/* Assign divider type and number for UART */
#define UART_CLK_DIV_TYPE (CY_SYSCLK_DIV_8_BIT)
#define UART_CLK_DIV_NUMBER (0U)
/* Connect assigned divider to be a clock source for UART */
Cy_SysClk_PeriphAssignDivider(PCLK_SCB5_CLOCK_SCB_EN, UART_CLK_DIV_TYPE, UART_CLK_DIV_NUMBER);
Cy_SysClk_PeriphAssignDivider
cy_en_sysclk_status_t Cy_SysClk_PeriphAssignDivider(en_clk_dst_t ipBlock, cy_en_divider_types_t dividerType, uint32_t dividerNum)
Assigns a programmable divider to a selected IP block, such as a TCPWM or SCB.
Definition: cy_sysclk_v2.c:2175

## Configure Baud Rate

To get the UART to operate with the desired baud rate, the clk_scb frequency and the oversample must be configured. Use the SysClk (System Clock) driver API to configure clk_scb frequency. Set the oversample parameter in configuration structure to define the number of the SCB clocks within one UART bit-time.

/* UART desired baud rate is 115200 bps (Standard mode).
* The UART baud rate = (clk_scb / Oversample).
* For clk_peri = 50 MHz, select divider value 36 and get SCB clock = (50 MHz / 36) = 1,389 MHz.
* Select Oversample = 12. These setting results UART data rate = 1,389 MHz / 12 = 115750 bps.
*/
Cy_SysClk_PeriphSetDivider (UART_CLK_DIV_TYPE, UART_CLK_DIV_NUMBER, 35UL);
Cy_SysClk_PeriphEnableDivider(UART_CLK_DIV_TYPE, UART_CLK_DIV_NUMBER);
Cy_SysClk_PeriphEnableDivider
cy_en_sysclk_status_t Cy_SysClk_PeriphEnableDivider(cy_en_divider_types_t dividerType, uint32_t dividerNum)
Enables the selected divider.
Definition: cy_sysclk_v2.c:2189
Cy_SysClk_PeriphSetDivider
cy_en_sysclk_status_t Cy_SysClk_PeriphSetDivider(cy_en_divider_types_t dividerType, uint32_t dividerNum, uint32_t dividerValue)
Sets one of the programmable clock dividers.
Definition: cy_sysclk_v2.c:2142

Refer to the technical reference manual (TRM) section UART sub-section Clocking and Oversampling to get information about how to configure the UART to run with desired baud rate.

## Configure Interrupt

The interrupt is optional for the UART operation. To configure interrupt the Cy_SCB_UART_Interrupt function must be called in the interrupt handler for the selected SCB instance. Also, this interrupt must be enabled in the NVIC. The interrupt must be configured when High-Level API will be used.

void UART_Isr(void)
{
Cy_SCB_UART_Interrupt(SCB5, &uartContext);
}
Cy_SCB_UART_Interrupt
void Cy_SCB_UART_Interrupt(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
This is the interrupt function for the SCB configured in the UART mode.
Definition: cy_scb_uart.c:1331
/* Assign UART interrupt number and priority */
#define UART_INTR_NUM ((IRQn_Type) scb_5_interrupt_IRQn)
#define UART_INTR_PRIORITY (7U)
/* Populate configuration structure (code specific for CM4) */
cy_stc_sysint_t uartIntrConfig =
{
.intrSrc = UART_INTR_NUM,
.intrPriority = UART_INTR_PRIORITY,
};
/* Hook interrupt service routine and enable interrupt */
(void) Cy_SysInt_Init(&uartIntrConfig, &UART_Isr);
NVIC_EnableIRQ(UART_INTR_NUM);
cy_stc_sysint_t::intrSrc
IRQn_Type intrSrc
Interrupt source.
Definition: cy_sysint.h:229
cy_stc_sysint_t
Initialization configuration structure for a single interrupt channel.
Definition: cy_sysint.h:227
Cy_SysInt_Init
cy_en_sysint_status_t Cy_SysInt_Init(const cy_stc_sysint_t *config, cy_israddress userIsr)
Initializes the referenced interrupt by setting the priority and the interrupt vector.
Definition: cy_sysint_v2.c:80

## Enable UART

Finally, enable the UART operation by calling Cy_SCB_UART_Enable.

/* Enable UART to operate */
Cy_SCB_UART_Enable(SCB5);
/* Enable global interrupts */
__enable_irq();
Cy_SCB_UART_Enable
__STATIC_INLINE void Cy_SCB_UART_Enable(CySCB_Type *base)
Enables the SCB block for the UART operation.
Definition: cy_scb_uart.h:1008

# Common Use Cases

The UART API is divided into two categories: Low-Level and High-Level.
Do not mix High-Level and Low-Level API because a Low-Level API can adversely affect the operation of a High-Level API.

## Low-Level API

The Low-Level functions allow interacting directly with the hardware and do not use Cy_SCB_UART_Interrupt. These functions do not require context for operation. Thus, NULL can be passed for context parameter in Cy_SCB_UART_Init and Cy_SCB_UART_Disable instead of a pointer to the context structure.

- To write data into the TX FIFO, use one of the provided functions: Cy_SCB_UART_Put, Cy_SCB_UART_PutArray, Cy_SCB_UART_PutArrayBlocking or Cy_SCB_UART_PutString. Note that putting data into the TX FIFO starts data transfer.
- To read data from the RX FIFO, use one of the provided functions: Cy_SCB_UART_Get, Cy_SCB_UART_GetArray or Cy_SCB_UART_GetArrayBlocking.
- The statuses can be polled using: Cy_SCB_UART_GetRxFifoStatus and Cy_SCB_UART_GetTxFifoStatus. The statuses are W1C (Write 1 to Clear) and after a status is set, it must be cleared. Note that there are statuses evaluated as level. These statuses remain set until an event is true. Therefore, after the clear operation, the status is cleared but then it is restored (if event is still true). Also, the following functions can be used for polling as well Cy_SCB_UART_IsTxComplete, Cy_SCB_UART_GetNumInRxFifo and Cy_SCB_UART_GetNumInTxFifo.

uint8_t txBuffer[BUFFER_SIZE];
/* Initialize txBuffer with command to transfer */
txBuffer[0] = CMD_START_TRANSFER;
txBuffer[1] = 0x00U;
txBuffer[2] = 0x01U;
Cy_SCB_UART_PutArrayBlocking(SCB5, txBuffer, sizeof(txBuffer));
/* Blocking wait for transfer completion */
while (!Cy_SCB_UART_IsTxComplete(SCB5))
{
}
Cy_SCB_UART_IsTxComplete
__STATIC_INLINE bool Cy_SCB_UART_IsTxComplete(CySCB_Type const *base)
Checks whether the TX FIFO and Shifter are empty and there is no more data to send.
Definition: cy_scb_uart.h:1682
Cy_SCB_UART_PutArrayBlocking
__STATIC_INLINE void Cy_SCB_UART_PutArrayBlocking(CySCB_Type *base, void *buffer, uint32_t size)
Places an array of data in the UART TX FIFO.
Definition: cy_scb_uart.h:1568

## High-Level API

The High-Level API use Cy_SCB_UART_Interrupt to execute the transfer. Call Cy_SCB_UART_Transmit to start transmission. Call Cy_SCB_UART_Receive to start receive operation. After the operation is started the Cy_SCB_UART_Interrupt handles the data transfer until its completion. Therefore Cy_SCB_UART_Interrupt must be called inside the user interrupt handler to make the High-Level API work. To monitor status of transmit operation, use Cy_SCB_UART_GetTransmitStatus and Cy_SCB_UART_GetReceiveStatus to monitor receive status appropriately. Alternatively use Cy_SCB_UART_RegisterCallback to register callback function to be notified about UART Callback Events.

Receive Operation

uint8_t rxBuffer[BUFFER_SIZE];
/* Start receive operation (do not check status) */
(void) Cy_SCB_UART_Receive(SCB5, rxBuffer, sizeof(rxBuffer), &uartContext);
/* Blocking wait until buffer is full */
while (0UL != (CY_SCB_UART_RECEIVE_ACTIVE & Cy_SCB_UART_GetReceiveStatus(SCB5, &uartContext)))
{
}
/* Handle received data */
Cy_SCB_UART_GetReceiveStatus
uint32_t Cy_SCB_UART_GetReceiveStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
Returns the status of the receive operation.
Definition: cy_scb_uart.c:1065
Cy_SCB_UART_Receive
cy_en_scb_uart_status_t Cy_SCB_UART_Receive(CySCB_Type *base, void *buffer, uint32_t size, cy_stc_scb_uart_context_t *context)
This function starts a UART receive operation.
Definition: cy_scb_uart.c:853
CY_SCB_UART_RECEIVE_ACTIVE
#define CY_SCB_UART_RECEIVE_ACTIVE
The receive operation started by Cy_SCB_UART_Receive is in progress.
Definition: cy_scb_uart.h:817

Transmit Operation

uint8_t txBuffer[BUFFER_SIZE];
/* Initialize txBuffer with data to transfer */
txBuffer[0] = CMD_START_TRANSFER;
txBuffer[1] = 0x00U;
txBuffer[2] = 0x01U;
/* Start transmit operation (do not check status) */
(void) Cy_SCB_UART_Transmit(SCB5, txBuffer, sizeof(txBuffer), &uartContext);
/* Blocking wait for transmission completion */
while (0UL != (CY_SCB_UART_TRANSMIT_ACTIVE & Cy_SCB_UART_GetTransmitStatus(SCB5, &uartContext)))
{
}
Cy_SCB_UART_Transmit
cy_en_scb_uart_status_t Cy_SCB_UART_Transmit(CySCB_Type *base, void *buffer, uint32_t size, cy_stc_scb_uart_context_t *context)
This function starts a UART transmit operation.
Definition: cy_scb_uart.c:1113
Cy_SCB_UART_GetTransmitStatus
uint32_t Cy_SCB_UART_GetTransmitStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
Returns the status of the transmit operation.
Definition: cy_scb_uart.c:1244
CY_SCB_UART_TRANSMIT_ACTIVE
#define CY_SCB_UART_TRANSMIT_ACTIVE
The transmit operation started by Cy_SCB_UART_Transmit is in progress.
Definition: cy_scb_uart.h:850

There is also capability to insert a receive ring buffer that operates between the RX FIFO and the user buffer. The received data is copied into the ring buffer from the RX FIFO. This process runs in the background after the ring buffer operation is started by Cy_SCB_UART_StartRingBuffer. When Cy_SCB_UART_Receive is called, it first reads data from the ring buffer and then sets up an interrupt to receive more data if the required amount has not yet been read.

# DMA Trigger

The SCB provides TX and RX output trigger signals that can be routed to the DMA controller inputs. These signals are assigned based on the data availability in the TX and RX FIFOs appropriately.

- The RX trigger signal is active while the number of data elements in the RX FIFO is greater than the value of RX FIFO level. Use function Cy_SCB_SetRxFifoLevel or set configuration structure rxFifoTriggerLevel parameter to configure RX FIFO level value.
  For example, the RX FIFO has 8 data elements and the RX FIFO level is 0. The RX trigger signal is active until DMA reads all data from the RX FIFO.
- The TX trigger signal is active while the number of data elements in the TX FIFO is less than the value of TX FIFO level. Use function Cy_SCB_SetTxFifoLevel or set configuration structure txFifoTriggerLevel parameter to configure TX FIFO level value.
  For example, the TX FIFO has 0 data elements (empty) and the TX FIFO level is 7. The TX trigger signal is active until DMA loads TX FIFO with 8 data elements (note that after the first TX load operation, the data element goes to the shift register and TX FIFO is empty).

To route SCB TX or RX trigger signals to DMA controller use TrigMux (Trigger Multiplexer) driver API.

Note
  To properly handle DMA level request signal activation and de-activation from the SCB peripheral block the DMA Descriptor typically must be configured to re-trigger after 16 Clk_Slow cycles.

# Low Power Support

The UART driver provides callback functions to handle power mode transition. The callback Cy_SCB_UART_DeepSleepCallback must be called during execution of Cy_SysPm_CpuEnterDeepSleep Cy_SCB_UART_HibernateCallback must be called during execution of Cy_SysPm_SystemEnterHibernate. To trigger the callback execution, the callback must be registered before calling the power mode transition function. Refer to SysPm (System Power Management) driver for more information about power mode transitions and callback registration.

The UART is disabled during Deep Sleep and Hibernate and stops driving the output pins. The state of the UART output pins TX and RTS is High-Z, which can cause unexpected behavior of the UART receiver due to possible glitches on these lines. These pins must be set to the inactive state before entering Deep Sleep or Hibernate mode. These pins must keep the inactive level (the same state when UART TX is enabled and does not transfer data) before entering Deep Sleep or Hibernate mode. To do that, write the GPIO data register of each pin to the inactive level for each output pin. Then configure High-Speed Input Output Multiplexer (HSIOM) of each pin to be controlled by the GPIO (use GPIO (General Purpose Input Output) driver API). After exiting Deep Sleep mode the UART must be enabled and the pins configuration restored to return the UART control of the pins (after exiting Hibernate mode, the system initialization code does the same). Copy either or both Cy_SCB_UART_DeepSleepCallback and Cy_SCB_UART_HibernateCallback as appropriate, and make the changes described above inside the function. Alternately, external pull-up or pull-down resistors can be connected to the appropriate UART lines to keep them inactive during Deep-Sleep or Hibernate.

## API Reference
| Macros
| Functions
| Data Structures
| Enumerated Types