Интерфейсная микросхема поддерживает работу с интерфейсом I2C (не путать с I2S!) в режиме MPSSE (Multi-Protocol Synchronous Serial Engine). Кроме I2C данный режим поддерживает целый перечень стандартных последовательных интерфейсов, таких как SPI, JTAG и т. п. Есть возможность реализации собственных интерфейсов в случае необходимости. Данное описание рассказывает о ряде нюансов поддержки интерфейса I2C, а так же дает повод поболтать на смежную тематику.
Дисклэймер: данная статья написана по рабочим материалам и в первую очередь предназначена для автора статьи, когда он потеряет оригинальный документ. В то же время, информация приведенная ниже может быть интересна и узкому кругу специалистов. Не рекомендуется для прочтения широкому кругу читателей кроме случаев, когда тот самый читатель хочет ненадолго погрузиться в мир отладки программно-аппаратных средств. Исследования проводились более года назад, однако указанная информация остается актуальной и в настоящий момент, поскольку библиотеки на сайте производителя не обновлялись. Информация об обнаруженных проблемах отправлялась производителю, однако никакой обратной связи не последовало. Написан пост по мотивам вот этого, за который автору выражается отдельная благодарность
Поддерживается независимая работа двух каналов I2C (один канал для FT232H). Пример схемы включения приведен в AN113 — в качестве примера используется коммуникация между FT2232H и микросхемой энергонезависимой памяти 24LC256. Непосредственно к интерфейсу I2C относятся только два сигнала: SCL (тактовый сигнал, на рисунке обозван SCC) и SDA (передаваемые данные). Согласно спецификации, каждый из этих сигналов может быть двунаправленным, однако часто на шине присутствует только одно ведущее устройство (мастер) и именно оно и задает тактовый сигнал. Данные в любом случае двунапраленные — на каждые 8 бит передаваемых данных следует 1 бит подтверждения.
На программном уровне работа с шиной I2C возможна двумя способами:
Исследования проводились с использованием одной из имеющихся плат. В качестве ведомого устройства на шине I2C использовался измеритель мощности INA219. Поскольку плата была взята та, что оказалась под рукой, между микросхемами FT2232H и INA219 оказалась FPGA (как мне повезло я понял несколько позже). Изначально я планировал ее использовать только для преобразование 3-х проводного интерфейса FT2232H в двухпроводной интерфейс шины I2C — в нормальном устройстве подобное преобразование происходит за счет схемы, см. рисунок выше.
Как уже писалось, при передаче данных на каждые 8 бит передаваемой информации следует подтверждение (ACK) – перевод сигнала в состояние 0 со стороны принимающего устройства. Если передающее устройство видит это подтверждение — значит его услышали и можно продолжать дальше. Если подтверждения нет — значит продолжать дальше бесполезно и обмен можно прекращать.
В процессе исследований было установлено, что библиотека LibMPSSE-I2C имеет ошибку, блокирующую возможность чтения более чем одного байта по шине в большинстве случаев. Ошибка проявляется возникновением глитча на тактовом сигнале перед выставлением подтверждения ACK о первом прочитанном байте со стороны FT2232H на шину. Длина глитча составляет 1 период частоты 12 МГц (порядка 8 нс). Данный глитч воспринимается слэйв-устройством на шине как тактовый сигнал, появляющийся в тот момент, когда признак ACK еще не установлен. После этого слэйв-устройство прерывает транзакцию. Пример подобной транзакции, в рамках которой происходит попытка чтения двух байт из устройства, показан на рисунках (захват данных производился на частоте 120 МГц, глитч присутствует на временных отсчетах 20968-20967). Временные диаграммы получены с использованием встраиваемого логического анализатора SignalTap для альтеровских FPGA (здесь я первый раз порадовался затесавшейся FPGA). На картинках видно, что по линии DI читается первый байт из устройства, далее устройство отваливается (получив некорректное подтверждение от мастера) и вместо второго байта читается 0xFF.
В случае фильтрации данного импульса обеспечивалась правильная процедура чтения по шине. В тестовом окружении фильтрация производилась на FPGA цифровым способом (был написан небольшой модуль на VHDL, отбрасывающий глитчи на входных сигналах). Другой возможный способ — фильтрация с использованием RC-цепочки на шине SCL, однако это ограничит максимальную частоту шины (в виду некоторой маразматичности, глубоко данное решение не анализировалось). Пример успешной транзакции (при условии фильтрации глитча) приведен на следующем рисунке. Теперь по шине DI мы видим корректное чтение двух байт.
Естественно, что хочется добраться до истинных причин такого поведения. К сожалению, исходные коды библиотеки LibMPSSE-I2C недоступны, дизассемблирование бинарников — не наша специализация. Но проанализировать обмен данными по USB при наличии открытого описания протокола — дело 5 минут. Ну часа. Ну уж никак не больше дня.
Детальное исследование показало проблему в формировании команд для контроллера MPSSE, формируемого библиотекой LibMPSSE-I2C. Далее приводится набор команд используемых для чтения 2х байт по шине (стоп-бит в конце не выставляется). Выделенные команды показывают место проблемы и способ решения (запрет перехода в 1 либо изменение фазы подаваемого тактового сигнала для признака ACK):
Таким образом, проблема локализована, решение найдено и все страждущие разделяются на 3 потока:
В процессе исследований создано два тестовых программных проекта, основанных на примерах, поставляемых FTDI. Проект, базирующийся на библиотеке LibMPSSE-I2C имеет название i2c_direct (основной файл i2c_direct.cpp). Проект, программирующий режим MPSSE самостоятельно – I2CTEST (основной файл I2CTEST.cpp). Желающие найдут примеры исходных файлов в архиве типа rarjpeg в первой картинке поста.
Ссылки:
AN108 Command Processor For MPSSE and MCU Host Bus Emulation Modes
AN113 Interfacing FT2232H Hi-Speed Devices To I2C Bus
AN177 User Guide For LibMPSSE-I2C
Example of interface FT2232H Hi-Speed devices to I2C bus (via D2XX)
LibMPSSE-I2C Examples
Дисклэймер: данная статья написана по рабочим материалам и в первую очередь предназначена для автора статьи, когда он потеряет оригинальный документ. В то же время, информация приведенная ниже может быть интересна и узкому кругу специалистов. Не рекомендуется для прочтения широкому кругу читателей кроме случаев, когда тот самый читатель хочет ненадолго погрузиться в мир отладки программно-аппаратных средств. Исследования проводились более года назад, однако указанная информация остается актуальной и в настоящий момент, поскольку библиотеки на сайте производителя не обновлялись. Информация об обнаруженных проблемах отправлялась производителю, однако никакой обратной связи не последовало. Написан пост по мотивам вот этого, за который автору выражается отдельная благодарность
Поддерживается независимая работа двух каналов I2C (один канал для FT232H). Пример схемы включения приведен в AN113 — в качестве примера используется коммуникация между FT2232H и микросхемой энергонезависимой памяти 24LC256. Непосредственно к интерфейсу I2C относятся только два сигнала: SCL (тактовый сигнал, на рисунке обозван SCC) и SDA (передаваемые данные). Согласно спецификации, каждый из этих сигналов может быть двунаправленным, однако часто на шине присутствует только одно ведущее устройство (мастер) и именно оно и задает тактовый сигнал. Данные в любом случае двунапраленные — на каждые 8 бит передаваемых данных следует 1 бит подтверждения.
На программном уровне работа с шиной I2C возможна двумя способами:
- Непосредственно через драйвер D2XX. В этом случае необходимо производить ручное программирование режима MPSSE в соответствии с набором команд, описанных в AN108. Вся работа идет через функции FT_Read() и FT_Write(), а так же сопутствующие функции открытия/закрытия устройства и т.п.
- С использованием библиотеки LibMPSSE-I2C. Данная библиотека решает все вопросы программирования режима MPSSE и позволяет производить операции чтения и записи указанного числа байт по шине I2C с использованием вызовов I2C_DeviceWrite() и I2C_DeviceRead(). Описание библиотеки приведено в AN177.
Исследования проводились с использованием одной из имеющихся плат. В качестве ведомого устройства на шине I2C использовался измеритель мощности INA219. Поскольку плата была взята та, что оказалась под рукой, между микросхемами FT2232H и INA219 оказалась FPGA (как мне повезло я понял несколько позже). Изначально я планировал ее использовать только для преобразование 3-х проводного интерфейса FT2232H в двухпроводной интерфейс шины I2C — в нормальном устройстве подобное преобразование происходит за счет схемы, см. рисунок выше.
Как уже писалось, при передаче данных на каждые 8 бит передаваемой информации следует подтверждение (ACK) – перевод сигнала в состояние 0 со стороны принимающего устройства. Если передающее устройство видит это подтверждение — значит его услышали и можно продолжать дальше. Если подтверждения нет — значит продолжать дальше бесполезно и обмен можно прекращать.
В процессе исследований было установлено, что библиотека LibMPSSE-I2C имеет ошибку, блокирующую возможность чтения более чем одного байта по шине в большинстве случаев. Ошибка проявляется возникновением глитча на тактовом сигнале перед выставлением подтверждения ACK о первом прочитанном байте со стороны FT2232H на шину. Длина глитча составляет 1 период частоты 12 МГц (порядка 8 нс). Данный глитч воспринимается слэйв-устройством на шине как тактовый сигнал, появляющийся в тот момент, когда признак ACK еще не установлен. После этого слэйв-устройство прерывает транзакцию. Пример подобной транзакции, в рамках которой происходит попытка чтения двух байт из устройства, показан на рисунках (захват данных производился на частоте 120 МГц, глитч присутствует на временных отсчетах 20968-20967). Временные диаграммы получены с использованием встраиваемого логического анализатора SignalTap для альтеровских FPGA (здесь я первый раз порадовался затесавшейся FPGA). На картинках видно, что по линии DI читается первый байт из устройства, далее устройство отваливается (получив некорректное подтверждение от мастера) и вместо второго байта читается 0xFF.
В случае фильтрации данного импульса обеспечивалась правильная процедура чтения по шине. В тестовом окружении фильтрация производилась на FPGA цифровым способом (был написан небольшой модуль на VHDL, отбрасывающий глитчи на входных сигналах). Другой возможный способ — фильтрация с использованием RC-цепочки на шине SCL, однако это ограничит максимальную частоту шины (в виду некоторой маразматичности, глубоко данное решение не анализировалось). Пример успешной транзакции (при условии фильтрации глитча) приведен на следующем рисунке. Теперь по шине DI мы видим корректное чтение двух байт.
Естественно, что хочется добраться до истинных причин такого поведения. К сожалению, исходные коды библиотеки LibMPSSE-I2C недоступны, дизассемблирование бинарников — не наша специализация. Но проанализировать обмен данными по USB при наличии открытого описания протокола — дело 5 минут. Ну часа. Ну уж никак не больше дня.
Детальное исследование показало проблему в формировании команд для контроллера MPSSE, формируемого библиотекой LibMPSSE-I2C. Далее приводится набор команд используемых для чтения 2х байт по шине (стоп-бит в конце не выставляется). Выделенные команды показывают место проблемы и способ решения (запрет перехода в 1 либо изменение фазы подаваемого тактового сигнала для признака ACK):
0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, // SDA, SCL high
0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, // SDA low: START
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x00, 0x13, // SDA, SCL low
0x80, 0x02, 0x13, // SDA high, SCL low
0x13, 0x07, 0x81, // Write address
0x80, 0x00, 0x11, // SDA, SCL low
0x22, 0x00, // Read ACK from slave
0x80, 0x00, 0x11, // SDA, SCL low
0x22, 0x07, // Read 8 bits
0x80, 0x02, 0x13, // SDA high, SCL low
//0x80, 0x00, 0x13, // Optional fix (use instead prev. command) to avoid SDA to go High
//0x12, 0x00, 0x00, // Write 1 bit: ACK - error here in LibMPSSE-I2C
0x13, 0x00, 0x00, // Write 1 bit: ACK - fixed version *************************************
0x80, 0x00, 0x11,
0x22, 0x07,
0x80, 0x02, 0x13,
0x12, 0x00, 0x00
Таким образом, проблема локализована, решение найдено и все страждущие разделяются на 3 потока:
- Общаются с FTDI на предмет описанного выше в ожидании разъяснений.
- Дизассемблируют-таки бинарную библиотеку в поисках того места, где формируются соответствующие команды и правят ее.
- Пишут без использования библиотеки LibMPSSE-I2C, напрямую посылая управляющие последовательности подобные приведенным выше, тем самым программируя режим MPSSE в обход библиотеки.
В процессе исследований создано два тестовых программных проекта, основанных на примерах, поставляемых FTDI. Проект, базирующийся на библиотеке LibMPSSE-I2C имеет название i2c_direct (основной файл i2c_direct.cpp). Проект, программирующий режим MPSSE самостоятельно – I2CTEST (основной файл I2CTEST.cpp). Желающие найдут примеры исходных файлов в архиве типа rarjpeg в первой картинке поста.
Ссылки:
AN108 Command Processor For MPSSE and MCU Host Bus Emulation Modes
AN113 Interfacing FT2232H Hi-Speed Devices To I2C Bus
AN177 User Guide For LibMPSSE-I2C
Example of interface FT2232H Hi-Speed devices to I2C bus (via D2XX)
LibMPSSE-I2C Examples