Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Странности i2c
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
the_spirit
Решил поисследовать 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 КОм.
stells
Цитата(the_spirit @ Jul 21 2012, 18:06) *
У меня такое ощущения что что-то криво в коде, я прав?
...
резисторы 5.1 КОм.

код смотреть неинтересно, интересно в первую очередь посмотреть осциллограммы сигналов, фронты
-SANYCH-
Цитата
Но в обоих случаях при использовании пограничных значений частот передача либо начиналась и проходила без ошибок, либо ошибки сыпались бесконечно.


Исходя из вашего ответа, у Вас проблема в длинном кабеле, а не в коде. Проверяется это легко: соедините устройство сначала без кабеля (коротким проводом) и протестируйте, а потом с кабелем и тоже протестируйте на ошибки. Если с кабелем будут ошибки, а без кабеля нет, значит, ваша программа работает нормально.
the_spirit
Да не, с коротким кабелем все работает, и даже с длинным на стандартной частоте. Меня беспокоит то, что при повышении частоты устройство перестает работать внезапно. У меня в программе считаются доставленные и не доставленные посылки, и при переходе в 1 khz, например от 571 к 572 посылки перестают доставляться совсем, и нет ситуации при которой доходила бы например половина или одна треть от всех отправленных посылок.

Осциллограммы можно устроить, но это не раньше понедельника. В принципе для разных частот картинка не отличается, тоесть фронты сильно завалены но приблизительно одинаково что для 570 khz что для 571.
stells
Цитата(the_spirit @ Jul 22 2012, 18:28) *
Да не, с коротким кабелем все работает, и даже с длинным на стандартной частоте.

так а для чего Вы блох ловите, если работает? начиная с определенной частоты строб чтения бита приходит в тот момент, когда уровень сигнала не достиг порогового уровня из-за завала фронта
_Артём_
Цитата(the_spirit @ Jul 22 2012, 17:28) *
и при переходе в 1 khz, например от 571 к 572 посылки перестают доставляться совсем, и нет ситуации при которой доходила бы например половина или одна треть от всех отправленных посылок.

Разве максимальная частота не 400 кГц?
На 571 кГц TWI вообще не обязано работать. Да ещё и на 10 м.
the_spirit
Ну было интересно посмотреть до какой частоты можно разогнать интерфейс. На 10 м. обязана работать, поскольку требования по предельной емкости шины соблюдены.

Ну в том то и проблема, что на предельной частоте, иногда передача срабатывает, и, если срабатывает, то Master и Slave могут обмениваться сообщениями довольно продолжительное время.Мне этот процесс не понятен, и это меня напрягает.
stells
Цитата(the_spirit @ Jul 22 2012, 19:14) *
Ну было интересно посмотреть до какой частоты можно разогнать интерфейс.

снижайте сопротивления резисторов до минимально возможного значения (с точки зрения нагрузочной способности портов), может и мегагерц вытянете

Цитата(the_spirit @ Jul 22 2012, 19:14) *
Мне этот процесс не понятен

а чтобы процесс понять, нужно смотреть осциллограммы
the_spirit
Ок, спасибо, попробуем. Осциллограммы постараюсь к понедельнику сделать, если успею разобраться как осцил к компу подключается, раньше не было необходимости)
Ruslan1
Цитата(the_spirit @ Jul 22 2012, 17:28) *
Меня беспокоит то, что при повышении частоты устройство перестает работать внезапно. У меня в программе считаются доставленные и не доставленные посылки, и при переходе в 1 khz, например от 571 к 572 посылки перестают доставляться совсем, и нет ситуации при которой доходила бы например половина или одна треть от всех отправленных посылок.

Внутри шага в один килогерц есть еще много мааааленьких шажочков. Если бы Вы двигались не на килогерц, а , например на герц или на микрогерц, то наверняка бы смогли зафиксировать любой процент ошибок от 0 до 100% с любым нужным Вам разрешением (скажем, 17.097% ошибок на частоте 570192.55 Гц). Также Вы можете построить функцию зависимости количества ошибок на такой пограничной частоте от излучения солнца или скорости ветра в лаборатории. Только зачем все это?

P.S. Есть такой экспресс-тест линии связи- подать меандр (скажем, 1КГц) и снять осциллограмму. На основании исследования фронтов со стороны приемника можно прогнозировать, что через этот провод можно прокачать без ошибок, что с ошибками, а что вообще не пролезет. Это- аргументированно и обосновано. То что делаете Вы- метод ненаучного тыка. У Вас на столе сегодня результат такой, завтра у соседа что-то другое получится.
the_spirit
Да, спасибо за разъяснение. По шине SCL фактически и передается меандр, осциллограммы смотрел с нее со стороны приемника , фронты завалены, работе это не мешает. Про более мелкий шаг думал, вопрос собственно был в том, почему на пограничной частоте интерфейс то работает то нет, и не связанно ли это с ошибкой в коде.
ILYAUL
Вы библиотеки откуда брали?
the_spirit
Из AVR Libc пришлось чуть чуть поменять чтобы заработала под IAR и не зависала.
ILYAUL
Тогда код можно смело вычёркивать из списка , а остальное уже написал RUSLAN1
the_spirit
Спасибо!
the_spirit
Простите господа сегодня осциллограмм не будет, нужен rs232 кабель, лишнего на работе не нашлось.
Спасибо всем за дельные советы и пояснения!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.