1 /***************************************************************************//**
2 * \file cy_scb_ezi2c.c
3 * \version 3.20
4 *
5 * Provides EZI2C 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_ezi2c.h"
30 
31 #if defined(__cplusplus)
32 extern "C" {
33 #endif
34 
35 
36 /***************************************
37 *        Function Prototypes
38 ***************************************/
39 
40 static void HandleErrors      (CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context);
41 static void HandleAddress     (CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context);
42 static void UpdateRxFifoLevel (CySCB_Type *base, uint32_t bufSize);
43 static void HandleDataReceive (CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context);
44 static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context);
45 static void HandleStop        (CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context);
46 static void UpdateAddressMask (CySCB_Type *base, cy_stc_scb_ezi2c_context_t const *context);
47 
48 
49 /*******************************************************************************
50 * Function Name: Cy_SCB_EZI2C_Init
51 ****************************************************************************//**
52 *
53 * Initializes the SCB for the EZI2C operation.
54 *
55 * \param base
56 * The pointer to the EZI2C SCB instance.
57 *
58 * \param config
59 * The pointer to the configuration structure \ref cy_stc_scb_ezi2c_config_t.
60 *
61 * \param context
62 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
63 * allocated by the user. The structure is used during the EZI2C operation for
64 * internal configuration and data retention. The user must not modify anything
65 * in this structure.
66 *
67 * \return
68 * \ref cy_en_scb_ezi2c_status_t
69 *
70 * \note
71 * Ensure that the SCB block is disabled before calling this function.
72 *
73 *******************************************************************************/
Cy_SCB_EZI2C_Init(CySCB_Type * base,cy_stc_scb_ezi2c_config_t const * config,cy_stc_scb_ezi2c_context_t * context)74 cy_en_scb_ezi2c_status_t Cy_SCB_EZI2C_Init(CySCB_Type *base, cy_stc_scb_ezi2c_config_t const *config,
75                                            cy_stc_scb_ezi2c_context_t *context)
76 {
77     /* Input parameters verification */
78     if ((NULL == base) || (NULL == config) || (NULL == context))
79     {
80         return CY_SCB_EZI2C_BAD_PARAM;
81     }
82 
83     CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID(config->slaveAddress1));
84     CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID(config->slaveAddress2));
85     CY_ASSERT_L2(config->slaveAddress1 != config->slaveAddress2);
86     CY_ASSERT_L3(CY_SCB_EZI2C_IS_NUM_OF_ADDR_VALID  (config->numberOfAddresses));
87     CY_ASSERT_L3(CY_SCB_EZI2C_IS_SUB_ADDR_SIZE_VALID(config->subAddressSize));
88 
89     /* Configure the EZI2C interface */
90     SCB_CTRL(base) = _BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, (config->numberOfAddresses == CY_SCB_EZI2C_TWO_ADDRESSES)) |
91                  _BOOL2FLD(SCB_CTRL_EC_AM_MODE, config->enableWakeFromSleep);
92 #if ((defined (CY_IP_MXSCB_VERSION) && CY_IP_MXSCB_VERSION==1))
93     SCB_CTRL(base) |= SCB_CTRL_BYTE_MODE_Msk;
94 #endif /* CY_IP_MXSCB_VERSION */
95     SCB_I2C_CTRL(base) = CY_SCB_EZI2C_I2C_CTRL;
96 
97     /* Configure the RX direction */
98     SCB_RX_CTRL(base)      = CY_SCB_EZI2C_RX_CTRL;
99     SCB_RX_FIFO_CTRL(base) = 0UL;
100 
101     /* Set the default address and mask */
102     if (config->numberOfAddresses == CY_SCB_EZI2C_ONE_ADDRESS)
103     {
104         context->address2 = 0U;
105         Cy_SCB_EZI2C_SetAddress1(base, config->slaveAddress1, context);
106     }
107     else
108     {
109         Cy_SCB_EZI2C_SetAddress1(base, config->slaveAddress1, context);
110         Cy_SCB_EZI2C_SetAddress2(base, config->slaveAddress2, context);
111     }
112 
113     /* Configure the TX direction */
114     SCB_TX_CTRL(base)      = CY_SCB_EZI2C_TX_CTRL;
115     SCB_TX_FIFO_CTRL(base) = CY_SCB_EZI2C_HALF_FIFO_SIZE;
116 
117     /* Configure the interrupt sources */
118     SCB_INTR_SPI_EC_MASK(base) = 0UL;
119     SCB_INTR_I2C_EC_MASK(base) = 0UL;
120     SCB_INTR_RX_MASK(base)     = 0UL;
121     SCB_INTR_TX_MASK(base)     = 0UL;
122     SCB_INTR_M_MASK(base)      = 0UL;
123     SCB_INTR_S_MASK(base)      = CY_SCB_EZI2C_SLAVE_INTR;
124 
125     /* Initialize the context */
126     context->status = 0UL;
127     context->state  = CY_SCB_EZI2C_STATE_IDLE;
128 
129     context->subAddrSize = config->subAddressSize;
130 
131     context->buf1Size      = 0UL;
132     context->buf1rwBondary = 0UL;
133     context->baseAddr1     = 0UL;
134 
135     context->buf2Size      = 0UL;
136     context->buf2rwBondary = 0UL;
137     context->baseAddr2     = 0UL;
138 
139     return CY_SCB_EZI2C_SUCCESS;
140 }
141 
142 
143 /*******************************************************************************
144 *  Function Name: Cy_SCB_EZI2C_DeInit
145 ****************************************************************************//**
146 *
147 * De-initializes the SCB block, returns the register values to default.
148 *
149 * \param base
150 * The pointer to the EZI2C SCB instance.
151 *
152 * \note
153 * Ensure that the SCB block is disabled before calling this function.
154 *
155 *******************************************************************************/
Cy_SCB_EZI2C_DeInit(CySCB_Type * base)156 void Cy_SCB_EZI2C_DeInit(CySCB_Type *base)
157 {
158     /* Return the block registers into the default state */
159     SCB_CTRL(base)     = CY_SCB_CTRL_DEF_VAL;
160     SCB_I2C_CTRL(base) = CY_SCB_I2C_CTRL_DEF_VAL;
161 
162     SCB_RX_CTRL(base)      = CY_SCB_RX_CTRL_DEF_VAL;
163     SCB_RX_FIFO_CTRL(base) = 0UL;
164     SCB_RX_MATCH(base)     = 0UL;
165 
166     SCB_TX_CTRL(base)      = CY_SCB_TX_CTRL_DEF_VAL;
167     SCB_TX_FIFO_CTRL(base) = 0UL;
168 
169     SCB_INTR_SPI_EC_MASK(base) = 0UL;
170     SCB_INTR_I2C_EC_MASK(base) = 0UL;
171     SCB_INTR_RX_MASK(base)     = 0UL;
172     SCB_INTR_TX_MASK(base)     = 0UL;
173     SCB_INTR_M_MASK(base)      = 0UL;
174     SCB_INTR_S_MASK(base)      = 0UL;
175 }
176 
177 
178 /*******************************************************************************
179 * Function Name: Cy_SCB_EZI2C_Disable
180 ****************************************************************************//**
181 *
182 * Disables the SCB block and clears the context statuses.
183 * Note that after the block is disabled, the TX and RX FIFOs and hardware
184 * statuses are cleared. Also, the hardware stops driving the output and
185 * ignores the input.
186 *
187 * \param base
188 * The pointer to the EZI2C SCB instance.
189 *
190 * \param context
191 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
192 * allocated by the user. The structure is used during the EZI2C operation for
193 * internal configuration and data retention. The user must not modify anything
194 * in this structure.
195 *
196 * \note
197 * Calling this function while EZI2C is busy (the slave has been addressed and is
198 * communicating with the master), may cause transaction corruption because
199 * the hardware stops driving the output and ignores the input. Ensure that
200 * the EZI2C slave is not busy before calling this function.
201 *
202 *******************************************************************************/
Cy_SCB_EZI2C_Disable(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)203 void Cy_SCB_EZI2C_Disable(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
204 {
205     SCB_CTRL(base) &= (uint32_t) ~SCB_CTRL_ENABLED_Msk;
206 
207     /* Set the state to default and clear the statuses */
208     context->status = 0UL;
209     context->state  = CY_SCB_EZI2C_STATE_IDLE;
210 }
211 
212 
213 /*******************************************************************************
214 * Function Name: Cy_SCB_EZI2C_DeepSleepCallback
215 ****************************************************************************//**
216 *
217 * This function handles the transition of the EZI2C SCB into and out of
218 * Deep Sleep mode. It prevents the device from entering Deep Sleep mode if
219 * the EZI2C slave is actively communicating.
220 * The following behavior of the EZI2C depends on whether the SCB block is
221 * wakeup-capable:
222 * * <b>Wakeup-capable</b>: on the incoming EZI2C slave address, the slave
223 *   receives the address and stretches the clock until the device is woken from
224 *   Deep Sleep mode. If the slave address occurs before the device enters
225 *   Deep Sleep mode, the device will not enter Deep Sleep mode.
226 * * <b>Not wakeup-capable</b>: the EZI2C is disabled. It is enabled
227 *   when the device fails to enter Deep Sleep mode or it is woken from Deep Sleep
228 *   mode. While the EZI2C is disabled, it stops driving the outputs and
229 *   ignores the input lines. The slave NACKs all incoming addresses.
230 *
231 * This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep.
232 * To do this, register this function as a callback before calling
233 * \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback
234 * type and call \ref Cy_SysPm_RegisterCallback.
235 *
236 * \param callbackParams
237 * The pointer to the callback parameters structure.
238 * \ref cy_stc_syspm_callback_params_t.
239 *
240 * \param mode
241 * Callback mode, see \ref cy_en_syspm_callback_mode_t
242 *
243 * \return
244 * \ref cy_en_syspm_status_t
245 *
246 * \note
247 * Only applicable for <b>rev-08 of the CY8CKIT-062-BLE</b>.
248 * For proper operation, when the EZI2C slave is configured to be a wakeup source
249 * from Deep Sleep mode, this function must be copied and modified by the user.
250 * The EZI2C clock disable code must be inserted in the
251 * \ref CY_SYSPM_BEFORE_TRANSITION and clock enable code in the
252 * \ref CY_SYSPM_AFTER_TRANSITION mode processing.
253 *
254 *******************************************************************************/
Cy_SCB_EZI2C_DeepSleepCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)255 cy_en_syspm_status_t Cy_SCB_EZI2C_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
256 {
257     CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
258     cy_stc_scb_ezi2c_context_t *locContext = (cy_stc_scb_ezi2c_context_t *) callbackParams->context;
259 
260     cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;
261 
262     switch (mode)
263     {
264         case CY_SYSPM_CHECK_READY:
265         {
266             /* Disable the slave interrupt sources to protect the state */
267             Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_CLEAR_ALL_INTR_SRC);
268 
269             /* If the EZI2C is in the IDLE state, it is ready for Deep Sleep
270             *  mode. Otherwise, it returns fail and restores the slave interrupt
271             * sources.
272             */
273             if (CY_SCB_EZI2C_STATE_IDLE == locContext->state)
274             {
275                 if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
276                 {
277                     /* The SCB is wakeup-capable: do not restore the address
278                     * match interrupt source. The next transaction intended
279                     * for the slave will be paused (the SCL is stretched) before
280                     * the address is ACKed because the corresponding interrupt
281                     * source is disabled.
282                     */
283                     Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR_NO_ADDR);
284                 }
285                 else
286                 {
287                     /* The SCB is NOT wakeup-capable: disable the EZI2C.
288                     * The slave stops responding to the master until the
289                     * EZI2C is enabled. This happens when the device fails
290                     * to enter Deep Sleep mode or it is woken from Deep Sleep
291                     * mode.
292                     */
293                     Cy_SCB_EZI2C_Disable(locBase, locContext);
294                     Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR);
295                 }
296 
297                 retStatus = CY_SYSPM_SUCCESS;
298             }
299             else
300             {
301                 /* Restore the slave interrupt sources */
302                 Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR);
303             }
304         }
305         break;
306 
307         case CY_SYSPM_CHECK_FAIL:
308         {
309             /* The other driver is not ready for Deep Sleep mode. Restore
310             * Active mode configuration.
311             */
312 
313             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
314             {
315                 /* The SCB is wakeup-capable: restore the slave interrupt
316                 * sources.
317                 */
318                 Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR);
319             }
320             else
321             {
322                 /* The SCB is NOT wakeup-capable: enable the slave to operate. */
323                 Cy_SCB_EZI2C_Enable(locBase);
324             }
325 
326             retStatus = CY_SYSPM_SUCCESS;
327         }
328         break;
329 
330         case CY_SYSPM_BEFORE_TRANSITION:
331         {
332             /* This code executes inside the critical section and enabling the
333             * active interrupt source makes the interrupt pending in the NVIC.
334             * However, the interrupt processing is delayed until the code exists
335             * the critical section. The pending interrupt force WFI instruction
336             * does nothing and the device remains in Active mode.
337             */
338 
339             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
340             {
341                 /* The SCB is wakeup-capable: enable the I2C wakeup interrupt
342                 * source. If any transaction was paused the the EZI2C interrupt
343                 * becomes pending and prevents entering Deep Sleep mode.
344                 * The transaction continues as soon as the global interrupts
345                 * are enabled.
346                 */
347                 Cy_SCB_SetI2CInterruptMask(locBase, CY_SCB_I2C_INTR_WAKEUP);
348 
349                 /* Disable SCB clock */
350                 SCB_I2C_CFG(locBase) &= (uint32_t) ~CY_SCB_I2C_CFG_CLK_ENABLE_Msk;
351 
352                 /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
353                 * for proper entering Deep Sleep mode the I2C clock must be disabled.
354                 * This code must be inserted by the user because the driver
355                 * does not have access to the clock.
356                 */
357             }
358 
359             retStatus = CY_SYSPM_SUCCESS;
360         }
361         break;
362 
363         case CY_SYSPM_AFTER_TRANSITION:
364         {
365             if (_FLD2BOOL(SCB_CTRL_EC_AM_MODE, SCB_CTRL(locBase)))
366             {
367                 /* Enable SCB clock */
368                 SCB_I2C_CFG(locBase) |= CY_SCB_I2C_CFG_CLK_ENABLE_Msk;
369 
370                 /* IMPORTANT (replace line above for the CY8CKIT-062 rev-08):
371                 * for proper exiting Deep Sleep mode, the I2C clock must be enabled.
372                 * This code must be inserted by the user because the driver
373                 * does not have access to the clock.
374                 */
375 
376                 /* The SCB is wakeup-capable: disable the I2C wakeup interrupt
377                 * source and restore slave interrupt sources.
378                 */
379                 Cy_SCB_SetI2CInterruptMask  (locBase, CY_SCB_CLEAR_ALL_INTR_SRC);
380                 Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR);
381             }
382             else
383             {
384                 /* The SCB is NOT wakeup-capable: enable the slave to operate */
385                 Cy_SCB_EZI2C_Enable(locBase);
386             }
387 
388             retStatus = CY_SYSPM_SUCCESS;
389         }
390         break;
391 
392         default:
393             /* Unknown state */
394             break;
395     }
396 
397     return (retStatus);
398 }
399 
400 
401 /*******************************************************************************
402 * Function Name: Cy_SCB_EZI2C_HibernateCallback
403 ****************************************************************************//**
404 *
405 * This function handles the transition of the EZI2C SCB block into Hibernate
406 * mode. It prevents the device from entering Hibernate mode if the EZI2C slave
407 * is actively communicating.
408 * If the EZI2C is ready to enter Hibernate mode, it is disabled. If the device
409 * fails to enter Hibernate mode, the EZI2C is enabled. While the EZI2C
410 * is disabled, it stops driving the output and ignores the inputs.
411 * The slave NACKs all incoming addresses.
412 *
413 * This function must be called during execution of \ref Cy_SysPm_SystemEnterHibernate.
414 * To do this, register this function as a callback before calling
415 * \ref Cy_SysPm_SystemEnterHibernate : specify \ref CY_SYSPM_HIBERNATE as the callback
416 * type and call \ref Cy_SysPm_RegisterCallback.
417 *
418 * \param callbackParams
419 * The pointer to the callback parameters structure
420 * \ref cy_stc_syspm_callback_params_t.
421 *
422 * \param mode
423 * Callback mode, see \ref cy_en_syspm_callback_mode_t
424 *
425 * \return
426 * \ref cy_en_syspm_status_t
427 *
428 *******************************************************************************/
Cy_SCB_EZI2C_HibernateCallback(cy_stc_syspm_callback_params_t * callbackParams,cy_en_syspm_callback_mode_t mode)429 cy_en_syspm_status_t Cy_SCB_EZI2C_HibernateCallback(cy_stc_syspm_callback_params_t *callbackParams, cy_en_syspm_callback_mode_t mode)
430 {
431     CySCB_Type *locBase = (CySCB_Type *) callbackParams->base;
432     cy_stc_scb_ezi2c_context_t *locContext = (cy_stc_scb_ezi2c_context_t *) callbackParams->context;
433 
434     cy_en_syspm_status_t retStatus = CY_SYSPM_FAIL;
435 
436     switch (mode)
437     {
438         case CY_SYSPM_CHECK_READY:
439         {
440             /* Disable the slave interrupt sources to protect the state */
441             Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_CLEAR_ALL_INTR_SRC);
442 
443             /* If the EZI2C is in the IDLE state, it is ready for Hibernate mode.
444             * Otherwise, returns fail and restores the slave interrupt sources.
445             */
446             if (CY_SCB_EZI2C_STATE_IDLE == locContext->state)
447             {
448                 /* Disable the EZI2C. It stops responding to the master until
449                 * the EZI2C is enabled. This happens if the device fails to
450                 * enter Hibernate mode.
451                 */
452                 Cy_SCB_EZI2C_Disable(locBase, locContext);
453 
454                 retStatus = CY_SYSPM_SUCCESS;
455             }
456 
457             /* Restore the slave interrupt sources */
458             Cy_SCB_SetSlaveInterruptMask(locBase, CY_SCB_EZI2C_SLAVE_INTR);
459         }
460         break;
461 
462         case CY_SYSPM_CHECK_FAIL:
463         {
464             /* The other driver is not ready for Hibernate mode. Restore the
465             * Active mode configuration.
466             */
467 
468             /* Enable the slave to operate */
469             Cy_SCB_EZI2C_Enable(locBase);
470 
471             retStatus = CY_SYSPM_SUCCESS;
472         }
473         break;
474 
475         case CY_SYSPM_BEFORE_TRANSITION:
476         case CY_SYSPM_AFTER_TRANSITION:
477         {
478             /* The SCB is not capable of waking up from Hibernate mode: do nothing */
479             retStatus = CY_SYSPM_SUCCESS;
480         }
481         break;
482 
483         default:
484         /* Unknown state */
485         break;
486     }
487 
488     return (retStatus);
489 }
490 
491 
492 /*******************************************************************************
493 * Function Name: Cy_SCB_EZI2C_GetActivity
494 ****************************************************************************//**
495 *
496 * Returns a non-zero value if an I2C Read or Write cycle has occurred since the
497 * last time this function was called. All flags are reset to zero at the end of
498 * this function call, except the \ref CY_SCB_EZI2C_STATUS_BUSY.
499 *
500 * \param base
501 * The pointer to the EZI2C SCB instance.
502 *
503 * \param context
504 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
505 * allocated by the user. The structure is used during the EZI2C operation for
506 * internal configuration and data retention. The user must not modify anything
507 * in this structure.
508 *
509 * \return
510 * \ref group_scb_ezi2c_macros_get_activity.
511 *
512 *******************************************************************************/
Cy_SCB_EZI2C_GetActivity(CySCB_Type const * base,cy_stc_scb_ezi2c_context_t * context)513 uint32_t Cy_SCB_EZI2C_GetActivity(CySCB_Type const *base, cy_stc_scb_ezi2c_context_t *context)
514 {
515     uint32_t intrState;
516     uint32_t retStatus;
517 
518     /* Suppress a compiler warning about unused variables */
519     (void) base;
520 
521     intrState = Cy_SysLib_EnterCriticalSection();
522 
523     retStatus = context->status;
524     context->status &= CY_SCB_EZI2C_STATUS_BUSY;
525 
526     Cy_SysLib_ExitCriticalSection(intrState);
527 
528     return (retStatus);
529 }
530 
531 
532 /*******************************************************************************
533 * Function Name: Cy_SCB_EZI2C_SetAddress1
534 ****************************************************************************//**
535 *
536 * Sets the primary EZI2C slave address.
537 *
538 * \param base
539 * The pointer to the EZI2C SCB instance.
540 *
541 * \param addr
542 * The 7-bit right justified slave address.
543 *
544 * \param context
545 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
546 * allocated by the user. The structure is used during the EZI2C operation for
547 * internal configuration and data retention. The user must not modify anything
548 * in this structure.
549 *
550 *******************************************************************************/
Cy_SCB_EZI2C_SetAddress1(CySCB_Type * base,uint8_t addr,cy_stc_scb_ezi2c_context_t * context)551 void Cy_SCB_EZI2C_SetAddress1(CySCB_Type *base, uint8_t addr, cy_stc_scb_ezi2c_context_t *context)
552 {
553     CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID(addr));
554     CY_ASSERT_L2(addr != context->address2);
555 
556     context->address1 = addr;
557 
558     CY_REG32_CLR_SET(SCB_RX_MATCH(base), SCB_RX_MATCH_ADDR, ((uint32_t)((uint32_t) addr << 1UL)));
559 
560     UpdateAddressMask(base, context);
561 }
562 
563 
564 /*******************************************************************************
565 * Function Name: Cy_SCB_EZI2C_GetAddress1
566 ****************************************************************************//**
567 *
568 * Returns the primary the EZI2C slave address.
569 *
570 * \param base
571 * The pointer to the EZI2C SCB instance.
572 *
573 * * \param context
574 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
575 * allocated by the user. The structure is used during the EZI2C operation for
576 * internal configuration and data retention. The user must not modify anything
577 * in this structure.
578 *
579 * \return
580 * The 7-bit right justified slave address.
581 *
582 *******************************************************************************/
Cy_SCB_EZI2C_GetAddress1(CySCB_Type const * base,cy_stc_scb_ezi2c_context_t const * context)583 uint32_t Cy_SCB_EZI2C_GetAddress1(CySCB_Type const *base, cy_stc_scb_ezi2c_context_t const *context)
584 {
585     /* Suppress a compiler warning about unused variables */
586     (void) base;
587 
588     return ((uint32_t) context->address1);
589 }
590 
591 
592 /*******************************************************************************
593 * Function Name: Cy_SCB_EZI2C_SetBuffer1
594 ****************************************************************************//**
595 *
596 * Sets up the data buffer to be exposed to the I2C master on the primary slave
597 * address request.
598 *
599 * \param base
600 * The pointer to the EZI2C SCB instance.
601 *
602 * \param buffer
603 * The pointer to the data buffer.
604 *
605 * \param size
606 * The size of the buffer in bytes.
607 *
608 * \param rwBoundary
609 * The number of data bytes starting from the beginning of the buffer with Read and
610 * Write access. The data bytes located at rwBoundary or greater are read only.
611 *
612 * \param context
613 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
614 * allocated by the user. The structure is used during the EZI2C operation for
615 * internal configuration and data retention. The user must not modify anything
616 * in this structure.
617 *
618 * \note
619 * * This function is not interrupt-protected and to prevent a race condition,
620 *   it must be protected from the EZI2C interruption in the place where it
621 *   is called.
622 * * Calling this function in the middle of a transaction intended for the
623 *   secondary slave address leads to unexpected behavior.
624 *
625 *******************************************************************************/
Cy_SCB_EZI2C_SetBuffer1(CySCB_Type const * base,uint8_t * buffer,uint32_t size,uint32_t rwBoundary,cy_stc_scb_ezi2c_context_t * context)626 void Cy_SCB_EZI2C_SetBuffer1(CySCB_Type const *base, uint8_t *buffer, uint32_t size, uint32_t rwBoundary,
627                              cy_stc_scb_ezi2c_context_t *context)
628 {
629     CY_ASSERT_L1(CY_SCB_IS_I2C_BUFFER_VALID(buffer, size));
630     CY_ASSERT_L2(rwBoundary <= size);
631 
632     /* Suppress a compiler warning about unused variables */
633     (void) base;
634 
635     context->buf1          = buffer;
636     context->buf1Size      = size;
637     context->buf1rwBondary = rwBoundary;
638 }
639 
640 
641 /*******************************************************************************
642 * Function Name: Cy_SCB_EZI2C_SetAddress2
643 ****************************************************************************//**
644 *
645 * Sets the secondary EZI2C slave address.
646 *
647 * \param base
648 * The pointer to the EZI2C SCB instance.
649 *
650 * \param addr
651 * The 7-bit right justified slave address.
652 *
653 * \param context
654 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
655 * allocated by the user. The structure is used during the EZI2C operation for
656 * internal configuration and data retention. The user must not modify anything
657 * in this structure.
658 *
659 * \note
660 * Calling this function when the EZI2C slave is configured for one-address
661 * operation leads to unexpected behavior because it updates the address mask.
662 *
663 * \note
664 * Please observe following limitation while using both primary and secondary
665 * slave addresses. EZI2C IP has single address match mask. This mask is setup as
666 * (address1 ^ address2), This can generate false address match. For example, if
667 * address1 is 0x24 and address2 is 0x10, then slave address 0x20 will also
668 * generate a false match. Hence, choose address1 and 2 such that all other
669 * slave address on the bus satisfy
670 * ((slave address) & (address1 ^ address2)) != 0
671 *
672 *******************************************************************************/
Cy_SCB_EZI2C_SetAddress2(CySCB_Type * base,uint8_t addr,cy_stc_scb_ezi2c_context_t * context)673 void Cy_SCB_EZI2C_SetAddress2(CySCB_Type *base, uint8_t addr, cy_stc_scb_ezi2c_context_t *context)
674 {
675     CY_ASSERT_L2(CY_SCB_IS_I2C_ADDR_VALID(addr));
676     CY_ASSERT_L2(addr != context->address1);
677 
678     context->address2 = addr;
679 
680     UpdateAddressMask(base, context);
681 }
682 
683 
684 /*******************************************************************************
685 * Function Name: Cy_SCB_EZI2C_GetAddress2
686 ****************************************************************************//**
687 *
688 * Returns the secondary EZI2C slave address.
689 *
690 * \param base
691 * The pointer to the EZI2C SCB instance.
692 *
693 * \param context
694 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
695 * allocated by the user. The structure is used during the EZI2C operation for
696 * internal configuration and data retention. The user must not modify anything
697 * in this structure.
698 *
699 * \return
700 * The 7-bit right justified slave address.
701 *
702 *******************************************************************************/
Cy_SCB_EZI2C_GetAddress2(CySCB_Type const * base,cy_stc_scb_ezi2c_context_t const * context)703 uint32_t Cy_SCB_EZI2C_GetAddress2(CySCB_Type const *base, cy_stc_scb_ezi2c_context_t const *context)
704 {
705     /* Suppress a compiler warning about unused variables */
706     (void) base;
707 
708     return ((uint32_t) context->address2);
709 }
710 
711 
712 /*******************************************************************************
713 * Function Name: Cy_SCB_EZI2C_SetBuffer2
714 ****************************************************************************//**
715 *
716 * Sets up the data buffer to be exposed to the I2C master on the secondary
717 * slave address request.
718 *
719 * \param base
720 * The pointer to the EZI2C SCB instance.
721 *
722 * \param buffer
723 * The pointer to the data buffer.
724 *
725 * \param size
726 * The size of the buffer in bytes.
727 *
728 * \param rwBoundary
729 * The number of data bytes starting from the beginning of the buffer with Read and
730 * Write access. The data bytes located at rwBoundary or greater are read only.
731 *
732 * \param context
733 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t
734 * allocated by the user. The structure is used during the EZI2C operation for
735 * internal configuration and data retention. The user must not modify anything
736 * in this structure.
737 *
738 * \note
739 * * This function is not interrupt-protected. To prevent a race condition,
740 *   it must be protected from the EZI2C interruption in the place where it
741 *   is called.
742 * * Calling this function in the middle of a transaction intended for the
743 *   secondary slave address leads to unexpected behavior.
744 *
745 *******************************************************************************/
Cy_SCB_EZI2C_SetBuffer2(CySCB_Type const * base,uint8_t * buffer,uint32_t size,uint32_t rwBoundary,cy_stc_scb_ezi2c_context_t * context)746 void Cy_SCB_EZI2C_SetBuffer2(CySCB_Type const *base, uint8_t *buffer, uint32_t size, uint32_t rwBoundary,
747                              cy_stc_scb_ezi2c_context_t *context)
748 {
749     CY_ASSERT_L1(CY_SCB_IS_I2C_BUFFER_VALID(buffer, size));
750     CY_ASSERT_L2(rwBoundary <= size);
751 
752     /* Suppress a compiler warning about unused variables */
753     (void) base;
754 
755     context->buf2          = buffer;
756     context->buf2Size      = size;
757     context->buf2rwBondary = rwBoundary;
758 }
759 
760 
761 /*******************************************************************************
762 * Function Name: Cy_SCB_EZI2C_Interrupt
763 ****************************************************************************//**
764 *
765 * This is the interrupt function for the SCB configured in the EZI2C mode.
766 * This function must be called inside the user-defined interrupt service
767 * routine to make the EZI2C slave work.
768 *
769 * \param base
770 * The pointer to the EZI2C SCB instance.
771 *
772 * \param context
773 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
774 * by the user. The structure is used during the EZI2C operation for internal
775 * configuration and data retention. The user must not modify anything
776 * in this structure.
777 *
778 *******************************************************************************/
Cy_SCB_EZI2C_Interrupt(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)779 void Cy_SCB_EZI2C_Interrupt(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
780 {
781     uint32_t slaveIntrStatus;
782 
783     /* Handle an I2C wake-up event */
784     if (0UL != (CY_SCB_I2C_INTR_WAKEUP & Cy_SCB_GetI2CInterruptStatusMasked(base)))
785     {
786         /* Move from IDLE state, the slave was addressed. Following address match
787         * interrupt continue transfer.
788         */
789         context->state = CY_SCB_EZI2C_STATE_ADDR;
790 
791         Cy_SCB_ClearI2CInterrupt(base, CY_SCB_I2C_INTR_WAKEUP);
792     }
793 
794     /* Get the slave interrupt sources */
795     slaveIntrStatus = Cy_SCB_GetSlaveInterruptStatusMasked(base);
796 
797     /* Handle the error conditions */
798     if (0UL != (CY_SCB_EZI2C_SLAVE_INTR_ERROR & slaveIntrStatus))
799     {
800         HandleErrors(base, context);
801 
802         Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_EZI2C_SLAVE_INTR_ERROR);
803 
804         /* Trigger the stop handling to complete the transaction */
805         slaveIntrStatus |= CY_SCB_SLAVE_INTR_I2C_STOP;
806     }
807     else
808     {
809         if ((CY_SCB_EZI2C_STATE_RX_DATA1 == context->state) &&
810             (0UL != (CY_SCB_SLAVE_INTR_I2C_STOP & slaveIntrStatus)))
811         {
812             /* Get data from the RX FIFO after Stop is generated */
813             Cy_SCB_SetRxInterrupt    (base, CY_SCB_RX_INTR_LEVEL);
814             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
815         }
816     }
817 
818     /* Handle the receive direction (master writes data) */
819     if (0UL != (CY_SCB_RX_INTR_LEVEL & Cy_SCB_GetRxInterruptStatusMasked(base)))
820     {
821         HandleDataReceive(base, context);
822 
823         Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
824     }
825 
826     /* Handle the transaction completion */
827     if (0UL != (CY_SCB_SLAVE_INTR_I2C_STOP & slaveIntrStatus))
828     {
829         HandleStop(base, context);
830 
831         Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_SLAVE_INTR_I2C_STOP);
832 
833         /* Update the slave interrupt status */
834         slaveIntrStatus = Cy_SCB_GetSlaveInterruptStatusMasked(base);
835     }
836 
837     /* Handle the address byte */
838     if (0UL != (CY_SCB_SLAVE_INTR_I2C_ADDR_MATCH & slaveIntrStatus))
839     {
840         HandleAddress(base, context);
841 
842         Cy_SCB_ClearI2CInterrupt  (base, CY_SCB_I2C_INTR_WAKEUP);
843         Cy_SCB_ClearSlaveInterrupt(base, CY_SCB_SLAVE_INTR_I2C_ADDR_MATCH);
844     }
845 
846     /* Handle the transmit direction (master reads data) */
847     if (0UL != (CY_SCB_TX_INTR_LEVEL & Cy_SCB_GetTxInterruptStatusMasked(base)))
848     {
849         HandleDataTransmit(base, context);
850 
851         Cy_SCB_ClearTxInterrupt(base, CY_SCB_TX_INTR_LEVEL);
852     }
853 }
854 
855 
856 
857 /*******************************************************************************
858 * Function Name: HandleErrors
859 ****************************************************************************//**
860 *
861 * Handles an error conditions.
862 *
863 * \param base
864 * The pointer to the EZI2C SCB instance.
865 *
866 * \param context
867 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
868 * by the user. The structure is used during the EZI2C operation for internal
869 * configuration and data retention. The user must not modify anything
870 * in this structure.
871 *
872 *******************************************************************************/
HandleErrors(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)873 static void HandleErrors(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
874 {
875     context->status |= CY_SCB_EZI2C_STATUS_ERR;
876 
877     /* Drop any data available in the RX FIFO */
878     Cy_SCB_ClearRxFifo(base);
879 
880     /* Stop the TX and RX processing */
881     Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
882     Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
883 }
884 
885 
886 /*******************************************************************************
887 * Function Name: HandleAddress
888 ****************************************************************************//**
889 *
890 * Prepares the EZI2C slave for the following read or write transfer after the
891 * matched address was received.
892 *
893 * \param base
894 * The pointer to the EZI2C SCB instance.
895 *
896 * \param context
897 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
898 * by the user. The structure is used during the EZI2C operation for internal
899 * configuration and data retention. The user must not modify anything
900 * in this structure.
901 *
902 *******************************************************************************/
HandleAddress(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)903 static void HandleAddress(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
904 {
905     /* Default actions: ACK address 1 */
906     uint32_t cmd = SCB_I2C_S_CMD_S_ACK_Msk;
907     context->addr1Active = true;
908 
909     if (0U != context->address2)
910     {
911         /* Get an address from the RX FIFO and make it a 7-bit address */
912         uint32_t address = (Cy_SCB_ReadRxFifo(base) >> 1UL);
913         Cy_SCB_ClearRxInterrupt(base, CY_SCB_RX_INTR_LEVEL);
914 
915         /* Decide whether the address matches */
916         if ((address == context->address1) || (address == context->address2))
917         {
918             /* ACK the address */
919             if (address == context->address2)
920             {
921                 context->addr1Active = false;
922             }
923 
924             /* Clear and enable the stop interrupt source */
925             Cy_SCB_ClearSlaveInterrupt  (base, CY_SCB_SLAVE_INTR_I2C_STOP);
926             Cy_SCB_SetSlaveInterruptMask(base, CY_SCB_EZI2C_SLAVE_INTR);
927         }
928         else
929         {
930             /* NACK the address */
931             cmd = SCB_I2C_S_CMD_S_NACK_Msk;
932 
933             /* Disable the stop interrupt source */
934             Cy_SCB_SetI2CInterruptMask(base, CY_SCB_EZI2C_SLAVE_INTR_NO_STOP);
935         }
936     }
937 
938     /* Clear the TX FIFO before continuing the transaction */
939     Cy_SCB_ClearTxFifo(base);
940 
941     /* Set the command to an ACK or NACK address */
942     SCB_I2C_S_CMD(base) = cmd;
943 
944     if (cmd == SCB_I2C_S_CMD_S_ACK_Msk)
945     {
946         context->status |= CY_SCB_EZI2C_STATUS_BUSY;
947 
948         /* Prepare for a transaction */
949         if (_FLD2BOOL(SCB_I2C_STATUS_S_READ, SCB_I2C_STATUS(base)))
950         {
951             /* The master reads data from the slave */
952             context->state = CY_SCB_EZI2C_STATE_TX_DATA;
953 
954             /* Prepare the buffer for transmit */
955             if (context->addr1Active)
956             {
957                 context->curBuf  = &context->buf1[context->baseAddr1];
958                 context->bufSize = context->buf1Size - context->baseAddr1;
959             }
960             else
961             {
962                 context->curBuf  = &context->buf2[context->baseAddr2];
963                 context->bufSize = context->buf2Size - context->baseAddr2;
964             }
965 
966             Cy_SCB_SetTxInterruptMask(base, CY_SCB_TX_INTR_LEVEL);
967         }
968         else
969         {
970             /* The master writes data into the slave */
971             context->state = CY_SCB_EZI2C_STATE_RX_OFFSET_MSB;
972 
973             context->bufSize = ((context->addr1Active) ? context->buf1Size : context->buf2Size);
974 
975             Cy_SCB_SetRxFifoLevel    (base, 0UL);
976             Cy_SCB_SetRxInterruptMask(base, CY_SCB_RX_INTR_LEVEL);
977         }
978     }
979 }
980 
981 
982 /*******************************************************************************
983 * Function Name: HandleDataReceive
984 ****************************************************************************//**
985 *
986 * Updates the RX FIFO level to trigger the next read from it. It also manages
987 * the auto-data NACK feature.
988 *
989 * \param base
990 * The pointer to the EZI2C SCB instance.
991 *
992 * \param bufSize
993 * The size of the buffer in bytes.
994 *
995 *******************************************************************************/
UpdateRxFifoLevel(CySCB_Type * base,uint32_t bufSize)996 static void UpdateRxFifoLevel(CySCB_Type *base, uint32_t bufSize)
997 {
998     uint32_t level;
999     uint32_t fifoSize = CY_SCB_EZI2C_FIFO_SIZE;
1000 
1001     if (bufSize > fifoSize)
1002     {
1003         /* Continue the transaction: there is space in the buffer */
1004         level = (bufSize - fifoSize);
1005         level = ((level > fifoSize) ? (fifoSize / 2UL) : level) - 1UL;
1006     }
1007     else
1008     {
1009         /* Prepare to end the transaction: after the FIFO becomes full, NACK the next byte.
1010         * The NACKed byte is dropped by the hardware.
1011         */
1012         SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk;
1013 
1014         level = ((bufSize == 0UL) ? (0UL) : (bufSize - 1UL));
1015         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1016     }
1017 
1018     Cy_SCB_SetRxFifoLevel(base, level);
1019 }
1020 
1021 
1022 /*******************************************************************************
1023 * Function Name: HandleDataReceive
1024 ****************************************************************************//**
1025 *
1026 * Handles the data read from the RX FIFO.
1027 *
1028 * \param base
1029 * The pointer to the EZI2C SCB instance.
1030 *
1031 * \param context
1032 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
1033 * by the user. The structure is used during the EZI2C operation for internal
1034 * configuration and data retention. The user must not modify anything
1035 * in this structure.
1036 *
1037 *******************************************************************************/
HandleDataReceive(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)1038 static void HandleDataReceive(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
1039 {
1040     switch(context->state)
1041     {
1042         case CY_SCB_EZI2C_STATE_RX_OFFSET_MSB:
1043         case CY_SCB_EZI2C_STATE_RX_OFFSET_LSB:
1044         {
1045             /* Default actions: compare the base address and ACK it */
1046             bool checkBaseAddr = true;
1047 
1048             /* Get the base address from the RX FIFO */
1049             uint32_t baseAddr = Cy_SCB_ReadRxFifo(base);
1050 
1051             if (context->subAddrSize == CY_SCB_EZI2C_SUB_ADDR16_BITS)
1052             {
1053                 if (context->state == CY_SCB_EZI2C_STATE_RX_OFFSET_MSB)
1054                 {
1055                     /* ACK base address MSB */
1056                     SCB_I2C_S_CMD(base) = SCB_I2C_S_CMD_S_ACK_Msk;
1057 
1058                     /* Temporary store base address MSB */
1059                     context->idx = (uint32_t) (baseAddr << 8UL);
1060 
1061                     /* Do not compare until 16 bits are received */
1062                     checkBaseAddr = false;
1063                     context->state = CY_SCB_EZI2C_STATE_RX_OFFSET_LSB;
1064                 }
1065                 else
1066                 {
1067                     /* Get the base address (MSB | LSB) */
1068                     baseAddr |= context->idx;
1069                 }
1070             }
1071 
1072             /* Check whether the received base address is valid */
1073             if (checkBaseAddr)
1074             {
1075                 uint32_t cmd = SCB_I2C_S_CMD_S_ACK_Msk;
1076 
1077                 /* Decide whether the base address within the buffer range */
1078                 if (baseAddr < context->bufSize)
1079                 {
1080                     /* Accept the new base address */
1081                     if (context->addr1Active)
1082                     {
1083                         context->baseAddr1 = baseAddr;
1084                     }
1085                     else
1086                     {
1087                         context->baseAddr2 = baseAddr;
1088                     }
1089 
1090                     /* Store the base address to use it later */
1091                     context->idx = baseAddr;
1092                 }
1093                 else
1094                 {
1095                     /* Restore the valid base address */
1096                     context->idx = ((context->addr1Active) ? context->baseAddr1 : context->baseAddr2);
1097 
1098                     /* The base address is out of range - NACK it */
1099                     cmd = SCB_I2C_S_CMD_S_NACK_Msk;
1100                 }
1101 
1102                 /* Set the command to an ACK or NACK address */
1103                 SCB_I2C_S_CMD(base) = cmd;
1104 
1105                 if (cmd == SCB_I2C_S_CMD_S_ACK_Msk)
1106                 {
1107                     /* Prepare the buffer for a write */
1108                     if (context->addr1Active)
1109                     {
1110                         context->curBuf  = &context->buf1[context->baseAddr1];
1111                         context->bufSize = ((context->baseAddr1 < context->buf1rwBondary) ?
1112                                                     (context->buf1rwBondary - context->baseAddr1) : (0UL));
1113                     }
1114                     else
1115                     {
1116                         context->curBuf  = &context->buf2[context->baseAddr2];
1117                         context->bufSize = ((context->baseAddr2 < context->buf2rwBondary) ?
1118                                                     (context->buf2rwBondary - context->baseAddr2) : (0UL));
1119                     }
1120 
1121                     /* Choice receive scheme  */
1122                     if ((0U != context->address2) || (context->bufSize < CY_SCB_EZI2C_FIFO_SIZE))
1123                     {
1124                         /* Handle each byte separately */
1125                         context->state = CY_SCB_EZI2C_STATE_RX_DATA0;
1126                     }
1127                     else
1128                     {
1129                         /* Use the RX FIFO and the auto-ACK/NACK features */
1130                         SCB_I2C_CTRL(base) |= SCB_I2C_CTRL_S_READY_DATA_ACK_Msk;
1131                         UpdateRxFifoLevel(base, context->bufSize);
1132 
1133                         context->state = CY_SCB_EZI2C_STATE_RX_DATA1;
1134                     }
1135                 }
1136             }
1137         }
1138         break;
1139 
1140         case CY_SCB_EZI2C_STATE_RX_DATA0:
1141         {
1142             uint32_t byte = Cy_SCB_ReadRxFifo(base);
1143 
1144             /* Check whether there is space to store the byte */
1145             if (context->bufSize > 0UL)
1146             {
1147                 /* Continue the transfer: send an ACK */
1148                 SCB_I2C_S_CMD(base) = SCB_I2C_S_CMD_S_ACK_Msk;
1149 
1150                 /* Store the byte in the buffer */
1151                 context->curBuf[0UL] = (uint8_t) byte;
1152                 context->bufSize--;
1153                 context->curBuf++;
1154 
1155                 /* Update the base address to notice that the buffer is modified */
1156                 context->idx++;
1157             }
1158             else
1159             {
1160                 /* Finish the transfer: send a NACK. Drop the received byte */
1161                 SCB_I2C_S_CMD(base) = SCB_I2C_S_CMD_S_NACK_Msk;
1162                 Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1163             }
1164         }
1165         break;
1166 
1167         case CY_SCB_EZI2C_STATE_RX_DATA1:
1168         {
1169             /* Get the number of bytes to read from the RX FIFO */
1170             uint32_t numToCopy = Cy_SCB_GetRxFifoLevel(base) + 1UL;
1171 
1172             /* Get data from the RX FIFO */
1173             numToCopy = Cy_SCB_ReadArray(base, context->curBuf, numToCopy);
1174             context->bufSize -= numToCopy;
1175             context->curBuf  += numToCopy;
1176 
1177             /* Configure the next RX FIFO read event */
1178             UpdateRxFifoLevel(base, context->bufSize);
1179 
1180             /* Update the base address to notice that the buffer is modified */
1181             context->idx++;
1182         }
1183         break;
1184 
1185         default:
1186         /* Unknown state */
1187         break;
1188     }
1189 }
1190 
1191 
1192 /*******************************************************************************
1193 * Function Name: HandleDataTransmit
1194 ****************************************************************************//**
1195 *
1196 * Loads the TX FIFO with data from the buffer.
1197 *
1198 * \param base
1199 * The pointer to the EZI2C SCB instance.
1200 *
1201 * \param context
1202 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
1203 * by the user. The structure is used during the EZI2C operation for internal
1204 * configuration and data retention. The user must not modify anything
1205 * in this structure.
1206 *
1207 *******************************************************************************/
HandleDataTransmit(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)1208 static void HandleDataTransmit(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
1209 {
1210     if (context->bufSize > 0UL)
1211     {
1212         /* Write data into the TX FIFO from the buffer */
1213         uint32_t numToCopy = Cy_SCB_WriteArray(base, context->curBuf, context->bufSize);
1214         context->bufSize  -= numToCopy;
1215         context->curBuf   += numToCopy;
1216     }
1217 
1218     if (0UL == context->bufSize)
1219     {
1220         /* Write the default bytes into the TX FIFO */
1221         (void) Cy_SCB_WriteDefaultArray(base, CY_SCB_EZI2C_DEFAULT_TX, CY_SCB_EZI2C_FIFO_SIZE);
1222     }
1223 }
1224 
1225 
1226 /*******************************************************************************
1227 * Function Name: HandleStop
1228 ****************************************************************************//**
1229 *
1230 * Handles the transfer completion.
1231 * It is triggered by a Stop or Restart condition on the bus.
1232 *
1233 * \param base
1234 * The pointer to the EZI2C SCB instance.
1235 *
1236 * \param context
1237 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
1238 * by the user. The structure is used during the EZI2C operation for internal
1239 * configuration and data retention. The user must not modify anything
1240 * in this structure.
1241 *
1242 *******************************************************************************/
HandleStop(CySCB_Type * base,cy_stc_scb_ezi2c_context_t * context)1243 static void HandleStop(CySCB_Type *base, cy_stc_scb_ezi2c_context_t *context)
1244 {
1245     /* Check for errors */
1246     if (0UL != (CY_SCB_EZI2C_STATUS_ERR & context->status))
1247     {
1248         /* Re-enable the SCB to recover from errors */
1249         Cy_SCB_FwBlockReset(base);
1250     }
1251 
1252     /* Clean up the hardware to be ready for the next transaction */
1253     if (CY_SCB_EZI2C_STATE_TX_DATA == context->state)
1254     {
1255         Cy_SCB_SetTxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1256     }
1257     else
1258     {
1259         Cy_SCB_SetRxInterruptMask(base, CY_SCB_CLEAR_ALL_INTR_SRC);
1260 
1261         SCB_I2C_CTRL(base) &= (uint32_t) ~(SCB_I2C_CTRL_S_READY_DATA_ACK_Msk |
1262                                            SCB_I2C_CTRL_S_NOT_READY_DATA_NACK_Msk);
1263     }
1264 
1265     /* Update the statuses */
1266     context->status &= (uint32_t) ~CY_SCB_EZI2C_STATUS_BUSY;
1267 
1268     if (context->addr1Active)
1269     {
1270         context->status |= ((CY_SCB_EZI2C_STATE_TX_DATA == context->state) ? CY_SCB_EZI2C_STATUS_READ1 :
1271                              ((context->baseAddr1 != context->idx) ?  CY_SCB_EZI2C_STATUS_WRITE1 : 0UL));
1272     }
1273     else
1274     {
1275         context->status |= ((CY_SCB_EZI2C_STATE_TX_DATA == context->state) ? CY_SCB_EZI2C_STATUS_READ2 :
1276                              ((context->baseAddr2 != context->idx) ? CY_SCB_EZI2C_STATUS_WRITE2 : 0UL));
1277     }
1278 
1279     /* Back to the idle state */
1280     context->state = CY_SCB_EZI2C_STATE_IDLE;
1281 }
1282 
1283 
1284 /*******************************************************************************
1285 * Function Name: UpdateAddressMask
1286 ****************************************************************************//**
1287 *
1288 * Updates the slave address mask to enable the SCB hardware to receive matching
1289 * slave addresses.
1290 *
1291 * \param base
1292 * The pointer to the EZI2C SCB instance.
1293 *
1294 * \param context
1295 * The pointer to the context structure \ref cy_stc_scb_ezi2c_context_t allocated
1296 * by the user. The structure is used during the EZI2C operation for internal
1297 * configuration and data retention. The user must not modify anything
1298 * in this structure.
1299 *
1300 * \note
1301 * Please observe following limitation while using both primary and secondary
1302 * slave addresses. EZI2C IP has single address match mask. This mask is setup as
1303 * (address1 ^ address2), This can generate false address match. For example, if
1304 * address1 is 0x24 and address2 is 0x10, then slave address 0x20 will also
1305 * generate a false match. Hence, choose address1 and 2 such that all other
1306 * slave address on the bus satisfy
1307 * ((slave address) & (address1 ^ address2)) != 0
1308 *
1309 *******************************************************************************/
UpdateAddressMask(CySCB_Type * base,cy_stc_scb_ezi2c_context_t const * context)1310 static void UpdateAddressMask(CySCB_Type *base, cy_stc_scb_ezi2c_context_t const *context)
1311 {
1312     uint32_t addrMask;
1313 
1314     /* Check how many addresses are used: */
1315     if (0U != context->address2)
1316     {
1317         /* If (addr1 and addr2) bits match - mask bit equals 1; otherwise 0 */
1318         addrMask  = (uint32_t) ~((uint32_t) context->address1 ^ (uint32_t) context->address2);
1319     }
1320     else
1321     {
1322         addrMask = CY_SCB_EZI2C_ONE_ADDRESS_MASK;
1323     }
1324 
1325     /* Update the hardware address match */
1326     CY_REG32_CLR_SET(SCB_RX_MATCH(base), SCB_RX_MATCH_MASK, ((uint32_t) addrMask << 1UL));
1327 }
1328 
1329 
1330 #if defined(__cplusplus)
1331 }
1332 #endif
1333 
1334 #endif /* (defined (CY_IP_MXSCB) || defined (CY_IP_MXS22SCB)) */
1335 
1336 /* [] END OF FILE */
1337