PSOC4 I2C slave with interrupt

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
lock attach
Attachments are accessible only for community members.
SiYe_3979446
Level 1
Level 1
First like given

hi,

   I am working on PSOC4 with I2C with interrupt driven when I2c slave stop condition reached.I am able receive data properly from Master when it is 7 bytes,but if I want receive more than 7 bytes I am facing problem,after sending 2 times from master,I am receiving in slave,but this problem is not observed in without interrupt scenario,If i use I2c with interrupt i am facing this problem,can any one faced this problem.how can i use I2C slave interrupt with more than 8 bytes  coming from Master,without issue,the following is the code,

0 Likes
1 Solution
lock attach
Attachments are accessible only for community members.
Aashita_R
Moderator
Moderator
Moderator
50 likes received 100 solutions authored 250 replies posted

Hi SiYe_3979446​,

I have gone through your attached project. The interrupt issue is being created unnecessarily due to the checking of the condition I2CS_INTR_SLAVE_I2C_WRITE_STOP explicitly. The conditions of FIFO write and read flags being set is taken care by the component ISR itself, therefore you need not check the condition with every slave write complete transfer using the macro.

I have shared my project in which I have included cyapicallbacks.h in the main file and used the I2CS_I2C_SlaveCompleteCallback function to service the interrupt. This callback function is called when slave transfer is completed.  I have defined I2CS_I2C_SLAVE_CMPLT_CALLBACK in the header file. You can go through this macro in the component datasheet.  Please go through the attached project and let us know if you are facing the same issue again.

Also, the number of bytes should not be a problem as the size of software buffer is enough to handle as per the maximum size of RAM.

Thanks and Regards,

Aashita

View solution in original post

3 Replies
lock attach
Attachments are accessible only for community members.
Aashita_R
Moderator
Moderator
Moderator
50 likes received 100 solutions authored 250 replies posted

Hi SiYe_3979446​,

I have gone through your attached project. The interrupt issue is being created unnecessarily due to the checking of the condition I2CS_INTR_SLAVE_I2C_WRITE_STOP explicitly. The conditions of FIFO write and read flags being set is taken care by the component ISR itself, therefore you need not check the condition with every slave write complete transfer using the macro.

I have shared my project in which I have included cyapicallbacks.h in the main file and used the I2CS_I2C_SlaveCompleteCallback function to service the interrupt. This callback function is called when slave transfer is completed.  I have defined I2CS_I2C_SLAVE_CMPLT_CALLBACK in the header file. You can go through this macro in the component datasheet.  Please go through the attached project and let us know if you are facing the same issue again.

Also, the number of bytes should not be a problem as the size of software buffer is enough to handle as per the maximum size of RAM.

Thanks and Regards,

Aashita

Thank you AashitaR_11,your solution was very helpful

0 Likes

Hi Aashita,

                    Actually I have  seen your reply late,so I found another solution,by changing custom handler position in the Serial.I2C.INT.c,it was solved,you can see that in below

/***************************************************************************//**

* \file Serial_I2C_INT.c

* \version 4.0

*

* \brief

*  This file provides the source code to the Interrupt Service Routine for

*  the SCB Component in I2C mode.

*

* Note:

*

********************************************************************************

* \copyright

* Copyright 2013-2017, Cypress Semiconductor Corporation.  All rights reserved.

* You may use this file only in accordance with the license, terms, conditions,

* disclaimers, and limitations in the end user license agreement accompanying

* the software package with which this file was provided.

*******************************************************************************/

#include "Serial_PVT.h"

#include "Serial_I2C_PVT.h"

#include "cyapicallbacks.h"

/*******************************************************************************

* Function Name: Serial_I2C_ISR

****************************************************************************//**

*

*  Handles the Interrupt Service Routine for the SCB I2C mode.

*

*******************************************************************************/

CY_ISR(Serial_I2C_ISR)

{

    uint32 diffCount;

    uint32 endTransfer;

#ifdef Serial_I2C_ISR_ENTRY_CALLBACK

    Serial_I2C_ISR_EntryCallback();

#endif /* Serial_I2C_ISR_ENTRY_CALLBACK */

#if (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST)

    uint32 response;

    response = Serial_I2C_ACK_ADDR;

#endif /* (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST) */

    endTransfer = 0u; /* Continue active transfer */

//    /* Calls customer routine if registered */

//    if(NULL != Serial_customIntrHandler)                                  //commenting custom handler,because it is creating issue

//    {                                                                                            //it is invoking before processing data,thats why placing it at the end

//        Serial_customIntrHandler();

//    }

    if(Serial_CHECK_INTR_I2C_EC_MASKED(Serial_INTR_I2C_EC_WAKE_UP))

    {

        /* Mask-off after wakeup */

        Serial_SetI2CExtClkInterruptMode(Serial_NO_INTR_SOURCES);

    }

    /* Master and Slave error tracking:

    * Add the master state check to track only the master errors when the master is active or

    * track slave errors when the slave is active or idle.

    * A special MMS case: in the address phase with misplaced Start: the master sets the LOST_ARB and

    * slave BUS_ERR. The valid event is LOST_ARB comes from the master.

    */

    if(Serial_CHECK_I2C_FSM_MASTER)

    {

        #if(Serial_I2C_MASTER)

        {

            /* INTR_MASTER_I2C_BUS_ERROR:

            * A misplaced Start or Stop condition occurred on the bus: complete the transaction.

            * The interrupt is cleared in I2C_FSM_EXIT_IDLE.

            */

            if(Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_BUS_ERROR))

            {

                Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_ERR_XFER |

                                                         Serial_I2C_MSTAT_ERR_BUS_ERROR);

                endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

            }

            /* INTR_MASTER_I2C_ARB_LOST:

            * The MultiMaster lost arbitrage during transaction.

            * A Misplaced Start or Stop condition is treated as lost arbitration when the master drives the SDA.

            * The interrupt source is cleared in I2C_FSM_EXIT_IDLE.

            */

            if(Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_ARB_LOST))

            {

                Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_ERR_XFER |

                                                         Serial_I2C_MSTAT_ERR_ARB_LOST);

                endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

            }

            #if(Serial_I2C_MULTI_MASTER_SLAVE)

            {

                /* I2C_MASTER_CMD_M_START_ON_IDLE:

                * MultiMaster-Slave does not generate start, because Slave was addressed.

                * Pass control to slave.

                */

                if(Serial_CHECK_I2C_MASTER_CMD(Serial_I2C_MASTER_CMD_M_START_ON_IDLE))

                {

                    Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_ERR_XFER |

                                                             Serial_I2C_MSTAT_ERR_ABORT_XFER);

                    endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                }

            }

            #endif

            /* The error handling common part:

            * Sets a completion flag of the master transaction and passes control to:

            *  - I2C_FSM_EXIT_IDLE - to complete transaction in case of: ARB_LOST or BUS_ERR.

            *  - I2C_FSM_IDLE      - to take chance for the slave to process incoming transaction.

            */

            if(0u != endTransfer)

            {

                /* Set completion flags for master */

                Serial_mstrStatus |= (uint16) Serial_GET_I2C_MSTAT_CMPLT;

                #if(Serial_I2C_MULTI_MASTER_SLAVE)

                {

                    if(Serial_CHECK_I2C_FSM_ADDR)

                    {

                        /* Start generation is set after another master starts accessing Slave.

                        * Clean-up master and turn to slave. Set state to IDLE.

                        */

                        if(Serial_CHECK_I2C_MASTER_CMD(Serial_I2C_MASTER_CMD_M_START_ON_IDLE))

                        {

                            Serial_I2C_MASTER_CLEAR_START;

                            endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER; /* Pass control to Slave */

                        }

                        /* Valid arbitration lost on the address phase happens only when: master LOST_ARB is set and

                        * slave BUS_ERR is cleared. Only in that case set the state to IDLE without SCB IP re-enable.

                        */

                        else if((!Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_BUS_ERROR))

                               && Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_ARB_LOST))

                        {

                            endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER; /* Pass control to Slave */

                        }

                        else

                        {

                            endTransfer = 0u; /* Causes I2C_FSM_EXIT_IDLE to be set below */

                        }

                        if(0u != endTransfer) /* Clean-up master to proceed with slave */

                        {

                            Serial_CLEAR_TX_FIFO; /* Shifter keeps address, clear it */

                            Serial_DISABLE_MASTER_AUTO_DATA_ACK; /* In case of reading disable autoACK */

                            /* Clean-up master interrupt sources */

                            Serial_ClearMasterInterruptSource(Serial_INTR_MASTER_ALL);

                            /* Disable data processing interrupts: they have to be cleared before */

                            Serial_SetRxInterruptMode(Serial_NO_INTR_SOURCES);

                            Serial_SetTxInterruptMode(Serial_NO_INTR_SOURCES);

                            Serial_state = Serial_I2C_FSM_IDLE;

                        }

                        else

                        {

                            /* Set I2C_FSM_EXIT_IDLE for BUS_ERR and ARB_LOST (that is really bus error) */

                            Serial_state = Serial_I2C_FSM_EXIT_IDLE;

                        }

                    }

                    else

                    {

                        /* Set I2C_FSM_EXIT_IDLE if any other state than address */

                        Serial_state = Serial_I2C_FSM_EXIT_IDLE;

                    }

                }

                #else

                {

                    /* In case of LOST*/

                    Serial_state = Serial_I2C_FSM_EXIT_IDLE;

                }

                #endif

            }

        }

        #endif

    }

    else /* (Serial_CHECK_I2C_FSM_SLAVE) */

    {

        #if(Serial_I2C_SLAVE)

        {

            /* INTR_SLAVE_I2C_BUS_ERROR or Serial_INTR_SLAVE_I2C_ARB_LOST:

            * A Misplaced Start or Stop condition occurred on the bus: set a flag

            * to notify an error condition.

            */

            if(Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_BUS_ERROR |

                                                        Serial_INTR_SLAVE_I2C_ARB_LOST))

            {

                if(Serial_CHECK_I2C_FSM_RD)

                {

                    /* TX direction: master reads from slave */

                    Serial_slStatus &= (uint8) ~Serial_I2C_SSTAT_RD_BUSY;

                    Serial_slStatus |= (uint8) (Serial_I2C_SSTAT_RD_ERR |

                                                          Serial_I2C_SSTAT_RD_CMPLT);

                }

                else

                {

                    /* RX direction: master writes into slave */

                    Serial_slStatus &= (uint8) ~Serial_I2C_SSTAT_WR_BUSY;

                    Serial_slStatus |= (uint8) (Serial_I2C_SSTAT_WR_ERR |

                                                          Serial_I2C_SSTAT_WR_CMPLT);

                }

                Serial_state = Serial_I2C_FSM_EXIT_IDLE;

            }

        }

        #endif

    }

    /* States description:

    * Any Master operation starts from: the ADDR_RD/WR state as the master generates traffic on the bus.

    * Any Slave operation starts from: the IDLE state as the slave always waits for actions from the master.

    */

    /* FSM Master */

    if(Serial_CHECK_I2C_FSM_MASTER)

    {

        #if(Serial_I2C_MASTER)

        {

            /* INTR_MASTER_I2C_STOP:

            * A Stop condition was generated by the master: the end of the transaction.

            * Set completion flags to notify the API.

            */

            if(Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_STOP))

            {

                Serial_ClearMasterInterruptSource(Serial_INTR_MASTER_I2C_STOP);

                Serial_mstrStatus |= (uint16) Serial_GET_I2C_MSTAT_CMPLT;

                Serial_state       = Serial_I2C_FSM_IDLE;

            }

            else

            {

                if(Serial_CHECK_I2C_FSM_ADDR) /* Address stage */

                {

                    /* INTR_MASTER_I2C_NACK:

                    * The master sent an address but it was NACKed by the slave. Complete transaction.

                    */

                    if(Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_NACK))

                    {

                        Serial_ClearMasterInterruptSource(Serial_INTR_MASTER_I2C_NACK);

                        Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_ERR_XFER |

                                                                 Serial_I2C_MSTAT_ERR_ADDR_NAK);

                        endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                    }

                    /* INTR_TX_UNDERFLOW. The master sent an address:

                    *  - TX direction: the clock is stretched after the ACK phase, because the TX FIFO is

                    *    EMPTY. The TX EMPTY cleans all the TX interrupt sources.

                    *  - RX direction: the 1st byte is received, but there is no ACK permission,

                    *    the clock is stretched after 1 byte is received.

                    */

                    else

                    {

                        if(Serial_CHECK_I2C_FSM_RD) /* Reading */

                        {

                            Serial_state = Serial_I2C_FSM_MSTR_RD_DATA;

                        }

                        else /* Writing */

                        {

                            Serial_state = Serial_I2C_FSM_MSTR_WR_DATA;

                            if(0u != Serial_mstrWrBufSize)

                            {

                                /* Enable INTR.TX_EMPTY if there is data to transmit */

                                Serial_SetTxInterruptMode(Serial_INTR_TX_EMPTY);

                            }

                        }

                    }

                }

                if(Serial_CHECK_I2C_FSM_DATA) /* Data phase */

                {

                    if(Serial_CHECK_I2C_FSM_RD) /* Reading */

                    {

                        /* INTR_RX_FULL:

                        * RX direction: the master received 8 bytes.

                        * Get data from RX FIFO and decide whether to ACK or  NACK the following bytes.

                        */

                        if(Serial_CHECK_INTR_RX_MASKED(Serial_INTR_RX_FULL))

                        {

                            /* Calculate difference */

                            diffCount =  Serial_mstrRdBufSize -

                                        (Serial_mstrRdBufIndex + Serial_GET_RX_FIFO_ENTRIES);

                            /* Proceed transaction or end it when RX FIFO becomes FULL again */

                            if(diffCount > Serial_I2C_FIFO_SIZE)

                            {

                                diffCount = Serial_I2C_FIFO_SIZE;

                            }

                            else

                            {

                                if(0u == diffCount)

                                {

                                    Serial_DISABLE_MASTER_AUTO_DATA_ACK;

                                    diffCount   = Serial_I2C_FIFO_SIZE;

                                    endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                                }

                            }

                            for(; (0u != diffCount); diffCount--)

                            {

                                Serial_mstrRdBufPtr[Serial_mstrRdBufIndex] = (uint8)

                                                                                        Serial_RX_FIFO_RD_REG;

                                Serial_mstrRdBufIndex++;

                            }

                        }

                        /* INTR_RX_NOT_EMPTY:

                        * RX direction: the master received one data byte, ACK or NACK it.

                        * The last byte is stored and NACKed by the master. The NACK and Stop is

                        * generated by one command generate Stop.

                        */

                        else if(Serial_CHECK_INTR_RX_MASKED(Serial_INTR_RX_NOT_EMPTY))

                        {

                            /* Put data in component buffer */

                            Serial_mstrRdBufPtr[Serial_mstrRdBufIndex] = (uint8) Serial_RX_FIFO_RD_REG;

                            Serial_mstrRdBufIndex++;

                            if(Serial_mstrRdBufIndex < Serial_mstrRdBufSize)

                            {

                                Serial_I2C_MASTER_GENERATE_ACK;

                            }

                            else

                            {

                               endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                            }

                        }

                        else

                        {

                            /* Do nothing */

                        }

                        Serial_ClearRxInterruptSource(Serial_INTR_RX_ALL);

                    }

                    else /* Writing */

                    {

                        /* INTR_MASTER_I2C_NACK :

                        * The master writes data to the slave and NACK was received: not all the bytes were

                        * written to the slave from the TX FIFO. Revert the index if there is data in

                        * the TX FIFO and pass control to a complete transfer.

                        */

                        if(Serial_CHECK_INTR_MASTER_MASKED(Serial_INTR_MASTER_I2C_NACK))

                        {

                            Serial_ClearMasterInterruptSource(Serial_INTR_MASTER_I2C_NACK);

                            /* Rollback write buffer index: NACKed byte remains in shifter */

                            Serial_mstrWrBufIndexTmp -= (Serial_GET_TX_FIFO_ENTRIES +

                                                                   Serial_GET_TX_FIFO_SR_VALID);

                            /* Update number of transferred bytes */

                            Serial_mstrWrBufIndex = Serial_mstrWrBufIndexTmp;

                            Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_ERR_XFER |

                                                                     Serial_I2C_MSTAT_ERR_SHORT_XFER);

                            Serial_CLEAR_TX_FIFO;

                            endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                        }

                        /* INTR_TX_EMPTY :

                        * TX direction: the TX FIFO is EMPTY, the data from the buffer needs to be put there.

                        * When there is no data in the component buffer, the underflow interrupt is

                        * enabled to catch when all the data has been transferred.

                        */

                        else if(Serial_CHECK_INTR_TX_MASKED(Serial_INTR_TX_EMPTY))

                        {

                            while(Serial_I2C_FIFO_SIZE != Serial_GET_TX_FIFO_ENTRIES)

                            {

                                /* The temporary mstrWrBufIndexTmp is used because slave could NACK the byte and index

                                * roll-back required in this case. The mstrWrBufIndex is updated at the end of transfer.

                                */

                                if(Serial_mstrWrBufIndexTmp < Serial_mstrWrBufSize)

                                {

                                #if(!Serial_CY_SCBIP_V0)

                                   /* Clear INTR_TX.UNDERFLOW before putting the last byte into TX FIFO. This ensures

                                    * a proper trigger at the end of transaction when INTR_TX.UNDERFLOW single trigger

                                    * event. Ticket ID# 156735.

                                    */

                                    if(Serial_mstrWrBufIndexTmp == (Serial_mstrWrBufSize - 1u))

                                    {

                                        Serial_ClearTxInterruptSource(Serial_INTR_TX_UNDERFLOW);

                                        Serial_SetTxInterruptMode(Serial_INTR_TX_UNDERFLOW);

                                    }

                                 #endif /* (!Serial_CY_SCBIP_V0) */

                                    /* Put data into TX FIFO */

                                    Serial_TX_FIFO_WR_REG = (uint32) Serial_mstrWrBufPtr[Serial_mstrWrBufIndexTmp];

                                    Serial_mstrWrBufIndexTmp++;

                                }

                                else

                                {

                                    break; /* No more data to put */

                                }

                            }

                        #if(Serial_CY_SCBIP_V0)

                            if(Serial_mstrWrBufIndexTmp == Serial_mstrWrBufSize)

                            {

                                Serial_SetTxInterruptMode(Serial_INTR_TX_UNDERFLOW);

                            }

                            Serial_ClearTxInterruptSource(Serial_INTR_TX_ALL);

                        #else

                            Serial_ClearTxInterruptSource(Serial_INTR_TX_EMPTY);

                        #endif /* (Serial_CY_SCBIP_V0) */

                        }

                        /* INTR_TX_UNDERFLOW:

                        * TX direction: all data from the TX FIFO was transferred to the slave.

                        * The transaction needs to be completed.

                        */

                        else if(Serial_CHECK_INTR_TX_MASKED(Serial_INTR_TX_UNDERFLOW))

                        {

                            /* Update number of transferred bytes */

                            Serial_mstrWrBufIndex = Serial_mstrWrBufIndexTmp;

                            endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                        }

                        else

                        {

                            /* Do nothing */

                        }

                    }

                }

                if(0u != endTransfer) /* Complete transfer */

                {

                    /* Clean-up master after reading: only in case of NACK */

                    Serial_DISABLE_MASTER_AUTO_DATA_ACK;

                    /* Disable data processing interrupts: they have to be cleared before */

                    Serial_SetRxInterruptMode(Serial_NO_INTR_SOURCES);

                    Serial_SetTxInterruptMode(Serial_NO_INTR_SOURCES);

                    if(Serial_CHECK_I2C_MODE_NO_STOP(Serial_mstrControl))

                    {

                        /* On-going transaction is suspended: the ReStart is generated by the API request */

                        Serial_mstrStatus |= (uint16) (Serial_I2C_MSTAT_XFER_HALT |

                                                                 Serial_GET_I2C_MSTAT_CMPLT);

                        Serial_state = Serial_I2C_FSM_MSTR_HALT;

                    }

                    else

                    {

                        /* Complete transaction: exclude the data processing state and generate Stop.

                        * The completion status will be set after Stop generation.

                        * A special case is read: because NACK and Stop are generated by the command below.

                        * Lost arbitration can occur during NACK generation when

                        * the other master is still reading from the slave.

                        */

                        Serial_I2C_MASTER_GENERATE_STOP;

                    }

                }

            }

        } /* (Serial_I2C_MASTER) */

        #endif

    } /* (Serial_CHECK_I2C_FSM_MASTER) */

    /* FSM Slave */

    else if(Serial_CHECK_I2C_FSM_SLAVE)

    {

        #if(Serial_I2C_SLAVE)

        {

            /* INTR_SLAVE_NACK:

            * The master completes reading the slave: the appropriate flags have to be set.

            * The TX FIFO is cleared after an overflow condition is set.

            */

            if(Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_NACK))

            {

                Serial_ClearSlaveInterruptSource(Serial_INTR_SLAVE_I2C_NACK);

                /* All entries that remain in TX FIFO are: FIFO Size + 1 (SHIFTER) */

                diffCount = (Serial_GET_TX_FIFO_ENTRIES + Serial_GET_TX_FIFO_SR_VALID);

                if(Serial_slOverFlowCount > diffCount) /* Overflow */

                {

                    Serial_slStatus |= (uint8) Serial_I2C_SSTAT_RD_OVFL;

                }

                else /* No Overflow */

                {

                    /* Roll-back temporary index */

                    Serial_slRdBufIndexTmp -= (diffCount - Serial_slOverFlowCount);

                }

                /* Update slave of transferred bytes */

                Serial_slRdBufIndex = Serial_slRdBufIndexTmp;

                /* Clean-up TX FIFO */

                Serial_SetTxInterruptMode(Serial_NO_INTR_SOURCES);

                Serial_slOverFlowCount = 0u;

                Serial_CLEAR_TX_FIFO;

                /* Complete master reading */

                Serial_slStatus &= (uint8) ~Serial_I2C_SSTAT_RD_BUSY;

                Serial_slStatus |= (uint8)  Serial_I2C_SSTAT_RD_CMPLT;

                Serial_state     =  Serial_I2C_FSM_IDLE;

              

            #ifdef Serial_I2C_SLAVE_CMPLT_CALLBACK

                /* Read complete */

                Serial_I2C_SlaveCompleteCallback();

            #endif /* Serial_I2C_SLAVE_CMPLT_CALLBACK */

            }

            /* INTR_SLAVE_I2C_WRITE_STOP:

            * The master completes writing to the slave: the appropriate flags have to be set.

            * The RX FIFO contains 1-8 bytes from the previous transaction which needs to be read.

            * There is a possibility that RX FIFO contains an address, it needs to leave it there.

            */

            if(Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_WRITE_STOP))

            {

                Serial_ClearSlaveInterruptSource(Serial_INTR_SLAVE_I2C_WRITE_STOP);

                /* Read bytes from RX FIFO when auto data ACK receive logic is enabled. Otherwise all data bytes

                * were already read from the RX FIFO except for address byte which has to stay here to be handled by

                * I2C_ADDR_MATCH.

                */

                if (0u != (Serial_I2C_CTRL_REG & Serial_I2C_CTRL_S_READY_DATA_ACK))

                {

                    while(0u != Serial_GET_RX_FIFO_ENTRIES)

                    {

                        #if(Serial_CHECK_I2C_ACCEPT_ADDRESS)

                        {

                            if((1u == Serial_GET_RX_FIFO_ENTRIES) &&

                               (Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_ADDR_MATCH)))

                            {

                                break; /* Leave address in RX FIFO */

                            }

                        }

                        #endif

                        /* Put data in component buffer */

                        Serial_slWrBufPtr[Serial_slWrBufIndex] = (uint8) Serial_RX_FIFO_RD_REG;

                        Serial_slWrBufIndex++;

                    }

                    Serial_DISABLE_SLAVE_AUTO_DATA;

                }

                if(Serial_CHECK_INTR_RX(Serial_INTR_RX_OVERFLOW))

                {

                    Serial_slStatus |= (uint8) Serial_I2C_SSTAT_WR_OVFL;

                }

                /* Clears RX interrupt sources triggered on data receiving */

                Serial_SetRxInterruptMode(Serial_NO_INTR_SOURCES);

                Serial_ClearRxInterruptSource(Serial_INTR_RX_ALL);

                /* Complete master writing */

                Serial_slStatus &= (uint8) ~Serial_I2C_SSTAT_WR_BUSY;

                Serial_slStatus |= (uint8)  Serial_I2C_SSTAT_WR_CMPLT;

                Serial_state     =  Serial_I2C_FSM_IDLE;

            #ifdef Serial_I2C_SLAVE_CMPLT_CALLBACK

                /* Write complete */

                Serial_I2C_SlaveCompleteCallback();

            #endif /* Serial_I2C_SLAVE_CMPLT_CALLBACK */

            }

            /* INTR_SLAVE_I2C_ADDR_MATCH or INTR_SLAVE_I2C_GENERAL:

            * The address match or general call address event starts the slave operation:

            * after leaving the TX or RX direction has to be chosen.

            * The wakeup interrupt must be cleared only after an address match is set.

            */

        #if (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST)

            if (Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_ADDR_MATCH |

                                                         Serial_INTR_SLAVE_I2C_GENERAL))

        #else

            if (Serial_CHECK_INTR_SLAVE_MASKED(Serial_INTR_SLAVE_I2C_ADDR_MATCH))

        #endif /* (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST) */

            {

                /* Clear externally clocked address match interrupt source when internally clocked is set */

                Serial_ClearI2CExtClkInterruptSource(Serial_INTR_I2C_EC_WAKE_UP);

                #if (Serial_I2C_CUSTOM_ADDRESS_HANDLER)

                {

                    if (NULL != Serial_customAddressHandler)

                    {

                        /* Call custom address handler */

                        response = Serial_customAddressHandler();

                    }

                    else

                    {

                        /* Read address from the RX FIFO. If there is no address underflow triggers but

                        * component does not use that source. */

                        (void) Serial_RX_FIFO_RD_REG;

                        response = Serial_I2C_ACK_ADDR;

                    }

                    /* Clears RX sources after address was received in the RX FIFO */

                    Serial_ClearRxInterruptSource(Serial_INTR_RX_ALL);

                }

                #endif

            #if (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST)

                if (response == Serial_I2C_NAK_ADDR)

                {

                #if (!Serial_CY_SCBIP_V0)

                    /* Disable write stop interrupt source as it triggers after address was NACKed. Ticket ID#156094 */

                    Serial_DISABLE_INTR_SLAVE(Serial_INTR_SLAVE_I2C_WRITE_STOP);

                #endif /* (!Serial_CY_SCBIP_V0) */

                    /* Clear address match and stop history */

                    Serial_ClearSlaveInterruptSource(Serial_INTR_SLAVE_ALL);

                    /* ACK the address byte */

                    Serial_I2C_SLAVE_GENERATE_NACK;

                }

                else

            #endif /* (Serial_I2C_CUSTOM_ADDRESS_HANDLER_CONST) */

                {

                    if(Serial_CHECK_I2C_STATUS(Serial_I2C_STATUS_S_READ))

                    /* TX direction: master reads from slave */

                    {

                        Serial_SetTxInterruptMode(Serial_INTR_TX_EMPTY);

                        /* Set temporary index to address buffer clear from API */

                        Serial_slRdBufIndexTmp = Serial_slRdBufIndex;

                        /* Start master reading */

                        Serial_slStatus |= (uint8) Serial_I2C_SSTAT_RD_BUSY;

                        Serial_state     = Serial_I2C_FSM_SL_RD;

                    }

                    else

                    /* RX direction: master writes into slave */

                    {

                        /* Calculate available buffer size */

                        diffCount = (Serial_slWrBufSize - Serial_slWrBufIndex);

                    #if (Serial_CY_SCBIP_V0)

                        if(diffCount < Serial_I2C_FIFO_SIZE)

                        /* Receive data: byte-by-byte */

                        {

                            Serial_SetRxInterruptMode(Serial_INTR_RX_NOT_EMPTY);

                        }

                        else

                        /* Receive data: into RX FIFO */

                        {

                            if(diffCount == Serial_I2C_FIFO_SIZE)

                            {

                                /* NACK when RX FIFO become FULL */

                                Serial_ENABLE_SLAVE_AUTO_DATA;

                            }

                            else

                            {

                                /* Stretch clock when RX FIFO becomes FULL */

                                Serial_ENABLE_SLAVE_AUTO_DATA_ACK;

                                Serial_SetRxInterruptMode(Serial_INTR_RX_FULL);

                            }

                        }

                    #else

                        #if(Serial_CHECK_I2C_ACCEPT_ADDRESS)

                        {

                            /* Enable RX.NOT_EMPTY interrupt source to receive byte by byte.

                            * The byte by byte receive is always chosen for the case when an address is accepted

                            * in RX FIFO. Ticket ID#175559.

                            */

                            Serial_SetRxInterruptMode(Serial_INTR_RX_NOT_EMPTY);

                        }

                        #else

                        {

                            if(diffCount < Serial_I2C_FIFO_SIZE)

                            /* Receive data: byte-by-byte */

                            {

                                Serial_SetRxInterruptMode(Serial_INTR_RX_NOT_EMPTY);

                            }

                            else

                            /* Receive data: into RX FIFO */

                            {

                                if(diffCount == Serial_I2C_FIFO_SIZE)

                                {

                                    /* NACK when RX FIFO become FULL */

                                    Serial_ENABLE_SLAVE_AUTO_DATA;

                                }

                                else

                                {

                                    /* Stretch clock when RX FIFO becomes FULL */

                                    Serial_ENABLE_SLAVE_AUTO_DATA_ACK;

                                    Serial_SetRxInterruptMode(Serial_INTR_RX_FULL);

                                }

                            }

                        }

                        #endif

                    #endif /* (Serial_CY_SCBIP_V0) */

                        /* Start master reading */

                        Serial_slStatus |= (uint8) Serial_I2C_SSTAT_WR_BUSY;

                        Serial_state     = Serial_I2C_FSM_SL_WR;

                    }

                    /* Clear address match and stop history */

                    Serial_ClearSlaveInterruptSource(Serial_INTR_SLAVE_ALL);

                #if (!Serial_CY_SCBIP_V0)

                    /* Enable write stop interrupt source as it triggers after address was NACKed. Ticket ID#156094 */

                    Serial_ENABLE_INTR_SLAVE(Serial_INTR_SLAVE_I2C_WRITE_STOP);

                #endif /* (!Serial_CY_SCBIP_V0) */

                    /* ACK the address byte */

                    Serial_I2C_SLAVE_GENERATE_ACK;

                }

            }

            /* Serial_INTR_RX_FULL:

            * Get data from the RX FIFO and decide whether to ACK or NACK the following bytes

            */

            if(Serial_CHECK_INTR_RX_MASKED(Serial_INTR_RX_FULL))

            {

                /* Calculate available buffer size to take into account that RX FIFO is FULL */

                diffCount =  Serial_slWrBufSize -

                            (Serial_slWrBufIndex + Serial_I2C_FIFO_SIZE);

                if(diffCount > Serial_I2C_FIFO_SIZE) /* Proceed transaction */

                {

                    diffCount   = Serial_I2C_FIFO_SIZE;

                    endTransfer = 0u;  /* Continue active transfer */

                }

                else /* End when FIFO becomes FULL again */

                {

                    endTransfer = Serial_I2C_CMPLT_ANY_TRANSFER;

                }

                for(; (0u != diffCount); diffCount--)

                {

                    /* Put data in component buffer */

                    Serial_slWrBufPtr[Serial_slWrBufIndex] = (uint8) Serial_RX_FIFO_RD_REG;

                    Serial_slWrBufIndex++;

                }

                if(0u != endTransfer) /* End transfer sending NACK */

                {

                    Serial_ENABLE_SLAVE_AUTO_DATA_NACK;

                    /* INTR_RX_FULL triggers earlier than INTR_SLAVE_I2C_STOP:

                    * disable all RX interrupt sources.

                    */

                    Serial_SetRxInterruptMode(Serial_NO_INTR_SOURCES);

                }

                Serial_ClearRxInterruptSource(Serial_INTR_RX_FULL);

            }

            /* Serial_INTR_RX_NOT_EMPTY:

            * The buffer size is less than 8: it requires processing in byte-by-byte mode.

            */

            else if(Serial_CHECK_INTR_RX_MASKED(Serial_INTR_RX_NOT_EMPTY))

            {

                diffCount = Serial_RX_FIFO_RD_REG;

                if(Serial_slWrBufIndex < Serial_slWrBufSize)

                {

                    Serial_I2C_SLAVE_GENERATE_ACK;

                    /* Put data into component buffer */

                    Serial_slWrBufPtr[Serial_slWrBufIndex] = (uint8) diffCount;

                    Serial_slWrBufIndex++;

                }

                else /* Overflow: there is no space in write buffer */

                {

                    Serial_I2C_SLAVE_GENERATE_NACK;

                    Serial_slStatus |= (uint8) Serial_I2C_SSTAT_WR_OVFL;

                }

                Serial_ClearRxInterruptSource(Serial_INTR_RX_NOT_EMPTY);

            }

            else

            {

                /* Does nothing */

            }

            /* Serial_INTR_TX_EMPTY:

            * The master reads the slave: provide data to read or 0xFF in the case of the end of the buffer

            * The overflow condition must be captured, but not set until the end of transaction.

            * There is a possibility of a false overflow due to TX FIFO utilization.

            */

            if(Serial_CHECK_INTR_TX_MASKED(Serial_INTR_TX_EMPTY))

            {

                while(Serial_I2C_FIFO_SIZE != Serial_GET_TX_FIFO_ENTRIES)

                {

                    /* Temporary slRdBufIndexTmp is used because the master can NACK the byte and

                    * index roll-back is required in this case. The slRdBufIndex is updated at the end

                    * of the read transfer.

                    */

                    if(Serial_slRdBufIndexTmp < Serial_slRdBufSize)

                    /* Data from buffer */

                    {

                        Serial_TX_FIFO_WR_REG = (uint32) Serial_slRdBufPtr[Serial_slRdBufIndexTmp];

                        Serial_slRdBufIndexTmp++;

                    }

                    else

                    /* Probably Overflow */

                    {

                        Serial_TX_FIFO_WR_REG = Serial_I2C_SLAVE_OVFL_RETURN;

                        if(Serial_slOverFlowCount <= Serial_I2C_TX_OVERFLOW_COUNT)

                        {

                            /* Get counter in range of overflow. */

                            Serial_slOverFlowCount++;

                        }

                    }

                }

                Serial_ClearTxInterruptSource(Serial_INTR_TX_EMPTY);

            }

        }  /* (Serial_I2C_SLAVE) */

        #endif

    }

    /* Calls customer routine if registered */

    if(NULL != Serial_customIntrHandler)

    {

        Serial_customIntrHandler();                                 //Calling custom handler at the end of ISTR to process STOP or read  completion

    }

    /* FSM EXIT:

    * Slave:  INTR_SLAVE_I2C_BUS_ERROR, INTR_SLAVE_I2C_ARB_LOST

    * Master: INTR_MASTER_I2C_BUS_ERROR, INTR_MASTER_I2C_ARB_LOST.

    */

    else

    {

        Serial_I2CFwBlockReset();

      

    #ifdef Serial_I2C_SLAVE_CMPLT_CALLBACK

        #if(Serial_I2C_SLAVE)

        {

            /* Error condition: read or write complete is set */

            Serial_I2C_SlaveCompleteCallback();

        }

        #endif

    #endif /* Serial_I2C_SLAVE_CMPLT_CALLBACK */

    }

#ifdef Serial_I2C_ISR_EXIT_CALLBACK

    Serial_I2C_ISR_ExitCallback();

#endif /* Serial_I2C_ISR_EXIT_CALLBACK */

}

/* [] END OF FILE */

0 Likes