/***************************************************************************//** * \file cy_scb_uart.c * \version 2.80 * * Provides UART API implementation of the SCB driver. * ******************************************************************************** * \copyright * Copyright 2016-2021 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. *******************************************************************************/ #include "cy_device.h" #if defined (CY_IP_MXSCB) #include "cy_scb_uart.h" #if defined(__cplusplus) extern "C" { #endif /* Static functions */ static void HandleDataReceive (CySCB_Type *base, cy_stc_scb_uart_context_t *context); static void HandleRingBuffer (CySCB_Type *base, cy_stc_scb_uart_context_t *context); static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context); static uint32_t SelectRxFifoLevel(CySCB_Type const *base); /******************************************************************************* * Function Name: Cy_SCB_UART_SetOverSample ****************************************************************************//** * * Sets oversample bits of UART. * * \param base * The pointer to the UART SCB instance. * * \param overSample * Value of oversample to be set. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * User should not pass NULL as pointer to context. * * \return * \ref cy_en_scb_uart_status_t * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_OVS * *******************************************************************************/ cy_en_scb_uart_status_t Cy_SCB_UART_SetOverSample(CySCB_Type *base, uint32_t overSample, cy_stc_scb_uart_context_t *context) { CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 10.8', 1, \ 'Intentional typecast to cy_en_scb_uart_mode_t enum to validate arguments.'); if((NULL == base) || (NULL == context) || ((CY_SCB_UART_IS_OVERSAMPLE_VALID(overSample, ((cy_en_scb_uart_mode_t)_FLD2VAL(SCB_UART_CTRL_MODE,SCB_UART_CTRL(base))), context->irdaEnableLowPowerReceiver)) == false)) { return CY_SCB_UART_BAD_PARAM; } CY_MISRA_BLOCK_END('MISRA C-2012 Rule 10.8'); uint32_t ovs; if (((uint32_t)CY_SCB_UART_IRDA == _FLD2VAL(SCB_UART_CTRL_MODE,SCB_UART_CTRL(base))) && (!context->irdaEnableLowPowerReceiver)) { /* For Normal IrDA mode oversampling is always zero */ ovs = 0UL; } else { ovs = overSample - 1UL; } /* Set oversample bits */ CY_REG32_CLR_SET(SCB_CTRL(base), SCB_CTRL_OVS, ovs); return CY_SCB_UART_SUCCESS; } /******************************************************************************* * Function Name: Cy_SCB_UART_SetDataWidth ****************************************************************************//** * * Sets datawidth for UART transaction. * * \param base * The pointer to the UART SCB instance. * * \param dataWidth * The width of UART data in the UART transaction. * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_DATA_WIDTH * *******************************************************************************/ void Cy_SCB_UART_SetDataWidth(CySCB_Type *base, uint32_t dataWidth) { CY_ASSERT_L2(CY_SCB_UART_IS_DATA_WIDTH_VALID (dataWidth)); /* Configure the memory width */ Cy_SCB_SetByteMode(base, (dataWidth <= CY_SCB_BYTE_WIDTH)); CY_REG32_CLR_SET(SCB_RX_CTRL(base), SCB_RX_CTRL_DATA_WIDTH, (dataWidth - 1UL)); CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_DATA_WIDTH, (dataWidth - 1UL)); } /******************************************************************************* * Function Name: Cy_SCB_UART_SetParity ****************************************************************************//** * * Sets parity for UART transaction. * * \param base * The pointer to the UART SCB instance. * * \param parity * The UART parity bit in the UART transaction. * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_PARITY * *******************************************************************************/ void Cy_SCB_UART_SetParity(CySCB_Type *base, cy_en_scb_uart_parity_t parity) { CY_ASSERT_L3(CY_SCB_UART_IS_PARITY_VALID (parity)); /* Configure the RX direction with given parameters */ CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), CY_SCB_UART_RX_CTRL_SET_PARITY, (uint32_t) parity); /* Configure the TX direction with given parameters*/ CY_REG32_CLR_SET(SCB_UART_TX_CTRL(base), CY_SCB_UART_TX_CTRL_SET_PARITY, (uint32_t) parity); } /******************************************************************************* * Function Name: Cy_SCB_UART_SetStopBits ****************************************************************************//** * * Sets stop bits for UART transaction. * * \param base * The pointer to the UART SCB instance. * * \param stopBits * The number of stop bits in the UART transaction. * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_STOP_BITS * *******************************************************************************/ void Cy_SCB_UART_SetStopBits(CySCB_Type *base, cy_en_scb_uart_stop_bits_t stopBits) { CY_ASSERT_L3(CY_SCB_UART_IS_STOP_BITS_VALID (stopBits)); /* Configure the RX direction with given parameters */ CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), SCB_UART_RX_CTRL_STOP_BITS, ((uint32_t) stopBits) - 1UL); /* Configure the TX direction with given parameters*/ CY_REG32_CLR_SET(SCB_UART_TX_CTRL(base), SCB_UART_TX_CTRL_STOP_BITS, ((uint32_t) stopBits) - 1UL); } /******************************************************************************* * Function Name: Cy_SCB_UART_SetDropOnParityError ****************************************************************************//** * * Sets SetDropOnParityError for UART transaction. * * \param base * The pointer to the UART SCB instance. * * \param dropOnParityError * To enable the hardware to drop data in the RX FIFO when a parity error is * detected in the UART transaction. * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_DROP_ON_PARITY_ERROR * *******************************************************************************/ void Cy_SCB_UART_SetDropOnParityError(CySCB_Type *base, bool dropOnParityError) { /* Configure the RX direction with given parameters */ CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), SCB_UART_RX_CTRL_DROP_ON_PARITY_ERROR, dropOnParityError); } /******************************************************************************* * Function Name: Cy_SCB_UART_SetEnableMsbFirst ****************************************************************************//** * * Sets enableMsbFirst for UART transaction. * * \param base * The pointer to the UART SCB instance. * * \param enableMsbFirst * Enables the hardware to shift out data element MSB first; * otherwise, LSB first in the UART transaction. * * \note * Ensure that the SCB block is disabled before calling this function. * * \snippet scb/uart_snippet/main.c UART_SET_ENABLE_MSB_FIRST * *******************************************************************************/ void Cy_SCB_UART_SetEnableMsbFirst(CySCB_Type *base, bool enableMsbFirst) { /* Configure the RX direction with given parameters */ CY_REG32_CLR_SET(SCB_RX_CTRL(base), SCB_RX_CTRL_MSB_FIRST, enableMsbFirst); /* Configure the TX direction with given parameters*/ CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_MSB_FIRST, enableMsbFirst); } /******************************************************************************* * Function Name: Cy_SCB_UART_Init ****************************************************************************//** * * Initializes the SCB for UART operation. * * \param base * The pointer to the UART SCB instance. * * \param config * The pointer to configuration structure \ref cy_stc_scb_uart_config_t. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * If only UART \ref group_scb_uart_ll will be used pass NULL as pointer to * context. * * \return * \ref cy_en_scb_uart_status_t * * \note * Ensure that the SCB block is disabled before calling this function. * *******************************************************************************/ 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) { if ((NULL == base) || (NULL == config)) { return CY_SCB_UART_BAD_PARAM; } CY_ASSERT_L3(CY_SCB_UART_IS_MODE_VALID (config->uartMode)); CY_ASSERT_L3(CY_SCB_UART_IS_STOP_BITS_VALID(config->stopBits)); CY_ASSERT_L3(CY_SCB_UART_IS_PARITY_VALID (config->parity)); CY_ASSERT_L3(CY_SCB_UART_IS_POLARITY_VALID (config->ctsPolarity)); CY_ASSERT_L3(CY_SCB_UART_IS_POLARITY_VALID (config->rtsPolarity)); CY_ASSERT_L2(CY_SCB_UART_IS_OVERSAMPLE_VALID (config->oversample, config->uartMode, config->irdaEnableLowPowerReceiver)); CY_ASSERT_L2(CY_SCB_UART_IS_DATA_WIDTH_VALID (config->dataWidth)); CY_ASSERT_L2(CY_SCB_UART_IS_ADDRESS_VALID (config->receiverAddress)); CY_ASSERT_L2(CY_SCB_UART_IS_ADDRESS_MASK_VALID(config->receiverAddressMask)); CY_ASSERT_L2(CY_SCB_UART_IS_MUTLI_PROC_VALID (config->enableMutliProcessorMode, config->uartMode, config->dataWidth, config->parity)); CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->rxFifoIntEnableMask, CY_SCB_UART_RX_INTR_MASK)); CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->txFifoIntEnableMask, CY_SCB_UART_TX_INTR_MASK)); uint32_t ovs; if ((CY_SCB_UART_IRDA == config->uartMode) && (!config->irdaEnableLowPowerReceiver)) { /* For Normal IrDA mode oversampling is always zero */ ovs = 0UL; } else { ovs = (config->oversample - 1UL); } /* Configure the UART interface */ #if(CY_IP_MXSCB_VERSION>=3) SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, config->acceptAddrInFifo) | _VAL2FLD(SCB_CTRL_MEM_WIDTH, ((config->dataWidth <= CY_SCB_BYTE_WIDTH)? 0UL:1UL)) | _VAL2FLD(SCB_CTRL_OVS, ovs) | _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART); #elif(CY_IP_MXSCB_VERSION==1) SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, config->acceptAddrInFifo) | _BOOL2FLD(SCB_CTRL_BYTE_MODE, (config->dataWidth <= CY_SCB_BYTE_WIDTH)) | _VAL2FLD(SCB_CTRL_OVS, ovs) | _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART); #endif /* CY_IP_MXSCB_VERSION */ /* Configure SCB_CTRL.BYTE_MODE then verify levels */ CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->rxFifoTriggerLevel)); CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->txFifoTriggerLevel)); CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->rtsRxFifoLevel)); SCB_UART_CTRL(base) = _VAL2FLD(SCB_UART_CTRL_MODE, (uint32_t) config->uartMode); /* Configure the RX direction */ SCB_UART_RX_CTRL(base) = _BOOL2FLD(SCB_UART_RX_CTRL_POLARITY, config->irdaInvertRx) | _BOOL2FLD(SCB_UART_RX_CTRL_MP_MODE, config->enableMutliProcessorMode) | _BOOL2FLD(SCB_UART_RX_CTRL_DROP_ON_PARITY_ERROR, config->dropOnParityError) | _BOOL2FLD(SCB_UART_RX_CTRL_DROP_ON_FRAME_ERROR, config->dropOnFrameError) | _VAL2FLD(SCB_UART_RX_CTRL_BREAK_WIDTH, (config->breakWidth - 1UL)) | _VAL2FLD(SCB_UART_RX_CTRL_STOP_BITS, ((uint32_t) config->stopBits) - 1UL) | _VAL2FLD(CY_SCB_UART_RX_CTRL_SET_PARITY, (uint32_t) config->parity); #if(CY_IP_MXSCB_VERSION>=3) SCB_UART_RX_CTRL(base)|=_BOOL2FLD(SCB_UART_RX_CTRL_BREAK_LEVEL, config->breaklevel); #endif /* CY_IP_MXSCB_VERSION */ SCB_RX_CTRL(base) = _BOOL2FLD(SCB_RX_CTRL_MSB_FIRST, config->enableMsbFirst) | _BOOL2FLD(SCB_RX_CTRL_MEDIAN, ((config->enableInputFilter) || \ (config->uartMode == CY_SCB_UART_IRDA))) | _VAL2FLD(SCB_RX_CTRL_DATA_WIDTH, (config->dataWidth - 1UL)); SCB_RX_MATCH(base) = _VAL2FLD(SCB_RX_MATCH_ADDR, config->receiverAddress) | _VAL2FLD(SCB_RX_MATCH_MASK, config->receiverAddressMask); /* Configure SCB_CTRL.RX_CTRL then verify break width */ CY_ASSERT_L2(CY_SCB_UART_IS_RX_BREAK_WIDTH_VALID(base, config->breakWidth)); /* Configure the TX direction */ SCB_UART_TX_CTRL(base) = _BOOL2FLD(SCB_UART_TX_CTRL_RETRY_ON_NACK, ((config->smartCardRetryOnNack) && \ (config->uartMode == CY_SCB_UART_SMARTCARD))) | _VAL2FLD(SCB_UART_TX_CTRL_STOP_BITS, ((uint32_t) config->stopBits) - 1UL) | _VAL2FLD(CY_SCB_UART_TX_CTRL_SET_PARITY, (uint32_t) config->parity); SCB_TX_CTRL(base) = _BOOL2FLD(SCB_TX_CTRL_MSB_FIRST, config->enableMsbFirst) | _VAL2FLD(SCB_TX_CTRL_DATA_WIDTH, (config->dataWidth - 1UL)) | _BOOL2FLD(SCB_TX_CTRL_OPEN_DRAIN, (config->uartMode == CY_SCB_UART_SMARTCARD)); SCB_RX_FIFO_CTRL(base) = _VAL2FLD(SCB_RX_FIFO_CTRL_TRIGGER_LEVEL, config->rxFifoTriggerLevel); /* Configure the flow control */ SCB_UART_FLOW_CTRL(base) = _BOOL2FLD(SCB_UART_FLOW_CTRL_CTS_ENABLED, config->enableCts) | _BOOL2FLD(SCB_UART_FLOW_CTRL_CTS_POLARITY, (CY_SCB_UART_ACTIVE_HIGH == config->ctsPolarity)) | _BOOL2FLD(SCB_UART_FLOW_CTRL_RTS_POLARITY, (CY_SCB_UART_ACTIVE_HIGH == config->rtsPolarity)) | _VAL2FLD(SCB_UART_FLOW_CTRL_TRIGGER_LEVEL, config->rtsRxFifoLevel); SCB_TX_FIFO_CTRL(base) = _VAL2FLD(SCB_TX_FIFO_CTRL_TRIGGER_LEVEL, config->txFifoTriggerLevel); /* Set up interrupt sources */ SCB_INTR_RX_MASK(base) = (config->rxFifoIntEnableMask & CY_SCB_UART_RX_INTR_MASK); SCB_INTR_TX_MASK(base) = (config->txFifoIntEnableMask & CY_SCB_UART_TX_INTR_MASK); /* Initialize context */ if (NULL != context) { context->rxStatus = 0UL; context->txStatus = 0UL; context->rxRingBuf = NULL; context->rxRingBufSize = 0UL; context->rxBufIdx = 0UL; context->txLeftToTransmit = 0UL; context->cbEvents = NULL; context->irdaEnableLowPowerReceiver = config->irdaEnableLowPowerReceiver; #if !defined(NDEBUG) /* Put an initialization key into the initKey variable to verify * context initialization in the transfer API. */ context->initKey = CY_SCB_UART_INIT_KEY; #endif /* !(NDEBUG) */ } return CY_SCB_UART_SUCCESS; } /******************************************************************************* * Function Name: Cy_SCB_UART_DeInit ****************************************************************************//** * * De-initializes the SCB block. Returns the register values to default. * * \param base * The pointer to the UART SCB instance. * * \note * Ensure that the SCB block is disabled before calling this function. * *******************************************************************************/ void Cy_SCB_UART_DeInit(CySCB_Type *base) { /* De-initialize the UART interface */ SCB_CTRL(base) = CY_SCB_CTRL_DEF_VAL; SCB_UART_CTRL(base) = CY_SCB_UART_CTRL_DEF_VAL; /* De-initialize the RX direction */ SCB_UART_RX_CTRL(base) = 0UL; SCB_RX_CTRL(base) = CY_SCB_RX_CTRL_DEF_VAL; SCB_RX_FIFO_CTRL(base) = 0UL; SCB_RX_MATCH(base) = 0UL; /* De-initialize the TX direction */ SCB_UART_TX_CTRL(base) = 0UL; SCB_TX_CTRL(base) = CY_SCB_TX_CTRL_DEF_VAL; SCB_TX_FIFO_CTRL(base) = 0UL; /* De-initialize the flow control */ SCB_UART_FLOW_CTRL(base) = 0UL; /* De-initialize the interrupt sources */ SCB_INTR_SPI_EC_MASK(base) = 0UL; SCB_INTR_I2C_EC_MASK(base) = 0UL; SCB_INTR_RX_MASK(base) = 0UL; SCB_INTR_TX_MASK(base) = 0UL; SCB_INTR_M_MASK(base) = 0UL; SCB_INTR_S_MASK(base) = 0UL; } /******************************************************************************* * Function Name: Cy_SCB_UART_Disable ****************************************************************************//** * * Disables the SCB block and clears context statuses. * Note that after the block is disabled, the TX and RX FIFOs and * hardware statuses are cleared. Also, the hardware stops driving the * output and ignores the input. Refer to section \ref group_scb_uart_lp for more * information about UART pins when SCB disabled. * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * If only UART functions that do not require context will be used to pass NULL * as pointer to context. * * \note * Calling this function when the UART is busy (transmitter preforms data * transfer or receiver is in the middle of data reception) may result transfer * corruption because the hardware stops driving the outputs and ignores * the inputs. * Ensure that the UART is not busy before calling this function. * *******************************************************************************/ void Cy_SCB_UART_Disable(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { SCB_CTRL(base) &= (uint32_t) ~SCB_CTRL_ENABLED_Msk; if (NULL != context) { context->rxStatus = 0UL; context->txStatus = 0UL; context->rxBufIdx = 0UL; context->txLeftToTransmit = 0UL; } } /******************************************************************************* * Function Name: Cy_SCB_UART_DeepSleepCallback ****************************************************************************//** * * This function handles the transition of the SCB UART into and out of * Deep Sleep mode. It prevents the device from entering Deep Sleep * mode if the UART is transmitting data or has any data in the RX FIFO. If the * UART is ready to enter Deep Sleep mode, it is disabled. The UART is enabled * when the device fails to enter Deep Sleep mode or it is awakened from * Deep Sleep mode. While the UART is disabled, it stops driving the outputs * and ignores the inputs. Any incoming data is ignored. Refer to section * \ref group_scb_uart_lp for more information about UART pins when SCB disabled. * * This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep, * to do it, register this function as a callback before calling * \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback * type and call \ref Cy_SysPm_RegisterCallback. * * \param callbackParams * The pointer to the callback parameters structure * \ref cy_stc_syspm_callback_params_t. * * \param mode * Callback mode, see \ref cy_en_syspm_callback_mode_t * * \return * \ref cy_en_syspm_status_t * *******************************************************************************/ cy_en_syspm_status_t Cy_SCB_UART_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode) { cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL; CySCB_Type *locBase = (CySCB_Type *) callbackParams->base; cy_stc_scb_uart_context_t *locContext = (cy_stc_scb_uart_context_t *) callbackParams->context; switch(mode) { case CY_SYSPM_CHECK_READY: { /* Check whether the High-level API is not busy executing the transmit * or receive operation. */ if ((0UL == (CY_SCB_UART_TRANSMIT_ACTIVE & Cy_SCB_UART_GetTransmitStatus(locBase, locContext))) && (0UL == (CY_SCB_UART_RECEIVE_ACTIVE & Cy_SCB_UART_GetReceiveStatus (locBase, locContext)))) { /* If all data elements are transmitted from the TX FIFO and * shifter and the RX FIFO is empty: the UART is ready to enter * Deep Sleep mode. */ if (Cy_SCB_UART_IsTxComplete(locBase)) { if (0UL == Cy_SCB_UART_GetNumInRxFifo(locBase)) { /* Disable the UART. The transmitter stops driving the * lines and the receiver stops receiving data until * the UART is enabled. * This happens when the device failed to enter Deep * Sleep or it is awaken from Deep Sleep mode. */ Cy_SCB_UART_Disable(locBase, locContext); retStatus = CY_SYSPM_SUCCESS; } } } } break; case CY_SYSPM_CHECK_FAIL: { /* The other driver is not ready for Deep Sleep mode. Restore the * Active mode configuration. */ /* Enable the UART to operate */ Cy_SCB_UART_Enable(locBase); retStatus = CY_SYSPM_SUCCESS; } break; case CY_SYSPM_BEFORE_TRANSITION: /* Do noting: the UART is not capable of waking up from * Deep Sleep mode. */ break; case CY_SYSPM_AFTER_TRANSITION: { /* Enable the UART to operate */ Cy_SCB_UART_Enable(locBase); retStatus = CY_SYSPM_SUCCESS; } break; default: /* Unknown state */ break; } return (retStatus); } /******************************************************************************* * Function Name: Cy_SCB_UART_HibernateCallback ****************************************************************************//** * * This function handles the transition of the SCB UART into Hibernate mode. * It prevents the device from entering Hibernate mode if the UART is * transmitting data or has any data in the RX FIFO. If the UART is ready * to enter Hibernate mode, it is disabled. If the device fails to enter * Hibernate mode, the UART is enabled. While the UART is disabled, it stops * driving the outputs and ignores the inputs. Any incoming data is ignored. * Refer to section \ref group_scb_uart_lp for more information about UART pins * when SCB disabled. * * This function must be called during execution of \ref Cy_SysPm_SystemEnterHibernate. * To do it, register this function as a callback before calling * \ref Cy_SysPm_SystemEnterHibernate : specify \ref CY_SYSPM_HIBERNATE as the callback type * and call \ref Cy_SysPm_RegisterCallback. * * \param callbackParams * The pointer to the callback parameters structure * \ref cy_stc_syspm_callback_params_t. * * \param mode * Callback mode, see \ref cy_en_syspm_callback_mode_t * * \return * \ref cy_en_syspm_status_t * *******************************************************************************/ cy_en_syspm_status_t Cy_SCB_UART_HibernateCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode) { return Cy_SCB_UART_DeepSleepCallback(callbackParams, mode); } /************************* High-Level Functions ******************************** * The following functions are considered high-level. They provide the layer of * intelligence to the SCB. These functions require interrupts. * Low-level and high-level functions must not be mixed because low-level API * can adversely affect the operation of high-level functions. *******************************************************************************/ /******************************************************************************* * Function Name: Cy_SCB_UART_StartRingBuffer ****************************************************************************//** * * Starts the receive ring buffer operation. * The RX interrupt source is configured to get data from the RX * FIFO and put into the ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param buffer * Pointer to the user defined ring buffer. * The element size is defined by the data type, which depends on the configured * data width. * * \param size * The size of the receive ring buffer. * Note that one data element is used for internal use, so if the size is 32, * then only 31 data elements are used for data storage. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \note * * The buffer must not be modified and stay allocated while the ring buffer * operates. * * This function overrides the RX interrupt sources and changes the * RX FIFO level. * *******************************************************************************/ void Cy_SCB_UART_StartRingBuffer(CySCB_Type *base, void *buffer, uint32_t size, cy_stc_scb_uart_context_t *context) { CY_ASSERT_L1(NULL != context); #if !defined(NDEBUG) CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey); #endif CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size)); if ((NULL != buffer) && (size > 0UL)) { uint32_t irqRxLevel = SelectRxFifoLevel(base); context->rxRingBuf = buffer; context->rxRingBufSize = size; context->rxRingBufHead = 0UL; context->rxRingBufTail = 0UL; /* Set up an RX interrupt to handle the ring buffer */ Cy_SCB_SetRxFifoLevel(base, (size >= irqRxLevel) ? (irqRxLevel - 1UL) : (size - 1UL)); Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL); } } /******************************************************************************* * Function Name: SelectRxFifoLevel ****************************************************************************//** * Select RX FIFO level as RTS level if it is valid (>0) or half of RX FIFO size * in other case. * * \return * The RX FIFO level. * *******************************************************************************/ static uint32_t SelectRxFifoLevel(CySCB_Type const *base) { uint32_t halfFifoSize = Cy_SCB_GetFifoSize(base) / 2UL; uint32_t rtsFifoLevel = Cy_SCB_UART_GetRtsFifoLevel(base); return ((rtsFifoLevel != 0UL ) ? (rtsFifoLevel) : (halfFifoSize)); } /******************************************************************************* * Function Name: Cy_SCB_UART_StopRingBuffer ****************************************************************************//** * * Stops receiving data into the ring buffer and clears the ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ void Cy_SCB_UART_StopRingBuffer(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { Cy_SCB_SetRxInterruptMask (base, CY_SCB_CLEAR_ALL_INTR_SRC); Cy_SCB_UART_ClearRingBuffer(base, context); context->rxRingBuf = NULL; context->rxRingBufSize = 0UL; } /******************************************************************************* * Function Name: Cy_SCB_UART_GetNumInRingBuffer ****************************************************************************//** * * Returns the number of data elements in the ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * The number of data elements in the receive ring buffer. * * \note * One data element is used for internal use, so when the buffer is full, * this function returns (Ring Buffer size - 1). * *******************************************************************************/ uint32_t Cy_SCB_UART_GetNumInRingBuffer(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context) { uint32_t size; uint32_t locHead = context->rxRingBufHead; /* Suppress a compiler warning about unused variables */ (void) base; if (locHead >= context->rxRingBufTail) { size = (locHead - context->rxRingBufTail); } else { size = (locHead + (context->rxRingBufSize - context->rxRingBufTail)); } return (size); } /******************************************************************************* * Function Name: Cy_SCB_UART_ClearRingBuffer ****************************************************************************//** * * Clears the ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ void Cy_SCB_UART_ClearRingBuffer(CySCB_Type const *base, cy_stc_scb_uart_context_t *context) { /* Suppress a compiler warning about unused variables */ (void) base; context->rxRingBufHead = context->rxRingBufTail; } /******************************************************************************* * Function Name: Cy_SCB_UART_Receive ****************************************************************************//** * * This function starts a UART receive operation. * It configures the receive interrupt sources to get data available in the * receive FIFO and returns. The \ref Cy_SCB_UART_Interrupt manages the further * data transfer. * * If the ring buffer is enabled, this function first reads data from the ring * buffer. If there is more data to receive, it configures the receive interrupt * sources to copy the remaining bytes from the RX FIFO when they arrive. * * When the receive operation is completed (requested number of data elements * received) the \ref CY_SCB_UART_RECEIVE_ACTIVE status is cleared and * the \ref CY_SCB_UART_RECEIVE_DONE_EVENT event is generated. * * \param base * The pointer to the UART SCB instance. * * \param buffer * Pointer to buffer to store received data. * The element size is defined by the data type, which depends on the configured * data width. * * \param size * The number of data elements to receive. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * \ref cy_en_scb_uart_status_t * * \note * * The buffer must not be modified and stay allocated until end of the * receive operation. * * This function overrides the RX interrupt sources and changes the * RX FIFO level. * *******************************************************************************/ 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) { CY_ASSERT_L1(NULL != context); #if !defined(NDEBUG) CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey); #endif CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size)); cy_en_scb_uart_status_t retStatus = CY_SCB_UART_RECEIVE_BUSY; /* check whether there are no active transfer requests */ if (0UL == (context->rxStatus & CY_SCB_UART_RECEIVE_ACTIVE)) { uint8_t *tmpBuf = (uint8_t *) buffer; uint32_t numToCopy = 0UL; /* Disable the RX interrupt source to stop the ring buffer update */ Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); if (NULL != context->rxRingBuf) { /* Get the items available in the ring buffer */ numToCopy = Cy_SCB_UART_GetNumInRingBuffer(base, context); if (numToCopy > 0UL) { uint32_t idx; uint32_t locTail = context->rxRingBufTail; bool byteMode = Cy_SCB_IsRxDataWidthByte(base); /* Adjust the number of items to be read */ if (numToCopy > size) { numToCopy = size; } /* Copy the data elements from the ring buffer */ for (idx = 0UL; idx < numToCopy; ++idx) { ++locTail; if (locTail == context->rxRingBufSize) { locTail = 0UL; } if (byteMode) { uint8_t *buf = (uint8_t *) buffer; buf[idx] = ((uint8_t *) context->rxRingBuf)[locTail]; } else { uint16_t *buf = (uint16_t *) buffer; buf[idx] = ((uint16_t *) context->rxRingBuf)[locTail]; } } /* Update the ring buffer tail after data has been copied */ context->rxRingBufTail = locTail; /* Update with the copied bytes */ size -= numToCopy; context->rxBufIdx = numToCopy; /* Check whether all requested data has been read from the ring buffer */ if (0UL == size) { /* Enable the RX-error interrupt sources to update the error status */ Cy_SCB_SetRxInterruptMask(base, CY_SCB_UART_RECEIVE_ERR); /* Call a completion callback if there was no abort receive called * in the interrupt. The abort clears the number of the received bytes. */ if (context->rxBufIdx > 0UL) { if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_RECEIVE_DONE_EVENT); } } /* Continue receiving data in the ring buffer */ Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL); } else { tmpBuf = &tmpBuf[(byteMode) ? (numToCopy) : (2UL * numToCopy)]; } } } /* Set up a direct RX FIFO receive */ if (size > 0UL) { uint32_t irqRxLevel = SelectRxFifoLevel(base); /* Set up context */ context->rxStatus = CY_SCB_UART_RECEIVE_ACTIVE; context->rxBuf = (void *) tmpBuf; context->rxBufSize = size; context->rxBufIdx = numToCopy; /* Set the RX FIFO level to the trigger interrupt */ Cy_SCB_SetRxFifoLevel(base, (size > irqRxLevel) ? (irqRxLevel - 1UL) : (size - 1UL)); /* Enable the RX interrupt sources to continue data reading */ Cy_SCB_SetRxInterruptMask(base, CY_SCB_UART_RX_INTR); } retStatus = CY_SCB_UART_SUCCESS; } return (retStatus); } /******************************************************************************* * Function Name: Cy_SCB_UART_AbortReceive ****************************************************************************//** * * Abort the current receive operation by clearing the receive status. * * If the ring buffer is disabled, the receive interrupt sources are disabled. * * If the ring buffer is enabled, the receive interrupt source is configured * to get data from the receive FIFO and put it into the ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \note * * The RX FIFO and ring buffer are not cleared after abort of receive * operation. * * If after the abort of the receive operation the transmitter continues * sending data, it gets into the RX FIFO. To drop this data, the RX FIFO * and ring buffer (if enabled) must be cleared when the transmitter * stops sending data. Otherwise, received data will be kept and copied * to the buffer when \ref Cy_SCB_UART_Receive is called. * *******************************************************************************/ void Cy_SCB_UART_AbortReceive(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { if (NULL == context->rxRingBuf) { Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); } context->rxBufSize = 0UL; context->rxBufIdx = 0UL; context->rxStatus = 0UL; } /******************************************************************************* * Function Name: Cy_SCB_UART_GetNumReceived ****************************************************************************//** * * Returns the number of data elements received since the last call to \ref * Cy_SCB_UART_Receive. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * The number of data elements received. * *******************************************************************************/ uint32_t Cy_SCB_UART_GetNumReceived(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context) { /* Suppress a compiler warning about unused variables */ (void) base; return (context->rxBufIdx); } /******************************************************************************* * Function Name: Cy_SCB_UART_GetReceiveStatus ****************************************************************************//** * * Returns the status of the receive operation. * This status is a bit mask and the value returned may have multiple bits set. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * \ref group_scb_uart_macros_receive_status. * * \note * The status is only cleared by calling \ref Cy_SCB_UART_Receive again. * *******************************************************************************/ uint32_t Cy_SCB_UART_GetReceiveStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context) { /* Suppress a compiler warning about unused variables */ (void) base; return (context->rxStatus); } /******************************************************************************* * Function Name: Cy_SCB_UART_Transmit ****************************************************************************//** * * This function starts a UART transmit operation. * It configures the transmit interrupt sources and returns. * The \ref Cy_SCB_UART_Interrupt manages the further data transfer. * * When the transmit operation is completed (requested number of data elements * sent on the bus), the \ref CY_SCB_UART_TRANSMIT_ACTIVE status is cleared and * the \ref CY_SCB_UART_TRANSMIT_DONE_EVENT event is generated. * * \param base * The pointer to the UART SCB instance. * * \param buffer * Pointer to user data to place in transmit buffer. * The element size is defined by the data type, which depends on the configured * data width. * * \param size * The number of data elements to transmit. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * \ref cy_en_scb_uart_status_t * * \note * * The buffer must not be modified and must stay allocated until its content is * copied into the TX FIFO. * * This function overrides the TX FIFO interrupt sources and changes the * TX FIFO level. * *******************************************************************************/ 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) { CY_ASSERT_L1(NULL != context); #if !defined(NDEBUG) CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey); #endif CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size)); cy_en_scb_uart_status_t retStatus = CY_SCB_UART_TRANSMIT_BUSY; /* Check whether there are no active transfer requests */ if (0UL == (CY_SCB_UART_TRANSMIT_ACTIVE & context->txStatus)) { /* Set up context */ context->txStatus = CY_SCB_UART_TRANSMIT_ACTIVE; context->txBuf = buffer; context->txBufSize = size; /* Set the level in TX FIFO to start a transfer */ Cy_SCB_SetTxFifoLevel(base, (Cy_SCB_GetFifoSize(base) / 2UL)); /* Enable the interrupt sources */ if (((uint32_t) CY_SCB_UART_SMARTCARD) == _FLD2VAL(SCB_UART_CTRL_MODE, SCB_UART_CTRL(base))) { /* Transfer data into TX FIFO and track SmartCard-specific errors */ Cy_SCB_SetTxInterruptMask(base, CY_SCB_UART_TX_INTR); } else { /* Transfer data into TX FIFO */ Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL); } retStatus = CY_SCB_UART_SUCCESS; } return (retStatus); } /******************************************************************************* * Function Name: Cy_SCB_UART_AbortTransmit ****************************************************************************//** * * Aborts the current transmit operation. * It disables the transmit interrupt sources and clears the transmit FIFO * and status. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \sideeffect * The transmit FIFO clear operation also clears the shift register, so that * the shifter can be cleared in the middle of a data element transfer, * corrupting it. The data element corruption means that all bits that have * not been transmitted are transmitted as "ones" on the bus. * *******************************************************************************/ void Cy_SCB_UART_AbortTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); Cy_SCB_UART_ClearTxFifo(base); context->txBufSize = 0UL; context->txLeftToTransmit = 0UL; context->txStatus = 0UL; } /******************************************************************************* * Function Name: Cy_SCB_UART_GetNumLeftToTransmit ****************************************************************************//** * * Returns the number of data elements left to transmit since the last call to * \ref Cy_SCB_UART_Transmit. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * The number of data elements left to transmit. * *******************************************************************************/ uint32_t Cy_SCB_UART_GetNumLeftToTransmit(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context) { /* Suppress a compiler warning about unused variables */ (void) base; return (context->txLeftToTransmit); } /******************************************************************************* * Function Name: Cy_SCB_UART_GetTransmitStatus ****************************************************************************//** * * Returns the status of the transmit operation. * This status is a bit mask and the value returned may have multiple bits set. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * * \return * \ref group_scb_uart_macros_transmit_status. * * \note * The status is only cleared by calling \ref Cy_SCB_UART_Transmit or * \ref Cy_SCB_UART_AbortTransmit. * *******************************************************************************/ uint32_t Cy_SCB_UART_GetTransmitStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context) { /* Suppress a compiler warning about unused variables */ (void) base; return (context->txStatus); } /******************************************************************************* * Function Name: Cy_SCB_UART_SendBreakBlocking ****************************************************************************//** * * Sends a break condition (logic low) of specified width on UART TX line. * Blocks until break is completed. Only call this function when UART TX FIFO * and shifter are empty. * * \param base * The pointer to the UART SCB instance. * * \param breakWidth * Width of break condition. Valid range is the TX data width (4 to 16 bits) * * \note * Before sending break all UART TX interrupt sources are disabled. The state * of UART TX interrupt sources is restored before function returns. * * \sideeffect * If this function is called while there is data in the TX FIFO or shifter that * data will be shifted out in packets the size of breakWidth. * *******************************************************************************/ void Cy_SCB_UART_SendBreakBlocking(CySCB_Type *base, uint32_t breakWidth) { uint32_t txCtrlReg; uint32_t txIntrReg; CY_ASSERT_L2(CY_SCB_UART_IS_TX_BREAK_WIDTH_VALID(breakWidth)); /* Disable all UART TX interrupt sources and clear UART TX Done history */ txIntrReg = Cy_SCB_GetTxInterruptMask(base); Cy_SCB_SetTxInterruptMask(base, 0UL); Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UART_DONE); /* Store TX_CTRL configuration */ txCtrlReg = SCB_TX_CTRL(base); /* Set break width: start bit adds one 0 bit */ CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_DATA_WIDTH, (breakWidth - 1UL)); /* Generate break */ Cy_SCB_WriteTxFifo(base, 0UL); /* Wait for break completion */ while (0UL == (Cy_SCB_GetTxInterruptStatus(base) & CY_SCB_TX_INTR_UART_DONE)) { } /* Clear all UART TX interrupt sources */ Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_MASK); /* Restore TX data width and interrupt sources */ SCB_TX_CTRL(base) = txCtrlReg; Cy_SCB_SetTxInterruptMask(base, txIntrReg); } /******************************************************************************* * Function Name: Cy_SCB_UART_Interrupt ****************************************************************************//** * * This is the interrupt function for the SCB configured in the UART mode. * This function must be called inside a user-defined interrupt service * routine to make \ref Cy_SCB_UART_Transmit and \ref Cy_SCB_UART_Receive * work. The ring buffer operation that enabled by calling \ref Cy_SCB_UART_StartRingBuffer * also requires interrupt processing. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ void Cy_SCB_UART_Interrupt(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { if (0UL != (CY_SCB_RX_INTR & Cy_SCB_GetInterruptCause(base))) { /* Get RX error events: a frame error, parity error, and overflow */ uint32_t locRxErr = (CY_SCB_UART_RECEIVE_ERR & Cy_SCB_GetRxInterruptStatusMasked(base)); /* Handle the error conditions */ if (0UL != locRxErr) { context->rxStatus |= locRxErr; Cy_SCB_ClearRxInterrupt(base, locRxErr); if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_RECEIVE_ERR_EVENT); } } /* Break the detect */ if (0UL != (CY_SCB_RX_INTR_UART_BREAK_DETECT & Cy_SCB_GetRxInterruptStatusMasked(base))) { context->rxStatus |= CY_SCB_UART_RECEIVE_BREAK_DETECT; Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_UART_BREAK_DETECT); } /* Copy the received data */ if (0UL != (CY_SCB_RX_INTR_LEVEL & Cy_SCB_GetRxInterruptStatusMasked(base))) { if (context->rxBufSize > 0UL) { HandleDataReceive(base, context); } else { if (NULL != context->rxRingBuf) { HandleRingBuffer(base, context); } } Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL); } if (0UL != (CY_SCB_RX_INTR_NOT_EMPTY & Cy_SCB_GetRxInterruptStatusMasked(base))) { if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_RECEIVE_NOT_EMTPY); } Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_NOT_EMPTY); } } if (0UL != (CY_SCB_TX_INTR & Cy_SCB_GetInterruptCause(base))) { uint32_t locTxErr = (CY_SCB_UART_TRANSMIT_ERR & Cy_SCB_GetTxInterruptStatusMasked(base)); /* Handle the TX error conditions */ if (0UL != locTxErr) { context->txStatus |= locTxErr; Cy_SCB_ClearTxInterrupt(base, locTxErr); if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_TRANSMIT_ERR_EVENT); } } /* Load data to transmit */ if (0UL != (CY_SCB_TX_INTR_LEVEL & Cy_SCB_GetTxInterruptStatusMasked(base))) { HandleDataTransmit(base, context); Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL); } /* Handle the TX complete */ if (0UL != (CY_SCB_TX_INTR_UART_DONE & Cy_SCB_GetTxInterruptStatusMasked(base))) { /* Disable all TX interrupt sources */ Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); context->txStatus &= (uint32_t) ~CY_SCB_UART_TRANSMIT_ACTIVE; context->txLeftToTransmit = 0UL; if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_TRANSMIT_DONE_EVENT); } } if (0UL != (CY_SCB_UART_TX_EMPTY & Cy_SCB_GetTxInterruptStatusMasked(base))) { if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_TRANSMIT_EMTPY); } Cy_SCB_ClearTxInterrupt(base, CY_SCB_UART_TX_EMPTY); } } } /******************************************************************************* * Function Name: HandleDataReceive ****************************************************************************//** * * Reads data from the receive FIFO into the buffer provided by * \ref Cy_SCB_UART_Receive. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ static void HandleDataReceive(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { uint32_t numCopied; uint32_t irqRxLevel = SelectRxFifoLevel(base); /* Get data from RX FIFO */ numCopied = Cy_SCB_UART_GetArray(base, context->rxBuf, context->rxBufSize); /* Move the buffer */ context->rxBufIdx += numCopied; context->rxBufSize -= numCopied; if (0UL == context->rxBufSize) { if (NULL != context->rxRingBuf) { /* Adjust the level to proceed with the ring buffer */ Cy_SCB_SetRxFifoLevel(base, (context->rxRingBufSize >= irqRxLevel) ? (irqRxLevel - 1UL) : (context->rxRingBufSize - 1UL)); Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL); } else { Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); } /* Update the status */ context->rxStatus &= (uint32_t) ~CY_SCB_UART_RECEIVE_ACTIVE; /* Notify that receive is done in a callback */ if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_RECEIVE_DONE_EVENT); } } else { uint8_t *buf = (uint8_t *) context->rxBuf; buf = &buf[(Cy_SCB_IsRxDataWidthByte(base) ? (numCopied) : (2UL * numCopied))]; context->rxBuf = (void *) buf; if (context->rxBufSize < irqRxLevel) { /* Set the RX FIFO level to trigger an interrupt */ Cy_SCB_SetRxFifoLevel(base, (context->rxBufSize - 1UL)); } } } /******************************************************************************* * Function Name: HandleRingBuffer ****************************************************************************//** * * Reads data from the receive FIFO into the receive ring buffer. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ static void HandleRingBuffer(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { uint32_t irqRxLevel = SelectRxFifoLevel(base); uint32_t numToCopy = Cy_SCB_GetNumInRxFifo(base); uint32_t locHead = context->rxRingBufHead; uint32_t rxData; /* Get data into the ring buffer */ while (numToCopy > 0UL) { ++locHead; if (locHead == context->rxRingBufSize) { locHead = 0UL; } if (locHead == context->rxRingBufTail) { /* The ring buffer is full, trigger a callback */ if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_RB_FULL_EVENT); } /* The ring buffer is still full. Disable the RX interrupt not to put data into the ring buffer. * The data is stored in the RX FIFO until it overflows. Revert the head index. */ if (locHead == context->rxRingBufTail) { Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC); locHead = (locHead > 0UL) ? (locHead - 1UL) : (context->rxRingBufSize - 1UL); break; } } /* Get data from RX FIFO. */ rxData = Cy_SCB_ReadRxFifo(base); /* Put a data item in the ring buffer */ if (Cy_SCB_IsRxDataWidthByte(base)) { ((uint8_t *) context->rxRingBuf)[locHead] = (uint8_t) rxData; } else { ((uint16_t *) context->rxRingBuf)[locHead] = (uint16_t) rxData; } --numToCopy; } /* Update the head index */ context->rxRingBufHead = locHead; /* Get free entries in the ring buffer */ numToCopy = context->rxRingBufSize - Cy_SCB_UART_GetNumInRingBuffer(base, context); if (numToCopy < irqRxLevel) { /* Adjust the level to copy to the ring buffer */ uint32_t level = (numToCopy > 0UL) ? (numToCopy - 1UL) : 0UL; Cy_SCB_SetRxFifoLevel(base, level); } } /******************************************************************************* * Function Name: HandleDataTransmit ****************************************************************************//** * * Loads the transmit FIFO with data provided by \ref Cy_SCB_UART_Transmit. * * \param base * The pointer to the UART SCB instance. * * \param context * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated * by the user. The structure is used during the UART operation for internal * configuration and data retention. The user must not modify anything * in this structure. * *******************************************************************************/ static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context) { uint32_t numToCopy; uint32_t fifoSize = Cy_SCB_GetFifoSize(base); bool byteMode = Cy_SCB_IsTxDataWidthByte(base); if (context->txBufSize > 1UL) { uint8_t *buf = (uint8_t *) context->txBuf; /* Get the number of items left for transmission */ context->txLeftToTransmit = context->txBufSize; /* Put data into TX FIFO */ numToCopy = Cy_SCB_UART_PutArray(base, context->txBuf, (context->txBufSize - 1UL)); /* Move the buffer */ context->txBufSize -= numToCopy; buf = &buf[(byteMode) ? (numToCopy) : (2UL * numToCopy)]; context->txBuf = (void *) buf; } /* Put the last data item into TX FIFO */ if ((fifoSize != Cy_SCB_GetNumInTxFifo(base)) && (1UL == context->txBufSize)) { uint32_t txData; uint32_t intrStatus; context->txBufSize = 0UL; /* Get the last item from the buffer */ txData = (uint32_t) ((byteMode) ? ((uint8_t *) context->txBuf)[0UL] : ((uint16_t *) context->txBuf)[0UL]); /* Put the last data element and make sure that "TX done" will happen for it */ intrStatus = Cy_SysLib_EnterCriticalSection(); Cy_SCB_WriteTxFifo(base, txData); Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UART_DONE); Cy_SysLib_ExitCriticalSection(intrStatus); /* Disable the level interrupt source and enable "transfer done" */ Cy_SCB_SetTxInterruptMask(base, (CY_SCB_TX_INTR_UART_DONE | (Cy_SCB_GetTxInterruptMask(base) & (uint32_t) ~CY_SCB_TX_INTR_LEVEL))); /* Data is copied into TX FIFO */ context->txStatus |= CY_SCB_UART_TRANSMIT_IN_FIFO; if (NULL != context->cbEvents) { context->cbEvents(CY_SCB_UART_TRANSMIT_IN_FIFO_EVENT); } } } #if defined(__cplusplus) } #endif #endif /* CY_IP_MXSCB */ /* [] END OF FILE */