|
Организация стабильной работы шины I2C |
|
|
|
Nov 18 2014, 19:41
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Добрый вечер! Имеется микроконтроллер, имеется некоторое периферийное устройство, подключенное к первому по шине 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))); // ожидание установки флага нельзя нигде. Мало ли почему флаг не установится, программа зациклится и что-нибудь взорвется Насколько я знаю, для таких целей предусматривают таймауты, по истечению которых обрабатывается произошедший казус. Но на I2C как обработать ошибку? У меня вариант только один - сделать управляемым питание ведомого устройства. Через полевой транзистор, например. Чуть что - перезапустили и дальше работаем. Благодарю за внимание!
|
|
|
|
|
 |
Ответов
(1 - 9)
|
Nov 18 2014, 23:14
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Ну во-первых надо заменить Код 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 таймер. Это называется "сбоеустойчивый код".
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Nov 19 2014, 09:44
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Сергей Борщ, Цитата На шине I2C пассивное состояние (лог. единица) формируется резисторами подтяжки. И если во время инициализации ваш контроллер каким-то образом умудряется сформировать там случайные нули - исправляйте программу.
Существует и стандартная процедура сброса автомата приема ведомого - нужно подать 9 импульсов SCLK не притягивая SDAT к нулю. После этого ведомое будет ожидать старт-условие. Инициализация как ни странно - правильная. А артефакты бывают тогда, когда подключаю ведомое двухметровым проводом, но - на минимальной скорости. Про 9 бит надо попробовать, спасибо! MiklPolikov, благодарю за подсказку!
Сообщение отредактировал Arlleex - Nov 19 2014, 09:45
|
|
|
|
|
Nov 19 2014, 10:22
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Arlleex @ Nov 19 2014, 11:44)  когда подключаю ведомое двухметровым проводом Тут каждый сам себе злобный Буратина. В стандарте довольно четко оговорен и кабель (если он превышает 10 см в длину) и порядок проводов в кабеле и сопротивление резисторов подтяжек. Если вы не выполнили эти требования - скорее всего проблема аппаратная и решать ее надо на аппаратном уровне. Каким кабелем вы подключаете, резисторы подтяжек какого номинала используете? Само название шины - Inter-IC bus как бы намекает, что она задумана для связи между микросхемами, а не между устройствами.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 19 2014, 11:50
|

Местный
  
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264

|
Про правильное включение I2C я знаю. Про то, что она для связи микросхем - тоже. Подключаю экранированным двужильным кабелем (марку не помню, к сожалению). Резисторы по 4,7к. Я проводил эксперименты, где микроконтроллер несколько раз в секунду взаимодействовал с ведомым на низкой скорости. Результаты на самом деле хорошие - произошло 250 000 обращений и связь нарушилась. Я оставлял плату на день и уходил по своим делам, фиксируя все на дисплее. Следовательно, результаты не плохие, но, нужно уметь избавляться от любых проблем на шине, ведь перезапустив устройства, можно спокойно совершить столько же обращений (ну как повезет - может меньше, а может больше).
|
|
|
|
|
Nov 20 2014, 03:31
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Arlleex @ Nov 19 2014, 17:50)  Про правильное включение I2C я знаю. Про то, что она для связи микросхем - тоже. Если знаете, то почему не сделаете правильно? Пропустите через кабель не I2C, а подходящий для такого использования интерфейс, а на той стороне поставьте простейший контроллер с I2C. Цитата(Arlleex @ Nov 19 2014, 17:50)  Следовательно, результаты не плохие, но, нужно уметь избавляться от любых проблем на шине, ведь перезапустив устройства, можно спокойно совершить столько же обращений (ну как повезет - может меньше, а может больше). Если Вам просто костыль нужен, то как вариант - на удалённую сторону поставить WatchDog на линию SCLK, сигнал RESET с него завести на вход enable LDO, питающего I2C-слэйвы (раз у них нет входов сброса). Для сброса ведомых I2C достаточно будет просто приостановить опрос на время более периода таймаута сторожевика.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|