|
Странности i2c |
|
|
|
Jul 21 2012, 14:06
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Решил поисследовать 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 КОм.
|
|
|
|
|
Jul 22 2012, 08:17
|
Местный
  
Группа: Свой
Сообщений: 289
Регистрация: 6-12-05
Пользователь №: 11 864

|
Цитата Но в обоих случаях при использовании пограничных значений частот передача либо начиналась и проходила без ошибок, либо ошибки сыпались бесконечно. Исходя из вашего ответа, у Вас проблема в длинном кабеле, а не в коде. Проверяется это легко: соедините устройство сначала без кабеля (коротким проводом) и протестируйте, а потом с кабелем и тоже протестируйте на ошибки. Если с кабелем будут ошибки, а без кабеля нет, значит, ваша программа работает нормально.
|
|
|
|
|
Jul 22 2012, 14:28
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Да не, с коротким кабелем все работает, и даже с длинным на стандартной частоте. Меня беспокоит то, что при повышении частоты устройство перестает работать внезапно. У меня в программе считаются доставленные и не доставленные посылки, и при переходе в 1 khz, например от 571 к 572 посылки перестают доставляться совсем, и нет ситуации при которой доходила бы например половина или одна треть от всех отправленных посылок.
Осциллограммы можно устроить, но это не раньше понедельника. В принципе для разных частот картинка не отличается, тоесть фронты сильно завалены но приблизительно одинаково что для 570 khz что для 571.
|
|
|
|
|
Jul 22 2012, 15:14
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Ну было интересно посмотреть до какой частоты можно разогнать интерфейс. На 10 м. обязана работать, поскольку требования по предельной емкости шины соблюдены.
Ну в том то и проблема, что на предельной частоте, иногда передача срабатывает, и, если срабатывает, то Master и Slave могут обмениваться сообщениями довольно продолжительное время.Мне этот процесс не понятен, и это меня напрягает.
Сообщение отредактировал the_spirit - Jul 22 2012, 15:19
|
|
|
|
|
Jul 22 2012, 16:27
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Ок, спасибо, попробуем. Осциллограммы постараюсь к понедельнику сделать, если успею разобраться как осцил к компу подключается, раньше не было необходимости)
|
|
|
|
|
Jul 22 2012, 19:31
|
Гуру
     
Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025

|
Цитата(the_spirit @ Jul 22 2012, 17:28)  Меня беспокоит то, что при повышении частоты устройство перестает работать внезапно. У меня в программе считаются доставленные и не доставленные посылки, и при переходе в 1 khz, например от 571 к 572 посылки перестают доставляться совсем, и нет ситуации при которой доходила бы например половина или одна треть от всех отправленных посылок. Внутри шага в один килогерц есть еще много мааааленьких шажочков. Если бы Вы двигались не на килогерц, а , например на герц или на микрогерц, то наверняка бы смогли зафиксировать любой процент ошибок от 0 до 100% с любым нужным Вам разрешением (скажем, 17.097% ошибок на частоте 570192.55 Гц). Также Вы можете построить функцию зависимости количества ошибок на такой пограничной частоте от излучения солнца или скорости ветра в лаборатории. Только зачем все это? P.S. Есть такой экспресс-тест линии связи- подать меандр (скажем, 1КГц) и снять осциллограмму. На основании исследования фронтов со стороны приемника можно прогнозировать, что через этот провод можно прокачать без ошибок, что с ошибками, а что вообще не пролезет. Это- аргументированно и обосновано. То что делаете Вы- метод ненаучного тыка. У Вас на столе сегодня результат такой, завтра у соседа что-то другое получится.
|
|
|
|
|
Jul 22 2012, 21:15
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Да, спасибо за разъяснение. По шине SCL фактически и передается меандр, осциллограммы смотрел с нее со стороны приемника , фронты завалены, работе это не мешает. Про более мелкий шаг думал, вопрос собственно был в том, почему на пограничной частоте интерфейс то работает то нет, и не связанно ли это с ошибкой в коде.
|
|
|
|
|
Jul 22 2012, 22:04
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Из AVR Libc пришлось чуть чуть поменять чтобы заработала под IAR и не зависала.
|
|
|
|
|
Jul 22 2012, 22:12
|
Участник

Группа: Участник
Сообщений: 42
Регистрация: 25-11-10
Из: Красногорск
Пользователь №: 61 170

|
Спасибо!
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|