Перейти к содержанию

Почему шина I2C зависает после перезагрузки микроконтроллера?

Обновлено Редакция GAW

Ведущий и ведомый на шине I2C не имеют общего сигнала сброса. Если микроконтроллер перезагрузился посреди транзакции — от сторожевого таймера, кнопки или просадки питания, — датчик об этом не узнает. Он остаётся в том месте байта, где его застал сброс.

Как это происходит

  1. Микроконтроллер читает данные, датчик выставляет на SDA очередной бит — 0.
  2. В этот момент микроконтроллер перезагружается и перестаёт выдавать такты SCL.
  3. Датчик ждёт следующего такта и держит SDA в нуле сколько угодно.
  4. После старта контроллер I2C видит SDA в нуле, считает шину занятой и не может сформировать START.

Снаружи это выглядит так: до перезагрузки всё работало, после — датчик «пропал», и помогает только выключение питания.

Что делать

По UM10204 действия зависят от того, какая линия застряла:

Линия в нулеЧто делать по UM10204
SDAведущий выдаёт до девяти тактов SCL, датчик отпускает линию, затем STOP
SCLаппаратный сброс устройств или снятие питания для внутреннего сброса по включению

Девять тактов — это восемь бит байта и бит подтверждения: за это время любой прерванный байт заканчивается. Наш расчёт: на 100 кГц это 90 мкс, поэтому очистку шины ставят в начало программы всегда, перед инициализацией I2C, — вреда от неё нет.

Если SCL держит медленное устройство, это может быть и законное растягивание такта — тогда ждут, а не сбрасывают. Как убедиться, что линии свободны, рассказано в ответе «Как проверить шину I2C», последовательность битов транзакции показывает калькулятор «Транзакция I²C по байтам». Устройство шины — в статье «Шина I²C».

Похожие вопросы

Почему шина зависает не после каждой перезагрузки?

Зависание бывает, только если сброс пришёлся на момент, когда датчик сам передаёт бит 0 или подтверждение. Если в этот момент линию держал ведущий или передача уже закончилась, датчик ничего не ждёт. Поэтому ошибка выглядит случайной и чаще всплывает после срабатываний сторожевого таймера.

Поможет ли перезагрузить только микроконтроллер ещё раз?

Нет, если программа при старте не очищает шину: датчик продолжает держать SDA. Помогают девять тактов SCL перед инициализацией I2C или выключение питания самого датчика — UM10204 предлагает именно эти два пути.

Как сбросить шину, если датчик стоит за коммутатором TCA9548A?

У TCA9548A есть вход RESET: низкий уровень сбрасывает коммутатор и отключает все каналы, и зависший канал перестаёт блокировать основную шину. После этого канал можно выбрать снова и выдать в нём девять тактов.

Источники

  1. NXP. UM10204 I2C-bus specification and user manual (Rev. 7.0, 1 October 2021) — разд. Bus clear (3.1.16 в тексте): если SCL застряла в нуле, сбрасывают устройства аппаратным сигналом сброса, а без него — выключением питания, чтобы сработал обязательный внутренний сброс; если в нуле SDA, ведущий выдаёт девять тактов, и устройство должно отпустить линию, иначе — аппаратный сброс или питание; разд. 3.1.14 — программный сброс через общий вызов (необязательная функция, есть не у всех устройств)
  2. Texas Instruments. TCA9548A Low-Voltage 8-Channel I2C Switch with Reset (SCPS207H, revised September 2024) — вход RESET с активным низким уровнем — сброс и отключение всех каналов без снятия питания, чтобы восстановиться, если нижняя шина застряла в нуле; длительность импульса RESET не меньше 6 нс

Нашли ошибку?