реклама на сайте
подробности

 
 
> Организация стабильной работы шины I2C
Arlleex
сообщение Nov 18 2014, 19:41
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 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))); // ожидание установки флага

нельзя нигде. Мало ли почему флаг не установится, программа зациклится и что-нибудь взорвется laughing.gif
Насколько я знаю, для таких целей предусматривают таймауты, по истечению которых обрабатывается произошедший казус. Но на I2C как обработать ошибку? У меня вариант только один - сделать управляемым питание ведомого устройства. Через полевой транзистор, например. Чуть что - перезапустили и дальше работаем.
Благодарю за внимание!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 9)
iosifk
сообщение Nov 18 2014, 19:59
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 4 011
Регистрация: 8-09-05
Из: спб
Пользователь №: 8 369



Цитата(Arlleex @ Nov 18 2014, 23:41) *
Имеется микроконтроллер, имеется некоторое периферийное устройство, подключенное к первому по шине I2C.

Если у ведомого есть вход аппаратного сброса, то заведите на него выход с микроконтроллера, чтобы можно было проинициализировать микроконтроллер, потом сбросить периферию и только потом с ней работать... Да и при зависаниях периферии чтобы ее можно было сбросить...


--------------------
www.iosifk.narod.ru
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Nov 18 2014, 20:44
Сообщение #3


Местный
***

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



Так в том и проблема, что у ведомого никаких входов сброса и аппаратного контроля, к сожалению.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 18 2014, 22:28
Сообщение #4


Гуру
******

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



На шине I2C пассивное состояние (лог. единица) формируется резисторами подтяжки. И если во время инициализации ваш контроллер каким-то образом умудряется сформировать там случайные нули - исправляйте программу.

Существует и стандартная процедура сброса автомата приема ведомого - нужно подать 9 импульсов SCLK не притягивая SDAT к нулю. После этого ведомое будет ожидать старт-условие.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MiklPolikov
сообщение Nov 18 2014, 23:14
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 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 таймер. Это называется "сбоеустойчивый код".


--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Nov 19 2014, 09:44
Сообщение #6


Местный
***

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



Сергей Борщ,
Цитата
На шине I2C пассивное состояние (лог. единица) формируется резисторами подтяжки. И если во время инициализации ваш контроллер каким-то образом умудряется сформировать там случайные нули - исправляйте программу.

Существует и стандартная процедура сброса автомата приема ведомого - нужно подать 9 импульсов SCLK не притягивая SDAT к нулю. После этого ведомое будет ожидать старт-условие.


Инициализация как ни странно - правильная. А артефакты бывают тогда, когда подключаю ведомое двухметровым проводом, но - на минимальной скорости. Про 9 бит надо попробовать, спасибо!

MiklPolikov, благодарю за подсказку!

Сообщение отредактировал Arlleex - Nov 19 2014, 09:45
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 19 2014, 10:22
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Nov 19 2014, 11:50
Сообщение #8


Местный
***

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



Про правильное включение I2C я знаю. Про то, что она для связи микросхем - тоже. Подключаю экранированным двужильным кабелем (марку не помню, к сожалению). Резисторы по 4,7к.
Я проводил эксперименты, где микроконтроллер несколько раз в секунду взаимодействовал с ведомым на низкой скорости. Результаты на самом деле хорошие - произошло 250 000 обращений и связь нарушилась. Я оставлял плату на день и уходил по своим делам, фиксируя все на дисплее.
Следовательно, результаты не плохие, но, нужно уметь избавляться от любых проблем на шине, ведь перезапустив устройства, можно спокойно совершить столько же обращений (ну как повезет - может меньше, а может больше).
Go to the top of the page
 
+Quote Post
jcxz
сообщение Nov 20 2014, 03:31
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 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 достаточно будет просто приостановить опрос на время более периода таймаута сторожевика.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 20 2014, 07:10
Сообщение #10


Гуру
******

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



Цитата(Arlleex @ Nov 19 2014, 13:50) *
Резисторы по 4,7к.
По-хорошему надо бы измерить емкость вашего кабеля и выбрать их номинал по графикам в стандарте исходя из емкости. Но этого никто делать не будет, к гадалке не ходи. Поэтому просто умньшите их до 1.5к.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st June 2025 - 15:15
Рейтинг@Mail.ru


Страница сгенерированна за 0.01459 секунд с 7
ELECTRONIX ©2004-2016