Пролог
Накануне я столкнулся с ситуацией, когда берешь uHAL драйвер от вендора микроконтроллера, собираешь его как в примерах и код не работает. Никогда такого не было, и вот опять…
На этот раз осечка в драйвере I2C трансивера. При попытке прочитать 16-битный регистр родным драйвером I2C шина за стороне slave просто берёт и зависает. Микроконтроллер показывает постоянный bus busy флаг, re-init I2C трансивера ничего не меняет. Выход один, перезагрузка по питанию всей PCB. Только это позволяет вновь хоть как-то достучаться до регистров ASIC(а).
Проблема еще и в том, что в родных драйверах от вендора никогда не бывает функции для сканирования шины. То ли поленились сделать, то ли не поняли, что так можно было… А функция такая порой надобна… Вот у меня есть плата, а там висит шесть I2C чипов. Как я проверю качество пайки без сканирование I2C шины?
Надежный I2C нужен всегда и везде. Вот лишь малый список ASIC(ов), которые управляются по I2C: at24cxx, lis3dh, bh1750, bmp180, nau8814, sa51034, ds3231, fda801, ltr390, max9860, si4703, ssd1306, wm8731 и прочие.
В связи с этим пришлось разрабатывать собственный полноценный драйвер I2C, буквально на регистрах I2C трансивера.
Постановка задачи
Написать на Си драйвер I2C в котором будут следующие функции:
-
Проверка присутствия микросхемы по её 7-ми битному I2C адресу
bool i2c_check_addr(uint8_t num, uint8_t chip_addr);
-
Чтение 16-битного регистра по адресу ячейки внутри ASIC(a)
bool i2c_read_word(uint8_t num, uint8_t chip_addr, uint8_t reg_addr, uint16_t* const word);
-
Запись 16-битного слова в ASIC по его адресу на шине I2C
bool i2c_write_word(uint8_t num, uint8_t chip_addr, uint16_t word);
и тому подобное
Что надо из оборудования?
Любая разработка начинается только тогда, когда появляются полноценные средства для отладки. В связи с этим необходима следующая аппаратура:
# |
Оборудование |
1 |
Логический анализатор Saleae Logic Pro 16 для чтения сырых сигналов на цифровой шине I2C |
2 |
Электронная плата с микроконтроллером, который поддерживает аппаратный I2C трансивер. В моем случае это электронная плата с MCU AT32F435ZM |
3 |
Какой-нибудь ASIC c поддержкой I2C трансивера. В моём случае это аудиокодек NAU8814 |
Что надо из софтвера?
№ |
Софтвер |
Назначение |
1 |
GCC ToolChain |
Для сборки прошивки |
2 |
Процессор электронных таблиц |
Для составления документации по конечному автомату |
3 |
Векторный графический редактор. Например inkscape |
Чтобы нарисовать граф конечного автомата |
4 |
Поддержка в прошивке UART-CLI |
Для управления прошивкой и отладке кода. |
В прошивке должен быть реализован интерфейс командной строки (TUI). Чтобы была возможность в run time запускать на исполнение произвольном порядке команды драйвера I2C трансивера,
запускать модульные тесты ассоциированные с драйвером I2C и управлять уровнями логирования, чтобы смотреть и анализировать log(и) трассировки ветвей алгоритмов внутри микроконтроллера.
Теоретический минимум
I2C — это последовательный, синхронный, цифровой, полудуплексный, двухпроводной , много-мастерный физический интерфейс с топологией общая шина. Плюс протокол канального уровня модели OSI-7. На I2C чем-то похож интерфейс MDIO, SWD. Там тоже два провода и один-тактирование. По моим наблюдениям в каждом микроконтроллере присутствует аппаратный I2C трансивер. Да не один.
Несколько фактов про I2C:
1—Биты передаются старшим битом вперед (MSB).
2—Байты передаются в формате big-endian
3—В шине I2C есть мастер и ведомый устройства. Большинство I2C ASICов это slave устройства.
4—I2C интерфейс схемотехнически это общий коллектор. Это значит, что провода должны быть подтянуты к питанию. А узлы просто по очереди прижимают шину к земле. Получается кто угодно на шине может взять и прижать шину к GND. В таком случае обмен данными будет невозможен. Ноль это доминантный бит. Такое можно встретить также в интерфейсах LIN и 1-Wire.
5—В 90% случаев I2C применяется для обмена данными между микросхемами в пределах одной электронной платы PCB. То есть это интерфейс для обмена данными между микросхемами. Нынче почти все микросхемы это программно-управляемые устройства, которые работают согласно своей конфигурации в ячейках RAM памяти.
Хотя, справедливости ради, надо отметить, что ещё I2C интерфейс присутствует в HDMI шине, которая соединяет материнскую плату и монитор.
6—I2C это полудуплексный интерфейс. То есть в один момент времени на шине может происходить либо передача, либо приём битов, но никак не одновременно.
7—I2C это протокол канального уровня, так как есть структура пакета. Протокол оперирует 7 битными адресами. Это значит, что на шине может быть до 128 микросхем. По факту каждое новое I2C устройство добавляет в шину паразитную ёмкость и общая битовая скорость из-за этого понижается.
8—Бит данных захватывается по положительному перепаду на проводе SCL. То есть в момент перехода от 0V в 3.3V.
9—I2C последовательный интерфейс. Это значит что биты передаются один за другим. Как в UART, SPI, CAN, SWD, 1-wire.
10—I2C это синхронный интерфейс. Значит, что есть тактирование как в SPI, MDIO и SWD.
11—I2C это двухпроводной интерфейс. Прям как CAN, UART.
12—I2C это цифровая общая шина.
На низком уровне I2C оперирует сигналами. Вот полный реестр сигналов I2C.
Терминология
Слово (Word)- целое неотрицательное 16-битное число. От нуля до 0xFFFF=65536
Вот шпаргалка по I2C
Вот типичная структура пакета для чтения 16-битного слова по I2C.
Реализация
Конечно-автоматная методика разработки ПО хороша тем, что она универсальна и очень хорошо формализована. Есть учебники по этой теме, которые уходят корнями в 195х-е года. Любая разработка FSM на состоит из восьми шагов.
номер |
фаза |
1 |
Перечислить состояния конечного автомата |
2 |
Перечислить входы конечного автомата |
3 |
Перечислить выходы конечного автомата |
4 |
Построить таблицу переходов конечного автомата |
5 |
Построить таблицу выходов конечного автомата |
6 |
Нарисовать граф переходов конечного автомата |
7 |
Написать код |
8 |
прогнать модульные тесты |
В прочем, обо всем по-порядку…
Фаза 1: Перечислить состояния
Фаза 2: Перечислить входные воздействия
Для нашего конечного автомата входами будут биты в статусных регистрах микроконтроллера. Как правило там такой список битов.
Тут сразу стоит отметить, что не все флаги статуса обладают одинаковым приоритетом. Достаточно часто будет происходить такая ситуация, что на данной итерации FSM произошло сразу два события! В этом случае надо выбирать в обработку то событие, у которого выше приоритет.
Фаза 3: Перечислить выходы конечного автомата
То есть сказать, что должен делать конечный автомат в ответ на стимулы извне. Перечислить легальные действия
Фаза 4 и 5: Построить таблицы переходов.
Таблицы переходов это двухмерные матрицы которые показывают в какое состояние надо переходить в зависимости от нынешнего состояния и входного сигнала. Для данного конечного автомата таблица будет весьма громоздкая, поэтому я составлю её в Google Spreadsheets.
Таблица переходов составляется на основе образцовых временных диаграмм успешной транзакции. Вот так, например, должна выглядеть времянка на чтение слова.
Фаза 6: Изобразить граф конечного автомата
Как говорит пословица: «Картинка стоит тысячи слов.» В самом упрощенном виде граф конечного автомата I2C мастера может выглядеть так.
Я нарисовал его в программе inkscape.
Фаза 7: Написать код
В целом, обладая перечисленной документацией код уже может написать абсолютно любой программист-микроконтроллеров. Исходники это не код на Си. Исходники — это документация: таблицы, формулы и схемы.
Достоинства реализации драйвера I2C на основе конечного автомата:
1++ У вас один код цикла для всех функций: чтение, запись, сканирование. Изменение в одном месте автоматически раскатывается на все операции. Нет дублирования кода как такового. В результате реализация получается лаконичная.
2++ Разработка через FSM хороша тем, что алгоритм сам составляется по мере отладки. Даже если изначально решение абсолютно неочевидное. При использовании методологии конечных автоматов алгоритм уточняется по мере получения красных модульных тестов.
3++ Обрабатываются все варианты использования алгоритма, как штатные, так и не штатные ситуации. FSM алгоритмы самые надежные. Безотказные, как автомат Калашникова.
4++ Для всех комбинаций возможных входных воздействий и нынешних состояний есть алгоритм для работы. Нет никаких исключительных ситуаций.
5++ Когда драйвер I2C реализован в виде конечного автомата то ему даже прерывания не нужны. Всё можно реализовать в одном супер цикле с выходом по таймауту.
6++ Код написанный на конечно автоматной методологии очень легко отлаживать. Достаточно только включить повыше уровень логирования и проанализировать цветной лог. Даже нет нужды в пошаговой отладке как таковой.
7++ Код написанный по FSM очень легко масштабировать. Достаточно добавить новые состояния и появится новый функционал.
Отладка автомата I2C
Отлаживать код — это то же, что работать детективом. Тут надо тщательнейшим образом анализировать логи в UART-CLI. Как водится, первым делом просканируем шину.
-
Сканирование шины I2C это фундаментальная операция. Она показывает что плата пропаяна, что есть питание на микросхемах, что есть подтягивающие резисторы. Сканирование это smoke тест. Опа! Видим знакомый символ 0x1a. Это как раз NAU8814. Второе число это то же самое что 0x1a. Дело в том, что адрес семи битный, а алгоритм перебирает 8-битные числа. Вот старший бит и отбрасывается.
-
Чтение слова. Это осциллограмма для чтения 16 бит регистра по I2C.
Лог операции чтения слова:
-
Запись 9-битного регистра по 7-ми битному адресу. По сути запись 16бит слова по I2C.
Лог записи регистра в виде отправки слова по шине I2C
Все операции работают как часы. Модульные тесты проходят.
Пару слов про опыт работы с I2C интерфейс
Как можно заметить, драйвер интерфейса I2C это весьма сложная вещь. Надо следить за тем, чтобы шина не зависла. Работать с I2C надо предельно аккуратно. Программировать I2C трансивер — это как ходить двум параллельно натянутым канатам. Шаг влево или шаг вправо и происходит bus error или bus busy. И привет… Именно по этому I2C — самый ненадёжный проводной интерфейс!
I2C slave микросхемы имеют свойство спонтанно зависать прижимая к земле провод тактирования SCL!
В таких случаях на своей стороне мастер ничего не может сделать, чтобы хоть как-то распетлять ситуацию. Происходить окончательная потеря link(а)… Вот такие вот пирожки с капустой… Понимаете?…
В связи с этим, в особенно ответственных электронных устройствах (automotive, aerospace, military области) я бы рекомендовал следующие схемотехнические меры:
1- Вообще не использовать I2C. Как правило, каждый I2C совместимый чип помимо I2C поддерживает ещё и SPI режим. Примерами таких ASICов являются LIS3DH и NAU8814. В таких случаях надо отдавать предпочтение именно SPI интерфейсу. Легче будет поддерживать этот прибор. В SPI в принципе нечему ломаться.
2- На чип I2C ставить аналоговый ключ для электронного пере сброса электропитания на этом чипе по GPIO от MCU. Тогда в случае зависания можно будет пере инициализировать и хоть как-то дальше работать.
Итоги
Удалось написать работающий драйвер I2C трансивера в виде конечного автомата на девяти состояниях. В очередной раз убеждаюсь что программы нужно проектировать, а не писать.
Применяйте конечные автоматы в разработке system software для микроконтроллеров. В этом нет абсолютно ничего сложного.
Надеюсь, что этот текст поможет и другим программистам микроконтроллеров в покорении I2C интерфейса на разных микроконтроллерах.
Словарь
Акроним |
Расшифровка |
PCB |
Printed circuit board |
ASIC |
Application-specific integrated circuit |
I2C |
Inter-Integrated Circuit |
FSM |
Finite-state machine |
Ссылки
Конечные автоматы — это настолько универсальный шаблон проектирования программного обеспечения, что коллекция его применения в моём опыте насчитывает уже более 9-ти случаев. FSM — золотой молоток!
№ |
Гиперссылка |
URL |
1 |
||
3 |
||
2 |
Создаем I2C Master Controller на Verilog. Логический уровень |
|
4 |
Запуск I2S Трансивера на Artery [часть 2] (DMA, FSM, PipeLine) |
|
5 |
Cross-Detect для Проверки Качества Пайки в Электронных Цепях |
|
6 |
Синтаксический разбор CSV строчек |
|
7 |
Принцип Определения Дальности Между UWB Трансиверами (Конечный Автомат Для DS-TWR) |
|
8 |
H-мост: Load Detect (или как выявлять вандализм) |
|
9 |
Техникум: Конечный Aвтомат Обработки Сигнала с Кнопки |
|
10 |
Техникум: Распознавание Вещественного Числа из Строчки |
|
11 |
Load-Detect для Проверки Качества Пайки |
|
12 |
Задача про две ёмкости для жидкости |
ссылка на оригинал статьи https://habr.com/ru/articles/856548/
Добавить комментарий