Как обнаружить ошибки I2C с помощью requestFrom()

Я собираюсь использовать чипы MCP23017, и некоторые из них будут соединены неэкранированным кабелем длиной не более 1 метра. Я ожидаю, что некоторые передачи могут привести к ошибкам. Поэтому я хочу решить эту проблему, используя встроенное обнаружение ошибок I2C, часто опрашивая входы (каждые 20 мс или около того) и выводя полученные данные в код, сравнивая предыдущее состояние с текущим состоянием каждого входного контакта.

Если вы записываете байты в ведомый I2C с проводом библиотеки. Вы можете использовать возвращаемое значение Wire.endTransmission(); для проверки, подтвердило ли ведомое устройство сообщение.

Как это работает, когда вы запрашиваете байты с помощью Wire.requestFrom( address, 3 ); например. Эта функция возвращает количество полученных байтов. Можем ли мы проверить это значение со значением количества запрошенных байтов?

Я прочитал документ TI о том, как работает I2C

Ведущий будет продолжать посылать тактовые импульсы, но освободит линию SDA, чтобы ведомый мог передавать данные. В конце каждого байта данных ведущий отправит ACK ведомому, давая знать, что он готов к большему количеству данных. Как только ведущий получил количество байтов, которое он ожидает, он отправит NACK, сигнализируя ведомому устройству, чтобы остановить связь и освободить шину. Мастер будет следовать этому с условием ОСТАНОВКИ

Таким образом, мастер либо ACKs, либо NACKs считанный байт. Делает ли библиотека проводов автоматически несколько попыток чтения? Или есть что-то в библиотеке проводов, что мы можем использовать для обнаружения неудачной операции чтения?

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

Так что я мог бы попробовать что-то вроде

doItAllAgain:

for(int i = 0 ; i < 5 ; i ++ )
{
    Wire.beginTransmission( address ) ;
    Wire.write( register ) ;
    if( !Wire.endTransmission() ) break ; // если нет ошибки, остановка цикла for
    Serial.println(F("write operation failed");
}

Serial.println(F("write operation succes");

byte requestedBytes = 3 ;
byte returnedBytes = Wire.requestFrom( address, requestedBytes ) ;

if( requestedBytes != returnedBytes )
{
    Serial.println(F("read operation failed");
    goto doItAllAgain ;
}
else
{
    Serial.println(F("read operation also succes");
    byte byte1 = Wire.read() ;
    byte byte2 = Wire.read() ;
    byte byte3 = Wire.read() ;
}

, 👍3

Обсуждение

Вы можете получить лишь небольшую информацию о неудачной передаче, если, например, ведомый, который на самом деле существует, не подтвердит. I2C не имеет возможности выяснить, повреждены ли передаваемые данные или нет. Это проблема мэра, потому что вместо того, чтобы не реагировать, рабы могут вести себя беспорядочно. Чтобы справиться с этим, вам необходимо самостоятельно выполнить проверку ошибок, например, путем проверки контрольной суммы., @Sim Son

Из того, что я понимаю. Если у линии данных есть боковое изменение, в то время как тактовая линия высока, будет NACK, и это должно работать в 2 направлениях. Независимо от того, как я мог бы добавить контрольную сумму при считывании устройства Mcp23017? Чтобы иметь систему контрольной суммы, подчиненное устройство должно быть в состоянии правильно принимать и передавать байты контрольной суммы? У меня на столе голый arduino без устройств I2C, я проверю, что возвращает функция `requestFrom (), когда устройства нет, @bask185

Итак, Wire.requestFrom () возвращает 0, если устройство не подключено. Это означает, что эта функция включает проверку битов NACK., @bask185


1 ответ


Лучший ответ:

3

Проводная библиотека не дает вам никакой возможности получить состояния ошибок при запросе байтов от ведомого устройства. В основном вы застряли с количеством считываемых байтов.

Хотя кое-какую информацию из этого можно прочесть. Если число байтов равно нулю, ведомый не ответил (либо потому, что его там нет, либо потому, что он не может отправить ни одного байта в данный момент). Это равносильно NACK ведомого устройства после байта адреса.

Кроме этого, протокол I2C не дает никакой дополнительной информации. При запросе ведомый посылает данные, а ведущий подтверждает их. Это означает, что раб не может генерировать NACK в этом процессе. На самом деле это также означает, что возвращаемое число байтов может быть только нулевым (on NACK on address) или равным числу запрошенных байтов, так как после получения адреса ACK от ведомого устройства ведущий будет продолжать генерировать тактовые импульсы до тех пор, пока не прочитает все нужные ему байты. Если у ведомого устройства больше нет данных для отправки до этого, он не может остановить передачу. Он просто перестанет управлять линией передачи данных, что приведет ко всем высоким байтам данных (0xFF).

Также я сомневаюсь, что это было бы действительно полезно в вашем случае. I2C производится на небольших расстояниях, в основном на одной печатной плате. Он может использоваться для больших расстояний, но ваш пробег может отличаться. Если ваша установка действительно может повредить связь на линиях I2C, вашей самой большой проблемой будет застрявшая шина. Протокол I2C обычно не подготовлен для шумных сред и включает в себя состояния, в которых устройства на шине могут ждать бесконечно. Это также отражено в библиотеке Wire. Это означает, что большой шум на линиях часто приводит к тому, что шина застревает в середине транзакции, и вам приходится сбрасывать устройства (не только ведомые, но и ведущие), чтобы снова освободить шину. Я бы зашел так далеко, чтобы сказать, что это скорее приведет к тому, что автобус застрянет, чем к получению поврежденных данных. Таким образом, любая информация об ошибках на самом деле не поможет вам здесь, так как вы не выйдете из requestFrom() в первую очередь. Ваш код вполне может там застрять.

Я предлагаю вам тщательно протестировать свою установку с требуемым временем выполнения. Если шина застревает слишком часто для вас, то вам следует сделать вашу установку более надежной (экранированные кабели или использование дополнительного MCU с ведомым устройством I2C и использование более надежного коммуникационного интерфейса между основным MCU и дополнительным MCU).

,