// // Originally, 'endTransmission' was an f(void) function. // It has been modified to take one parameter indicating // whether or not a STOP should be performed on the bus. // Calling endTransmission(false) allows a sketch to // perform a repeated start. // // WARNING: Nothing in the library keeps track of whether // the bus tenure has been properly ended with a STOP. It // is very possible to leave the bus in a hung state if // no call to endTransmission(true) is made. Some I2C // devices will behave oddly if they do not see a STOP. // uint8_t TwoWire::endTransmission(uint8_t sendStop) { /* Set direction to send for sending of address and data. */ uint8_t result = (uint8_t)getWriteError(); if(result != 0) { // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; // indicate that we are done transmitting transmitting_master = false; return 1; } uint32_t t0 = millis(); while(I2C_HAL_GetStatusFlag(instance, kI2CBusBusy) && !I2C_HAL_IsMaster(instance)) { if(millis() - t0 >= 25) return 4; //timeout } uint16_t slaveAddress; slaveAddress = (txAddress << 1U) & 0x00FFU; bool sent = sendAddress(slaveAddress); //tx buffer also sent by interrupt // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; // indicate that we are done transmitting transmitting_master = false; clearWriteError(); result = 4; if(sent) //sent without timeout { if(master_state == MASTER_STATE_COMPLETE) { result = 0; } else if(master_state == MASTER_STATE_TX_NAK) //failed { result = (txBufferIndex == 0) ? 2 : 3; //address or data fail sendStop = true; } if(sendStop) { I2C_HAL_SendStop(instance); } } I2C_HAL_SetDirMode(instance, kI2CReceive); return result; }
int i2c_stop(i2c_t *obj) { volatile uint32_t n = 0; uint32_t i2c_addrs[] = I2C_BASE_ADDRS; if (I2C_HAL_IsMaster(i2c_addrs[obj->instance])) I2C_HAL_SendStop(i2c_addrs[obj->instance]); // It seems that there are timing problems // when there is no waiting time after a STOP. // This wait is also included on the samples // code provided with the freedom board for (n = 0; n < 200; n++) __NOP(); return 0; }
/*! * @brief Pass IRQ control to either the master or slave driver. * * The address of the IRQ handlers are checked to make sure they are non-zero before * they are called. If the IRQ handler's address is zero, it means that driver was * not present in the link (because the IRQ handlers are marked as weak). This would * actually be a program error, because it means the master/slave config for the IRQ * was set incorrectly. * * @param instance Instance number of the I2C module. */ void I2C_DRV_IRQHandler(uint32_t instance) { assert(instance < I2C_INSTANCE_COUNT); I2C_Type * base = g_i2cBase[instance]; if (I2C_HAL_IsMaster(base)) { /** Master mode.*/ I2C_DRV_MasterIRQHandler(instance); } else { /** Slave mode.*/ I2C_DRV_SlaveIRQHandler(instance); } }
/*! * @brief Pass IRQ control to either the master or slave driver. * * The address of the IRQ handlers are checked to make sure they are non-zero before * they are called. If the IRQ handler's address is zero, it means that driver was * not present in the link (because the IRQ handlers are marked as weak). This would * actually be a program error, because it means the master/slave config for the IRQ * was set incorrectly. * * @param instance Instance number of the I2C module. */ void I2C_DRV_IRQHandler(uint32_t instance) { assert(instance < I2C_INSTANCE_COUNT); I2C_Type * base = g_i2cBase[instance]; if(I2C_HAL_GetStatusFlag(base, kI2CArbitrationLost)) { /* Master mode.*/ I2C_DRV_MasterIRQHandler(instance); } else { if (I2C_HAL_IsMaster(base)) { /* Master mode.*/ I2C_DRV_MasterIRQHandler(instance); } else { /* Slave mode.*/ I2C_DRV_SlaveIRQHandler(instance); } } }
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; } }
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { if(quantity == 0) return 0; uint32_t t0 = millis(); while(I2C_HAL_GetStatusFlag(instance, kI2CBusBusy) && !I2C_HAL_IsMaster(instance)) { if(millis() - t0 >= 25) return 4; //timeout } if(quantity > BUFFER_LENGTH){ quantity = BUFFER_LENGTH; } rxBufferQuantity = quantity; rxBufferIndex = 0; rxBufferLength = 0; uint16_t slaveAddr = (address << 1U) | 1; if(!sendAddress(slaveAddr) || master_state != MASTER_STATE_READ_READY) { I2C_HAL_SendStop(instance); I2C_HAL_SetDirMode(instance, kI2CReceive); return 0; } master_send_stop = sendStop; master_state = MASTER_STATE_IDLE; I2C_HAL_SetDirMode(instance, kI2CReceive); /* Send NAK if only one byte to read. */ if (rxBufferQuantity == 0x1U) { I2C_HAL_SendNak(instance); } else { I2C_HAL_SendAck(instance); } I2C_HAL_ReadByte(instance); t0 = millis(); while(master_state == MASTER_STATE_IDLE) { if(millis() - t0 >= 25) { rxBufferIndex = 0; rxBufferLength = 0; I2C_HAL_SendStop(instance); I2C_HAL_SetDirMode(instance, kI2CReceive); return 0; //timeout } } if(master_state == MASTER_STATE_COMPLETE) { rxBufferIndex = 0; return rxBufferLength; } else { rxBufferIndex = 0; rxBufferLength = 0; rxBufferQuantity = 0; I2C_HAL_SendStop(instance); I2C_HAL_SetDirMode(instance, kI2CReceive); return 0; //timeout } }