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