Arlleex 131 18 ноября, 2014 Опубликовано 18 ноября, 2014 · Жалоба Добрый вечер! Имеется микроконтроллер, имеется некоторое периферийное устройство, подключенное к первому по шине I2C. Однажды, при отладке их взаимодействия, я столкнулся с особенностью, на первый взгляд интересной, но в то же время привносящей плачевные последствия. Дело в том, что, в отличие от синхронных интерфейсов, имеющих отдельную физическую линию разрешения (CS, EN, и т.д.), например, SPI, шина I2C таковой не является: только две линии - SDA и SCL. Усугубляется это обстоятельство еще и идеологией сигналов: в зависимости от состояний логических уровней на этих линиях различают старт-бит, повторный старт, стоп бит. При включении питания микроконтроллер начинает инициализировать свою внутреннюю периферию, в том числе линии портов ввода/вывода, к которым подключена шина I2C. И заранее никто не защищен от переходных процессов на шине в этот момент - там может и всплеск быть короткий, и что угодно. Пагубное влияние таких всплесков налицо - они случайно могут служить условиями старта для I2C. Когда-то так получалось и у меня, пока я не посмотрел осциллограммы сигналов на интерфейсных линиях. Действительно, там был кратковременный всплеск, и I2C-ведомые думали, что микроконтроллер сформировал условие старта. А МК, ничего об этом не подозревая, шлет реальный старт-бит, вводя ведомое устройство в ступор (ну железно зашитый в нем конечный автомат, чего поделать). Далее все просто - ведомый не отправляет бит подтверждения, а в некоторых случаях может сам подтянуть линию SCL к низкому логическому уровню. А что в этот момент делает микроконтроллер? Он опрашивает различные флаги (произошло на линии условие старта или нет, передался ли адрес, принялся ли бит подтверждения и т.д.). И, к сожалению, если делать это так: while(!(STATUS_I2C_REG & (1 << 5))); // ожидание установки флага и в этот момент на шине ничего не произойдет для установки этого флага, микроконтроллер тут и повиснет. Можно сделать на прерывании, но сути не изменится - аппаратная ошибка на шине, которую можно обнаружить в регистрах I2C-интерфейса микроконтроллера, и соответственно отреагировать, но ведомому-то до этого какое дело? Вот произошла ошибка в момент передачи данных, ведомый притянул линию SCL к земле - вот и ничего не поделаешь уже, МК не сможет даже условие стопа сформировать, чтобы потом снова попытаться обратиться к этому ведомому. Я думаю вы поняли к чему я веду: случайная наводка на интерфейсной шине может сформировать определенный сигнал на шине, причем микроконтроллер еще сможет это обнаружить, но ведомый - нет. Он все так же будет ждать следующим битом, например, стоп-бит, а микроконтроллер еще только отправляет последний бит данных... Тут возникает жестокий ступор, и как вывести ведомого из него - как раз мой вопрос. Ведь по идее делать так: while(!(STATUS_I2C_REG & (1 << 5))); // ожидание установки флага нельзя нигде. Мало ли почему флаг не установится, программа зациклится и что-нибудь взорвется :laughing: Насколько я знаю, для таких целей предусматривают таймауты, по истечению которых обрабатывается произошедший казус. Но на I2C как обработать ошибку? У меня вариант только один - сделать управляемым питание ведомого устройства. Через полевой транзистор, например. Чуть что - перезапустили и дальше работаем. Благодарю за внимание! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iosifk 3 18 ноября, 2014 Опубликовано 18 ноября, 2014 · Жалоба Имеется микроконтроллер, имеется некоторое периферийное устройство, подключенное к первому по шине I2C. Если у ведомого есть вход аппаратного сброса, то заведите на него выход с микроконтроллера, чтобы можно было проинициализировать микроконтроллер, потом сбросить периферию и только потом с ней работать... Да и при зависаниях периферии чтобы ее можно было сбросить... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 18 ноября, 2014 Опубликовано 18 ноября, 2014 · Жалоба Так в том и проблема, что у ведомого никаких входов сброса и аппаратного контроля, к сожалению. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 18 ноября, 2014 Опубликовано 18 ноября, 2014 · Жалоба На шине I2C пассивное состояние (лог. единица) формируется резисторами подтяжки. И если во время инициализации ваш контроллер каким-то образом умудряется сформировать там случайные нули - исправляйте программу. Существует и стандартная процедура сброса автомата приема ведомого - нужно подать 9 импульсов SCLK не притягивая SDAT к нулю. После этого ведомое будет ожидать старт-условие. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiklPolikov 0 18 ноября, 2014 Опубликовано 18 ноября, 2014 · Жалоба Ну во-первых надо заменить while(!(STATUS_I2C_REG & (1 << 5))); на i=0; while(!(STATUS_I2C_REG & (1 << 5))) { i++; if(i>100000) break; } if(i>10000) { //// Обработка тайм-аута } Ну и так далее. Обрабатываться должны абсолютно все исключительные ситуации. Никаких бесконечных циклов без тайм-аута или делений на результат из АЦП без проверки того что АЦП не выдал 0. Разница между "выдающим ошибки" I2S и "стабильным" SPI лишь в том, что в SPI ошибки происходят в 1000 раз реже, и Вы их не видите, пока отлаживаете. Но это не значит, что не нужно заботится об их обработке. Исходите из того, что в программе на МК любой флаг может не выставиться и любая переменная может принять любое значение. Устройство при этом не должно впасть в каматоз. Последний форпост - WDT таймер. Это называется "сбоеустойчивый код". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 19 ноября, 2014 Опубликовано 19 ноября, 2014 (изменено) · Жалоба Сергей Борщ, На шине I2C пассивное состояние (лог. единица) формируется резисторами подтяжки. И если во время инициализации ваш контроллер каким-то образом умудряется сформировать там случайные нули - исправляйте программу. Существует и стандартная процедура сброса автомата приема ведомого - нужно подать 9 импульсов SCLK не притягивая SDAT к нулю. После этого ведомое будет ожидать старт-условие. Инициализация как ни странно - правильная. А артефакты бывают тогда, когда подключаю ведомое двухметровым проводом, но - на минимальной скорости. Про 9 бит надо попробовать, спасибо! MiklPolikov, благодарю за подсказку! Изменено 19 ноября, 2014 пользователем Arlleex Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 19 ноября, 2014 Опубликовано 19 ноября, 2014 · Жалоба когда подключаю ведомое двухметровым проводомТут каждый сам себе злобный Буратина. В стандарте довольно четко оговорен и кабель (если он превышает 10 см в длину) и порядок проводов в кабеле и сопротивление резисторов подтяжек. Если вы не выполнили эти требования - скорее всего проблема аппаратная и решать ее надо на аппаратном уровне. Каким кабелем вы подключаете, резисторы подтяжек какого номинала используете? Само название шины - Inter-IC bus как бы намекает, что она задумана для связи между микросхемами, а не между устройствами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 19 ноября, 2014 Опубликовано 19 ноября, 2014 · Жалоба Про правильное включение I2C я знаю. Про то, что она для связи микросхем - тоже. Подключаю экранированным двужильным кабелем (марку не помню, к сожалению). Резисторы по 4,7к. Я проводил эксперименты, где микроконтроллер несколько раз в секунду взаимодействовал с ведомым на низкой скорости. Результаты на самом деле хорошие - произошло 250 000 обращений и связь нарушилась. Я оставлял плату на день и уходил по своим делам, фиксируя все на дисплее. Следовательно, результаты не плохие, но, нужно уметь избавляться от любых проблем на шине, ведь перезапустив устройства, можно спокойно совершить столько же обращений (ну как повезет - может меньше, а может больше). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 20 ноября, 2014 Опубликовано 20 ноября, 2014 · Жалоба Про правильное включение I2C я знаю. Про то, что она для связи микросхем - тоже. Если знаете, то почему не сделаете правильно? Пропустите через кабель не I2C, а подходящий для такого использования интерфейс, а на той стороне поставьте простейший контроллер с I2C. Следовательно, результаты не плохие, но, нужно уметь избавляться от любых проблем на шине, ведь перезапустив устройства, можно спокойно совершить столько же обращений (ну как повезет - может меньше, а может больше). Если Вам просто костыль нужен, то как вариант - на удалённую сторону поставить WatchDog на линию SCLK, сигнал RESET с него завести на вход enable LDO, питающего I2C-слэйвы (раз у них нет входов сброса). Для сброса ведомых I2C достаточно будет просто приостановить опрос на время более периода таймаута сторожевика. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 ноября, 2014 Опубликовано 20 ноября, 2014 · Жалоба Резисторы по 4,7к.По-хорошему надо бы измерить емкость вашего кабеля и выбрать их номинал по графикам в стандарте исходя из емкости. Но этого никто делать не будет, к гадалке не ходи. Поэтому просто умньшите их до 1.5к. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться