1 /***************************************************************************//**
2 * \file cy_scb_spi.c
3 * \version 3.20
4 *
5 * Provides SPI 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_spi.h"
30 
31 #if defined(__cplusplus)
32 extern "C" {
33 #endif
34 
35 /* Static functions */
36 static void HandleTransmit(CySCB_Type *base, cy_stc_scb_spi_context_t *context);
37 static void HandleReceive (CySCB_Type *base, cy_stc_scb_spi_context_t *context);
38 static void DiscardArrayNoCheck(CySCB_Type const *base, uint32_t size);
39 
40 /*******************************************************************************
41 * Function Name: Cy_SCB_SPI_Init
42 ****************************************************************************//**
43 *
44 * Initializes the SCB for SPI operation.
45 *
46 * \param base
47 * The pointer to the SPI SCB instance.
48 *
49 * \param config
50 * The pointer to the configuration structure \ref cy_stc_scb_spi_config_t.
51 *
52 * \param context
53 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
54 * by the user. The structure is used during the SPI operation for internal
55 * configuration and data retention. The user must not modify anything
56 * in this structure.
57 * If only SPI \ref group_scb_spi_ll will be used pass NULL as pointer to
58 * context.
59 *
60 * \return
61 * \ref cy_en_scb_spi_status_t
62 *
63 * \note
64 * If SCB is already enabled, ensure that the SCB block is disabled
65 * \ref Cy_SCB_SPI_Disable before calling this function.
66 *
67 *******************************************************************************/
Cy_SCB_SPI_Init(CySCB_Type * base,cy_stc_scb_spi_config_t const * config,cy_stc_scb_spi_context_t * context)68 cy_en_scb_spi_status_t Cy_SCB_SPI_Init(CySCB_Type *base, cy_stc_scb_spi_config_t const *config, cy_stc_scb_spi_context_t *context)
69 {
70     /* Input parameters verification */
71     if ((NULL == base) || (NULL == config))
72     {
73         return CY_SCB_SPI_BAD_PARAM;
74     }
75 #if((defined CY_IP_MXSCB_VERSION && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
76     uint32_t memWidth_type = CY_SCB_MEM_WIDTH_BYTE;
77 #endif /* CY_IP_MXSCB_VERSION */
78     CY_ASSERT_L3(CY_SCB_SPI_IS_MODE_VALID     (config->spiMode));
79     CY_ASSERT_L3(CY_SCB_SPI_IS_SUB_MODE_VALID (config->subMode));
80     CY_ASSERT_L3(CY_SCB_SPI_IS_SCLK_MODE_VALID(config->sclkMode));
81 
82     CY_ASSERT_L2(CY_SCB_SPI_IS_OVERSAMPLE_VALID (config->oversample, config->spiMode));
83     CY_ASSERT_L2(CY_SCB_SPI_IS_SS_POLARITY_VALID(config->ssPolarity));
84     CY_ASSERT_L2(CY_SCB_SPI_IS_DATA_WIDTH_VALID (config->rxDataWidth));
85     CY_ASSERT_L2(CY_SCB_SPI_IS_DATA_WIDTH_VALID (config->txDataWidth));
86     CY_ASSERT_L2(CY_SCB_SPI_IS_BOTH_DATA_WIDTH_VALID(config->subMode, config->rxDataWidth, config->txDataWidth));
87 
88     CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->rxFifoIntEnableMask, CY_SCB_SPI_RX_INTR_MASK));
89     CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->txFifoIntEnableMask, CY_SCB_SPI_TX_INTR_MASK));
90     CY_ASSERT_L2(CY_SCB_IS_INTR_VALID(config->masterSlaveIntEnableMask, CY_SCB_SPI_MASTER_SLAVE_INTR_MASK));
91 
92     uint32_t locSclkMode = CY_SCB_SPI_GetSclkMode(config->subMode, config->sclkMode);
93 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
94     uint32_t memWidth = config->rxDataWidth <= config->txDataWidth ? config->txDataWidth : config->rxDataWidth ;
95 
96     if(memWidth <= CY_SCB_BYTE_WIDTH)
97     {
98         memWidth_type = CY_SCB_MEM_WIDTH_BYTE;
99     }
100     else if(memWidth <= CY_SCB_HALF_WORD_WIDTH)
101     {
102         memWidth_type = CY_SCB_MEM_WIDTH_HALFWORD;
103     }
104     else
105     {
106         memWidth_type = CY_SCB_MEM_WIDTH_WORD;
107     }
108 #elif((defined (CY_IP_MXSCB_VERSION) && CY_IP_MXSCB_VERSION==1))
109     bool byteMode = (config->rxDataWidth <= CY_SCB_BYTE_WIDTH) && (config->txDataWidth <= CY_SCB_BYTE_WIDTH);
110 #endif /* CY_IP_MXSCB_VERSION */
111     /* Configure an SPI interface */
112     SCB_CTRL(base) =_BOOL2FLD(SCB_CTRL_EC_AM_MODE, config->enableWakeFromSleep) |
113                  _VAL2FLD(SCB_CTRL_OVS, (config->oversample - 1UL))          |
114                  _VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_SPI);
115 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
116     Cy_SCB_SetMemWidth(base, memWidth_type);
117 #elif((defined (CY_IP_MXSCB_VERSION) && CY_IP_MXSCB_VERSION==1))
118     SCB_CTRL(base) |=_BOOL2FLD(SCB_CTRL_BYTE_MODE, byteMode);
119 #endif /* CY_IP_MXSCB_VERSION */
120 
121     /* Configure SCB_CTRL.BYTE_MODE then verify levels */
122     CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->rxFifoTriggerLevel));
123     CY_ASSERT_L2(CY_SCB_IS_TRIGGER_LEVEL_VALID(base, config->txFifoTriggerLevel));
124 
125     SCB_SPI_CTRL(base) = _BOOL2FLD(SCB_SPI_CTRL_SSEL_CONTINUOUS, (!config->enableTransferSeperation)) |
126                      _BOOL2FLD(SCB_SPI_CTRL_SELECT_PRECEDE,  (CY_SCB_SPI_TI_PRECEDES == config->subMode)) |
127                      _BOOL2FLD(SCB_SPI_CTRL_LATE_MISO_SAMPLE, config->enableMisoLateSample)       |
128                      _BOOL2FLD(SCB_SPI_CTRL_SCLK_CONTINUOUS,  config->enableFreeRunSclk)          |
129                      _BOOL2FLD(SCB_SPI_CTRL_MASTER_MODE,     (CY_SCB_SPI_MASTER == config->spiMode)) |
130                      _VAL2FLD(CY_SCB_SPI_CTRL_CLK_MODE,      locSclkMode)                         |
131                      _VAL2FLD(CY_SCB_SPI_CTRL_SSEL_POLARITY, config->ssPolarity)                  |
132                      _VAL2FLD(SCB_SPI_CTRL_MODE,  (uint32_t) config->subMode);
133 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
134     if(config->subMode == CY_SCB_SPI_MOTOROLA)
135     {
136         SCB_SPI_CTRL(base) &= ~SCB_SPI_CTRL_SSEL_SETUP_DEL_Msk;
137         SCB_SPI_CTRL(base) |=  _VAL2FLD(SCB_SPI_CTRL_SSEL_SETUP_DEL, config->ssSetupDelay);
138 
139         SCB_SPI_CTRL(base) &= ~SCB_SPI_CTRL_SSEL_HOLD_DEL_Msk;
140         SCB_SPI_CTRL(base) |=  _VAL2FLD(SCB_SPI_CTRL_SSEL_HOLD_DEL, config->ssHoldDelay);
141 
142         SCB_SPI_CTRL(base) &= ~SCB_SPI_CTRL_SSEL_INTER_FRAME_DEL_Msk;
143         SCB_SPI_CTRL(base) |=  _VAL2FLD(SCB_SPI_CTRL_SSEL_INTER_FRAME_DEL, config->ssInterFrameDelay);
144     }
145 #endif /* CY_IP_MXSCB_VERSION */
146 
147     /* Configure the RX direction */
148     SCB_RX_CTRL(base) = _BOOL2FLD(SCB_RX_CTRL_MSB_FIRST, config->enableMsbFirst) |
149                     _BOOL2FLD(SCB_RX_CTRL_MEDIAN, config->enableInputFilter) |
150                     _VAL2FLD(SCB_RX_CTRL_DATA_WIDTH, (config->rxDataWidth - 1UL));
151 
152     SCB_RX_FIFO_CTRL(base) = _VAL2FLD(SCB_RX_FIFO_CTRL_TRIGGER_LEVEL, config->rxFifoTriggerLevel);
153 
154     /* Configure the TX direction */
155     SCB_TX_CTRL(base) = _BOOL2FLD(SCB_TX_CTRL_MSB_FIRST, config->enableMsbFirst) |
156                     _VAL2FLD(SCB_TX_CTRL_DATA_WIDTH, (config->txDataWidth - 1UL));
157 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
158     if(config->subMode == CY_SCB_SPI_MOTOROLA)
159     {
160         /* Configure the TX direction */
161         SCB_SPI_TX_CTRL(base) = _VAL2FLD(CY_SCB_SPI_TX_CTRL_SET_PARITY, (uint32_t) config->parity);
162     }
163 #endif /* CY_IP_MXSCB_VERSION */
164 
165     SCB_TX_FIFO_CTRL(base) = _VAL2FLD(SCB_TX_FIFO_CTRL_TRIGGER_LEVEL, config->txFifoTriggerLevel);
166 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
167     if(config->subMode == CY_SCB_SPI_MOTOROLA)
168     {
169         /* Configure the RX direction */
170         SCB_SPI_RX_CTRL(base) = _BOOL2FLD(SCB_SPI_RX_CTRL_DROP_ON_PARITY_ERROR, config->dropOnParityError) |
171                              _VAL2FLD(CY_SCB_SPI_RX_CTRL_SET_PARITY, (uint32_t) config->parity);
172     }
173 #endif /* CY_IP_MXSCB_VERSION */
174 
175     /* Set up interrupt sources */
176     SCB_INTR_RX_MASK(base) = (config->rxFifoIntEnableMask & CY_SCB_SPI_RX_INTR_MASK);
177     SCB_INTR_TX_MASK(base) = (config->txFifoIntEnableMask & CY_SCB_SPI_TX_INTR_MASK);
178     SCB_INTR_M_MASK(base)       = (config->masterSlaveIntEnableMask & CY_SCB_SPI_MASTER_DONE);
179     SCB_INTR_S_MASK(base)       = (config->masterSlaveIntEnableMask & CY_SCB_SPI_SLAVE_ERR);
180     SCB_INTR_SPI_EC_MASK(base) = 0UL;
181 
182     /* Initialize the context */
183     if (NULL != context)
184     {
185         context->status    = 0UL;
186 
187         context->txBufIdx  = 0UL;
188         context->rxBufIdx  = 0UL;
189 
190         context->cbEvents = NULL;
191 
192     #if !defined(NDEBUG)
193         /* Put an initialization key into the initKey variable to verify
194         * context initialization in the transfer API.
195         */
196         context->initKey = CY_SCB_SPI_INIT_KEY;
197     #endif /* !(NDEBUG) */
198     }
199 
200     return CY_SCB_SPI_SUCCESS;
201 }
202 
203 
204 /*******************************************************************************
205 * Function Name: Cy_SCB_SPI_DeInit
206 ****************************************************************************//**
207 *
208 * De-initializes the SCB block; returns the register values to default.
209 *
210 * \param base
211 * The pointer to the SPI SCB instance.
212 *
213 * \note
214 * Ensure that the SCB block is disabled \ref Cy_SCB_SPI_Disable
215 * before calling this function.
216 *
217 *******************************************************************************/
Cy_SCB_SPI_DeInit(CySCB_Type * base)218 void Cy_SCB_SPI_DeInit(CySCB_Type *base)
219 {
220     /* SPI interface */
221     SCB_CTRL(base)         = CY_SCB_CTRL_DEF_VAL;
222     SCB_SPI_CTRL(base)     = CY_SCB_SPI_CTRL_DEF_VAL;
223 
224     /* RX direction */
225 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
226     SCB_SPI_RX_CTRL(base) = 0UL;
227 #endif /* CY_IP_MXSCB_VERSION */
228     SCB_RX_CTRL(base)      = CY_SCB_RX_CTRL_DEF_VAL;
229     SCB_RX_FIFO_CTRL(base) = 0UL;
230 
231     /* TX direction */
232 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
233     SCB_SPI_TX_CTRL(base) = 0UL;
234 #endif /* CY_IP_MXSCB_VERSION */
235     SCB_TX_CTRL(base)      = CY_SCB_TX_CTRL_DEF_VAL;
236     SCB_TX_FIFO_CTRL(base) = 0UL;
237 
238     /* Disable all interrupt sources */
239     SCB_INTR_SPI_EC_MASK(base) = 0UL;
240     SCB_INTR_I2C_EC_MASK(base) = 0UL;
241     SCB_INTR_RX_MASK(base)     = 0UL;
242     SCB_INTR_TX_MASK(base)     = 0UL;
243     SCB_INTR_M_MASK(base)      = 0UL;
244     SCB_INTR_S_MASK(base)      = 0UL;
245 }
246 
247 
248 /*******************************************************************************
249 * Function Name: Cy_SCB_SPI_Disable
250 ****************************************************************************//**
251 *
252 * Disables the SCB block, clears context statuses, and disables
253 * TX and RX interrupt sources.
254 * Note that after the block is disabled, the TX and RX FIFOs and
255 * hardware statuses are cleared. Also, the hardware stops driving the output
256 * and ignores the input. Refer to section \ref group_scb_spi_lp for more
257 * information about SPI pins when SCB disabled.
258 *
259 * \param base
260 * The pointer to the SPI SCB instance.
261 *
262 * \param context
263 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
264 * by the user. The structure is used during the SPI operation for internal
265 * configuration and data retention. The user must not modify anything
266 * in this structure.
267 * If only SPI functions that do not require context will be used to pass NULL
268 * as pointer to context.
269 *
270 * \note
271 * Calling this function when the SPI is busy (master preforms data transfer or
272 * slave communicates with the master) may cause transfer corruption because the
273 * hardware stops driving the outputs and ignores the inputs.
274 * Ensure that the SPI is not busy before calling this function.
275 *
276 *******************************************************************************/
Cy_SCB_SPI_Disable(CySCB_Type * base,cy_stc_scb_spi_context_t * context)277 void Cy_SCB_SPI_Disable(CySCB_Type *base, cy_stc_scb_spi_context_t *context)
278 {
279     SCB_CTRL(base) &= (uint32_t) ~SCB_CTRL_ENABLED_Msk;
280 
281     if (NULL != context)
282     {
283         context->status    = 0UL;
284 
285         context->rxBufIdx  = 0UL;
286         context->txBufIdx  = 0UL;
287     }
288 
289     /* Disable RX and TX interrupt sources for the slave because
290     * RX overflow and TX underflow are kept enabled after the 1st call of
291     * Cy_SCB_SPI_Transfer().
292     */
293     if (!_FLD2BOOL(SCB_SPI_CTRL_MASTER_MODE, SCB_SPI_CTRL(base)))
294     {
295         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
296         Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
297     }
298 }
299 
300 
301 /*******************************************************************************
302 * Function Name: Cy_SCB_SPI_DeepSleepCallback
303 ****************************************************************************//**
304 *
305 * This function handles the transition of the SCB SPI into and out of
306 * Deep Sleep mode. It prevents the device from entering Deep Sleep mode
307 * if the SPI slave or master is actively communicating, or there is any data
308 * in the TX or RX FIFOs.
309 * The following behavior of the SPI SCB depends on whether the SCB block is
310 * wakeup-capable or not:
311 * * <b>Wakeup-capable</b>: any transfer intended to the slave wakes up
312 *   the device from Deep Sleep mode. The slave responds with 0xFF to the
313 *   transfer and incoming data is ignored.
314 *   If the transfer occurs before the device enters Deep Sleep mode, the device
315 *   will not enter Deep Sleep mode and incoming data is stored in the RX FIFO.
316 *   The SCB clock is disabled before entering Deep Sleep and enabled after the
317 *   device exits Deep Sleep mode. The SCB clock disabling may lead to
318 *   corrupted data in the RX FIFO. Clear the RX FIFO after this callback is
319 *   executed.
320 *   Note that for proper SPI operation after Deep Sleep the source of
321 *   hf_clk[0] must be stable, this includes the FLL/PLL. The SysClk callback
322 *   ensures that hf_clk[0] gets stable and it must be called before
323 *   \ref Cy_SCB_SPI_DeepSleepCallback.
324 *   Only the SPI slave can be configured to be a wakeup source from Deep Sleep
325 *   mode.
326 * * <b>Not wakeup-capable</b>: the SPI is disabled. It is enabled when
327 *   the device fails to enter Deep Sleep mode or it is awakened from Deep Sleep
328 *   mode. While the SPI is disabled, it stops driving the outputs and ignores
329 *   the inputs. Any incoming data is ignored.
330 *   Refer to section \ref group_scb_spi_lp for more information about SPI pins
331 *   when SCB disabled.
332 *
333 * This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep.
334 * To do it, register this function as a callback before calling
335 * \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback
336 * type and call \ref Cy_SysPm_RegisterCallback.
337 *
338 * \param callbackParams
339 * The pointer to the callback parameters structure
340 * \ref cy_stc_syspm_callback_params_t.
341 *
342 * \param mode
343 * Callback mode, see \ref cy_en_syspm_callback_mode_t
344 *
345 * \return
346 * \ref cy_en_syspm_status_t
347 *
348 * \note
349 * Only applicable for <b>rev-08 of the CY8CKIT-062-BLE</b>.
350 * For proper operation, when the SPI slave is configured to be a wakeup source
351 * from Deep Sleep mode, this function must be copied and modified by the user.
352 * The SPI clock disable code must be inserted in the \ref CY_SYSPM_BEFORE_TRANSITION
353 * and clock enable code in the \ref CY_SYSPM_AFTER_TRANSITION mode processing.
354 *
355 *******************************************************************************/
Cy_SCB_SPI_DeepSleepCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)356 cy_en_syspm_status_t Cy_SCB_SPI_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
357 {
358     CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
359     cy_stc_scb_spi_context_t *locContext = (cy_stc_scb_spi_context_t *) callbackParams->context;
360 
361     cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;
362 
363     switch(mode)
364     {
365         case CY_SYSPM_CHECK_READY:
366         {
367             /* Check whether the High-level API is not busy executing the transfer
368             * operation.
369             */
370             if (0UL == (CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(locBase, locContext)))
371             {
372                 /* If the SPI bus is not busy, all data elements are transferred
373                 * on the bus from the TX FIFO and shifter and the RX FIFOs are
374                 * empty - the SPI is ready to enter Deep Sleep mode.
375                 */
376                 if (!Cy_SCB_SPI_IsBusBusy(locBase))
377                 {
378                     if (Cy_SCB_SPI_IsTxComplete(locBase))
379                     {
380                         if (0UL == Cy_SCB_SPI_GetNumInRxFifo(locBase))
381                         {
382                             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
383                             {
384                                 /* The SCB is wakeup-capable: clear the SPI
385                                 * wakeup interrupt source because it triggers
386                                 * during Active mode communication and make
387                                 * sure that a new transfer is not started after
388                                 * clearing.
389                                 */
390                                 Cy_SCB_ClearSpiInterrupt(locBase, CY_SCB_SPI_INTR_WAKEUP);
391 
392                                 if (!Cy_SCB_SPI_IsBusBusy(locBase))
393                                 {
394                                     retStatus = CY_SYSPM_SUCCESS;
395                                 }
396                             }
397                             else
398                             {
399                                 /* The SCB is NOT wakeup-capable: disable the
400                                 * SPI. The master and slave stop driving the
401                                 * bus until the SPI is enabled. This happens
402                                 * when the device fails to enter Deep Sleep
403                                 * mode or it is awakened from Deep Sleep mode.
404                                 */
405                                 Cy_SCB_SPI_Disable(locBase, locContext);
406 
407                                 retStatus = CY_SYSPM_SUCCESS;
408                             }
409                         }
410                     }
411                 }
412             }
413         }
414         break;
415 
416         case CY_SYSPM_CHECK_FAIL:
417         {
418             /* The other driver is not ready for Deep Sleep mode. Restore
419             * Active mode configuration.
420             */
421 
422             if (!_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
423             {
424                 /* The SCB is NOT wakeup-capable: enable the SPI to operate */
425                 Cy_SCB_SPI_Enable(locBase);
426             }
427 
428             retStatus = CY_SYSPM_SUCCESS;
429         }
430         break;
431 
432         case CY_SYSPM_BEFORE_TRANSITION:
433         {
434             /* This code executes inside the critical section and enabling the
435             * active interrupt source makes the interrupt pending in the NVIC.
436             * However, the interrupt processing is delayed until the code exits
437             * the critical section. The pending interrupt force WFI instruction
438             * does nothing and the device remains in Active mode.
439             */
440 
441             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
442             {
443                 /* The SCB is wakeup-capable: enable the SPI wakeup interrupt
444                 * source. If any transaction happens, the wakeup interrupt
445                 * becomes pending and prevents entering Deep Sleep mode.
446                 */
447                 Cy_SCB_SetSpiInterruptMask(locBase, CY_SCB_I2C_INTR_WAKEUP);
448 
449                 /* Disable SCB clock */
450                 SCB_I2C_CFG(locBase) &= (uint32_t) ~CY_SCB_I2C_CFG_CLK_ENABLE_Msk;
451 
452                 /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
453                 * for proper entering Deep Sleep mode the SPI clock must be disabled.
454                 * This code must be inserted by the user because the driver
455                 * does not have access to the clock.
456                 */
457             }
458 
459             retStatus = CY_SYSPM_SUCCESS;
460         }
461         break;
462 
463         case CY_SYSPM_AFTER_TRANSITION:
464         {
465             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
466             {
467                 /* Enable SCB clock */
468                 SCB_I2C_CFG(locBase) |= CY_SCB_I2C_CFG_CLK_ENABLE_Msk;
469 
470                 /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
471                 * for proper exiting Deep Sleep mode, the SPI clock must be enabled.
472                 * This code must be inserted by the user because the driver
473                 * does not have access to the clock.
474                 */
475 
476                 /* The SCB is wakeup-capable: disable the SPI wakeup interrupt
477                 * source
478                 */
479                 Cy_SCB_SetSpiInterruptMask(locBase, CY_SCB_CLEAR_ALL_INTR_SRC);
480             }
481             else
482             {
483                 /* The SCB is NOT wakeup-capable: enable the SPI to operate */
484                 Cy_SCB_SPI_Enable(locBase);
485             }
486 
487             retStatus = CY_SYSPM_SUCCESS;
488         }
489         break;
490 
491         default:
492             /* Unknown state */
493             break;
494     }
495 
496     return (retStatus);
497 }
498 
499 
500 /*******************************************************************************
501 * Function Name: Cy_SCB_SPI_HibernateCallback
502 ****************************************************************************//**
503 *
504 * This function handles the transition of the SCB SPI into Hibernate mode.
505 * It prevents the device from entering Hibernate mode if the SPI slave or
506 * master is actively communicating, or there is any data in the TX or RX FIFOs.
507 * If the SPI is ready to enter Hibernate mode, it is disabled. If the device
508 * failed to enter Hibernate mode, the SPI is re-enabled. While the SPI is
509 * disabled, it stops driving the outputs and ignores the inputs. Any incoming
510 * data is ignored. Refer to section \ref group_scb_spi_lp for more information
511 * about SPI pins when SCB disabled.
512 *
513 * This function must be called during execution of \ref Cy_SysPm_SystemEnterHibernate.
514 * To do it, register this function as a callback before calling
515 * \ref Cy_SysPm_SystemEnterHibernate : specify \ref CY_SYSPM_HIBERNATE as the callback
516 * type and call \ref Cy_SysPm_RegisterCallback.
517 *
518 * \param callbackParams
519 * The pointer to the callback parameters structure
520 * \ref cy_stc_syspm_callback_params_t.
521 *
522 * \param mode
523 * Callback mode, see \ref cy_en_syspm_callback_mode_t
524 *
525 * \return
526 * \ref cy_en_syspm_status_t
527 *
528 *******************************************************************************/
Cy_SCB_SPI_HibernateCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)529 cy_en_syspm_status_t Cy_SCB_SPI_HibernateCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
530 {
531     CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
532     cy_stc_scb_spi_context_t *locContext = (cy_stc_scb_spi_context_t *) callbackParams->context;
533 
534     cy_en_syspm_status_t  retStatus = CY_SYSPM_FAIL;
535 
536     switch(mode)
537     {
538         case CY_SYSPM_CHECK_READY:
539         {
540             /* Check whether the High-level API is not busy executing the transfer
541             * operation.
542             */
543             if (0UL == (CY_SCB_SPI_TRANSFER_ACTIVE & Cy_SCB_SPI_GetTransferStatus(locBase, locContext)))
544             {
545                 /* If the SPI bus is not busy, all data elements are transferred
546                 * on the bus from the TX FIFO and shifter and the RX FIFOs are
547                 * empty - the SPI is ready to enter Hibernate mode.
548                 */
549                 if (!Cy_SCB_SPI_IsBusBusy(locBase))
550                 {
551                     if (Cy_SCB_SPI_IsTxComplete(locBase))
552                     {
553                         if (0UL == Cy_SCB_SPI_GetNumInRxFifo(locBase))
554                         {
555                             /* Disable the SPI. The master or slave stops
556                             * driving the bus until the SPI is enabled.
557                             * This happens if the device failed to enter
558                             * Hibernate mode.
559                             */
560                             Cy_SCB_SPI_Disable(locBase, locContext);
561 
562                             retStatus = CY_SYSPM_SUCCESS;
563                         }
564                     }
565                 }
566             }
567         }
568         break;
569 
570         case CY_SYSPM_CHECK_FAIL:
571         {
572             /* The other driver is not ready for Hibernate mode. Restore Active
573             * mode configuration.
574             */
575 
576             /* Enable the SPI to operate */
577             Cy_SCB_SPI_Enable(locBase);
578 
579             retStatus = CY_SYSPM_SUCCESS;
580         }
581         break;
582 
583         case CY_SYSPM_BEFORE_TRANSITION:
584         case CY_SYSPM_AFTER_TRANSITION:
585         {
586             /* The SCB is not capable of waking up from Hibernate mode:
587             * do nothing.
588             */
589             retStatus = CY_SYSPM_SUCCESS;
590         }
591         break;
592 
593         default:
594             /* Unknown state */
595             break;
596     }
597 
598     return (retStatus);
599 }
600 
601 
602 /************************* High-Level Functions ********************************
603 * The following functions are considered high-level. They provide the layer of
604 * intelligence to the SCB. These functions require interrupts.
605 * Low-level and high-level functions must not be mixed because low-level API
606 * can adversely affect the operation of high-level functions.
607 *******************************************************************************/
608 
609 
610 /*******************************************************************************
611 * Function Name: Cy_SCB_SPI_Transfer
612 ****************************************************************************//**
613 *
614 * This function starts an SPI transfer operation.
615 * It configures transmit and receive buffers for an SPI transfer.
616 * If the data that will be received is not important, pass NULL as rxBuffer.
617 * If the data that will be transmitted is not important, pass NULL as txBuffer
618 * and then the \ref CY_SCB_SPI_DEFAULT_TX is sent out as each data element.
619 * Note that passing NULL as rxBuffer and txBuffer are considered invalid cases.
620 *
621 * After the function configures TX and RX interrupt sources, it returns and
622 * \ref Cy_SCB_SPI_Interrupt manages further data transfer.
623 *
624 * * In the master mode, the transfer operation starts after calling this
625 *   function
626 * * In the slave mode, the transfer registers and will start when
627 *   the master request arrives.
628 *
629 * When the transfer operation is completed (requested number of data elements
630 * sent and received), the \ref CY_SCB_SPI_TRANSFER_ACTIVE status is cleared
631 * and the \ref CY_SCB_SPI_TRANSFER_CMPLT_EVENT event is generated.
632 *
633 * \param base
634 * The pointer to the SPI SCB instance.
635 *
636 * \param txBuffer
637 * The pointer of the buffer with data to transmit.
638 * The element size is defined by the data type that depends on the configured
639 * TX data width.
640 *
641 * \param rxBuffer
642 * The pointer to the buffer to store received data.
643 * The element size is defined by the data type that depends on the configured
644 * RX data width.
645 *
646 * \param size
647 * The number of data elements to transmit and receive.
648 *
649 * \param context
650 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
651 * by the user. The structure is used during the SPI operation for internal
652 * configuration and data retention. The user must not modify anything
653 * in this structure.
654 *
655 * \return
656 * \ref cy_en_scb_spi_status_t
657 *
658 * \note
659 * * The buffers must not be modified and must stay allocated until the end of the
660 *   transfer.
661 * * This function overrides all RX and TX FIFO interrupt sources and changes
662 *   the RX and TX FIFO level.
663 *
664 *******************************************************************************/
Cy_SCB_SPI_Transfer(CySCB_Type * base,void * txBuffer,void * rxBuffer,uint32_t size,cy_stc_scb_spi_context_t * context)665 cy_en_scb_spi_status_t Cy_SCB_SPI_Transfer(CySCB_Type *base, void *txBuffer, void *rxBuffer, uint32_t size,
666                                            cy_stc_scb_spi_context_t *context)
667 {
668     CY_ASSERT_L1(NULL != context);
669     #if !defined(NDEBUG)
670     CY_ASSERT_L1(CY_SCB_SPI_INIT_KEY == context->initKey);
671     #endif
672     CY_ASSERT_L1(CY_SCB_SPI_IS_BUFFER_VALID(txBuffer, rxBuffer, size));
673 
674     cy_en_scb_spi_status_t retStatus = CY_SCB_SPI_TRANSFER_BUSY;
675 
676     /* Check whether there are no active transfer requests */
677     if (0UL == (CY_SCB_SPI_TRANSFER_ACTIVE & context->status))
678     {
679         uint32_t fifoSize = Cy_SCB_GetFifoSize(base);
680 
681         /* Set up the context */
682         context->status    = CY_SCB_SPI_TRANSFER_ACTIVE;
683 
684         context->txBuf            = txBuffer;
685         context->txBufSize        = size;
686         context->txBufIdx         = 0UL;
687 
688         context->rxBuf     = rxBuffer;
689         context->rxBufSize = size;
690         context->rxBufIdx  = 0UL;
691 
692         context->WriteFillSize = 0UL;
693         context->writeFill     = CY_SCB_SPI_DEFAULT_TX;
694 
695         /* Set the TX interrupt when half of FIFO was transmitted */
696         Cy_SCB_SetTxFifoLevel(base, fifoSize / 2UL);
697 
698         if (_FLD2BOOL(SCB_SPI_CTRL_MASTER_MODE, SCB_SPI_CTRL(base)))
699         {
700             /* Trigger an RX interrupt:
701             * - If the transfer size is equal to or less than FIFO, trigger at the end of the transfer.
702             * - If the transfer size is greater than FIFO, trigger 1 byte earlier than the TX interrupt.
703             */
704             Cy_SCB_SetRxFifoLevel(base, (size > fifoSize) ? ((fifoSize / 2UL) - 2UL) : (size - 1UL));
705 
706             Cy_SCB_SetMasterInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
707 
708             /* Enable interrupt sources to perform a transfer */
709             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
710             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
711         }
712         else
713         {
714             /* Trigger an RX interrupt:
715             * - If the transfer size is equal to or less than half of FIFO, trigger ??at the end of the transfer.
716             * - If the transfer size is greater than half of FIFO, trigger 1 byte earlier than a TX interrupt.
717             */
718             Cy_SCB_SetRxFifoLevel(base, (size > (fifoSize / 2UL)) ? ((fifoSize / 2UL) - 2UL) : (size - 1UL));
719 
720             Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_SLAVE_INTR_SPI_BUS_ERROR);
721 
722             /* Enable interrupt sources to perform a transfer */
723             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL | CY_SCB_RX_INTR_OVERFLOW);
724             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL | CY_SCB_TX_INTR_UNDERFLOW);
725         }
726 
727         retStatus = CY_SCB_SPI_SUCCESS;
728     }
729 
730     return (retStatus);
731 }
732 
733 
734 /*******************************************************************************
735 * Function Name: Cy_SCB_SPI_Transfer_Buffer
736 ****************************************************************************//**
737 *
738 * This function starts an SPI transfer operation with different lengths of Tx and
739 * Rx buffers.
740 * It configures transmit and receive buffers for an SPI transfer.
741 * If the data that will be received is not important, pass NULL as rxBuffer.
742 * If the data that will be transmitted is not important, pass NULL as txBuffer
743 * and then the \ref CY_SCB_SPI_DEFAULT_TX is sent out as each data element.
744 * Note that passing NULL as rxBuffer and txBuffer are considered invalid cases.
745 *
746 * After the function configures TX and RX interrupt sources, it returns and
747 * \ref Cy_SCB_SPI_Interrupt manages further data transfer.
748 *
749 * * In the master mode, the transfer operation starts after calling this
750 *   function
751 * * In the slave mode, the transfer registers and will start when
752 *   the master request arrives.
753 *
754 * When the transfer operation is completed (requested number of data elements
755 * sent and received), the \ref CY_SCB_SPI_TRANSFER_ACTIVE status is cleared
756 * and the \ref CY_SCB_SPI_TRANSFER_CMPLT_EVENT event is generated.
757 *
758 * \param base
759 * The pointer to the SPI SCB instance.
760 *
761 * \param txBuffer
762 * The pointer of the buffer with data to transmit.
763 * The element size is defined by the data type that depends on the configured
764 * TX data width.
765 *
766 * \param rxBuffer
767 * The pointer to the buffer to store received data.
768 * The element size is defined by the data type that depends on the configured
769 * RX data width.
770 *
771 * \param txSize
772 * The number of data elements to transmit.
773 *
774 * \param rxSize
775 * The number of data elements to receive.
776 *
777 * \param writeFill
778 * When rxSize is greater than txSize, writeFill value provided will be padded
779 * to the Tx. WriteFill value used will be as per TX FIFO byte mode configuration.
780 *
781 * \param context
782 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
783 * by the user. The structure is used during the SPI operation for internal
784 * configuration and data retention. The user must not modify anything
785 * in this structure.
786 *
787 * \return
788 * \ref cy_en_scb_spi_status_t
789 *
790 * \note
791 * * The buffers must not be modified and must stay allocated until the end of the
792 *   transfer.
793 * * This function overrides all RX and TX FIFO interrupt sources and changes
794 *   the RX and TX FIFO level.
795 *
796 *******************************************************************************/
Cy_SCB_SPI_Transfer_Buffer(CySCB_Type * base,void * txBuffer,void * rxBuffer,uint32_t txSize,uint32_t rxSize,uint32_t writeFill,cy_stc_scb_spi_context_t * context)797 cy_en_scb_spi_status_t Cy_SCB_SPI_Transfer_Buffer(CySCB_Type *base, void *txBuffer, void *rxBuffer,
798                                                                uint32_t txSize, uint32_t rxSize, uint32_t writeFill,
799                                                                cy_stc_scb_spi_context_t *context)
800 {
801     if((txSize == 0UL) && (rxSize == 0UL))
802     {
803         return CY_SCB_SPI_SUCCESS;
804     }
805 
806     CY_ASSERT_L1(NULL != context);
807     #if !defined(NDEBUG)
808     CY_ASSERT_L1(CY_SCB_SPI_INIT_KEY == context->initKey);
809     #endif
810     CY_ASSERT_L1(CY_SCB_SPI_IS_TX_RX_BUFFER_VALID(txBuffer, rxBuffer, txSize, rxSize));
811 
812     cy_en_scb_spi_status_t retStatus = CY_SCB_SPI_TRANSFER_BUSY;
813 
814     /* Check whether there are no active transfer requests */
815     if (0UL == (CY_SCB_SPI_TRANSFER_ACTIVE & context->status))
816     {
817         uint32_t fifoSize = Cy_SCB_GetFifoSize(base);
818 
819         /* Set up the context */
820         context->status    = CY_SCB_SPI_TRANSFER_ACTIVE;
821 
822         context->txBuf            = txBuffer;
823         context->txBufSize        = txSize;
824         context->txBufIdx         = 0UL;
825 
826         context->rxBuf     = rxBuffer;
827         context->rxBufSize = rxSize;
828         context->rxBufIdx  = 0UL;
829 
830         context->writeFill     = writeFill;
831 
832         /* If number of data elements to receive are greater than to transmit, then fill end of tx array
833         with user specified value. */
834         if(context->rxBufSize > context->txBufSize)
835         {
836             context->WriteFillSize = context->rxBufSize - context->txBufSize;
837             context->DiscardRxSize = 0UL;
838             if(txSize == 0UL)
839             {
840                 txSize                 = context->WriteFillSize;
841                 context->txBufSize     = context->WriteFillSize;
842                 context->WriteFillSize = 0UL;
843                 context->txBuf         = NULL;
844             }
845         }
846         else if(context->txBufSize > context->rxBufSize)
847         {
848             /* If number of data elements to transmit are greater than to receive, then discard those extra
849                data elements. */
850             context->WriteFillSize = 0UL;
851             context->DiscardRxSize = context->txBufSize - context->rxBufSize;
852             if(rxSize == 0UL)
853             {
854                 rxSize                 = context->DiscardRxSize;
855                 context->rxBufSize     = context->DiscardRxSize;
856                 context->DiscardRxSize = 0UL;
857                 context->rxBuf         = NULL;
858             }
859         }
860         else
861         {
862             context->WriteFillSize = 0UL;
863             context->DiscardRxSize = 0UL;
864         }
865 
866         /* Set the TX interrupt when half of FIFO was transmitted */
867         Cy_SCB_SetTxFifoLevel(base, ((txSize > fifoSize) ? ((fifoSize / 2UL) - 2UL) : ((txSize == 1UL) ? txSize : (txSize - 1UL))));
868 
869         if (_FLD2BOOL(SCB_SPI_CTRL_MASTER_MODE, SCB_SPI_CTRL(base)))
870         {
871             /* Trigger an RX interrupt:
872             * - If the transfer size is equal to or less than FIFO, trigger at the end of the transfer.
873             * - If the transfer size is greater than FIFO, trigger 1 byte earlier than the TX interrupt.
874             */
875             Cy_SCB_SetRxFifoLevel(base, (rxSize > fifoSize) ? ((fifoSize / 2UL) - 2UL) : (rxSize - 1UL));
876 
877             Cy_SCB_SetMasterInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
878 
879             /* Enable interrupt sources to perform a transfer */
880             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
881             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
882         }
883         else
884         {
885             /* Trigger an RX interrupt:
886             * - If the transfer size is equal to or less than half of FIFO, trigger ??at the end of the transfer.
887             * - If the transfer size is greater than half of FIFO, trigger 1 byte earlier than a TX interrupt.
888             */
889             Cy_SCB_SetRxFifoLevel(base, (rxSize > (fifoSize / 2UL)) ? ((fifoSize / 2UL) - 2UL) : (rxSize - 1UL));
890 
891             Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_SLAVE_INTR_SPI_BUS_ERROR);
892 
893             /* Enable interrupt sources to perform a transfer */
894             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL | CY_SCB_RX_INTR_OVERFLOW);
895             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL | CY_SCB_TX_INTR_UNDERFLOW);
896         }
897 
898         retStatus = CY_SCB_SPI_SUCCESS;
899     }
900 
901     return (retStatus);
902 }
903 
904 /*******************************************************************************
905 * Function Name: Cy_SCB_SPI_AbortTransfer
906 ****************************************************************************//**
907 *
908 * Aborts the current SPI transfer.
909 * It disables the TX and RX interrupt sources, clears the TX
910 * and RX FIFOs and the status.
911 *
912 * \param base
913 * The pointer to the SPI SCB instance.
914 *
915 * \param context
916 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
917 * by the user. The structure is used during the SPI operation for internal
918 * configuration and data retention. The user must not modify anything
919 * in this structure.
920 *
921 * \note
922 * If slave aborts transfer and the master is still transferring data,
923 * that data will be placed in the RX FIFO, and the TX underflow will be set.
924 * To drop data received into the RX FIFO, RX FIFO must be cleared when
925 * the transfer is complete. Otherwise, received data will be kept and
926 * copied to the buffer when \ref Cy_SCB_SPI_Transfer is called.
927 *
928 * \sideeffect
929 * The transmit FIFO clear operation also clears the shift register, so that
930 * the shifter can be cleared in the middle of a data element transfer,
931 * corrupting it. The data element corruption means that all bits that have
932 * not been transmitted are transmitted as "ones" on the bus.
933 *
934 *******************************************************************************/
Cy_SCB_SPI_AbortTransfer(CySCB_Type * base,cy_stc_scb_spi_context_t * context)935 void Cy_SCB_SPI_AbortTransfer(CySCB_Type *base, cy_stc_scb_spi_context_t *context)
936 {
937     /* Disable interrupt sources */
938     Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
939 
940     if (_FLD2BOOL(SCB_SPI_CTRL_MASTER_MODE, SCB_SPI_CTRL(base)))
941     {
942         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
943         Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
944     }
945     else
946     {
947         Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_OVERFLOW);
948         Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_UNDERFLOW);
949     }
950 
951     /* Clear FIFOs */
952     Cy_SCB_SPI_ClearTxFifo(base);
953     Cy_SCB_SPI_ClearRxFifo(base);
954 
955     /* Clear the status to allow a new transfer */
956     context->status = 0UL;
957 }
958 
959 
960 /*******************************************************************************
961 * Function Name: Cy_SCB_SPI_GetNumTransfered
962 ****************************************************************************//**
963 *
964 * Returns the number of data elements transferred since the last call to \ref
965 * Cy_SCB_SPI_Transfer.
966 *
967 * \param base
968 * The pointer to the SPI SCB instance.
969 *
970 * \param context
971 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
972 * by the user. The structure is used during the SPI operation for internal
973 * configuration and data retention. The user must not modify anything
974 * in this structure.
975 *
976 * \return
977 * The number of data elements transferred.
978 *
979 *******************************************************************************/
Cy_SCB_SPI_GetNumTransfered(CySCB_Type const * base,cy_stc_scb_spi_context_t const * context)980 uint32_t Cy_SCB_SPI_GetNumTransfered(CySCB_Type const *base, cy_stc_scb_spi_context_t const *context)
981 {
982     /* Suppress a compiler warning about unused variables */
983     (void) base;
984 
985     return (context->rxBufIdx);
986 }
987 
988 
989 /*******************************************************************************
990 * Function Name: Cy_SCB_SPI_GetTransferStatus
991 ****************************************************************************//**
992 *
993 * Returns the status of the transfer operation started by
994 * \ref Cy_SCB_SPI_Transfer.
995 * This status is a bit mask and the value returned may have a multiple-bit set.
996 *
997 * \param base
998 * The pointer to the SPI SCB instance.
999 *
1000 * \param context
1001 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
1002 * by the user. The structure is used during the SPI operation for internal
1003 * configuration and data retention. The user must not modify anything
1004 * in this structure.
1005 *
1006 * \return
1007 * \ref group_scb_spi_macros_xfer_status.
1008 *
1009 * \note
1010 * The status is cleared by calling \ref Cy_SCB_SPI_Transfer or
1011 * \ref Cy_SCB_SPI_AbortTransfer.
1012 *
1013 *******************************************************************************/
Cy_SCB_SPI_GetTransferStatus(CySCB_Type const * base,cy_stc_scb_spi_context_t const * context)1014 uint32_t Cy_SCB_SPI_GetTransferStatus(CySCB_Type const *base, cy_stc_scb_spi_context_t const *context)
1015 {
1016     /* Suppress a compiler warning about unused variables */
1017     (void) base;
1018 
1019     return (context->status);
1020 }
1021 
1022 
1023 /*******************************************************************************
1024 * Function Name: Cy_SCB_SPI_Interrupt
1025 ****************************************************************************//**
1026 *
1027 * This is the interrupt function for the SCB configured in the SPI mode.
1028 * This function must be called inside the  user-defined interrupt service
1029 * routine for \ref Cy_SCB_SPI_Transfer to work.
1030 *
1031 * \param base
1032 * The pointer to the SPI SCB instance.
1033 *
1034 * \param context
1035 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
1036 * by the user. The structure is used during the SPI operation for internal
1037 * configuration and data retention. The user must not modify anything
1038 * in this structure.
1039 *
1040 *******************************************************************************/
Cy_SCB_SPI_Interrupt(CySCB_Type * base,cy_stc_scb_spi_context_t * context)1041 void Cy_SCB_SPI_Interrupt(CySCB_Type *base, cy_stc_scb_spi_context_t *context)
1042 {
1043      bool locXferErr = false;
1044 
1045     /* Wake up on the slave select condition */
1046     if (0UL != (CY_SCB_SPI_INTR_WAKEUP & Cy_SCB_GetSpiInterruptStatusMasked(base)))
1047     {
1048         Cy_SCB_ClearSpiInterrupt(base, CY_SCB_SPI_INTR_WAKEUP);
1049     }
1050 
1051     /* The slave error condition */
1052     if (0UL != (CY_SCB_SLAVE_INTR_SPI_BUS_ERROR & Cy_SCB_GetSlaveInterruptStatusMasked(base)))
1053     {
1054         locXferErr       = true;
1055         context->status |= CY_SCB_SPI_SLAVE_TRANSFER_ERR;
1056 
1057         Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_SLAVE_INTR_SPI_BUS_ERROR);
1058     }
1059 
1060     /* The RX overflow error condition */
1061     if (0UL != (CY_SCB_RX_INTR_OVERFLOW & Cy_SCB_GetRxInterruptStatusMasked(base)))
1062     {
1063         locXferErr       = true;
1064         context->status |= CY_SCB_SPI_TRANSFER_OVERFLOW;
1065 
1066         Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_OVERFLOW);
1067     }
1068 
1069     /* The TX underflow error condition or slave complete data transfer */
1070     if (0UL != (CY_SCB_TX_INTR_UNDERFLOW & Cy_SCB_GetTxInterruptStatusMasked(base)))
1071     {
1072         locXferErr       = true;
1073         context->status |= CY_SCB_SPI_TRANSFER_UNDERFLOW;
1074 
1075         Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_UNDERFLOW);
1076     }
1077 
1078     /* Report an error, use a callback */
1079     if (locXferErr)
1080     {
1081         if (NULL != context->cbEvents)
1082         {
1083             context->cbEvents(CY_SCB_SPI_TRANSFER_ERR_EVENT);
1084         }
1085     }
1086 
1087     /* RX direction */
1088     if (0UL != (CY_SCB_RX_INTR_LEVEL & Cy_SCB_GetRxInterruptStatusMasked(base)))
1089     {
1090         HandleReceive(base, context);
1091 
1092         Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
1093     }
1094 
1095     /* TX direction */
1096     if (0UL != (CY_SCB_TX_INTR_LEVEL & Cy_SCB_GetTxInterruptStatusMasked(base)))
1097     {
1098         HandleTransmit(base, context);
1099 
1100         Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL);
1101     }
1102 
1103     /* The transfer is complete: all data is loaded in the TX FIFO
1104     * and all data is read from the RX FIFO
1105     */
1106     if ((0UL != (context->status & CY_SCB_SPI_TRANSFER_ACTIVE)) &&
1107         (0UL == context->rxBufSize) && (0UL == context->txBufSize))
1108     {
1109         /* The transfer is complete */
1110         context->status &= (uint32_t) ~CY_SCB_SPI_TRANSFER_ACTIVE;
1111 
1112         if (NULL != context->cbEvents)
1113         {
1114             context->cbEvents(CY_SCB_SPI_TRANSFER_CMPLT_EVENT);
1115         }
1116     }
1117 }
1118 
1119 
1120 /*******************************************************************************
1121 * Function Name: HandleReceive
1122 ****************************************************************************//**
1123 *
1124 * Reads data from RX FIFO into the buffer provided by \ref Cy_SCB_SPI_Transfer.
1125 *
1126 * \param base
1127 * The pointer to the SPI SCB instance.
1128 *
1129 * \param context
1130 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
1131 * by the user. The structure is used during the SPI operation for internal
1132 * configuration and data retention. The user must not modify anything
1133 * in this structure.
1134 *
1135 *******************************************************************************/
HandleReceive(CySCB_Type * base,cy_stc_scb_spi_context_t * context)1136 static void HandleReceive(CySCB_Type *base, cy_stc_scb_spi_context_t *context)
1137 {
1138     /* Get data in RX FIFO */
1139     uint32_t numToCopy = Cy_SCB_GetNumInRxFifo(base);
1140 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
1141     uint32_t mem_width;
1142 #endif /* CY_IP_MXSCB_VERSION */
1143 
1144     /* Adjust the number to read */
1145     if (numToCopy > context->rxBufSize)
1146     {
1147         numToCopy = context->rxBufSize;
1148     }
1149 
1150     context->rxBufSize -= numToCopy;
1151 
1152     /* Read data from RX FIFO */
1153     if (NULL != context->rxBuf)
1154     {
1155         context->rxBufIdx  += numToCopy;
1156 
1157         uint8_t *buf = (uint8_t *) context->rxBuf;
1158 
1159         Cy_SCB_ReadArrayNoCheck(base, context->rxBuf, numToCopy);
1160 
1161 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
1162         mem_width = _FLD2VAL(SCB_CTRL_MEM_WIDTH, SCB_CTRL(base));
1163         buf = &buf[((1UL << mem_width) * numToCopy)];
1164 #elif((defined (CY_IP_MXSCB_VERSION) && CY_IP_MXSCB_VERSION==1))
1165         buf = &buf[(Cy_SCB_IsRxDataWidthByte(base) ? (numToCopy) : (2UL * numToCopy))];
1166 #endif /* CY_IP_MXSCB_VERSION */
1167         context->rxBuf = (void *) buf;
1168     }
1169     else
1170     {
1171         /* Discard read data. */
1172         DiscardArrayNoCheck(base, numToCopy);
1173     }
1174 
1175     if (0UL == context->rxBufSize)
1176     {
1177         if(0UL == context->DiscardRxSize)
1178         {
1179             /* Disable the RX level interrupt */
1180             Cy_SCB_SetRxInterruptMask(base, (Cy_SCB_GetRxInterruptMask(base) & (uint32_t) ~CY_SCB_RX_INTR_LEVEL));
1181         }
1182         else
1183         {
1184             context->rxBuf         = NULL;
1185             context->rxBufSize     = context->DiscardRxSize;
1186             context->DiscardRxSize = 0UL;
1187 
1188             uint32_t fifoSize = Cy_SCB_GetFifoSize(base);
1189 
1190             Cy_SCB_SetRxFifoLevel(base, (context->rxBufSize > fifoSize) ? ((fifoSize / 2UL) - 2UL) : (context->rxBufSize - 1UL));
1191         }
1192     }
1193     else
1194     {
1195         uint32_t level = (_FLD2BOOL(SCB_SPI_CTRL_MASTER_MODE, SCB_SPI_CTRL(base))) ?
1196                                     Cy_SCB_GetFifoSize(base) : (Cy_SCB_GetFifoSize(base) / 2UL);
1197 
1198         if (context->rxBufSize < level)
1199         {
1200             Cy_SCB_SetRxFifoLevel(base, (context->rxBufSize - 1UL));
1201         }
1202     }
1203 }
1204 
1205 
1206 /*******************************************************************************
1207 * Function Name: HandleTransmit
1208 ****************************************************************************//**
1209 *
1210 * Loads TX FIFO with data provided by \ref Cy_SCB_SPI_Transfer.
1211 *
1212 * \param base
1213 * The pointer to the SPI SCB instance.
1214 *
1215 * \param context
1216 * The pointer to the context structure \ref cy_stc_scb_spi_context_t allocated
1217 * by the user. The structure is used during the SPI operation for internal
1218 * configuration and data retention. The user must not modify anything
1219 * in this structure.
1220 *
1221 *******************************************************************************/
HandleTransmit(CySCB_Type * base,cy_stc_scb_spi_context_t * context)1222 static void HandleTransmit(CySCB_Type *base, cy_stc_scb_spi_context_t *context)
1223 {
1224     uint32_t numToCopy;
1225     uint32_t fifoSize = Cy_SCB_GetFifoSize(base);
1226 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
1227     uint32_t mem_width;
1228 #endif /* CY_IP_MXSCB_VERSION */
1229 
1230     numToCopy = fifoSize - Cy_SCB_GetNumInTxFifo(base);
1231 
1232     /* Adjust the number to load */
1233     if (numToCopy > context->txBufSize)
1234     {
1235         numToCopy = context->txBufSize;
1236     }
1237 
1238     context->txBufSize -= numToCopy;
1239 
1240     /* Load TX FIFO with data */
1241     if (NULL != context->txBuf)
1242     {
1243         context->txBufIdx  += numToCopy;
1244 
1245         uint8_t *buf = (uint8_t *) context->txBuf;
1246 
1247         Cy_SCB_WriteArrayNoCheck(base, context->txBuf, numToCopy);
1248 
1249 #if((defined (CY_IP_MXSCB_VERSION) && (CY_IP_MXSCB_VERSION>=2)) || defined (CY_IP_MXS22SCB))
1250         mem_width = _FLD2VAL(SCB_CTRL_MEM_WIDTH, SCB_CTRL(base));
1251         buf = &buf[((1UL << mem_width) * numToCopy)];
1252 #elif((defined (CY_IP_MXSCB_VERSION) && CY_IP_MXSCB_VERSION==1))
1253         buf = &buf[(Cy_SCB_IsTxDataWidthByte(base) ? (numToCopy) : (2UL * numToCopy))];
1254 #endif /* CY_IP_MXSCB_VERSION */
1255         context->txBuf = (void *) buf;
1256     }
1257     else
1258     {
1259         Cy_SCB_WriteDefaultArrayNoCheck(base, context->writeFill, numToCopy);
1260     }
1261 
1262     if (0UL == context->txBufSize)
1263     {
1264         if(0UL == context->WriteFillSize)
1265         {
1266             /* Data is transferred into TX FIFO */
1267             context->status |= CY_SCB_SPI_TRANSFER_IN_FIFO;
1268 
1269             /* Disable the TX level interrupt */
1270             Cy_SCB_SetTxInterruptMask(base, (Cy_SCB_GetTxInterruptMask(base) & (uint32_t) ~CY_SCB_TX_INTR_LEVEL));
1271 
1272             if (NULL != context->cbEvents)
1273             {
1274                 context->cbEvents(CY_SCB_SPI_TRANSFER_IN_FIFO_EVENT);
1275             }
1276         }
1277         else
1278         {
1279             numToCopy = fifoSize - Cy_SCB_GetNumInTxFifo(base);
1280 
1281             if (numToCopy > context->WriteFillSize)
1282             {
1283                 numToCopy = context->WriteFillSize;
1284             }
1285 
1286             Cy_SCB_WriteDefaultArrayNoCheck(base, context->writeFill, numToCopy);
1287 
1288             uint32_t txFifoLevel = Cy_SCB_GetNumInTxFifo(base)+numToCopy;
1289 
1290             Cy_SCB_SetTxFifoLevel(base, ((txFifoLevel > fifoSize) ? ((fifoSize / 2UL) - 2UL) : ((txFifoLevel == 1UL) ? txFifoLevel : (txFifoLevel - 1UL))));
1291 
1292             context->txBuf         = NULL;
1293             context->txBufSize     = context->WriteFillSize - numToCopy;
1294             context->WriteFillSize = 0UL;
1295         }
1296     }
1297 }
1298 
1299 
1300 /*******************************************************************************
1301 * Function Name: DiscardArrayNoCheck
1302 ****************************************************************************//**
1303 *
1304 * Reads the number of data elements from the SPI RX FIFO. The read data is
1305 * discarded. Before calling this function, make sure that RX FIFO has
1306 * enough data elements to read.
1307 *
1308 * \param base
1309 * The pointer to the SPI SCB instance.
1310 *
1311 * \param size
1312 * The number of data elements to read.
1313 *
1314 *******************************************************************************/
DiscardArrayNoCheck(CySCB_Type const * base,uint32_t size)1315 static void DiscardArrayNoCheck(CySCB_Type const *base, uint32_t size)
1316 {
1317     while (size > 0UL)
1318     {
1319         (void) Cy_SCB_SPI_Read(base);
1320         --size;
1321     }
1322 }
1323 
1324 #if defined(__cplusplus)
1325 }
1326 #endif
1327 
1328 #endif /* (defined (CY_IP_MXSCB) || defined (CY_IP_MXS22SCB)) */
1329 
1330 /* [] END OF FILE */
1331