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