// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Initiates an async read operation void ee_readAHandler(void) { switch(_asyncStep) { // send a start signal case ASYNC_NEXT_START: _asyncStep = ASYNC_NEXT_DEVICE; i2cSendStartAsync(ee_readAHandler); break; // send SLA+R case ASYNC_NEXT_DEVICE: if (i2cGetStatus() != TW_START) { _asyncError(); break; } _asyncStep = ASYNC_NEXT_NACK; i2cSendByteAsync(_device | I2C_READ, ee_readAHandler); break; // setup TWI module to NACK the response case ASYNC_NEXT_NACK: if (i2cGetStatus() != TW_MR_SLA_ACK) { _asyncError(); break; } _asyncStep = ASYNC_NEXT_READ; i2cNackA(ee_readAHandler); break; // capture the received data case ASYNC_NEXT_READ: if (i2cGetStatus() != TW_MR_DATA_NACK) { _asyncError(); break; } // read received data _data = i2cGetReceivedByte(); i2cSendStop(); // mark transaction as complete _eeComplete(_data); // increment the address pointer incrementAddress(); break; } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Maps the selected page to the device & address, and writes the device and address // bytes to the device, leaving it in a state to accept more data. EE_STATUS __writeActiveAddress(uint16_t page) { // map device and address to selected page ee_mapdevice(page); // send start condition i2cSendStart(); i2cWaitForComplete(); // send device address with write i2cSendByte(_device & I2C_WRITE); i2cWaitForComplete(); // check if device is present and live // device did not ACK it's address, // data will not be transferred // return error if (i2cGetStatus() != TW_MT_SLA_ACK) { i2cSendStop(); return I2C_ERROR_NODEV; } // address MSB i2cSendByte(_address >> 8); i2cWaitForComplete(); // address LSB i2cSendByte(_address & 0xFF); i2cWaitForComplete(); return I2C_OK; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ee_poll(void) { /* ACKNOWLEDGE POLLING: Once the internally timed write cycle has started and the EEPROM inputs are disabled, acknowledge polling can be initiated. This involves sending a start condition followed by the device address word. The read/write bit is representative of the operation desired. Only if the internal write cycle has completed will the EEPROM respond with a zero, allowing the read or write sequence to continue. */ while(1) { i2cSendStart(); i2cWaitForComplete(); i2cSendByte(_device & I2C_WRITE); i2cWaitForComplete(); if (i2cGetStatus() == TW_MT_SLA_ACK) { i2cSendStop(); //i2cWaitForComplete(); break; } } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Performs an I2C acknoledge for the EEPROM. If the device is busy, it will NACK bool ee_busy(void) { i2cSendStart(); i2cWaitForComplete(); i2cSendByte(_device & I2C_WRITE); i2cWaitForComplete(); if (i2cGetStatus() == TW_MT_SLA_ACK) { i2cSendStop(); return false; } return true; }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Performs an asynchronous page read void ee_readBytesHandler(void) { // setting the current page in the device requires setting up the // device for a 'write' operation, but aborting the write before // sending any data to the chip. a re-start is initiated with the // device which starts the sequential read switch (_asyncStep) { // send start signal case ASYNC_MULTI_START: _asyncStep = ASYNC_MULTI_DEVICE; i2cSendStartAsync(ee_readBytesHandler); break; // send device address with write case ASYNC_MULTI_DEVICE: if (i2cGetStatus() != TW_START) { _asyncError(); break; } _asyncStep = ASYNC_MULTI_ADDRMSB; i2cSendByteAsync(_device & I2C_WRITE, ee_readBytesHandler); break; // send address MSB case ASYNC_MULTI_ADDRMSB: if (i2cGetStatus() != TW_MT_SLA_ACK) { _asyncError(); break; } _asyncStep = ASYNC_MULTI_ADDRLSB; i2cSendByteAsync(_address >> 8, ee_readBytesHandler); break; // send address LSB case ASYNC_MULTI_ADDRLSB: if (i2cGetStatus() != TW_MT_DATA_ACK) { _asyncError(); break; } _asyncStep = ASYNC_MULTI_READ; i2cSendByteAsync(_address & 0xff, ee_readBytesHandler); break; // prepare appropriate reply for recceived byte(s) case ASYNC_MULTI_READ: _asyncStep = ASYNC_MULTI_NEXT; if (_bufferLen) i2cAckA(ee_readBytesHandler); else i2cNackA(ee_readBytesHandler); break; // get the byte and case ASYNC_MULTI_NEXT: if (_bufferLen > 0) { _bufferLen--; *_pbuffer++ = i2cGetReceivedByte(); _asyncStep = ASYNC_MULTI_READ; // increment the address pointer incrementAddress(); } else _asyncStep = ASYNC_MULTI_STOP; break; // end the transaction case ASYNC_MULTI_STOP: if (i2cGetStatus() != TW_MT_DATA_ACK) { _asyncError(); break; } i2cSendStop(); _eeComplete(0); break; } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ee_setPageAHandler(void) { // setting the current page in the device requires setting up the // device for a 'write' operation, but aborting the write before // sending any data to the chip. a re-start is initiated with the // device which starts the sequential read switch (_asyncStep) { // send start signal case ASYNC_SEND_START: _asyncStep = ASYNC_SEND_DEVICE; i2cSendStartAsync(&ee_setPageAHandler); return; // send device address with write case ASYNC_SEND_DEVICE: if (i2cGetStatus() != TW_START) { _asyncError(); return; } _asyncStep = ASYNC_SEND_ADDRMSB; i2cSendByteAsync(_device & I2C_WRITE, &ee_setPageAHandler); return; // send address MSB case ASYNC_SEND_ADDRMSB: if (i2cGetStatus() != TW_MT_SLA_ACK) { _asyncError(); return; } _asyncStep = ASYNC_SEND_ADDRLSB; i2cSendByteAsync(_address >> 8, &ee_setPageAHandler); return; // send address LSB case ASYNC_SEND_ADDRLSB: if (i2cGetStatus() != TW_MT_DATA_ACK) { _asyncError(); return; } _asyncStep = ASYNC_SEND_STOP; i2cSendByteAsync(_address & 0xff, &ee_setPageAHandler); return; // end the transaction case ASYNC_SEND_STOP: if (i2cGetStatus() != TW_MT_DATA_ACK) { _asyncError(); return; } i2cSendStop(); _eeComplete(0); return; } }
// ************ EDP Master operations ************ u08 edpSendCommand(u08 deviceAddr, u08 cmdLength, EdpCommand* edpCommand) { EdpReply* edpCommandReply = (EdpReply*)EdpCommandReplyBuffer; u08* sendData; u08* replyData; u08 replyLength; u08 checksum; // initialize response variables edpCommandReply->Length = 0; EdpCommandReplyChecksum = 0; #ifdef EDP_DEBUG rprintf("\r\nBegin EdpSendCommand, TWSR:0x%x\r\n",inb(TWSR)); #endif // disable TWI interrupt cbi(TWCR, TWIE); // clear TWI interface //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)); // send start condition i2cSendStart(); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Start, TWSR:0x%x\r\n",inb(TWSR)); #endif // send device address with write i2cSendByte( (deviceAddr&0xFE) ); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Device Address+Write, TWSR:0x%x\r\n",inb(TWSR)); #endif // check if device is present and live if( i2cGetStatus() != TW_MT_SLA_ACK) { // device did not ACK it's address, command will not continue // transmit stop condition // leave with TWEA on for slave receiving i2cSendStop(); while( !(inb(TWCR) & BV(TWSTO)) ); #ifdef EDP_DEBUG rprintf("No Device!, Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); #endif // enable TWI interrupt sbi(TWCR, TWIE); // return error return EDP_COMMAND_NODEV; } // send data sendData = (u08*)edpCommand; checksum = 0; while(cmdLength) { i2cSendByte( *sendData ); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Data, TWSR:0x%x\r\n",inb(TWSR)); #endif checksum += *sendData++; cmdLength--; } // send the checksum i2cSendByte( ~checksum ); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Checksum, TWSR:0x%x\r\n",inb(TWSR)); #endif // send repeated start condition i2cSendStart(); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Repeated Start, TWSR:0x%x\r\n",inb(TWSR)); #endif // send device address with read i2cSendByte( deviceAddr|0x01 ); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Sent Device Address+Read, TWSR:0x%x\r\n",inb(TWSR)); #endif // read response code, return NACK i2cReceiveByte(FALSE); i2cWaitForComplete(); #ifdef EDP_DEBUG rprintf("Read Data, TWSR:0x%x\r\n",inb(TWSR)); #endif EdpCommandResponseCode = i2cGetReceivedByte(); if(EdpCommandResponseCode==EDP_RESP_DATA_REPLY) { // a data reply is being sent // send repeated start condition i2cSendStart(); i2cWaitForComplete(); // send device address with read i2cSendByte( deviceAddr|0x01 ); i2cWaitForComplete(); // get length, return ACK i2cReceiveByte(TRUE); i2cWaitForComplete(); edpCommandReply->Length = i2cGetReceivedByte(); // set temp variables replyLength = edpCommandReply->Length; replyData = edpCommandReply->Data; // get data, return ACKs // preset checksum with the datalength byte checksum = replyLength; while(replyLength > 1) { i2cReceiveByte(TRUE); // receive data byte and return ACK i2cWaitForComplete(); *replyData = i2cGetReceivedByte(); checksum += *replyData++; replyLength--; } // get last data (actually the checksum), return NACK (last-byte signal) i2cReceiveByte(FALSE); i2cWaitForComplete(); *replyData = i2cGetReceivedByte(); // add received checksum+1 to our checksum, the result should be zero checksum += (*replyData) + 1; // save the reply checksum EdpCommandReplyChecksum = checksum; } // transmit stop condition // leave with TWEA on for slave receiving i2cSendStop(); while( !(inb(TWCR) & BV(TWSTO)) ); #ifdef EDP_DEBUG rprintf("Sent Stop, TWSR:0x%x\r\n",inb(TWSR)); #endif // enable TWI interrupt sbi(TWCR, TWIE); return EDP_COMMAND_OK; }
bool TwoWire::busy(void){ return ((i2cGetStatus(i2c) & 16 )==16); }