/******************************************************************************* * Function Name: I2C_I2CResposeInsert ****************************************************************************//** * * Releases the read buffer to be read when a response is copied to the buffer * and a new read transaction starts. * Closes the read buffer when write transaction is started. * * \globalvars * I2C_applyBuffer - the flag to release the buffer with a response * to be read by the host. * *******************************************************************************/ static void I2C_I2CResposeInsert(void) { if (I2C_CHECK_INTR_SLAVE_MASKED(I2C_INTR_SLAVE_I2C_ADDR_MATCH)) { if (I2C_CHECK_I2C_STATUS(I2C_I2C_STATUS_S_READ)) { /* Address phase, host reads: release read buffer */ if (0u != I2C_applyBuffer) { I2C_slRdBufSize = I2C_applyBuffer; I2C_slRdBufIndex = 0u; I2C_applyBuffer = 0u; } } else { /* Address phase, host writes: close read buffer */ if (I2C_slRdBufIndex != I2C_slRdBufSize) { I2C_slRdBufIndex = I2C_slRdBufSize; } } } }
/******************************************************************************* * Function Name: I2C_I2CReStartGeneration ******************************************************************************** * * Summary: * Generates a ReStart condition: * SCB IP V1 and later: Generates ReStart using the scb IP functionality * Sets the I2C_MASTER_CMD_M_START and I2C_MASTER_CMD_M_NACK (if the previous * transaction was read) bits in the SCB.I2C_MASTER_CMD register. * This combination forces the master to generate ReStart. * * SCB IP V0: Generates Restart using the GPIO and scb IP functionality. * After the master completes write or read, the SCL is stretched. * The master waits until SDA line is released by the slave. Then the GPIO * function is enabled and the scb IP disabled as it already does not drive * the bus. In case of the previous transfer was read, the NACK is generated * by the GPIO. The delay of tLOW is added to manage the hold time. * Set I2C_M_CMD.START and enable the scb IP. The ReStart generation * is started after the I2C function is enabled for the SCL. * Note1: the scb IP due re-enable generates Start but on the I2C bus it * appears as ReStart. * Note2: the I2C_M_CMD.START is queued if scb IP is disabled. * Note3: the I2C_STATUS_M_READ is cleared is address was NACKed before. * * Parameters: * None * * Return: * None * * Side Effects: * SCB IP V0: The NACK generation by the GPIO may cause a greater SCL period * than expected for the selected master data rate. * *******************************************************************************/ void I2C_I2CReStartGeneration(void) { #if(I2C_CY_SCBIP_V0) /* Generates Restart use GPIO and scb IP functionality. Ticket ID#143715, ID#145238 and ID#173656 */ uint32 status = I2C_I2C_STATUS_REG; while(I2C_WAIT_SDA_SET_HIGH) { /* Wait when slave release SDA line: SCL tHIGH is complete */ } /* Prepare DR register to drive SCL line */ I2C_SET_I2C_SCL_DR(I2C_I2C_SCL_LOW); /* Switch HSIOM to GPIO: SCL goes low */ I2C_SET_I2C_SCL_HSIOM_SEL(I2C_HSIOM_GPIO_SEL); /* Disable SCB block */ I2C_CTRL_REG &= (uint32) ~I2C_CTRL_ENABLED; if(0u != (status & I2C_I2C_STATUS_M_READ)) { /* Generate NACK use GPIO functionality */ I2C_SET_I2C_SCL_DR(I2C_I2C_SCL_LOW); CyDelayUs(I2C_I2C_TLOW_TIME); /* Count tLOW */ I2C_SET_I2C_SCL_DR(I2C_I2C_SCL_HIGH); while(I2C_WAIT_SCL_SET_HIGH) { /* Wait until slave releases SCL in case if it stretches */ } CyDelayUs(I2C_I2C_THIGH_TIME); /* Count tHIGH */ } /* Count tLOW as hold time for write and read */ I2C_SET_I2C_SCL_DR(I2C_I2C_SCL_LOW); CyDelayUs(I2C_I2C_TLOW_TIME); /* Count tLOW */ /* Set command for Start generation: it will appear */ I2C_I2C_MASTER_CMD_REG = I2C_I2C_MASTER_CMD_M_START; /* Enable SCB block */ I2C_CTRL_REG |= (uint32) I2C_CTRL_ENABLED; /* Switch HSIOM to I2C: */ I2C_SET_I2C_SCL_HSIOM_SEL(I2C_HSIOM_I2C_SEL); /* Revert SCL DR register */ I2C_SET_I2C_SCL_DR(I2C_I2C_SCL_HIGH); #else uint32 cmd; /* Generates ReStart use scb IP functionality */ cmd = I2C_I2C_MASTER_CMD_M_START; cmd |= I2C_CHECK_I2C_STATUS(I2C_I2C_STATUS_M_READ) ? (I2C_I2C_MASTER_CMD_M_NACK) : (0u); I2C_I2C_MASTER_CMD_REG = cmd; #endif /* (I2C_CY_SCBIP_V1) */ }
/******************************************************************************* * Function Name: I2C_I2CMasterWriteBuf ******************************************************************************** * * Summary: * Automatically writes an entire buffer of data to a slave device. * Once the data transfer is initiated by this function, further data transfer * is handled by the included ISR. * Enables the I2C interrupt and clears SCB_ I2C_MSTAT_WR_CMPLT status. * * Parameters: * slaveAddr: 7-bit slave address. * xferData: Pointer to buffer of data to be sent. * cnt: Size of buffer to send. * mode: Transfer mode defines: start or restart condition generation at * begin of the transfer and complete the transfer or halt before * generating a stop. * * Return: * Error status. * * Global variables: * I2C_mstrStatus - used to store current status of I2C Master. * I2C_state - used to store current state of software FSM. * I2C_mstrControl - used to control master end of transaction with * or without the Stop generation. * I2C_mstrWrBufPtr - used to store pointer to master write buffer. * I2C_mstrWrBufIndex - used to current index within master write * buffer. * I2C_mstrWrBufSize - used to store master write buffer size. * *******************************************************************************/ uint32 I2C_I2CMasterWriteBuf(uint32 slaveAddress, uint8 * wrData, uint32 cnt, uint32 mode) { uint32 errStatus; errStatus = I2C_I2C_MSTR_NOT_READY; if(NULL != wrData) /* Check buffer pointer */ { /* Check FSM state and bus before generating Start/ReStart condition */ if(I2C_CHECK_I2C_FSM_IDLE) { I2C_DisableInt(); /* Lock from interruption */ /* Check bus state */ errStatus = I2C_CHECK_I2C_STATUS(I2C_I2C_STATUS_BUS_BUSY) ? I2C_I2C_MSTR_BUS_BUSY : I2C_I2C_MSTR_NO_ERROR; } else if(I2C_CHECK_I2C_FSM_HALT) { I2C_mstrStatus &= (uint16) ~I2C_I2C_MSTAT_XFER_HALT; errStatus = I2C_I2C_MSTR_NO_ERROR; } else { /* Unexpected FSM state: exit */ } } /* Check if master is ready to start */ if(I2C_I2C_MSTR_NO_ERROR == errStatus) /* No error proceed */ { #if (!I2C_CY_SCBIP_V0 && \ I2C_I2C_MULTI_MASTER_SLAVE_CONST && I2C_I2C_WAKE_ENABLE_CONST) I2C_I2CMasterDisableEcAm(); #endif /* (!I2C_CY_SCBIP_V0) */ /* Set up write transaction */ I2C_state = I2C_I2C_FSM_MSTR_WR_ADDR; I2C_mstrWrBufIndexTmp = 0u; I2C_mstrWrBufIndex = 0u; I2C_mstrWrBufSize = cnt; I2C_mstrWrBufPtr = (volatile uint8 *) wrData; I2C_mstrControl = (uint8) mode; slaveAddress = I2C_GET_I2C_8BIT_ADDRESS(slaveAddress); I2C_mstrStatus &= (uint16) ~I2C_I2C_MSTAT_WR_CMPLT; I2C_ClearMasterInterruptSource(I2C_INTR_MASTER_ALL); I2C_ClearTxInterruptSource(I2C_INTR_TX_UNDERFLOW); /* The TX and RX FIFO have to be EMPTY */ /* Enable interrupt source to catch when address is sent */ I2C_SetTxInterruptMode(I2C_INTR_TX_UNDERFLOW); /* Generate Start or ReStart */ if(I2C_CHECK_I2C_MODE_RESTART(mode)) { I2C_I2C_MASTER_GENERATE_RESTART; I2C_TX_FIFO_WR_REG = slaveAddress; } else { I2C_TX_FIFO_WR_REG = slaveAddress; I2C_I2C_MASTER_GENERATE_START; } } I2C_EnableInt(); /* Release lock */ return(errStatus); }
/******************************************************************************* * Function Name: I2C_I2CMasterSendStart ******************************************************************************** * * Summary: * Generates Start condition and sends slave address with read/write bit. * Disables the I2C interrupt. * This function is blocking and does not return until start condition and * address byte are sent and ACK/NACK response is received or errors occurred. * * Parameters: * slaveAddress: Right justified 7-bit Slave address (valid range 8 to 120). * bitRnW: Direction of the following transfer. It is defined by * read/write bit within address byte. * * Return: * Error status. * * Global variables: * I2C_state - used to store current state of software FSM. * *******************************************************************************/ uint32 I2C_I2CMasterSendStart(uint32 slaveAddress, uint32 bitRnW) { uint32 resetIp; uint32 errStatus; resetIp = 0u; errStatus = I2C_I2C_MSTR_NOT_READY; /* Check FSM state before generating Start condition */ if(I2C_CHECK_I2C_FSM_IDLE) { /* If bus is free, generate Start condition */ if(I2C_CHECK_I2C_STATUS(I2C_I2C_STATUS_BUS_BUSY)) { errStatus = I2C_I2C_MSTR_BUS_BUSY; } else { I2C_DisableInt(); /* Lock from interruption */ #if (!I2C_CY_SCBIP_V0 && \ I2C_I2C_MULTI_MASTER_SLAVE_CONST && I2C_I2C_WAKE_ENABLE_CONST) I2C_I2CMasterDisableEcAm(); #endif /* (!I2C_CY_SCBIP_V0) */ slaveAddress = I2C_GET_I2C_8BIT_ADDRESS(slaveAddress); if(0u == bitRnW) /* Write direction */ { I2C_state = I2C_I2C_FSM_MSTR_WR_DATA; } else /* Read direction */ { I2C_state = I2C_I2C_FSM_MSTR_RD_DATA; slaveAddress |= I2C_I2C_READ_FLAG; } /* TX and RX FIFO have to be EMPTY */ I2C_TX_FIFO_WR_REG = slaveAddress; /* Put address in TX FIFO */ I2C_ClearMasterInterruptSource(I2C_INTR_MASTER_ALL); I2C_I2C_MASTER_GENERATE_START; while(!I2C_CHECK_INTR_MASTER(I2C_INTR_MASTER_I2C_ACK | I2C_INTR_MASTER_I2C_NACK | I2C_INTR_MASTER_I2C_ARB_LOST | I2C_INTR_MASTER_I2C_BUS_ERROR)) { /* * Write: wait until address has been transferred * Read : wait until address has been transferred, data byte is going to RX FIFO as well. */ } /* Check the results of the address phase */ if(I2C_CHECK_INTR_MASTER(I2C_INTR_MASTER_I2C_ACK)) { errStatus = I2C_I2C_MSTR_NO_ERROR; } else if(I2C_CHECK_INTR_MASTER(I2C_INTR_MASTER_I2C_NACK)) { errStatus = I2C_I2C_MSTR_ERR_LB_NAK; } else if(I2C_CHECK_INTR_MASTER(I2C_INTR_MASTER_I2C_ARB_LOST)) { I2C_state = I2C_I2C_FSM_IDLE; errStatus = I2C_I2C_MSTR_ERR_ARB_LOST; resetIp = I2C_I2C_RESET_ERROR; } else /* I2C_INTR_MASTER_I2C_BUS_ERROR set is else condition */ { I2C_state = I2C_I2C_FSM_IDLE; errStatus = I2C_I2C_MSTR_ERR_BUS_ERR; resetIp = I2C_I2C_RESET_ERROR; } I2C_ClearMasterInterruptSource(I2C_INTR_MASTER_I2C_ACK | I2C_INTR_MASTER_I2C_NACK | I2C_INTR_MASTER_I2C_ARB_LOST | I2C_INTR_MASTER_I2C_BUS_ERROR); /* Reset block in case of: LOST_ARB or BUS_ERR */ if(0u != resetIp) { I2C_SCB_SW_RESET; } } } return(errStatus); }
/******************************************************************************* * Function Name: I2C_I2CMasterReadBuf ******************************************************************************** * * Summary: * Automatically reads an entire buffer of data from a slave device. * Once the data transfer is initiated by this function, further data transfer * is handled by the included ISR. * Enables the I2C interrupt and clears SCB_ I2C_MSTAT_RD_CMPLT status. * * Parameters: * slaveAddr: 7-bit slave address. * xferData: Pointer to buffer where to put data from slave. * cnt: Size of buffer to read. * mode: Transfer mode defines: start or restart condition generation at * begin of the transfer and complete the transfer or halt before * generating a stop. * * Return: * Error status. * * Global variables: * I2C_mstrStatus - used to store current status of I2C Master. * I2C_state - used to store current state of software FSM. * I2C_mstrControl - used to control master end of transaction with * or without the Stop generation. * I2C_mstrRdBufPtr - used to store pointer to master write buffer. * I2C_mstrRdBufIndex - used to current index within master write * buffer. * I2C_mstrRdBufSize - used to store master write buffer size. * *******************************************************************************/ uint32 I2C_I2CMasterReadBuf(uint32 slaveAddress, uint8 * rdData, uint32 cnt, uint32 mode) { uint32 errStatus; errStatus = I2C_I2C_MSTR_NOT_READY; if(NULL != rdData) { /* Check FSM state and bus before generating Start/ReStart condition */ if(I2C_CHECK_I2C_FSM_IDLE) { I2C_DisableInt(); /* Lock from interruption */ /* Check bus state */ errStatus = I2C_CHECK_I2C_STATUS(I2C_I2C_STATUS_BUS_BUSY) ? I2C_I2C_MSTR_BUS_BUSY : I2C_I2C_MSTR_NO_ERROR; } else if(I2C_CHECK_I2C_FSM_HALT) { I2C_mstrStatus &= (uint16) ~I2C_I2C_MSTAT_XFER_HALT; errStatus = I2C_I2C_MSTR_NO_ERROR; } else { /* Unexpected FSM state: exit */ } } /* Check master ready to proceed */ if(I2C_I2C_MSTR_NO_ERROR == errStatus) /* No error proceed */ { #if (!I2C_CY_SCBIP_V0 && \ I2C_I2C_MULTI_MASTER_SLAVE_CONST && I2C_I2C_WAKE_ENABLE_CONST) I2C_I2CMasterDisableEcAm(); #endif /* (!I2C_CY_SCBIP_V0) */ /* Set up read transaction */ I2C_state = I2C_I2C_FSM_MSTR_RD_ADDR; I2C_mstrRdBufIndex = 0u; I2C_mstrRdBufSize = cnt; I2C_mstrRdBufPtr = (volatile uint8 *) rdData; I2C_mstrControl = (uint8) mode; slaveAddress = (I2C_GET_I2C_8BIT_ADDRESS(slaveAddress) | I2C_I2C_READ_FLAG); I2C_mstrStatus &= (uint16) ~I2C_I2C_MSTAT_RD_CMPLT; I2C_ClearMasterInterruptSource(I2C_INTR_MASTER_ALL); /* TX and RX FIFO have to be EMPTY */ /* Prepare reading */ if(I2C_mstrRdBufSize < I2C_I2C_FIFO_SIZE) { /* Reading byte-by-byte */ I2C_SetRxInterruptMode(I2C_INTR_RX_NOT_EMPTY); } else { /* Receive RX FIFO chunks */ I2C_ENABLE_MASTER_AUTO_DATA_ACK; I2C_SetRxInterruptMode(I2C_INTR_RX_FULL); } /* Generate Start or ReStart */ if(I2C_CHECK_I2C_MODE_RESTART(mode)) { I2C_I2C_MASTER_GENERATE_RESTART; I2C_TX_FIFO_WR_REG = (slaveAddress); } else { I2C_TX_FIFO_WR_REG = (slaveAddress); I2C_I2C_MASTER_GENERATE_START; } } I2C_EnableInt(); /* Release lock */ return(errStatus); }