Arduino Zero (ATSAMD21G) - I2C - непрерывный поток неверных данных
Я столкнулся со странным поведением при выполнении тестов на 2-полосную передачу между 2 Arduino Zero (ATSAMD21G), одним ведущим и одним ведомым. Неправильные данные постоянно передаются в обоих направлениях. Ожидаемые данные также передаются между ними. Я должен отфильтровать полученные данные, чтобы поймать их (строка 41 в коде ведущего и 33 в ведомом).
Я использую стандартные библиотеки проводов (разные для 2 плат), а также "I2C_readAnything"Ника Гэммона.
Код магистра
Код раба
Я думаю, что этот непрерывный поток не позволяет освободить автобус. Возможно, это то, что делает невозможным общение со вторым мастером (и, возможно, вызывает мою предыдущую проблему).
Я также попробовал свой код между Mega 2560 (ведомый) и нулем (ведущий). Поддельные данные на этот раз отправляются только в одну сторону (только от Нуля до Мега).
Есть ли какой-то конкретный код, который нужно добавить для правильной отправки данных с плат ATSAMD? Это ошибка в библиотеке проводов SAMD?
Мне также пришлось добавить задержку в 1 мс после отправки данных от Мастера. Иначе это не прошло бы. Разве это не должно обрабатываться ATSAMD или библиотекой проводов?
@kb_, 👍1
2 ответа
Начните с одного байта, с очень маленького скетча, с ведущим и ведомым устройством на частоте 100 кГц. Когда это будет работать на 100% надежно, вы можете попытаться перенести структуру.
Подчиненная функция RequestEvent всегда должна возвращать действительные данные, а не каждые две секунды. Глобальные переменные, которые используются в receiveEvent или requestEvent и в цикле (), должны быть "изменчивыми". Отключите прерывания в цикле() при чтении или записи глобальной изменчивой структуры.
С помощью вашего скетча вы должны открыть последовательный монитор как для ведущего, так и для ведомого устройства.
Вы можете добавить дополнительные тесты, например, проверить возвращаемое значение Wire.endTransmissing, проверить параметр "Сколько", проверить фактическое число, возвращаемое Wire.request.
В кодексе было несколько проблем.
receiveEvent
на стороне ведомого устройства содержал таймер миллисекундного состояния, который определял время ожидания. Я переместил таймер на главную сторону, прежде чем вызвать
Wire.requestFrom
.
receiveEvent
, на стороне подчиненного, также путал реальные данные с входящим запросом
. Я добавил оператор if для сравнения
размера
данных receiveEvent с ожидаемым размером. Половина данных была неверной без этого фильтра (в идеале это должно обрабатываться в библиотеке проводов
).
Я установил глобальные переменные, используемые в событиях, как изменчивые
. Код тоже работает и без этого.
исправлен Мастер-код
исправлен ведомый код
Тактовая частота ведомого I2C составляет 100 кГц, ведущего-800 кГц. Начните с самых обычных настроек, то есть и Мастера на 100 кГц. Возвращаемые значения не проверяются в Мастере. Я думаю, что в этой ситуации вы должны их проверить. В ведомом устройстве вы можете проверить howMany и увеличить счетчик ошибок, если он неверен. Шина I2C не является отказоустойчивой, это означает, что она всегда должна работать на 100%. Если он ненадежен, вы должны его исправить. Какой длины провода ? Когда вы подключаете плату 3,3 В через I2C к плате 5 В, вы использовали переключатель уровня ? Вы подключили GND обеих плат ?, @Jot
Вы имеете в виду оставшиеся неправильные данные, которые я отфильтровываю, проверяя, сколько их там не должно быть? Когда я тестирую его, как вы советуете, я вижу, что это половина receiveEvent (больше не непрерывный поток, так что это достаточно хорошо, шина освобождается после каждой транзакции, так что multimaster теперь тоже работает). Вот почему я думаю, что это путает requestEvent с данными. Я пойму больше, как только получу свой логический анализатор., @kb_
Мастер устанавливает скорость шины I2C. Код ведомого устройства не содержит настройки скорости. 800 кГц отлично работает между 48 МГц Nano, но слишком много с Mega. Длина проводов составляет менее 1 м. Я использую сдвиг уровня между Нано и Мега. Все на том же GND. Я добавлю тест на содержание данных в свою окончательную заявку для дополнительной безопасности., @kb_
Мне все равно, работал ли 800 кГц в прошлом. Вы должны исправить ряд проблем, поэтому было бы разумно вернуться к 100 кГц. Если все работает нормально, вы можете попробовать более высокие тактовые частоты. Но вы еще не там. Связь I2C должна работать на 100%, а не на 99%. Когда howMany-это только половина receiveEvent okay, то ваша связь I2C работает на 50%. Вы должны исправить проблемы, чтобы сделать это на 100%. Начните с использования тактовой частоты I2C по умолчанию 100 кГц и проверьте возвращаемые значения в мастере. Может быть, вы также могли бы сохранить howMany в переменной, когда она была неправильной, и распечатать эту переменную., @Jot
То же самое при частоте 100 кГц. howMany = 0 для половины receiveEvent. Для них Wire.read возвращает -1, что означает отсутствие данных., @kb_
Спасибо за тестирование. Это очень странно. Обычно это может быть вызвано только столкновением в многомастерной шине. howMany - это количество допустимых байтов, ожидающих в буфере. Когда вы читаете больше, чем количество допустимых байтов, Wire.read возвращает -1. У меня кончились идеи. Это все еще может быть аппаратная проблема, у вас есть подтягивающие резисторы ? Мое лучшее предположение заключается в том, что это проблема в проволочной библиотеке для Нуля. Я могу найти ряд проблем с Wire library для Arduino Zero / Feather M0 / Arduino M0 (все ATSAMD21G)., @Jot
Я сделал еще несколько тестов. Подтягивания есть, около 2 Ком. Я сделал первый тест с 10 передачами, без howMany. Данные были случайно неправильными в серийном отпечатке, но все хорошо на логическом анализаторе! [код и result](https://github.com/kb-/Arduino-I2C-2way-anydata/tree/cb5ea4863f77e6eb323db0bbd84c01d5734e1fd9) Затем я сделал еще один тест с 10000 передачами, с howMany. Любая одиночная передача была хороша как в последовательной печати, так и в логическом анализаторе. [код и result](https://github.com/kb-/Arduino-I2C-2way-anydata/tree/b8525944b4ef0c0166e8c4d66c1b1bcf2adbd2cb). Меня смущает 1-й результат!, @kb_
Для меня это означает, что проводная библиотека иногда запускает receiveEvent, когда нет никаких входящих данных. Это не большая проблема, так как в шине нет неправильных данных или столкновений., @kb_
Вам нужно протестировать его на частоте 100 кГц. Если вы можете сделать то же самое на частоте 100 кГц, то я предлагаю предположить, что это ошибка в библиотеке, и вы должны обойти ее. Возможно, receiveEvent иногда случайно вызывается, когда транзакция I2C только началась. Когда Мастер запрашивает данные, Мастер должен отправить NAK в конце, но это не так. Я читал, что при записи регистра в ведомое устройство с последующим чтением этого регистра иногда требуется короткая задержка (1 мс) между Wire.endTransmission и Wire.requestFrom. Это означает, что уже есть три вещи, которые нужно улучшить для библиотеки проводов SAMD21., @Jot
Он ведет себя так же на частоте 100 кГц. Я вижу НАКА только в конце чтения, перед остановкой с логическим анализатором. Обходной путь howMany позволил осуществить передачу со 100% успехом. Спасибо за все ваши советы. Добавление других предложенных вами тестов плюс повторные попытки при столкновениях позволило использовать код для 2-полосной передачи с несколькими мастерами., @kb_
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
- Что означает в I2C «NACK получен»?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- Несколько датчиков I2C с одинаковым адресом
Я упростил код для тестирования с помощью однобайтовой 2-полосной передачи при частоте 100 кГц, используя летучие вещества в событиях, как вы советовали. Я все еще вижу то же самое поведение (после открытия монитора на обоих, конечно). Передача только в одну сторону работает правильно. Добавление дополнительных тестов звучит для меня так, что это только скроет, что поддельные данные текут между устройствами (как фильтрация, которую я сделал в своем первоначальном коде). Я должен избегать отключения прерываний, потому что мое окончательное приложение полагается на них (управление ПИД-двигателем и считывание энкодера...), @kb_
Результат на ведомом устройстве: -Arduino подключен ... y y m y y _BOS_ ... (должен получить только "m"; такое же поведение на стороне мастера) [Мастер](http://tinyurl.com/hm2nsfc) / [Рабыня](http://tinyurl.com/zyder4a]) / [Только один путь, Мастер](http://tinyurl.com/hq47p9v), @kb_
Я выяснил, что не сработало в упрощенном тесте. Миллисекундная задержка в requestEvent приводила к таймауту. Вместо этого я поместил эту задержку перед requestFrom в мастер. Я должен проверить параметр "howMany" в receiveEvent, чтобы он не путал входящие данные с requestEvent. На мой взгляд, это должно быть обработано wire library. [Исправлено code](https://github.com/kb-/Arduino-I2C-2way-anydata/commit/88d35b78301265cacf743e1f00232c59bbe0aadc), @kb_