/*FUNCTION********************************************************************** * * Function Name : I2C_DRV_SlaveSendData * Description : Send the data using a non-blocking method. * This function set buffer pointer and length to Tx buffer & Tx Size * A non-blocking (also known as synchronous) function means that the function * returns immediately after initiating the receive function. The application * has to get the receive status to see when the receive is complete. * *END**************************************************************************/ i2c_status_t I2C_DRV_SlaveSendData(uint32_t instance, const uint8_t * txBuff, uint32_t txSize) { assert(txBuff); assert(instance < HW_I2C_INSTANCE_COUNT); i2c_slave_state_t * i2cSlaveState = (i2c_slave_state_t *)g_i2cStatePtr[instance]; if(!i2cSlaveState->slaveListening) { if (i2cSlaveState->isTxBusy) { return kStatus_I2C_Busy; } /* Initialize the module driver state structure. */ i2cSlaveState->txBuff = txBuff; i2cSlaveState->txSize = txSize; i2cSlaveState->isTxBusy = true; #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT I2C_HAL_ClearStartFlag(g_i2cBaseAddr[instance]); #endif I2C_HAL_ClearInt(g_i2cBaseAddr[instance]); I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], true); return kStatus_I2C_Success; } else /* i2cSlaveState->slaveListening */ { return kStatus_I2C_Fail; } }
/*FUNCTION********************************************************************** * * Function Name : I2C_HAL_SlaveSendDataPolling * Description : Send out multiple bytes of data using polling method. * *END*/ i2c_status_t I2C_HAL_SlaveSendDataPolling(I2C_Type * base, const uint8_t* txBuff, uint32_t txSize) { #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT /** Wait until start detected */ while(!I2C_HAL_GetStartFlag(base)) {} I2C_HAL_ClearStartFlag(base); #endif /** Wait until addressed as a slave */ while(!I2C_HAL_GetStatusFlag(base, kI2CAddressAsSlave)) {} /** Wait interrupt flag is set */ while(!I2C_HAL_IsIntPending(base)) {} /** Clear interrupt flag */ I2C_HAL_ClearInt(base); /** Set direction mode */ if (I2C_HAL_GetStatusFlag(base, kI2CSlaveTransmit)) { /** Switch to TX mode*/ I2C_HAL_SetDirMode(base, kI2CSend); } else { /** Switch to RX mode.*/ I2C_HAL_SetDirMode(base, kI2CReceive); /** Read dummy character.*/ I2C_HAL_ReadByte(base); } /** While loop to transmit data */ while(txSize--) { /** Write byte to data register */ I2C_HAL_WriteByte(base, *txBuff++); /** Wait tranfer byte complete */ while(!I2C_HAL_IsIntPending(base)) {} /** Clear interrupt flag */ I2C_HAL_ClearInt(base); /** if NACK received */ if ((I2C_HAL_GetStatusFlag(base, kI2CReceivedNak)) && (txSize != 0)) { return kStatus_I2C_ReceivedNak; } } /** Switch to RX mode.*/ I2C_HAL_SetDirMode(base, kI2CReceive); /** Read dummy character.*/ I2C_HAL_ReadByte(base); return kStatus_I2C_Success; }
/*FUNCTION********************************************************************** * * Function Name : I2C_DRV_SlaveSendDataBlocking * Description : Send the data using a blocking method. * This function set buffer pointer and length to Tx buffer & Tx Size. * Then wait until the transmission is end ( NAK is detected) * *END**************************************************************************/ i2c_status_t I2C_DRV_SlaveSendDataBlocking(uint32_t instance, const uint8_t * txBuff, uint32_t txSize, uint32_t timeout_ms) { assert(txBuff); assert(instance < HW_I2C_INSTANCE_COUNT); i2c_slave_state_t * i2cSlaveState = (i2c_slave_state_t *)g_i2cStatePtr[instance]; if(!i2cSlaveState->slaveListening) { event_flags_t i2cIrqSetFlags; osa_status_t syncStatus; if (i2cSlaveState->isTxBusy) { return kStatus_I2C_Busy; } /* Initialize the module driver state structure. */ i2cSlaveState->txBuff = txBuff; i2cSlaveState->txSize = txSize; i2cSlaveState->isTxBusy = true; i2cSlaveState->isTxBlocking = true; #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT I2C_HAL_ClearStartFlag(g_i2cBaseAddr[instance]); #endif I2C_HAL_ClearInt(g_i2cBaseAddr[instance]); I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], true); /* Wait until the transmit is complete. */ do { syncStatus = OSA_EventWait(&i2cSlaveState->irqEvent, kI2CSlaveTxNAK | kI2CSlaveAbort, false, timeout_ms, &i2cIrqSetFlags); } while(syncStatus == kStatus_OSA_Idle); if (syncStatus != kStatus_OSA_Success) { I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], false); i2cSlaveState->status = kStatus_I2C_Timeout; } i2cSlaveState->isTxBlocking = false; return i2cSlaveState->status; } else /* i2cSlaveState->slaveListening */ { return kStatus_I2C_Fail; } }
/*FUNCTION********************************************************************** * * Function Name : I2C_HAL_SlaveReceiveDataPolling * Description : Receive multiple bytes of data using polling method. * *END*/ i2c_status_t I2C_HAL_SlaveReceiveDataPolling(I2C_Type * base, uint8_t *rxBuff, uint32_t rxSize) { #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT /** Wait until start detected */ while(!I2C_HAL_GetStartFlag(base)) {} I2C_HAL_ClearStartFlag(base); #endif /** Wait until addressed as a slave */ while(!I2C_HAL_GetStatusFlag(base, kI2CAddressAsSlave)) {} /** Wait interrupt flag is set */ while(!I2C_HAL_IsIntPending(base)) {} /** Clear interrupt flag */ I2C_HAL_ClearInt(base); /** Set direction mode */ if (I2C_HAL_GetStatusFlag(base, kI2CSlaveTransmit)) { /** Switch to TX mode*/ I2C_HAL_SetDirMode(base, kI2CSend); } else { /** Switch to RX mode.*/ I2C_HAL_SetDirMode(base, kI2CReceive); /** Read dummy character.*/ I2C_HAL_ReadByte(base); } /** While loop to receive data */ while(rxSize--) { /** Wait interrupt flag is set */ while(!I2C_HAL_IsIntPending(base)) {} /** Read byte from data register */ *rxBuff++ = I2C_HAL_ReadByte(base); /** Clear interrupt flag */ I2C_HAL_ClearInt(base); } return kStatus_I2C_Success; }
/*FUNCTION********************************************************************** * * Function Name : I2C_DRV_SlaveReceiveData * Description : Receive the data using a non-blocking method. * This function set buffer pointer and length to Rx buffer & Rx Size * A non-blocking (also known as synchronous) function means that the function * returns immediately after initiating the receive function. The application * has to get the receive status to see when the receive is complete. * *END**************************************************************************/ i2c_status_t I2C_DRV_SlaveReceiveData(uint32_t instance, uint8_t * rxBuff, uint32_t rxSize) { assert(rxBuff); assert(instance < HW_I2C_INSTANCE_COUNT); i2c_slave_state_t * i2cSlaveState = (i2c_slave_state_t *)g_i2cStatePtr[instance]; if(!i2cSlaveState->slaveListening) { if (i2cSlaveState->isRxBusy) { return kStatus_I2C_Busy; } i2cSlaveState->rxBuff = rxBuff; i2cSlaveState->rxSize = rxSize; i2cSlaveState->isRxBusy = true; /* If IAAS event already comes, read dummy to release the bus.*/ if(I2C_HAL_GetStatusFlag(g_i2cBaseAddr[instance], kI2CAddressAsSlave)) { /* Switch to RX mode.*/ I2C_HAL_SetDirMode(g_i2cBaseAddr[instance], kI2CReceive); I2C_HAL_ReadByte(g_i2cBaseAddr[instance]); } #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT I2C_HAL_ClearStartFlag(g_i2cBaseAddr[instance]); #endif I2C_HAL_ClearInt(g_i2cBaseAddr[instance]); I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], true); return kStatus_I2C_Success; } else /* i2cSlaveState->slaveListening */ { return kStatus_I2C_Fail; } }
/*FUNCTION********************************************************************** * * Function Name : I2C_DRV_SlaveIRQHandler * Description : I2C Slave Generic ISR. * ISR action be called inside I2C IRQ handler entry. * *END*/ void I2C_DRV_SlaveIRQHandler(uint32_t instance) { assert(instance < I2C_INSTANCE_COUNT); I2C_Type * base = g_i2cBase[instance]; uint8_t i2cData = 0x00; bool doTransmit = false; bool wasArbLost = I2C_HAL_GetStatusFlag(base, kI2CArbitrationLost); bool addressed = I2C_HAL_GetStatusFlag(base, kI2CAddressAsSlave); bool stopIntEnabled = false; #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT bool startDetected = I2C_HAL_GetStartFlag(base); bool startIntEnabled = I2C_HAL_GetStartStopIntCmd(base); bool stopDetected = I2C_HAL_GetStopFlag(base); stopIntEnabled = startIntEnabled; #endif #if FSL_FEATURE_I2C_HAS_STOP_DETECT bool stopDetected = I2C_HAL_GetStopFlag(base); stopIntEnabled = I2C_HAL_GetStopIntCmd(base); #endif /** Get current runtime structure */ i2c_slave_state_t * i2cSlaveState = (i2c_slave_state_t *)g_i2cStatePtr[instance]; /** Get current slave transfer direction */ i2c_direction_t direction = I2C_HAL_GetDirMode(base); #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT /*--------------- Handle START ------------------*/ if (startIntEnabled && startDetected) { I2C_HAL_ClearStartFlag(base); I2C_HAL_ClearInt(base); if(i2cSlaveState->slaveCallback != NULL) { /*Call callback to handle when the driver detect START signal*/ i2cSlaveState->slaveCallback(instance, kI2CSlaveStartDetect, i2cSlaveState->callbackParam); } return; } #endif #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT || FSL_FEATURE_I2C_HAS_STOP_DETECT /*--------------- Handle STOP ------------------*/ if (stopIntEnabled && stopDetected) { I2C_HAL_ClearStopFlag(base); I2C_HAL_ClearInt(base); if(!i2cSlaveState->slaveListening) { /** Disable I2C interrupt in the peripheral.*/ I2C_HAL_SetIntCmd(base, false); } if(i2cSlaveState->slaveCallback != NULL) { /*Call callback to handle when the driver detect STOP signal*/ i2cSlaveState->slaveCallback(instance, kI2CSlaveStopDetect, i2cSlaveState->callbackParam); } if (i2cSlaveState->isRxBlocking) { OSA_EventSet(&i2cSlaveState->irqEvent, kI2CSlaveStopDetect); } i2cSlaveState->status = kStatus_I2C_Idle; return; } #endif /** Clear I2C IRQ.*/ I2C_HAL_ClearInt(base); if (wasArbLost) { I2C_HAL_ClearArbitrationLost(base); if (!addressed) { i2cSlaveState->status = kStatus_I2C_AribtrationLost; if(!i2cSlaveState->slaveListening) { /** Disable I2C interrupt in the peripheral.*/ I2C_HAL_SetIntCmd(base, false); } return; } } /*--------------- Handle Address ------------------*/ /** Addressed only happens when receiving address. */ if (addressed) /** Slave is addressed. */ { /** Master read from Slave. Slave transmit.*/ if (I2C_HAL_GetStatusFlag(base, kI2CSlaveTransmit)) { /** Switch to TX mode*/ I2C_HAL_SetDirMode(base, kI2CSend); if(i2cSlaveState->slaveCallback != NULL) { /*Call callback to handle when the driver get read request*/ i2cSlaveState->slaveCallback(instance, kI2CSlaveTxReq, i2cSlaveState->callbackParam); } doTransmit = true; } else /** Master write to Slave. Slave receive.*/ { /** Switch to RX mode.*/ I2C_HAL_SetDirMode(base, kI2CReceive); if(i2cSlaveState->slaveCallback != NULL) { /*Call callback to handle when the driver get write request*/ i2cSlaveState->slaveCallback(instance, kI2CSlaveRxReq, i2cSlaveState->callbackParam); } /** Read dummy character.*/ I2C_HAL_ReadByte(base); } } /*--------------- Handle Transfer ------------------*/ else { /** Handle transmit */ if (direction == kI2CSend) { if (I2C_HAL_GetStatusFlag(base, kI2CReceivedNak)) { /** Switch to RX mode.*/ I2C_HAL_SetDirMode(base, kI2CReceive); /** Read dummy character to release bus */ I2C_HAL_ReadByte(base); if ((!i2cSlaveState->slaveListening) && (!stopIntEnabled)) { /** Disable I2C interrupt in the peripheral.*/ I2C_HAL_SetIntCmd(base, false); } if(i2cSlaveState->slaveCallback != NULL) { /** Receive TX NAK, mean transaction is finished, call callback to handle */ i2cSlaveState->slaveCallback(instance, kI2CSlaveTxNAK, i2cSlaveState->callbackParam); } if (i2cSlaveState->isTxBlocking) { OSA_EventSet(&i2cSlaveState->irqEvent, kI2CSlaveTxNAK); } i2cSlaveState->txSize = 0; i2cSlaveState->txBuff = NULL; i2cSlaveState->isTxBusy = false; } else /** ACK from receiver.*/ { doTransmit = true; } } /** Handle receive */ else { /** Get byte from data register */ i2cData = I2C_HAL_ReadByte(base); if (i2cSlaveState->rxSize) { *(i2cSlaveState->rxBuff) = i2cData; ++ i2cSlaveState->rxBuff; -- i2cSlaveState->rxSize; if (!i2cSlaveState->rxSize) { if (!stopIntEnabled) { if(!i2cSlaveState->slaveListening) { /** Disable I2C interrupt in the peripheral.*/ I2C_HAL_SetIntCmd(base, false); } /** All bytes are received, so we're done with this transfer */ if (i2cSlaveState->isRxBlocking) { OSA_EventSet(&i2cSlaveState->irqEvent, kI2CSlaveRxFull); } } i2cSlaveState->isRxBusy = false; i2cSlaveState->rxBuff = NULL; if(i2cSlaveState->slaveCallback != NULL) { /** Rx buffer is full, call callback to handle */ i2cSlaveState->slaveCallback(instance, kI2CSlaveRxFull, i2cSlaveState->callbackParam); } } } else { /** The Rxbuff is full --> Set kStatus_I2C_SlaveRxOverrun*/ i2cSlaveState->status = kStatus_I2C_SlaveRxOverrun; } } } /** DO TRANSMIT*/ if (doTransmit) { /** Send byte to data register */ if (i2cSlaveState->txSize) { i2cData = *(i2cSlaveState->txBuff); I2C_HAL_WriteByte(base, i2cData); ++ i2cSlaveState->txBuff; -- i2cSlaveState->txSize; if (!i2cSlaveState->txSize) { /** All bytes are received, so we're done with this transfer */ i2cSlaveState->txBuff = NULL; i2cSlaveState->isTxBusy = false; if(i2cSlaveState->slaveCallback != NULL) { /** Tx buffer is empty, finish transaction, call callback to handle */ i2cSlaveState->slaveCallback(instance, kI2CSlaveTxEmpty, i2cSlaveState->callbackParam); } } } else { /** The Txbuff is empty --> set kStatus_I2C_SlaveTxUnderrun*/ i2cSlaveState->status = kStatus_I2C_SlaveTxUnderrun ; } } }
void TwoWire::onService(void) { //interrupt handler uint8_t i2cData = 0x00; bool wasArbLost = I2C_HAL_GetStatusFlag(instance, kI2CArbitrationLost); bool addressed = I2C_HAL_GetStatusFlag(instance, kI2CAddressAsSlave); bool stopIntEnabled = false; bool startDetected = I2C_HAL_GetStartFlag(instance); bool startIntEnabled = I2C_HAL_GetStartStopIntCmd(instance); bool stopDetected = I2C_HAL_GetStopFlag(instance); stopIntEnabled = startIntEnabled; /* Get current slave transfer direction */ i2c_direction_t direction = I2C_HAL_GetDirMode(instance); /*--------------- Handle START, STOP or REPEAT START ------------------*/ if (stopIntEnabled && (startDetected || stopDetected)) { if(startDetected) I2C_HAL_ClearStartFlag(instance); if(stopDetected) I2C_HAL_ClearStopFlag(instance); I2C_HAL_ClearInt(instance); if(slaveBufferLength) { if(onReceiveCallback) { receiving_slave = true; onReceiveCallback(slaveBufferLength); receiving_slave = false; } slaveBufferIndex = 0; slaveBufferLength = 0; } return; } /* Clear I2C IRQ.*/ I2C_HAL_ClearInt(instance); if (wasArbLost) { I2C_HAL_ClearArbitrationLost(instance); if (!addressed) { master_state = MASTER_STATE_ARB_LOST; return; } } if(I2C_HAL_IsMaster(instance)) { if (direction == kI2CSend) { //check for NAK /* Check whether we got an ACK or NAK from the former byte we sent */ if (I2C_HAL_GetStatusFlag(instance, kI2CReceivedNak)) { master_state = MASTER_STATE_TX_NAK; } else if(transmitting_master) { /* Continue send if still have data. TxSize/txBuff index need * increment first because one byte is already sent in order * to trigger interrupt */ if (txBufferIndex < txBufferLength) { /* Transmit next byte and update buffer index */ I2C_HAL_WriteByte(instance, txBuffer[txBufferIndex++]); } else { /* Finish send data, send STOP, disable interrupt */ master_state = MASTER_STATE_COMPLETE; } } else { master_state = MASTER_STATE_READ_READY; //address sent for a read } } else { switch (--rxBufferQuantity) { case 0x0U: /* Finish receive data, send STOP, disable interrupt */ master_state = MASTER_STATE_COMPLETE; if(master_send_stop) I2C_HAL_SendStop(instance); else I2C_HAL_SendStart(instance); break; case 0x1U: /* For the byte before last, we need to set NAK */ I2C_HAL_SendNak(instance); break; default : I2C_HAL_SendAck(instance); break; } rxBuffer[rxBufferLength++] = I2C_HAL_ReadByte(instance); } return; } /*--------------- Handle Address ------------------*/ /* Addressed only happens when receiving address. */ if (addressed) /* Slave is addressed. */ { /* Master read from Slave. Slave transmit.*/ if (I2C_HAL_GetStatusFlag(instance, kI2CSlaveTransmit)) { /* Switch to TX mode*/ I2C_HAL_SetDirMode(instance, kI2CSend); transmitting_slave = true; slaveBufferIndex = 0; slaveBufferLength = 0; if (onRequestCallback) onRequestCallback(); //this needs to load the transmit buffer else // create a default 1-byte response write((uint8_t) 0); } else /* Master write to Slave. Slave receive.*/ { /* Switch to RX mode.*/ I2C_HAL_SetDirMode(instance, kI2CReceive); I2C_HAL_SendAck(instance); /* Read dummy character.*/ I2C_HAL_ReadByte(instance); slaveBufferIndex = 0; slaveBufferLength = 0; } } /*--------------- Handle Transfer ------------------*/ else { /* Handle transmit */ if (direction == kI2CSend) { if (I2C_HAL_GetStatusFlag(instance, kI2CReceivedNak)) { /* Switch to RX mode.*/ I2C_HAL_SetDirMode(instance, kI2CReceive); /* Read dummy character to release bus */ I2C_HAL_ReadByte(instance); transmitting_slave = false; slaveBufferIndex = 0; slaveBufferLength = 0; } else /* ACK from receiver.*/ { transmitting_slave = true; } } /* Handle receive */ else { /* Get byte from data register */ I2C_HAL_SendAck(instance); i2cData = I2C_HAL_ReadByte(instance); if(slaveBufferLength < BUFFER_LENGTH) slaveBuffer[slaveBufferLength++] = i2cData; } } if (transmitting_slave) { /* Send byte to data register */ if (slaveBufferIndex < slaveBufferLength) { I2C_HAL_WriteByte(instance, slaveBuffer[slaveBufferIndex++]); if (slaveBufferIndex >= slaveBufferLength) { slaveBufferIndex = 0; slaveBufferLength = 0; transmitting_slave = false; } } else transmitting_slave = false; } }
/*FUNCTION********************************************************************** * * Function Name : I2C_DRV_SlaveReceiveDataBlocking * Description : Receive the data using a blocking method. * This function set buffer pointer and length to Rx buffer &Rx Size. Then wait * until the transmission is end (all data are received or STOP signal is * detected) * *END**************************************************************************/ i2c_status_t I2C_DRV_SlaveReceiveDataBlocking(uint32_t instance, uint8_t * rxBuff, uint32_t rxSize, uint32_t timeout_ms) { assert(rxBuff); assert(instance < HW_I2C_INSTANCE_COUNT); i2c_slave_state_t * i2cSlaveState = (i2c_slave_state_t *)g_i2cStatePtr[instance]; if(!i2cSlaveState->slaveListening) { event_flags_t i2cIrqSetFlags; osa_status_t syncStatus; if (i2cSlaveState->isRxBusy) { return kStatus_I2C_Busy; } i2cSlaveState->rxBuff = rxBuff; i2cSlaveState->rxSize = rxSize; i2cSlaveState->isRxBusy = true; i2cSlaveState->isRxBlocking = true; /* If IAAS event already comes, read dummy to release the bus.*/ if(I2C_HAL_GetStatusFlag(g_i2cBaseAddr[instance], kI2CAddressAsSlave)) { /* Switch to RX mode.*/ I2C_HAL_SetDirMode(g_i2cBaseAddr[instance], kI2CReceive); I2C_HAL_ReadByte(g_i2cBaseAddr[instance]); } #if FSL_FEATURE_I2C_HAS_START_STOP_DETECT I2C_HAL_ClearStartFlag(g_i2cBaseAddr[instance]); #endif I2C_HAL_ClearInt(g_i2cBaseAddr[instance]); I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], true); /* Wait until the transmit is complete. */ do { syncStatus = OSA_EventWait(&i2cSlaveState->irqEvent, #if (FSL_FEATURE_I2C_HAS_START_STOP_DETECT || FSL_FEATURE_I2C_HAS_STOP_DETECT) kI2CSlaveStopDetect | #endif kI2CSlaveRxFull | kI2CSlaveAbort, false, timeout_ms, &i2cIrqSetFlags); } while(syncStatus == kStatus_OSA_Idle); if (syncStatus != kStatus_OSA_Success) { I2C_HAL_SetIntCmd(g_i2cBaseAddr[instance], false); i2cSlaveState->status = kStatus_I2C_Timeout; } i2cSlaveState->isRxBlocking = false; return i2cSlaveState->status; } else /* i2cSlaveState->slaveListening */ { return kStatus_I2C_Fail; } }