/** * End the transmission and transmit the tx buffer's contents over the bus * it returns false if succesful */ bool DWire::endTransmission( bool sendStop ) { // return, if there is nothing to transmit if (!*pTxBufferIndex) { return true; } // Wait until any ongoing (incoming) transmissions are finished timeout = 0xFFFF; while ( MAP_I2C_masterIsStopSent( module ) == EUSCI_B_I2C_SENDING_STOP && timeout) timeout--; if (!timeout) { /* If we can't start the transmission, then reset everything */ _resetBus( ); return true; } this->sendStop = sendStop; gotNAK = false; // Clear the interrupt flags and enable MAP_I2C_clearInterruptFlag( module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT ); MAP_I2C_enableInterrupt( module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + EUSCI_B_I2C_NAK_INTERRUPT ); // Set the master into transmit mode MAP_I2C_setMode( module, EUSCI_B_I2C_TRANSMIT_MODE ); // Send the start condition and initial byte (*pTxBufferSize) = *pTxBufferIndex; // Send the first byte, triggering the TX interrupt MAP_I2C_masterSendMultiByteStartWithTimeout( module, pTxBuffer[0], TIMEOUTLIMIT ); // make sure the transmitter buffer has been flushed timeout = TIMEOUTLIMIT; while (*pTxBufferIndex && timeout) timeout--; if (!timeout) { _resetBus( ); return true; } if (gotNAK) { _I2CDelay( ); MAP_I2C_masterReceiveMultiByteStop( module ); } return gotNAK; }
/** * Request data from a SLAVE as a MASTER */ uint8_t DWire::requestFrom(uint_fast8_t slaveAddress, uint_fast8_t numBytes) { // No point of doing anything else if there we're not a MASTER if (busRole != BUS_ROLE_MASTER) return 0; if (*pTxBufferIndex > 0) { endTransmission(false); } while (!sendStop) ; // Re-initialise the rx buffer *pRxBufferSize = numBytes; *pRxBufferIndex = 0; // Configure the correct slave MAP_I2C_setSlaveAddress(module, slaveAddress); this->slaveAddress = slaveAddress; MAP_I2C_disableInterrupt(module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); // Set the master into receive mode MAP_I2C_setMode(module, EUSCI_B_I2C_RECEIVE_MODE); // Send the START MAP_I2C_masterReceiveStart(module); // Send a stop early if we're only requesting one byte // to prevent timing issues if (numBytes == 1) { MAP_I2C_masterReceiveMultiByteStop(module); } // Initialize the flag showing the status of the request requestDone = false; gotNAK = false; // Wait until the request is done while (!requestDone) ; MAP_I2C_setMode(module, EUSCI_B_I2C_TRANSMIT_MODE); MAP_I2C_enableInterrupt(module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); MAP_I2C_clearInterruptFlag(module, EUSCI_B_I2C_TRANSMIT_INTERRUPT0); // Reset the buffer (*pRxBufferIndex) = 0; (*pRxBufferSize) = 0; if (gotNAK) { return 0; } else { return rxReadLength; } }
void EUSCIB3_IRQHandler(void) { // Send a STOP if we're done in request mode // This is done here as triggering the interrupt takes too long if ( MAP_I2C_getInterruptStatus(EUSCI_B3_BASE, EUSCI_B_I2C_RECEIVE_INTERRUPT0) && (EUSCIB3_rxBufferIndex == EUSCIB3_rxBufferSize - 1) && EUSCIB3_rxBufferIndex != 0) { MAP_I2C_masterReceiveMultiByteStop(EUSCI_B3_BASE); } IRQParam param; param.module = EUSCI_B3_BASE; param.rxBuffer = EUSCIB3_rxBuffer; param.rxBufferIndex = &EUSCIB3_rxBufferIndex; param.rxBufferSize = &EUSCIB3_rxBufferSize; param.txBuffer = EUSCIB3_txBuffer; param.txBufferIndex = &EUSCIB3_txBufferIndex; param.txBufferSize = &EUSCIB3_txBufferSize; IRQHandler(param); }
/** * Request data from a SLAVE as a MASTER */ uint8_t DWire::requestFrom( uint_fast8_t slaveAddress, uint_fast8_t numBytes ) { // No point of doing anything else if there we're not a MASTER if (busRole != BUS_ROLE_MASTER) return 0; // still something to send? Flush the TX buffer but do not send a STOP if (*pTxBufferIndex > 0) { // this is a repeated start: no point in trying to receive if we fail finishing the transmission if (endTransmission( false )) { return 0; } } else { // Wait until any request is finished timeout = TIMEOUTLIMIT; while ( MAP_I2C_masterIsStopSent( module ) == EUSCI_B_I2C_SENDING_STOP && timeout) timeout--; } if (!timeout) { /* If we get a timeout, then reset everything */ _resetBus( ); return 0; } // Re-initialise the rx buffer // and make sure we never request 1 byte only // this is an anomalous behaviour of the MSP432 related to the double // buffering of I2C. This is a workaround. if (numBytes == 1) { *pRxBufferSize = 2; } else { *pRxBufferSize = numBytes; } *pRxBufferIndex = 0; // Configure the correct slave MAP_I2C_setSlaveAddress( module, slaveAddress ); this->slaveAddress = slaveAddress; MAP_I2C_clearInterruptFlag( module, EUSCI_B_I2C_RECEIVE_INTERRUPT0 | EUSCI_B_I2C_NAK_INTERRUPT ); MAP_I2C_enableInterrupt( module, EUSCI_B_I2C_RECEIVE_INTERRUPT0 | EUSCI_B_I2C_NAK_INTERRUPT ); // Set the master into receive mode MAP_I2C_setMode( module, EUSCI_B_I2C_RECEIVE_MODE ); // Initialize the flag showing the status of the request requestDone = false; gotNAK = false; // Send the START MAP_I2C_masterReceiveStart( module ); // Wait until the request is done timeout = TIMEOUTLIMIT; while (!requestDone && timeout) timeout--; if (!timeout) { /* If we get a timeout, then reset everything */ _resetBus( ); return 0; } if (gotNAK) { _I2CDelay( ); MAP_I2C_masterReceiveMultiByteStop( module ); return 0; } else { if (numBytes == 1) { return --(*pRxBufferSize); } else { return *pRxBufferSize; } } }