Решил поисследовать i2c на предмет работы с длинными проводами. С проводами длиннее 10 м, если я не ошибаюсь, TWI не работает по спецификации. Поэтому эксперименты проводились с кабелем RC10 длиной 10м, Master-Atmega128, Slave-Atmega48. Результаты получились весьма странными. С подтягивающими резисторами на slave плате и на Master плате предельной частотой работы оказалось значение 571 Khz, , без резисторов на slave плате 276Khz. Но в обоих случаях при использовании пограничных значений частот передача либо начиналась и проходила без ошибок, либо ошибки сыпались бесконечно. У меня такое ощущения что что-то криво в коде, я прав? Код для работы с i2c на мастере:
void i2cInit(void) { // set pull-up resistors on I2C bus pins sbi(PORTD, 0); // i2c SCL on ATmega128,64 !!!!!!!!!!!!!!!!!!!!! sbi(PORTD, 1); // i2c SDA on ATmega128,64 !!!!!!!!!!!!!!!!!!!!!
// clear SlaveReceive and SlaveTransmit handler to null i2cSlaveReceive = 0; i2cSlaveTransmit = 0; // set i2c bit rate to 100KHz i2cSetBitrate(276); // enable TWI (two-wire interface) sbi(TWCR, TWEN); }
void i2cSetBitrate(u16 bitrateKHz) { u08 bitrate_div; // calculate bitrate division bitrate_div = ((F_CPU/1000l)/bitrateKHz); if(bitrate_div >= 16) bitrate_div = (bitrate_div-16)/2; outb(TWBR, bitrate_div); }
void i2cSetLocalDeviceAddr(u08 deviceAddr, u08 genCallEn) { // set local device address (used in slave mode only) outb(TWAR, ((deviceAddr&0xFE) | (genCallEn?1:0)) ); } inline void i2cSendStart(void) { // send start condition outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWSTA)); }
inline void i2cSendStop(void) { // transmit stop condition // leave with TWEA on for slave receiving outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)|BV(TWSTO)); }
inline void i2cWaitForComplete(void) { // wait for i2c interface to complete operation while( !(inb(TWCR) & BV(TWINT)) ){if(wait>2000){wait=0;return;}else{wait++;}} }
inline void i2cSendByte(u08 data) { // save data to the TWDR outb(TWDR, data); // begin send outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)); }
inline void i2cReceiveByte(u08 ackFlag) { // begin receive over i2c if( ackFlag ) { // ackFlag = TRUE: ACK the recevied data outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)|BV(TWEA)); } else { // ackFlag = FALSE: NACK the recevied data outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK)|BV(TWINT)); } }
inline u08 i2cGetReceivedByte(void) { // retieve received data byte from i2c TWDR return( inb(TWDR) ); }
inline u08 i2cGetStatus(void) { // retieve current i2c status from i2c TWSR return( inb(TWSR) ); }u08 i2cMasterSendNI(u08 deviceAddr, u08 length, u08* data) { u08 retval = I2C_OK;
// send start condition i2cSendStart(); i2cWaitForComplete();
// send device address with write i2cSendByte( deviceAddr & 0xFE ); i2cWaitForComplete();
// check if device is present and live if( inb(TWSR) == TW_MT_SLA_ACK) { // send data while(length) { i2cSendByte( *data++ ); i2cWaitForComplete(); length--; } } else { // device did not ACK it's address, // data will not be transferred // return error retval = I2C_ERROR_NODEV; }
// transmit stop condition // leave with TWEA on for slave receiving i2cSendStop(); i2cWaitForComplete();
return retval; }
u08 i2cMasterReceiveNI(u08 deviceAddr, u08 length, u08 *data) { u08 retval = I2C_OK;
// send start condition i2cSendStart(); i2cWaitForComplete();
// send device address with read i2cSendByte( deviceAddr | 0x01 ); i2cWaitForComplete();
// check if device is present and live if( inb(TWSR) == TW_MR_SLA_ACK) { // accept receive data and ack it while(length > 1) { i2cReceiveByte(TRUE); i2cWaitForComplete(); *data++ = i2cGetReceivedByte(); // decrement length length--; }
// accept receive data and nack it (last-byte signal) i2cReceiveByte(FALSE); i2cWaitForComplete(); *data++ = i2cGetReceivedByte(); } else { // device did not ACK it's address, // data will not be transferred // return error retval = I2C_ERROR_NODEV; }
// transmit stop condition // leave with TWEA on for slave receiving i2cSendStop(); i2cWaitForComplete(); return retval; }
резисторы 5.1 КОм.
|