1 /***************************************************************************//**
2 * \file cy_scb_uart.c
3 * \version 2.80
4 *
5 * Provides UART API implementation of the SCB driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2016-2021 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24 
25 #include "cy_device.h"
26 
27 #if defined (CY_IP_MXSCB)
28 
29 #include "cy_scb_uart.h"
30 
31 #if defined(__cplusplus)
32 extern "C" {
33 #endif
34 
35 /* Static functions */
36 static void HandleDataReceive (CySCB_Type *base, cy_stc_scb_uart_context_t *context);
37 static void HandleRingBuffer  (CySCB_Type *base, cy_stc_scb_uart_context_t *context);
38 static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context);
39 static uint32_t SelectRxFifoLevel(CySCB_Type const *base);
40 
41 /*******************************************************************************
42 * Function Name: Cy_SCB_UART_SetOverSample
43 ****************************************************************************//**
44 *
45 * Sets oversample bits of UART.
46 *
47 * \param base
48 * The pointer to the UART SCB instance.
49 *
50 * \param overSample
51 * Value of oversample to be set.
52 *
53 * \param context
54 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
55 * by the user. The structure is used during the UART operation for internal
56 * configuration and data retention. The user must not modify anything
57 * in this structure.
58 * User should not pass NULL as pointer to context.
59 *
60 * \return
61 * \ref cy_en_scb_uart_status_t
62 *
63 * \note
64 * Ensure that the SCB block is disabled before calling this function.
65 *
66 * \snippet scb/uart_snippet/main.c UART_SET_OVS
67 *
68 *******************************************************************************/
Cy_SCB_UART_SetOverSample(CySCB_Type * base,uint32_t overSample,cy_stc_scb_uart_context_t * context)69 cy_en_scb_uart_status_t Cy_SCB_UART_SetOverSample(CySCB_Type *base, uint32_t overSample, cy_stc_scb_uart_context_t *context)
70 {
71     CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 10.8', 1, \
72     'Intentional typecast to cy_en_scb_uart_mode_t enum to validate arguments.');
73     if((NULL == base) || (NULL == context) ||
74        ((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))
75     {
76         return CY_SCB_UART_BAD_PARAM;
77     }
78     CY_MISRA_BLOCK_END('MISRA C-2012 Rule 10.8');
79 
80     uint32_t ovs;
81 
82     if (((uint32_t)CY_SCB_UART_IRDA == _FLD2VAL(SCB_UART_CTRL_MODE,SCB_UART_CTRL(base))) && (!context->irdaEnableLowPowerReceiver))
83     {
84         /* For Normal IrDA mode oversampling is always zero */
85         ovs = 0UL;
86     }
87     else
88     {
89         ovs = overSample - 1UL;
90     }
91 
92     /* Set oversample bits */
93     CY_REG32_CLR_SET(SCB_CTRL(base), SCB_CTRL_OVS, ovs);
94 
95     return CY_SCB_UART_SUCCESS;
96 }
97 
98 /*******************************************************************************
99 * Function Name: Cy_SCB_UART_SetDataWidth
100 ****************************************************************************//**
101 *
102 * Sets datawidth for UART transaction.
103 *
104 * \param base
105 * The pointer to the UART SCB instance.
106 *
107 * \param dataWidth
108 * The width of UART data in the UART transaction.
109 *
110 * \note
111 * Ensure that the SCB block is disabled before calling this function.
112 *
113 * \snippet scb/uart_snippet/main.c UART_SET_DATA_WIDTH
114 *
115 *******************************************************************************/
Cy_SCB_UART_SetDataWidth(CySCB_Type * base,uint32_t dataWidth)116 void Cy_SCB_UART_SetDataWidth(CySCB_Type *base, uint32_t dataWidth)
117 {
118     CY_ASSERT_L2(CY_SCB_UART_IS_DATA_WIDTH_VALID (dataWidth));
119 
120     /* Configure the memory width */
121     Cy_SCB_SetByteMode(base, (dataWidth <= CY_SCB_BYTE_WIDTH));
122 
123     CY_REG32_CLR_SET(SCB_RX_CTRL(base), SCB_RX_CTRL_DATA_WIDTH, (dataWidth - 1UL));
124 
125     CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_DATA_WIDTH, (dataWidth - 1UL));
126 }
127 
128 /*******************************************************************************
129 * Function Name: Cy_SCB_UART_SetParity
130 ****************************************************************************//**
131 *
132 * Sets parity for UART transaction.
133 *
134 * \param base
135 * The pointer to the UART SCB instance.
136 *
137 * \param parity
138 * The UART parity bit in the UART transaction.
139 *
140 * \note
141 * Ensure that the SCB block is disabled before calling this function.
142 *
143 * \snippet scb/uart_snippet/main.c UART_SET_PARITY
144 *
145 *******************************************************************************/
Cy_SCB_UART_SetParity(CySCB_Type * base,cy_en_scb_uart_parity_t parity)146 void Cy_SCB_UART_SetParity(CySCB_Type *base, cy_en_scb_uart_parity_t parity)
147 {
148     CY_ASSERT_L3(CY_SCB_UART_IS_PARITY_VALID (parity));
149 
150     /* Configure the RX direction with given parameters */
151     CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), CY_SCB_UART_RX_CTRL_SET_PARITY, (uint32_t) parity);
152 
153     /* Configure the TX direction with given parameters*/
154     CY_REG32_CLR_SET(SCB_UART_TX_CTRL(base), CY_SCB_UART_TX_CTRL_SET_PARITY, (uint32_t) parity);
155 }
156 
157 /*******************************************************************************
158 * Function Name: Cy_SCB_UART_SetStopBits
159 ****************************************************************************//**
160 *
161 * Sets stop bits for UART transaction.
162 *
163 * \param base
164 * The pointer to the UART SCB instance.
165 *
166 * \param stopBits
167 * The number of stop bits in the UART transaction.
168 *
169 * \note
170 * Ensure that the SCB block is disabled before calling this function.
171 *
172 * \snippet scb/uart_snippet/main.c UART_SET_STOP_BITS
173 *
174 *******************************************************************************/
Cy_SCB_UART_SetStopBits(CySCB_Type * base,cy_en_scb_uart_stop_bits_t stopBits)175 void Cy_SCB_UART_SetStopBits(CySCB_Type *base, cy_en_scb_uart_stop_bits_t stopBits)
176 {
177     CY_ASSERT_L3(CY_SCB_UART_IS_STOP_BITS_VALID (stopBits));
178 
179     /* Configure the RX direction with given parameters */
180     CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), SCB_UART_RX_CTRL_STOP_BITS, ((uint32_t) stopBits) - 1UL);
181 
182     /* Configure the TX direction with given parameters*/
183     CY_REG32_CLR_SET(SCB_UART_TX_CTRL(base), SCB_UART_TX_CTRL_STOP_BITS, ((uint32_t) stopBits) - 1UL);
184 }
185 
186 /*******************************************************************************
187 * Function Name: Cy_SCB_UART_SetDropOnParityError
188 ****************************************************************************//**
189 *
190 * Sets SetDropOnParityError for UART transaction.
191 *
192 * \param base
193 * The pointer to the UART SCB instance.
194 *
195 * \param dropOnParityError
196 * To enable the hardware to drop data in the RX FIFO when a parity error is
197 * detected in the UART transaction.
198 *
199 * \note
200 * Ensure that the SCB block is disabled before calling this function.
201 *
202 * \snippet scb/uart_snippet/main.c UART_SET_DROP_ON_PARITY_ERROR
203 *
204 *******************************************************************************/
Cy_SCB_UART_SetDropOnParityError(CySCB_Type * base,bool dropOnParityError)205 void Cy_SCB_UART_SetDropOnParityError(CySCB_Type *base, bool dropOnParityError)
206 {
207     /* Configure the RX direction with given parameters */
208     CY_REG32_CLR_SET(SCB_UART_RX_CTRL(base), SCB_UART_RX_CTRL_DROP_ON_PARITY_ERROR, dropOnParityError);
209 }
210 
211 /*******************************************************************************
212 * Function Name: Cy_SCB_UART_SetEnableMsbFirst
213 ****************************************************************************//**
214 *
215 * Sets enableMsbFirst for UART transaction.
216 *
217 * \param base
218 * The pointer to the UART SCB instance.
219 *
220 * \param enableMsbFirst
221 * Enables the hardware to shift out data element MSB first;
222 * otherwise, LSB first in the UART transaction.
223 *
224 * \note
225 * Ensure that the SCB block is disabled before calling this function.
226 *
227 * \snippet scb/uart_snippet/main.c UART_SET_ENABLE_MSB_FIRST
228 *
229 *******************************************************************************/
Cy_SCB_UART_SetEnableMsbFirst(CySCB_Type * base,bool enableMsbFirst)230 void Cy_SCB_UART_SetEnableMsbFirst(CySCB_Type *base, bool enableMsbFirst)
231 {
232     /* Configure the RX direction with given parameters */
233     CY_REG32_CLR_SET(SCB_RX_CTRL(base), SCB_RX_CTRL_MSB_FIRST, enableMsbFirst);
234 
235     /* Configure the TX direction with given parameters*/
236     CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_MSB_FIRST, enableMsbFirst);
237 }
238 
239 /*******************************************************************************
240 * Function Name: Cy_SCB_UART_Init
241 ****************************************************************************//**
242 *
243 * Initializes the SCB for UART operation.
244 *
245 * \param base
246 * The pointer to the UART SCB instance.
247 *
248 * \param config
249 * The pointer to configuration structure \ref cy_stc_scb_uart_config_t.
250 *
251 * \param context
252 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
253 * by the user. The structure is used during the UART operation for internal
254 * configuration and data retention. The user must not modify anything
255 * in this structure.
256 * If only UART \ref group_scb_uart_ll will be used pass NULL as pointer to
257 * context.
258 *
259 * \return
260 * \ref cy_en_scb_uart_status_t
261 *
262 * \note
263 * Ensure that the SCB block is disabled before calling this function.
264 *
265 *******************************************************************************/
Cy_SCB_UART_Init(CySCB_Type * base,cy_stc_scb_uart_config_t const * config,cy_stc_scb_uart_context_t * context)266 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)
267 {
268     if ((NULL == base) || (NULL == config))
269     {
270         return CY_SCB_UART_BAD_PARAM;
271     }
272 
273     CY_ASSERT_L3(CY_SCB_UART_IS_MODE_VALID     (config->uartMode));
274     CY_ASSERT_L3(CY_SCB_UART_IS_STOP_BITS_VALID(config->stopBits));
275     CY_ASSERT_L3(CY_SCB_UART_IS_PARITY_VALID   (config->parity));
276     CY_ASSERT_L3(CY_SCB_UART_IS_POLARITY_VALID (config->ctsPolarity));
277     CY_ASSERT_L3(CY_SCB_UART_IS_POLARITY_VALID (config->rtsPolarity));
278 
279     CY_ASSERT_L2(CY_SCB_UART_IS_OVERSAMPLE_VALID  (config->oversample, config->uartMode, config->irdaEnableLowPowerReceiver));
280     CY_ASSERT_L2(CY_SCB_UART_IS_DATA_WIDTH_VALID  (config->dataWidth));
281     CY_ASSERT_L2(CY_SCB_UART_IS_ADDRESS_VALID     (config->receiverAddress));
282     CY_ASSERT_L2(CY_SCB_UART_IS_ADDRESS_MASK_VALID(config->receiverAddressMask));
283 
284     CY_ASSERT_L2(CY_SCB_UART_IS_MUTLI_PROC_VALID  (config->enableMutliProcessorMode, config->uartMode, config->dataWidth, config->parity));
285 
286     CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->rxFifoIntEnableMask, CY_SCB_UART_RX_INTR_MASK));
287     CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->txFifoIntEnableMask, CY_SCB_UART_TX_INTR_MASK));
288 
289     uint32_t ovs;
290 
291     if ((CY_SCB_UART_IRDA == config->uartMode) && (!config->irdaEnableLowPowerReceiver))
292     {
293         /* For Normal IrDA mode oversampling is always zero */
294         ovs = 0UL;
295     }
296     else
297     {
298         ovs = (config->oversample - 1UL);
299     }
300 
301     /* Configure the UART interface */
302 #if(CY_IP_MXSCB_VERSION>=3)
303     SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, config->acceptAddrInFifo)                      |
304                  _VAL2FLD(SCB_CTRL_MEM_WIDTH, ((config->dataWidth <= CY_SCB_BYTE_WIDTH)? 0UL:1UL))  |
305                  _VAL2FLD(SCB_CTRL_OVS, ovs)                                                        |
306                  _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
307 #elif(CY_IP_MXSCB_VERSION==1)
308     SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, config->acceptAddrInFifo)               |
309                  _BOOL2FLD(SCB_CTRL_BYTE_MODE, (config->dataWidth <= CY_SCB_BYTE_WIDTH)) |
310                  _VAL2FLD(SCB_CTRL_OVS, ovs)                                             |
311                  _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
312 #endif /* CY_IP_MXSCB_VERSION */
313     /* Configure SCB_CTRL.BYTE_MODE then verify levels */
314     CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->rxFifoTriggerLevel));
315     CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->txFifoTriggerLevel));
316     CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->rtsRxFifoLevel));
317 
318     SCB_UART_CTRL(base) = _VAL2FLD(SCB_UART_CTRL_MODE, (uint32_t) config->uartMode);
319 
320     /* Configure the RX direction */
321     SCB_UART_RX_CTRL(base) = _BOOL2FLD(SCB_UART_RX_CTRL_POLARITY, config->irdaInvertRx)                  |
322                          _BOOL2FLD(SCB_UART_RX_CTRL_MP_MODE, config->enableMutliProcessorMode)       |
323                          _BOOL2FLD(SCB_UART_RX_CTRL_DROP_ON_PARITY_ERROR, config->dropOnParityError) |
324                          _BOOL2FLD(SCB_UART_RX_CTRL_DROP_ON_FRAME_ERROR, config->dropOnFrameError)   |
325                          _VAL2FLD(SCB_UART_RX_CTRL_BREAK_WIDTH, (config->breakWidth - 1UL))          |
326                          _VAL2FLD(SCB_UART_RX_CTRL_STOP_BITS,   ((uint32_t) config->stopBits) - 1UL) |
327                          _VAL2FLD(CY_SCB_UART_RX_CTRL_SET_PARITY, (uint32_t) config->parity);
328 #if(CY_IP_MXSCB_VERSION>=3)
329     SCB_UART_RX_CTRL(base)|=_BOOL2FLD(SCB_UART_RX_CTRL_BREAK_LEVEL, config->breaklevel);
330 #endif /* CY_IP_MXSCB_VERSION */
331 
332     SCB_RX_CTRL(base) = _BOOL2FLD(SCB_RX_CTRL_MSB_FIRST, config->enableMsbFirst)          |
333                     _BOOL2FLD(SCB_RX_CTRL_MEDIAN, ((config->enableInputFilter) || \
334                                              (config->uartMode == CY_SCB_UART_IRDA))) |
335                     _VAL2FLD(SCB_RX_CTRL_DATA_WIDTH, (config->dataWidth - 1UL));
336 
337     SCB_RX_MATCH(base) = _VAL2FLD(SCB_RX_MATCH_ADDR, config->receiverAddress) |
338                      _VAL2FLD(SCB_RX_MATCH_MASK, config->receiverAddressMask);
339 
340     /* Configure SCB_CTRL.RX_CTRL then verify break width */
341     CY_ASSERT_L2(CY_SCB_UART_IS_RX_BREAK_WIDTH_VALID(base, config->breakWidth));
342 
343     /* Configure the TX direction */
344     SCB_UART_TX_CTRL(base) = _BOOL2FLD(SCB_UART_TX_CTRL_RETRY_ON_NACK, ((config->smartCardRetryOnNack) && \
345                                                               (config->uartMode == CY_SCB_UART_SMARTCARD))) |
346                          _VAL2FLD(SCB_UART_TX_CTRL_STOP_BITS, ((uint32_t) config->stopBits) - 1UL)          |
347                          _VAL2FLD(CY_SCB_UART_TX_CTRL_SET_PARITY, (uint32_t) config->parity);
348 
349     SCB_TX_CTRL(base)  = _BOOL2FLD(SCB_TX_CTRL_MSB_FIRST,  config->enableMsbFirst)    |
350                      _VAL2FLD(SCB_TX_CTRL_DATA_WIDTH,  (config->dataWidth - 1UL)) |
351                      _BOOL2FLD(SCB_TX_CTRL_OPEN_DRAIN, (config->uartMode == CY_SCB_UART_SMARTCARD));
352 
353     SCB_RX_FIFO_CTRL(base) = _VAL2FLD(SCB_RX_FIFO_CTRL_TRIGGER_LEVEL, config->rxFifoTriggerLevel);
354 
355     /* Configure the flow control */
356     SCB_UART_FLOW_CTRL(base) = _BOOL2FLD(SCB_UART_FLOW_CTRL_CTS_ENABLED, config->enableCts) |
357                            _BOOL2FLD(SCB_UART_FLOW_CTRL_CTS_POLARITY, (CY_SCB_UART_ACTIVE_HIGH == config->ctsPolarity)) |
358                            _BOOL2FLD(SCB_UART_FLOW_CTRL_RTS_POLARITY, (CY_SCB_UART_ACTIVE_HIGH == config->rtsPolarity)) |
359                            _VAL2FLD(SCB_UART_FLOW_CTRL_TRIGGER_LEVEL, config->rtsRxFifoLevel);
360 
361     SCB_TX_FIFO_CTRL(base) = _VAL2FLD(SCB_TX_FIFO_CTRL_TRIGGER_LEVEL, config->txFifoTriggerLevel);
362 
363     /* Set up interrupt sources */
364     SCB_INTR_RX_MASK(base) = (config->rxFifoIntEnableMask & CY_SCB_UART_RX_INTR_MASK);
365     SCB_INTR_TX_MASK(base) = (config->txFifoIntEnableMask & CY_SCB_UART_TX_INTR_MASK);
366 
367     /* Initialize context */
368     if (NULL != context)
369     {
370         context->rxStatus  = 0UL;
371         context->txStatus  = 0UL;
372 
373         context->rxRingBuf = NULL;
374         context->rxRingBufSize = 0UL;
375 
376         context->rxBufIdx  = 0UL;
377         context->txLeftToTransmit = 0UL;
378 
379         context->cbEvents = NULL;
380         context->irdaEnableLowPowerReceiver = config->irdaEnableLowPowerReceiver;
381 
382     #if !defined(NDEBUG)
383         /* Put an initialization key into the initKey variable to verify
384         * context initialization in the transfer API.
385         */
386         context->initKey = CY_SCB_UART_INIT_KEY;
387     #endif /* !(NDEBUG) */
388     }
389 
390     return CY_SCB_UART_SUCCESS;
391 }
392 
393 
394 /*******************************************************************************
395 * Function Name: Cy_SCB_UART_DeInit
396 ****************************************************************************//**
397 *
398 * De-initializes the SCB block. Returns the register values to default.
399 *
400 * \param base
401 * The pointer to the UART SCB instance.
402 *
403 * \note
404 * Ensure that the SCB block is disabled before calling this function.
405 *
406 *******************************************************************************/
Cy_SCB_UART_DeInit(CySCB_Type * base)407 void Cy_SCB_UART_DeInit(CySCB_Type *base)
408 {
409     /* De-initialize the UART interface */
410     SCB_CTRL(base)      = CY_SCB_CTRL_DEF_VAL;
411     SCB_UART_CTRL(base) = CY_SCB_UART_CTRL_DEF_VAL;
412 
413     /* De-initialize the RX direction */
414     SCB_UART_RX_CTRL(base) = 0UL;
415     SCB_RX_CTRL(base)      = CY_SCB_RX_CTRL_DEF_VAL;
416     SCB_RX_FIFO_CTRL(base) = 0UL;
417     SCB_RX_MATCH(base)     = 0UL;
418 
419     /* De-initialize the TX direction */
420     SCB_UART_TX_CTRL(base) = 0UL;
421     SCB_TX_CTRL(base)      = CY_SCB_TX_CTRL_DEF_VAL;
422     SCB_TX_FIFO_CTRL(base) = 0UL;
423 
424     /* De-initialize the flow control */
425     SCB_UART_FLOW_CTRL(base) = 0UL;
426 
427     /* De-initialize the interrupt sources */
428     SCB_INTR_SPI_EC_MASK(base) = 0UL;
429     SCB_INTR_I2C_EC_MASK(base) = 0UL;
430     SCB_INTR_RX_MASK(base)     = 0UL;
431     SCB_INTR_TX_MASK(base)     = 0UL;
432     SCB_INTR_M_MASK(base)      = 0UL;
433     SCB_INTR_S_MASK(base)      = 0UL;
434 }
435 
436 
437 /*******************************************************************************
438 * Function Name: Cy_SCB_UART_Disable
439 ****************************************************************************//**
440 *
441 * Disables the SCB block and clears context statuses.
442 * Note that after the block is disabled, the TX and RX FIFOs and
443 * hardware statuses are cleared. Also, the hardware stops driving the
444 * output and ignores the input. Refer to section \ref group_scb_uart_lp for more
445 * information about UART pins when SCB disabled.
446 
447 * \param base
448 * The pointer to the UART SCB instance.
449 *
450 * \param context
451 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
452 * by the user. The structure is used during the UART operation for internal
453 * configuration and data retention. The user must not modify anything
454 * in this structure.
455 * If only UART functions that do not require context will be used to pass NULL
456 * as pointer to context.
457 *
458 * \note
459 * Calling this function when the UART is busy (transmitter preforms data
460 * transfer or receiver is in the middle of data reception) may result transfer
461 * corruption because the hardware stops driving the outputs and ignores
462 * the inputs.
463 * Ensure that the UART is not busy before calling this function.
464 *
465 *******************************************************************************/
Cy_SCB_UART_Disable(CySCB_Type * base,cy_stc_scb_uart_context_t * context)466 void Cy_SCB_UART_Disable(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
467 {
468     SCB_CTRL(base) &= (uint32_t) ~SCB_CTRL_ENABLED_Msk;
469 
470     if (NULL != context)
471     {
472         context->rxStatus  = 0UL;
473         context->txStatus  = 0UL;
474 
475         context->rxBufIdx  = 0UL;
476         context->txLeftToTransmit = 0UL;
477     }
478 }
479 
480 
481 /*******************************************************************************
482 * Function Name: Cy_SCB_UART_DeepSleepCallback
483 ****************************************************************************//**
484 *
485 * This function handles the transition of the SCB UART into and out of
486 * Deep Sleep mode. It prevents the device from entering Deep Sleep
487 * mode if the UART is transmitting data or has any data in the RX FIFO. If the
488 * UART is ready to enter Deep Sleep mode, it is disabled. The UART is enabled
489 * when the device fails to enter Deep Sleep mode or it is awakened from
490 * Deep Sleep mode. While the UART is disabled, it stops driving the outputs
491 * and ignores the inputs. Any incoming data is ignored. Refer to section
492 * \ref group_scb_uart_lp for more information about UART pins when SCB disabled.
493 *
494 * This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep,
495 * to do it, register this function as a callback before calling
496 * \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback
497 * type and call \ref Cy_SysPm_RegisterCallback.
498 *
499 * \param callbackParams
500 * The pointer to the callback parameters structure
501 * \ref cy_stc_syspm_callback_params_t.
502 *
503 * \param mode
504 * Callback mode, see \ref cy_en_syspm_callback_mode_t
505 *
506 * \return
507 * \ref cy_en_syspm_status_t
508 *
509 *******************************************************************************/
Cy_SCB_UART_DeepSleepCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)510 cy_en_syspm_status_t Cy_SCB_UART_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
511 {
512     cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;
513 
514     CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
515     cy_stc_scb_uart_context_t *locContext = (cy_stc_scb_uart_context_t *) callbackParams->context;
516 
517     switch(mode)
518     {
519         case CY_SYSPM_CHECK_READY:
520         {
521             /* Check whether the High-level API is not busy executing the transmit
522             * or receive operation.
523             */
524             if ((0UL == (CY_SCB_UART_TRANSMIT_ACTIVE & Cy_SCB_UART_GetTransmitStatus(locBase, locContext))) &&
525                 (0UL == (CY_SCB_UART_RECEIVE_ACTIVE  & Cy_SCB_UART_GetReceiveStatus (locBase, locContext))))
526             {
527                 /* If all data elements are transmitted from the TX FIFO and
528                 * shifter and the RX FIFO is empty: the UART is ready to enter
529                 * Deep Sleep mode.
530                 */
531                 if (Cy_SCB_UART_IsTxComplete(locBase))
532                 {
533                     if (0UL == Cy_SCB_UART_GetNumInRxFifo(locBase))
534                     {
535                         /* Disable the UART. The transmitter stops driving the
536                         * lines and the receiver stops receiving data until
537                         * the UART is enabled.
538                         * This happens when the device failed to enter Deep
539                         * Sleep or it is awaken from Deep Sleep mode.
540                         */
541                         Cy_SCB_UART_Disable(locBase, locContext);
542 
543                         retStatus = CY_SYSPM_SUCCESS;
544                     }
545                 }
546             }
547         }
548         break;
549 
550         case CY_SYSPM_CHECK_FAIL:
551         {
552             /* The other driver is not ready for Deep Sleep mode. Restore the
553             * Active mode configuration.
554             */
555 
556             /* Enable the UART to operate */
557             Cy_SCB_UART_Enable(locBase);
558 
559             retStatus = CY_SYSPM_SUCCESS;
560         }
561         break;
562 
563         case CY_SYSPM_BEFORE_TRANSITION:
564             /* Do noting: the UART is not capable of waking up from
565             * Deep Sleep mode.
566             */
567         break;
568 
569         case CY_SYSPM_AFTER_TRANSITION:
570         {
571             /* Enable the UART to operate */
572             Cy_SCB_UART_Enable(locBase);
573 
574             retStatus = CY_SYSPM_SUCCESS;
575         }
576         break;
577 
578         default:
579             /* Unknown state */
580             break;
581     }
582 
583     return (retStatus);
584 }
585 
586 
587 /*******************************************************************************
588 * Function Name: Cy_SCB_UART_HibernateCallback
589 ****************************************************************************//**
590 *
591 * This function handles the transition of the SCB UART into Hibernate mode.
592 * It prevents the device from entering Hibernate mode if the UART is
593 * transmitting data or has any data in the RX FIFO. If the UART is ready
594 * to enter Hibernate mode, it is disabled. If the device fails to enter
595 * Hibernate mode, the UART is enabled. While the UART is disabled, it stops
596 * driving the outputs and ignores the inputs. Any incoming data is ignored.
597 * Refer to section \ref group_scb_uart_lp for more information about UART pins
598 * when SCB disabled.
599 *
600 * This function must be called during execution of \ref Cy_SysPm_SystemEnterHibernate.
601 * To do it, register this function as a callback before calling
602 * \ref Cy_SysPm_SystemEnterHibernate : specify \ref CY_SYSPM_HIBERNATE as the callback type
603 * and call \ref Cy_SysPm_RegisterCallback.
604 *
605 * \param callbackParams
606 * The pointer to the callback parameters structure
607 * \ref cy_stc_syspm_callback_params_t.
608 *
609 * \param mode
610 * Callback mode, see \ref cy_en_syspm_callback_mode_t
611 *
612 * \return
613 * \ref cy_en_syspm_status_t
614 *
615 *******************************************************************************/
Cy_SCB_UART_HibernateCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)616 cy_en_syspm_status_t Cy_SCB_UART_HibernateCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
617 {
618     return Cy_SCB_UART_DeepSleepCallback(callbackParams, mode);
619 }
620 
621 
622 /************************* High-Level Functions ********************************
623 * The following functions are considered high-level. They provide the layer of
624 * intelligence to the SCB. These functions require interrupts.
625 * Low-level and high-level functions must not be mixed because low-level API
626 * can adversely affect the operation of high-level functions.
627 *******************************************************************************/
628 
629 
630 /*******************************************************************************
631 * Function Name: Cy_SCB_UART_StartRingBuffer
632 ****************************************************************************//**
633 *
634 * Starts the receive ring buffer operation.
635 * The RX interrupt source is configured to get data from the RX
636 * FIFO and put into the ring buffer.
637 *
638 * \param base
639 * The pointer to the UART SCB instance.
640 *
641 * \param buffer
642 * Pointer to the user defined ring buffer.
643 * The element size is defined by the data type, which depends on the configured
644 * data width.
645 *
646 * \param size
647 * The size of the receive ring buffer.
648 * Note that one data element is used for internal use, so if the size is 32,
649 * then only 31 data elements are used for data storage.
650 *
651 * \param context
652 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
653 * by the user. The structure is used during the UART operation for internal
654 * configuration and data retention. The user must not modify anything
655 * in this structure.
656 *
657 * \note
658 * * The buffer must not be modified and stay allocated while the ring buffer
659 *   operates.
660 * * This function overrides the RX interrupt sources and changes the
661 *   RX FIFO level.
662 *
663 *******************************************************************************/
Cy_SCB_UART_StartRingBuffer(CySCB_Type * base,void * buffer,uint32_t size,cy_stc_scb_uart_context_t * context)664 void Cy_SCB_UART_StartRingBuffer(CySCB_Type *base, void *buffer, uint32_t size, cy_stc_scb_uart_context_t *context)
665 {
666     CY_ASSERT_L1(NULL != context);
667     #if !defined(NDEBUG)
668     CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey);
669     #endif
670     CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size));
671 
672     if ((NULL != buffer) && (size > 0UL))
673     {
674         uint32_t irqRxLevel =  SelectRxFifoLevel(base);
675 
676         context->rxRingBuf     = buffer;
677         context->rxRingBufSize = size;
678         context->rxRingBufHead = 0UL;
679         context->rxRingBufTail = 0UL;
680 
681         /* Set up an RX interrupt to handle the ring buffer */
682         Cy_SCB_SetRxFifoLevel(base, (size >= irqRxLevel) ? (irqRxLevel - 1UL) : (size - 1UL));
683 
684         Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
685     }
686 }
687 
688 
689 /*******************************************************************************
690 * Function Name: SelectRxFifoLevel
691 ****************************************************************************//**
692 * Select RX FIFO level as RTS level if it is valid (>0) or half of RX FIFO size
693 * in other case.
694 *
695 * \return
696 * The RX FIFO level.
697 *
698 *******************************************************************************/
SelectRxFifoLevel(CySCB_Type const * base)699 static uint32_t SelectRxFifoLevel(CySCB_Type const *base)
700 {
701     uint32_t halfFifoSize = Cy_SCB_GetFifoSize(base) / 2UL;
702     uint32_t rtsFifoLevel = Cy_SCB_UART_GetRtsFifoLevel(base);
703 
704     return ((rtsFifoLevel != 0UL ) ? (rtsFifoLevel) : (halfFifoSize));
705 }
706 
707 
708 /*******************************************************************************
709 * Function Name: Cy_SCB_UART_StopRingBuffer
710 ****************************************************************************//**
711 *
712 * Stops receiving data into the ring buffer and clears the ring buffer.
713 *
714 * \param base
715 * The pointer to the UART SCB instance.
716 *
717 * \param context
718 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
719 * by the user. The structure is used during the UART operation for internal
720 * configuration and data retention. The user must not modify anything
721 * in this structure.
722 *
723 *******************************************************************************/
Cy_SCB_UART_StopRingBuffer(CySCB_Type * base,cy_stc_scb_uart_context_t * context)724 void Cy_SCB_UART_StopRingBuffer(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
725 {
726     Cy_SCB_SetRxInterruptMask  (base, CY_SCB_CLEAR_ALL_INTR_SRC);
727     Cy_SCB_UART_ClearRingBuffer(base, context);
728 
729     context->rxRingBuf     = NULL;
730     context->rxRingBufSize = 0UL;
731 }
732 
733 
734 /*******************************************************************************
735 * Function Name: Cy_SCB_UART_GetNumInRingBuffer
736 ****************************************************************************//**
737 *
738 * Returns the number of data elements in the ring buffer.
739 *
740 * \param base
741 * The pointer to the UART SCB instance.
742 *
743 * \param context
744 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
745 * by the user. The structure is used during the UART operation for internal
746 * configuration and data retention. The user must not modify anything
747 * in this structure.
748 *
749 * \return
750 * The number of data elements in the receive ring buffer.
751 *
752 * \note
753 * One data element is used for internal use, so when the buffer is full,
754 * this function returns (Ring Buffer size - 1).
755 *
756 *******************************************************************************/
Cy_SCB_UART_GetNumInRingBuffer(CySCB_Type const * base,cy_stc_scb_uart_context_t const * context)757 uint32_t Cy_SCB_UART_GetNumInRingBuffer(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
758 {
759     uint32_t size;
760     uint32_t locHead = context->rxRingBufHead;
761 
762     /* Suppress a compiler warning about unused variables */
763     (void) base;
764 
765     if (locHead >= context->rxRingBufTail)
766     {
767         size = (locHead - context->rxRingBufTail);
768     }
769     else
770     {
771         size = (locHead + (context->rxRingBufSize - context->rxRingBufTail));
772     }
773 
774     return (size);
775 }
776 
777 
778 /*******************************************************************************
779 * Function Name: Cy_SCB_UART_ClearRingBuffer
780 ****************************************************************************//**
781 *
782 * Clears the ring buffer.
783 *
784 * \param base
785 * The pointer to the UART SCB instance.
786 *
787 * \param context
788 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
789 * by the user. The structure is used during the UART operation for internal
790 * configuration and data retention. The user must not modify anything
791 * in this structure.
792 *
793 *******************************************************************************/
Cy_SCB_UART_ClearRingBuffer(CySCB_Type const * base,cy_stc_scb_uart_context_t * context)794 void Cy_SCB_UART_ClearRingBuffer(CySCB_Type const *base, cy_stc_scb_uart_context_t *context)
795 {
796     /* Suppress a compiler warning about unused variables */
797     (void) base;
798 
799     context->rxRingBufHead = context->rxRingBufTail;
800 }
801 
802 
803 /*******************************************************************************
804 * Function Name: Cy_SCB_UART_Receive
805 ****************************************************************************//**
806 *
807 * This function starts a UART receive operation.
808 * It configures the receive interrupt sources to get data available in the
809 * receive FIFO and returns. The \ref Cy_SCB_UART_Interrupt manages the further
810 * data transfer.
811 *
812 * If the ring buffer is enabled, this function first reads data from the ring
813 * buffer. If there is more data to receive, it configures the receive interrupt
814 * sources to copy the remaining bytes from the RX FIFO when they arrive.
815 *
816 * When the receive operation is completed (requested number of data elements
817 * received) the \ref CY_SCB_UART_RECEIVE_ACTIVE status is cleared and
818 * the \ref CY_SCB_UART_RECEIVE_DONE_EVENT event is generated.
819 *
820 * \param base
821 * The pointer to the UART SCB instance.
822 *
823 * \param buffer
824 * Pointer to buffer to store received data.
825 * The element size is defined by the data type, which depends on the configured
826 * data width.
827 *
828 * \param size
829 * The number of data elements to receive.
830 *
831 * \param context
832 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
833 * by the user. The structure is used during the UART operation for internal
834 * configuration and data retention. The user must not modify anything
835 * in this structure.
836 *
837 * \return
838 * \ref cy_en_scb_uart_status_t
839 *
840 * \note
841 * * The buffer must not be modified and stay allocated until end of the
842 *   receive operation.
843 * * This function overrides the RX interrupt sources and changes the
844 *   RX FIFO level.
845 *
846 *******************************************************************************/
Cy_SCB_UART_Receive(CySCB_Type * base,void * buffer,uint32_t size,cy_stc_scb_uart_context_t * context)847 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)
848 {
849     CY_ASSERT_L1(NULL != context);
850     #if !defined(NDEBUG)
851     CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey);
852     #endif
853     CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size));
854 
855     cy_en_scb_uart_status_t retStatus = CY_SCB_UART_RECEIVE_BUSY;
856 
857     /* check whether there are no active transfer requests */
858     if (0UL == (context->rxStatus & CY_SCB_UART_RECEIVE_ACTIVE))
859     {
860         uint8_t  *tmpBuf = (uint8_t *) buffer;
861         uint32_t numToCopy = 0UL;
862 
863         /* Disable the RX interrupt source to stop the ring buffer update */
864         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
865 
866         if (NULL != context->rxRingBuf)
867         {
868             /* Get the items available in the ring buffer */
869             numToCopy = Cy_SCB_UART_GetNumInRingBuffer(base, context);
870 
871             if (numToCopy > 0UL)
872             {
873                 uint32_t idx;
874                 uint32_t locTail = context->rxRingBufTail;
875                 bool     byteMode = Cy_SCB_IsRxDataWidthByte(base);
876 
877                 /* Adjust the number of items to be read */
878                 if (numToCopy > size)
879                 {
880                     numToCopy = size;
881                 }
882 
883                 /* Copy the data elements from the ring buffer */
884                 for (idx = 0UL; idx < numToCopy; ++idx)
885                 {
886                     ++locTail;
887 
888                     if (locTail == context->rxRingBufSize)
889                     {
890                         locTail = 0UL;
891                     }
892 
893                     if (byteMode)
894                     {
895                         uint8_t *buf = (uint8_t *) buffer;
896                         buf[idx] = ((uint8_t *) context->rxRingBuf)[locTail];
897                     }
898                     else
899                     {
900                         uint16_t *buf = (uint16_t *) buffer;
901                         buf[idx] = ((uint16_t *) context->rxRingBuf)[locTail];
902                     }
903                 }
904 
905                 /* Update the ring buffer tail after data has been copied */
906                 context->rxRingBufTail = locTail;
907 
908                 /* Update with the copied bytes */
909                 size -= numToCopy;
910                 context->rxBufIdx = numToCopy;
911 
912                 /* Check whether all requested data has been read from the ring buffer */
913                 if (0UL == size)
914                 {
915                     /* Enable the RX-error interrupt sources to update the error status */
916                     Cy_SCB_SetRxInterruptMask(base, CY_SCB_UART_RECEIVE_ERR);
917 
918                     /* Call a completion callback if there was no abort receive called
919                     * in the interrupt. The abort clears the number of the received bytes.
920                     */
921                     if (context->rxBufIdx > 0UL)
922                     {
923                         if (NULL != context->cbEvents)
924                         {
925                             context->cbEvents(CY_SCB_UART_RECEIVE_DONE_EVENT);
926                         }
927                     }
928 
929                     /* Continue receiving data in the ring buffer */
930                     Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
931                 }
932                 else
933                 {
934                     tmpBuf = &tmpBuf[(byteMode) ? (numToCopy) : (2UL * numToCopy)];
935                 }
936             }
937         }
938 
939         /* Set up a direct RX FIFO receive */
940         if (size > 0UL)
941         {
942             uint32_t irqRxLevel = SelectRxFifoLevel(base);
943 
944             /* Set up context */
945             context->rxStatus  = CY_SCB_UART_RECEIVE_ACTIVE;
946 
947             context->rxBuf     = (void *) tmpBuf;
948             context->rxBufSize = size;
949             context->rxBufIdx =  numToCopy;
950 
951             /* Set the RX FIFO level to the trigger interrupt */
952             Cy_SCB_SetRxFifoLevel(base, (size > irqRxLevel) ? (irqRxLevel - 1UL) : (size - 1UL));
953 
954             /* Enable the RX interrupt sources to continue data reading */
955             Cy_SCB_SetRxInterruptMask(base, CY_SCB_UART_RX_INTR);
956         }
957 
958         retStatus = CY_SCB_UART_SUCCESS;
959     }
960 
961     return (retStatus);
962 }
963 
964 
965 /*******************************************************************************
966 * Function Name: Cy_SCB_UART_AbortReceive
967 ****************************************************************************//**
968 *
969 * Abort the current receive operation by clearing the receive status.
970 * * If the ring buffer is disabled, the receive interrupt sources are disabled.
971 * * If the ring buffer is enabled, the receive interrupt source is configured
972 *   to get data from the receive FIFO and put it into the ring buffer.
973 *
974 * \param base
975 * The pointer to the UART SCB instance.
976 *
977 * \param context
978 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
979 * by the user. The structure is used during the UART operation for internal
980 * configuration and data retention. The user must not modify anything
981 * in this structure.
982 *
983 * \note
984 * * The RX FIFO and ring buffer are not cleared after abort of receive
985 *   operation.
986 * * If after the abort of the receive operation the transmitter continues
987 *   sending data, it gets into the RX FIFO. To drop this data, the RX FIFO
988 *   and ring buffer (if enabled) must be cleared when the transmitter
989 *   stops sending data. Otherwise, received data will be kept and copied
990 *   to the buffer when \ref Cy_SCB_UART_Receive is called.
991 *
992 *******************************************************************************/
Cy_SCB_UART_AbortReceive(CySCB_Type * base,cy_stc_scb_uart_context_t * context)993 void Cy_SCB_UART_AbortReceive(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
994 {
995     if (NULL == context->rxRingBuf)
996     {
997         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
998     }
999 
1000     context->rxBufSize = 0UL;
1001     context->rxBufIdx  = 0UL;
1002 
1003     context->rxStatus  = 0UL;
1004 }
1005 
1006 
1007 /*******************************************************************************
1008 * Function Name: Cy_SCB_UART_GetNumReceived
1009 ****************************************************************************//**
1010 *
1011 * Returns the number of data elements received since the last call to \ref
1012 * Cy_SCB_UART_Receive.
1013 *
1014 * \param base
1015 * The pointer to the UART SCB instance.
1016 *
1017 * \param context
1018 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1019 * by the user. The structure is used during the UART operation for internal
1020 * configuration and data retention. The user must not modify anything
1021 * in this structure.
1022 *
1023 * \return
1024 * The number of data elements received.
1025 *
1026 *******************************************************************************/
Cy_SCB_UART_GetNumReceived(CySCB_Type const * base,cy_stc_scb_uart_context_t const * context)1027 uint32_t Cy_SCB_UART_GetNumReceived(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
1028 {
1029     /* Suppress a compiler warning about unused variables */
1030     (void) base;
1031 
1032     return (context->rxBufIdx);
1033 }
1034 
1035 
1036 /*******************************************************************************
1037 * Function Name: Cy_SCB_UART_GetReceiveStatus
1038 ****************************************************************************//**
1039 *
1040 * Returns the status of the receive operation.
1041 * This status is a bit mask and the value returned may have multiple bits set.
1042 *
1043 * \param base
1044 * The pointer to the UART SCB instance.
1045 *
1046 * \param context
1047 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1048 * by the user. The structure is used during the UART operation for internal
1049 * configuration and data retention. The user must not modify anything
1050 * in this structure.
1051 *
1052 * \return
1053 * \ref group_scb_uart_macros_receive_status.
1054 *
1055 * \note
1056 * The status is only cleared by calling \ref Cy_SCB_UART_Receive again.
1057 *
1058 *******************************************************************************/
Cy_SCB_UART_GetReceiveStatus(CySCB_Type const * base,cy_stc_scb_uart_context_t const * context)1059 uint32_t Cy_SCB_UART_GetReceiveStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
1060 {
1061     /* Suppress a compiler warning about unused variables */
1062     (void) base;
1063 
1064     return (context->rxStatus);
1065 }
1066 
1067 
1068 /*******************************************************************************
1069 * Function Name: Cy_SCB_UART_Transmit
1070 ****************************************************************************//**
1071 *
1072 * This function starts a UART transmit operation.
1073 * It configures the transmit interrupt sources and returns.
1074 * The \ref Cy_SCB_UART_Interrupt manages the further data transfer.
1075 *
1076 * When the transmit operation is completed (requested number of data elements
1077 * sent on the bus), the \ref CY_SCB_UART_TRANSMIT_ACTIVE status is cleared and
1078 * the \ref CY_SCB_UART_TRANSMIT_DONE_EVENT event is generated.
1079 *
1080 * \param base
1081 * The pointer to the UART SCB instance.
1082 *
1083 * \param buffer
1084 * Pointer to user data to place in transmit buffer.
1085 * The element size is defined by the data type, which depends on the configured
1086 * data width.
1087 *
1088 * \param size
1089 * The number of data elements to transmit.
1090 *
1091 * \param context
1092 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1093 * by the user. The structure is used during the UART operation for internal
1094 * configuration and data retention. The user must not modify anything
1095 * in this structure.
1096 *
1097 * \return
1098 * \ref cy_en_scb_uart_status_t
1099 *
1100 * \note
1101 * * The buffer must not be modified and must stay allocated until its content is
1102 *   copied into the TX FIFO.
1103 * * This function overrides the TX FIFO interrupt sources and changes the
1104 *   TX FIFO level.
1105 *
1106 *******************************************************************************/
Cy_SCB_UART_Transmit(CySCB_Type * base,void * buffer,uint32_t size,cy_stc_scb_uart_context_t * context)1107 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)
1108 {
1109     CY_ASSERT_L1(NULL != context);
1110     #if !defined(NDEBUG)
1111     CY_ASSERT_L1(CY_SCB_UART_INIT_KEY == context->initKey);
1112     #endif
1113     CY_ASSERT_L1(CY_SCB_IS_BUFFER_VALID(buffer, size));
1114 
1115     cy_en_scb_uart_status_t retStatus = CY_SCB_UART_TRANSMIT_BUSY;
1116 
1117     /* Check whether there are no active transfer requests */
1118     if (0UL == (CY_SCB_UART_TRANSMIT_ACTIVE & context->txStatus))
1119     {
1120         /* Set up context */
1121         context->txStatus  = CY_SCB_UART_TRANSMIT_ACTIVE;
1122 
1123         context->txBuf     = buffer;
1124         context->txBufSize = size;
1125 
1126         /* Set the level in TX FIFO to start a transfer */
1127         Cy_SCB_SetTxFifoLevel(base, (Cy_SCB_GetFifoSize(base) / 2UL));
1128 
1129         /* Enable the interrupt sources */
1130         if (((uint32_t) CY_SCB_UART_SMARTCARD) == _FLD2VAL(SCB_UART_CTRL_MODE, SCB_UART_CTRL(base)))
1131         {
1132             /* Transfer data into TX FIFO and track SmartCard-specific errors */
1133             Cy_SCB_SetTxInterruptMask(base, CY_SCB_UART_TX_INTR);
1134         }
1135         else
1136         {
1137             /* Transfer data into TX FIFO */
1138             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
1139         }
1140 
1141         retStatus = CY_SCB_UART_SUCCESS;
1142     }
1143 
1144     return (retStatus);
1145 }
1146 
1147 
1148 /*******************************************************************************
1149 * Function Name: Cy_SCB_UART_AbortTransmit
1150 ****************************************************************************//**
1151 *
1152 * Aborts the current transmit operation.
1153 * It disables the transmit interrupt sources and clears the transmit FIFO
1154 * and status.
1155 *
1156 * \param base
1157 * The pointer to the UART SCB instance.
1158 *
1159 * \param context
1160 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1161 * by the user. The structure is used during the UART operation for internal
1162 * configuration and data retention. The user must not modify anything
1163 * in this structure.
1164 *
1165 * \sideeffect
1166 * The transmit FIFO clear operation also clears the shift register, so that
1167 * the shifter can be cleared in the middle of a data element transfer,
1168 * corrupting it. The data element corruption means that all bits that have
1169 * not been transmitted are transmitted as "ones" on the bus.
1170 *
1171 *******************************************************************************/
Cy_SCB_UART_AbortTransmit(CySCB_Type * base,cy_stc_scb_uart_context_t * context)1172 void Cy_SCB_UART_AbortTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
1173 {
1174     Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1175 
1176     Cy_SCB_UART_ClearTxFifo(base);
1177 
1178     context->txBufSize = 0UL;
1179     context->txLeftToTransmit = 0UL;
1180 
1181     context->txStatus  = 0UL;
1182 }
1183 
1184 
1185 /*******************************************************************************
1186 * Function Name: Cy_SCB_UART_GetNumLeftToTransmit
1187 ****************************************************************************//**
1188 *
1189 * Returns the number of data elements left to transmit since the last call to
1190 * \ref Cy_SCB_UART_Transmit.
1191 *
1192 * \param base
1193 * The pointer to the UART SCB instance.
1194 *
1195 * \param context
1196 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1197 * by the user. The structure is used during the UART operation for internal
1198 * configuration and data retention. The user must not modify anything
1199 * in this structure.
1200 *
1201 * \return
1202 * The number of data elements left to transmit.
1203 *
1204 *******************************************************************************/
Cy_SCB_UART_GetNumLeftToTransmit(CySCB_Type const * base,cy_stc_scb_uart_context_t const * context)1205 uint32_t Cy_SCB_UART_GetNumLeftToTransmit(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
1206 {
1207     /* Suppress a compiler warning about unused variables */
1208     (void) base;
1209 
1210     return (context->txLeftToTransmit);
1211 }
1212 
1213 
1214 /*******************************************************************************
1215 * Function Name: Cy_SCB_UART_GetTransmitStatus
1216 ****************************************************************************//**
1217 *
1218 * Returns the status of the transmit operation.
1219 * This status is a bit mask and the value returned may have multiple bits set.
1220 *
1221 * \param base
1222 * The pointer to the UART SCB instance.
1223 *
1224 * \param context
1225 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1226 * by the user. The structure is used during the UART operation for internal
1227 * configuration and data retention. The user must not modify anything
1228 * in this structure.
1229 *
1230 * \return
1231 * \ref group_scb_uart_macros_transmit_status.
1232 *
1233 * \note
1234 * The status is only cleared by calling \ref Cy_SCB_UART_Transmit or
1235 * \ref Cy_SCB_UART_AbortTransmit.
1236 *
1237 *******************************************************************************/
Cy_SCB_UART_GetTransmitStatus(CySCB_Type const * base,cy_stc_scb_uart_context_t const * context)1238 uint32_t Cy_SCB_UART_GetTransmitStatus(CySCB_Type const *base, cy_stc_scb_uart_context_t const *context)
1239 {
1240     /* Suppress a compiler warning about unused variables */
1241     (void) base;
1242 
1243     return (context->txStatus);
1244 }
1245 
1246 
1247 /*******************************************************************************
1248 * Function Name: Cy_SCB_UART_SendBreakBlocking
1249 ****************************************************************************//**
1250 *
1251 * Sends a break condition (logic low) of specified width on UART TX line.
1252 * Blocks until break is completed. Only call this function when UART TX FIFO
1253 * and shifter are empty.
1254 *
1255 * \param base
1256 * The pointer to the UART SCB instance.
1257 *
1258 * \param breakWidth
1259 * Width of break condition. Valid range is the TX data width (4 to 16 bits)
1260 *
1261 * \note
1262 * Before sending break all UART TX interrupt sources are disabled. The state
1263 * of UART TX interrupt sources is restored before function returns.
1264 *
1265 * \sideeffect
1266 * If this function is called while there is data in the TX FIFO or shifter that
1267 * data will be shifted out in packets the size of breakWidth.
1268 *
1269 *******************************************************************************/
Cy_SCB_UART_SendBreakBlocking(CySCB_Type * base,uint32_t breakWidth)1270 void Cy_SCB_UART_SendBreakBlocking(CySCB_Type *base, uint32_t breakWidth)
1271 {
1272     uint32_t txCtrlReg;
1273     uint32_t txIntrReg;
1274 
1275     CY_ASSERT_L2(CY_SCB_UART_IS_TX_BREAK_WIDTH_VALID(breakWidth));
1276 
1277     /* Disable all UART TX interrupt sources and clear UART TX Done history */
1278     txIntrReg = Cy_SCB_GetTxInterruptMask(base);
1279     Cy_SCB_SetTxInterruptMask(base, 0UL);
1280     Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UART_DONE);
1281 
1282     /* Store TX_CTRL configuration */
1283     txCtrlReg = SCB_TX_CTRL(base);
1284 
1285     /* Set break width: start bit adds one 0 bit */
1286     CY_REG32_CLR_SET(SCB_TX_CTRL(base), SCB_TX_CTRL_DATA_WIDTH, (breakWidth - 1UL));
1287 
1288     /* Generate break */
1289     Cy_SCB_WriteTxFifo(base, 0UL);
1290 
1291     /* Wait for break completion */
1292     while (0UL == (Cy_SCB_GetTxInterruptStatus(base) & CY_SCB_TX_INTR_UART_DONE))
1293     {
1294     }
1295 
1296     /* Clear all UART TX interrupt sources */
1297     Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_MASK);
1298 
1299     /* Restore TX data width and interrupt sources */
1300     SCB_TX_CTRL(base) = txCtrlReg;
1301     Cy_SCB_SetTxInterruptMask(base, txIntrReg);
1302 }
1303 
1304 
1305 /*******************************************************************************
1306 * Function Name: Cy_SCB_UART_Interrupt
1307 ****************************************************************************//**
1308 *
1309 * This is the interrupt function for the SCB configured in the UART mode.
1310 * This function must be called inside a user-defined interrupt service
1311 * routine to make \ref Cy_SCB_UART_Transmit and \ref Cy_SCB_UART_Receive
1312 * work. The ring buffer operation that enabled by calling \ref Cy_SCB_UART_StartRingBuffer
1313 * also requires interrupt processing.
1314 *
1315 * \param base
1316 * The pointer to the UART SCB instance.
1317 *
1318 * \param context
1319 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1320 * by the user. The structure is used during the UART operation for internal
1321 * configuration and data retention. The user must not modify anything
1322 * in this structure.
1323 *
1324 *******************************************************************************/
Cy_SCB_UART_Interrupt(CySCB_Type * base,cy_stc_scb_uart_context_t * context)1325 void Cy_SCB_UART_Interrupt(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
1326 {
1327     if (0UL != (CY_SCB_RX_INTR & Cy_SCB_GetInterruptCause(base)))
1328     {
1329         /* Get RX error events: a frame error, parity error, and overflow */
1330         uint32_t locRxErr = (CY_SCB_UART_RECEIVE_ERR & Cy_SCB_GetRxInterruptStatusMasked(base));
1331 
1332         /* Handle the error conditions */
1333         if (0UL != locRxErr)
1334         {
1335             context->rxStatus |= locRxErr;
1336 
1337             Cy_SCB_ClearRxInterrupt(base, locRxErr);
1338 
1339             if (NULL != context->cbEvents)
1340             {
1341                 context->cbEvents(CY_SCB_UART_RECEIVE_ERR_EVENT);
1342             }
1343         }
1344 
1345         /* Break the detect */
1346         if (0UL != (CY_SCB_RX_INTR_UART_BREAK_DETECT & Cy_SCB_GetRxInterruptStatusMasked(base)))
1347         {
1348             context->rxStatus |= CY_SCB_UART_RECEIVE_BREAK_DETECT;
1349 
1350             Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_UART_BREAK_DETECT);
1351         }
1352 
1353         /* Copy the received data */
1354         if (0UL != (CY_SCB_RX_INTR_LEVEL & Cy_SCB_GetRxInterruptStatusMasked(base)))
1355         {
1356             if (context->rxBufSize > 0UL)
1357             {
1358                 HandleDataReceive(base, context);
1359             }
1360             else
1361             {
1362                 if (NULL != context->rxRingBuf)
1363                 {
1364                     HandleRingBuffer(base, context);
1365                 }
1366             }
1367 
1368             Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
1369         }
1370 
1371         if (0UL != (CY_SCB_RX_INTR_NOT_EMPTY & Cy_SCB_GetRxInterruptStatusMasked(base)))
1372         {
1373             if (NULL != context->cbEvents)
1374             {
1375                 context->cbEvents(CY_SCB_UART_RECEIVE_NOT_EMTPY);
1376             }
1377 
1378             Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_NOT_EMPTY);
1379         }
1380 
1381     }
1382 
1383     if (0UL != (CY_SCB_TX_INTR & Cy_SCB_GetInterruptCause(base)))
1384     {
1385         uint32_t locTxErr = (CY_SCB_UART_TRANSMIT_ERR & Cy_SCB_GetTxInterruptStatusMasked(base));
1386 
1387         /* Handle the TX error conditions */
1388         if (0UL != locTxErr)
1389         {
1390             context->txStatus |= locTxErr;
1391             Cy_SCB_ClearTxInterrupt(base, locTxErr);
1392 
1393             if (NULL != context->cbEvents)
1394             {
1395                 context->cbEvents(CY_SCB_UART_TRANSMIT_ERR_EVENT);
1396             }
1397         }
1398 
1399         /* Load data to transmit */
1400         if (0UL != (CY_SCB_TX_INTR_LEVEL & Cy_SCB_GetTxInterruptStatusMasked(base)))
1401         {
1402             HandleDataTransmit(base, context);
1403 
1404             Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL);
1405         }
1406 
1407         /* Handle the TX complete */
1408         if (0UL != (CY_SCB_TX_INTR_UART_DONE & Cy_SCB_GetTxInterruptStatusMasked(base)))
1409         {
1410             /* Disable all TX interrupt sources */
1411             Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1412 
1413             context->txStatus &= (uint32_t) ~CY_SCB_UART_TRANSMIT_ACTIVE;
1414             context->txLeftToTransmit = 0UL;
1415 
1416             if (NULL != context->cbEvents)
1417             {
1418                 context->cbEvents(CY_SCB_UART_TRANSMIT_DONE_EVENT);
1419             }
1420         }
1421 
1422         if (0UL != (CY_SCB_UART_TX_EMPTY & Cy_SCB_GetTxInterruptStatusMasked(base)))
1423         {
1424             if (NULL != context->cbEvents)
1425             {
1426                 context->cbEvents(CY_SCB_UART_TRANSMIT_EMTPY);
1427             }
1428 
1429             Cy_SCB_ClearTxInterrupt(base, CY_SCB_UART_TX_EMPTY);
1430         }
1431 
1432     }
1433 }
1434 
1435 
1436 
1437 /*******************************************************************************
1438 * Function Name: HandleDataReceive
1439 ****************************************************************************//**
1440 *
1441 * Reads data from the receive FIFO into the buffer provided by
1442 * \ref Cy_SCB_UART_Receive.
1443 *
1444 * \param base
1445 * The pointer to the UART SCB instance.
1446 *
1447 * \param context
1448 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1449 * by the user. The structure is used during the UART operation for internal
1450 * configuration and data retention. The user must not modify anything
1451 * in this structure.
1452 *
1453 *******************************************************************************/
HandleDataReceive(CySCB_Type * base,cy_stc_scb_uart_context_t * context)1454 static void HandleDataReceive(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
1455 {
1456     uint32_t numCopied;
1457     uint32_t irqRxLevel = SelectRxFifoLevel(base);
1458 
1459     /* Get data from RX FIFO */
1460     numCopied = Cy_SCB_UART_GetArray(base, context->rxBuf, context->rxBufSize);
1461 
1462     /* Move the buffer */
1463     context->rxBufIdx  += numCopied;
1464     context->rxBufSize -= numCopied;
1465 
1466     if (0UL == context->rxBufSize)
1467     {
1468         if (NULL != context->rxRingBuf)
1469         {
1470             /* Adjust the level to proceed with the ring buffer */
1471             Cy_SCB_SetRxFifoLevel(base, (context->rxRingBufSize >= irqRxLevel) ?
1472                                             (irqRxLevel - 1UL) : (context->rxRingBufSize - 1UL));
1473 
1474             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
1475         }
1476         else
1477         {
1478             Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1479         }
1480 
1481         /* Update the status */
1482         context->rxStatus &= (uint32_t) ~CY_SCB_UART_RECEIVE_ACTIVE;
1483 
1484         /* Notify that receive is done in a callback */
1485         if (NULL != context->cbEvents)
1486         {
1487             context->cbEvents(CY_SCB_UART_RECEIVE_DONE_EVENT);
1488         }
1489     }
1490     else
1491     {
1492         uint8_t *buf = (uint8_t *) context->rxBuf;
1493 
1494         buf = &buf[(Cy_SCB_IsRxDataWidthByte(base) ? (numCopied) : (2UL * numCopied))];
1495         context->rxBuf = (void *) buf;
1496 
1497         if (context->rxBufSize < irqRxLevel)
1498         {
1499             /* Set the RX FIFO level to trigger an interrupt */
1500             Cy_SCB_SetRxFifoLevel(base, (context->rxBufSize - 1UL));
1501         }
1502     }
1503 }
1504 
1505 
1506 /*******************************************************************************
1507 * Function Name: HandleRingBuffer
1508 ****************************************************************************//**
1509 *
1510 * Reads data from the receive FIFO into the receive ring buffer.
1511 *
1512 * \param base
1513 * The pointer to the UART SCB instance.
1514 *
1515 * \param context
1516 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1517 * by the user. The structure is used during the UART operation for internal
1518 * configuration and data retention. The user must not modify anything
1519 * in this structure.
1520 *
1521 *******************************************************************************/
HandleRingBuffer(CySCB_Type * base,cy_stc_scb_uart_context_t * context)1522 static void HandleRingBuffer(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
1523 {
1524     uint32_t irqRxLevel = SelectRxFifoLevel(base);
1525     uint32_t numToCopy = Cy_SCB_GetNumInRxFifo(base);
1526     uint32_t locHead = context->rxRingBufHead;
1527     uint32_t rxData;
1528 
1529     /* Get data into the ring buffer */
1530     while (numToCopy > 0UL)
1531     {
1532         ++locHead;
1533 
1534         if (locHead == context->rxRingBufSize)
1535         {
1536             locHead = 0UL;
1537         }
1538 
1539         if (locHead == context->rxRingBufTail)
1540         {
1541             /* The ring buffer is full, trigger a callback */
1542             if (NULL != context->cbEvents)
1543             {
1544                 context->cbEvents(CY_SCB_UART_RB_FULL_EVENT);
1545             }
1546 
1547             /* The ring buffer is still full. Disable the RX interrupt not to put data into the ring buffer.
1548             * The data is stored in the RX FIFO until it overflows. Revert the head index.
1549             */
1550             if (locHead == context->rxRingBufTail)
1551             {
1552                 Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1553 
1554                 locHead = (locHead > 0UL) ? (locHead - 1UL) : (context->rxRingBufSize - 1UL);
1555                 break;
1556             }
1557         }
1558 
1559         /* Get data from RX FIFO. */
1560         rxData = Cy_SCB_ReadRxFifo(base);
1561 
1562         /* Put a data item in the ring buffer */
1563         if (Cy_SCB_IsRxDataWidthByte(base))
1564         {
1565             ((uint8_t *) context->rxRingBuf)[locHead] = (uint8_t) rxData;
1566         }
1567         else
1568         {
1569             ((uint16_t *) context->rxRingBuf)[locHead] = (uint16_t) rxData;
1570         }
1571 
1572         --numToCopy;
1573     }
1574 
1575     /* Update the head index */
1576     context->rxRingBufHead = locHead;
1577 
1578     /* Get free entries in the ring buffer */
1579     numToCopy = context->rxRingBufSize - Cy_SCB_UART_GetNumInRingBuffer(base, context);
1580 
1581     if (numToCopy < irqRxLevel)
1582     {
1583         /* Adjust the level to copy to the ring buffer */
1584         uint32_t level = (numToCopy > 0UL) ? (numToCopy - 1UL) : 0UL;
1585         Cy_SCB_SetRxFifoLevel(base, level);
1586     }
1587 }
1588 
1589 
1590 /*******************************************************************************
1591 * Function Name: HandleDataTransmit
1592 ****************************************************************************//**
1593 *
1594 * Loads the transmit FIFO with data provided by \ref Cy_SCB_UART_Transmit.
1595 *
1596 * \param base
1597 * The pointer to the UART SCB instance.
1598 *
1599 * \param context
1600 * The pointer to the context structure \ref cy_stc_scb_uart_context_t allocated
1601 * by the user. The structure is used during the UART operation for internal
1602 * configuration and data retention. The user must not modify anything
1603 * in this structure.
1604 *
1605 *******************************************************************************/
HandleDataTransmit(CySCB_Type * base,cy_stc_scb_uart_context_t * context)1606 static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_uart_context_t *context)
1607 {
1608     uint32_t numToCopy;
1609     uint32_t fifoSize = Cy_SCB_GetFifoSize(base);
1610     bool     byteMode = Cy_SCB_IsTxDataWidthByte(base);
1611 
1612     if (context->txBufSize > 1UL)
1613     {
1614         uint8_t *buf = (uint8_t *) context->txBuf;
1615 
1616         /* Get the number of items left for transmission */
1617         context->txLeftToTransmit = context->txBufSize;
1618 
1619         /* Put data into TX FIFO */
1620         numToCopy = Cy_SCB_UART_PutArray(base, context->txBuf, (context->txBufSize - 1UL));
1621 
1622         /* Move the buffer */
1623         context->txBufSize -= numToCopy;
1624 
1625         buf = &buf[(byteMode) ? (numToCopy) : (2UL * numToCopy)];
1626         context->txBuf = (void *) buf;
1627     }
1628 
1629     /* Put the last data item into TX FIFO */
1630     if ((fifoSize != Cy_SCB_GetNumInTxFifo(base)) && (1UL == context->txBufSize))
1631     {
1632         uint32_t txData;
1633         uint32_t intrStatus;
1634 
1635         context->txBufSize = 0UL;
1636 
1637         /* Get the last item from the buffer */
1638         txData = (uint32_t) ((byteMode) ? ((uint8_t *)  context->txBuf)[0UL] :
1639                                           ((uint16_t *) context->txBuf)[0UL]);
1640 
1641         /* Put the last data element and make sure that "TX done" will happen for it */
1642         intrStatus = Cy_SysLib_EnterCriticalSection();
1643 
1644         Cy_SCB_WriteTxFifo(base, txData);
1645         Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UART_DONE);
1646 
1647         Cy_SysLib_ExitCriticalSection(intrStatus);
1648 
1649         /* Disable the level interrupt source and enable "transfer done" */
1650         Cy_SCB_SetTxInterruptMask(base, (CY_SCB_TX_INTR_UART_DONE |
1651                     (Cy_SCB_GetTxInterruptMask(base) & (uint32_t) ~CY_SCB_TX_INTR_LEVEL)));
1652 
1653         /* Data is copied into TX FIFO */
1654         context->txStatus |= CY_SCB_UART_TRANSMIT_IN_FIFO;
1655 
1656         if (NULL != context->cbEvents)
1657         {
1658             context->cbEvents(CY_SCB_UART_TRANSMIT_IN_FIFO_EVENT);
1659         }
1660     }
1661 }
1662 
1663 
1664 #if defined(__cplusplus)
1665 }
1666 #endif
1667 
1668 #endif /* CY_IP_MXSCB */
1669 
1670 /* [] END OF FILE */
1671