Multi Protocol Synchronous Serial Engine (MPSSE) это аппаратура, которая реализована на кристалле некоторых чипов FTDI. Она позволяет им реализовать такие синхронные последовательные интерфейсы, как I2C, SPI или JTAG, с которыми можно обмениваться данными через USB. В настоящий момент MPSSE доступна на кристаллах FT2232D, FT2232H, FT4232H и FT232H, которые подключаются к хосту управления (обычно это компьютер PC, подключенный к чипу FTDI через USB. Приложения PC или какой-либо встраиваемой системы обмениваются данными с MPSSE в этих чипах через драйверы D2XX USB [4].
MPSSE принимает различные команды для вывода данных из чипов в различных форматах, а именно I2C, SPI и JTAG. Библиотека libMPSSE предоставляет удобный для программиста API-интерфейс, позволяющий написать приложения для обмена с устройствами I2C/SPI/JTAG без необходимости глубокого понимания устройства системы MPSSE и изучения её команд. Однако если пользователю это необходимо, то он может изучить работу MPSSE и использовать её возможности напрямую с помощью вызова функций D2XX.
Рис. 1. Программный и аппаратный стек, через который проходит поток данных стандартных протоколов (I2C, SPI или JTAG).
Как показано на рис. 1, у библиотеки libMPSSE есть 3 разных вида API, каждый предназначен для I2C, SPI и JTAG. Этот документ (перевод даташита AN_178 [1]) рассматривает только SPI. Примеры кода, использующего libMPSSE (версии для Linux и Windows), замечания по релизу и все необходимые файлы можно загрузить с сайта FTDI по ссылке [3] (также см. [2]).
[Обзор системы]
Рис. 2. Общая организация системы.
На рис. 2 показан базовая структура системы реализации интерфейса SPI с помощью чипов FTDI и libMPSSE. Устройством PC/Host (хост приложения) может быть компьютер PC, устройство Android или какая-либо встраиваемая система. Чип FTDI и устройство SPI обычно размещаются на одной печатной плате, или соединяются друг с другом коротким кабелем. На рисунке показано только одно внешнее устройство SPI, однако к каждому блоку MPSSE может быть подключено до 5 устройств SPI.
[Интерфейс программирования (API)]
Функции libMPSSE-SPI API можно поделить на 2 больших набора. Первый состоит из 6 функций управления (control API), и второй содержит 2 набора API-функций для перемещения данных. Все API-функции возвращают значения кодов из перечисления FT_STATUS, как они определены в драйвере D2XX.
Примечание: описание структуры используемых в API структур и типах данных см. в разделе "Типы данных". Некоторые структуры см. в руководстве программирования драйвера D2XX [4].
Функции SPI. Ниже во врезках описаны функции SPI, которые позволяют аппаратно формировать сигналы SPI для чтения и записи данных при обмене с подчиненным устройством SPI (SPI slave).
Получает количество каналов SPI (портов), подключенных к системе хоста. Количество доступных портов может различаться для каждого чипа.
Параметры:
numChannels [out] Количество доступных для хоста каналов.
Чип FTDI представляет собой аппаратный мост между интерфейсом USB и внешним миром, и у него на борту есть несколько каналов для работы в режиме SPI. Однако не все эти каналы могут быть сконфигурированы как SPI master. Эта функция вернет общее количество каналов, которое может быть сконфигурировано как SPI. Например, если к компьютеру подключено сразу чипы FT2232D (1 порт MPSSE), FT232H (1 порт MPSSE), FT2232H (2 порта MPSSE) и FT4232H (2 порта MPSSE), то вызов SPI_GetNumChannels вернет 6 в переменной *numChannels.
Предупреждение: эта функция не должна вызываться из двух приложений или из двух потоков одновременно.
Эта функция принимает индекс канала (допустимы значения от 0 до значения, которое вернула SPI_GetNumChannels минус 1) и предоставляет информацию о канале в форме заполненной структуры FT_DEVICE_LIST_INFO_NODE.
Параметры:
index [in] Индекс опрашиваемого канала. chanInfo [out] Указатель на структуру FT_DEVICE_LIST_INFO_NODE.
Эта функция должна вызываться только после успешного вызова SPI_GetNumChannels.
Предупреждение: эта функция не должна вызываться из двух приложений или из двух потоков одновременно.
Функция откроет канал по указанному индексу и предоставит дескриптор для него (handle). Для индекса допустимы значения от 0 до значения, которое вернула SPI_GetNumChannels минус 1. Дескриптор используется для дальнейшей работы с этим каналом.
Параметры:
index [in] Индекс канала. handle [out] Указатель на ячейку памяти типа FT_HANDLE, куда будет записан дескриптор.
Если будет сделана попытка открыть уже открытый канал, то функция вернет код ошибки.
Функция инициализирует канал параметрами коммуникации.
Параметры:
handle [in] Дескриптор канала. config [in] Указатель на заполненную структуру с обновляемыми значениями для тактовой частоты и таймера задержки (latency timer).
Эта функция выполняет все необходимые действия по установке рабочего состояния канала, такие как сброс и разрешение работы MPSSE.
Функция прочитает указанное количество бит или байт (в зависимости от параметра transferOptions) из устройства SPI slave (подчиненное устройство шины SPI).
Параметры:
handle [in] Дескриптор канала. buffer [out] Указатель на буфер, куда должны быть помещены прочитанные данные. sizeToTransfer [in] Количество байт или бит, которые должны быть прочитаны. sizeTransferred [out] Указатель на ячейку, куда будет записано количество прочитанных байт или бит. transferOptions [in] Этот параметр задает опции транзакции данных. Позиции бит для этих опций следующие:
BIT0: если 1, то sizeToTransfer указывает количество бит, иначе количество байт. Маски для этого бита определены константами SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES и SPI_TRANSFER_OPTIONS_SIZE_IN_BITS. BIT1: если 1, то ножка выборки (chip select) сгенерирует сигнал активности перед началом транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE. BIT2: если 1, то ножка выборки снимет сигнал активности по окончанию транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE. BIT3 .. BIT31: зарезервированы.
Это блокирующая функция, которая не выполнит возврат из неё, пока не будет прочитано указанное количество данных, или пока не произойдет ошибка.
Функция запишет указанное количество бит или байт (в зависимости от параметра transferOptions) в устройство SPI slave (подчиненное устройство шины SPI).
Параметры:
handle [in] Дескриптор канала. buffer [in] Указатель на буфер, откуда должны быть взяты записываемые данные. sizeToTransfer [in] Количество байт или бит, которые должны быть записаны. sizeTransferred [out] Указатель на ячейку, куда будет записано количество записанных байт или бит. transferOptions [in] Этот параметр задает опции транзакции данных. Позиции бит для этих опций следующие:
BIT0: если 1, то sizeToTransfer указывает количество бит, иначе количество байт. Маски для этого бита определены константами SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES и SPI_TRANSFER_OPTIONS_SIZE_IN_BITS. BIT1: если 1, то ножка выборки (chip select) сгенерирует сигнал активности перед началом транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE. BIT2: если 1, то ножка выборки снимет сигнал активности по окончанию транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE. BIT3 .. BIT31: зарезервированы.
Это блокирующая функция, которая не выполнит возврат из неё, пока не будет передано указанное количество данных, или пока не произойдет ошибка.
Эта функция выполняет одновременное чтение и запись при обмене с устройством SPI slave. Т. е. при каждом такте вводится и выводится один бит данных.
Параметры:
handle [in] Дескриптор канала. inBbuffer [in] Указатель на буфер, куда должны быть записаны считываемые данные. outBbuffer [out] Указатель на буфер, откуда должны быть взяты записываемые данные. sizeToTransfer [in] Количество байт или бит, которые должны быть записаны. sizeTransferred [out] Указатель на ячейку, куда будет записано количество записанных байт или бит. transferOptions [in] Этот параметр задает опции транзакции данных. Позиции бит для этих опций следующие:
BIT0: если 1, то sizeToTransfer указывает количество бит, иначе количество байт. Маски для этого бита определены константами SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES и SPI_TRANSFER_OPTIONS_SIZE_IN_BITS. BIT1: если 1, то ножка выборки (chip select) сгенерирует сигнал активности перед началом транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE. BIT2: если 1, то ножка выборки снимет сигнал активности по окончанию транзакции. Маска для этого бита определена в SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE. BIT3 .. BIT31: зарезервированы.
Это блокирующая функция, которая не выполнит возврат из неё, пока не будет передано указанное количество данных, или пока не произойдет ошибка.
Эта функция опрашивает состояние линии MISO без выдачи тактов на шину SPI.
Для некоторых приложений требуется, чтобы SPI master опрашивал состояние сигнала MISO (Master Input Slave Output) без генерации тактов, чтобы определить, завершило ли устройство SPI slave предыдущую операцию, чтобы быть готовым к следующей операции. Для этой цели походит функция SPI_IsBusy.
Параметры:
handle [in] Дескриптор канала. state [out] Указатель на переменную, куда будет записано состояние MISO.
Функция изменит состояние сигнала выборки, который используется для обмена с устройством SPI slave.
Параметры:
handle [in] Дескриптор канала. configOptions [in] В этом параметре указывается способ генерации сигнала выборки (chip select) и выбирается один из четырех режимов (SPI mode). Тот же самый параметр в ChannelConfig.configOptions передается в функцию SPI_InitChannel. Подробно эти опции описаны в секции "Типы данных", см. описание структуры ChannelConfig.
Функции GPIO. Каждый канал MPSSE в чипе FTDI снабжен портом ввод/вывода общего назначения (General Purpose Input/Output, GPIO), у которого есть 8 линий, дополняющих синхронный последовательный обмен данныхми. Например, у чипа FT232H есть только один канал MPSSE с двумя 8-битными портами ADBUS и ACBUS. Из них ADBUS используется для синхронного последовательного обмена (I2C/SPI/JTAG), и ACBUS свободен для использования в качестве GPIO. Две описанные ниже функции предоставлены для доступа к этим линиям GPIO (также они называются старшим байтом линий MPSSE), которые доступны в различных чипах FTDI с блоками MPSSE.
Функция запишет данные в 8 линий GPIO, связанных со старшим байтом канала MPSSE.
Параметры:
handle [in] Дескриптор канала. dir [in] Каждый бит в этом байте представляет направление соответствующих линий GPIO. 0 задает вход, 1 выход. value [in] Если направление ножки порта GPIO настроено на выход, то соответствующий бит этого байта установит уровень этой ножки порта в заданное состояние. 0 установит выход в лог. 0, и 1 в лог. 1.
Функция прочитает состояние 8 линий GPIO, связанных со старшим байтом канала MPSSE.
Параметры:
handle [in] Дескриптор канала. value [out] Если направление ножки порта GPIO настроено на вход, то соответствующий бит этого байта покажет уровень на этой ножке порта. 0 означает что на входе лог. 0, и 1 означает на входе лог. 1.
Примечание: перед использованием функции FT_ReadGPIO необходимо вызвать функцию FT_WriteGPIO, где будет настроено направление работы 8 ножек портов GPIO.
Функции библиотечной инфраструктуры. Следующие 2 функции обычно не нужно вызывать в приложениях пользователя, поскольку они автоматически вызываются во время входа/выхода. Однако эти функции не будут вызваны автоматически, когда библиотека линкована статически с использованием Microsoft Visual C++. В этом случае они должны быть явно вызваны из приложений пользователя. Пример статической линковки, предоставленный в этом руководстве, использует макрос, который проверят, компилируется ли код с использованием тулчейна Microsoft, и если это так, то он автоматически вызовет эти функции.
ChannelConfig это структура, которая хранит параметры, используемые для инициализации канала.
/* Структура, содержащая информацию о конфигурации канала SPI. Она заполняется
в приложении пользователя во время инициализации канала, затем сохраняется
в связанный список и используется внутри других функций SPI при выполнении
их операций. Эта структура удаляется из списка, когда приложение пользователя
вызовет SPI_CloseChannel. */
typedefstruct ChannelConfig_t
{
DWORD ClockRate; /* частота тактов SPI, должно быть меньше или равна 30000000 */
UCHAR LatencyTimer; /* значение в миллисекундах, значение должно быть меньше
или равно 255 */
DWORD configOptions;/* Это поле предоставляет способ разрешить/запретить
отдельные функции, связанные с протоколом, как он
реализован в микросхеме.
BIT1-0=CPOL-CPHA: 00 - MODE0 - data captured on rising edge, propagated on falling
01 - MODE1 - data captured on falling edge, propagated on rising
10 - MODE2 - data captured on falling edge, propagated on rising
11 - MODE3 - data captured on rising edge, propagated on falling
BIT4-BIT2: 000 - A/B/C/D_DBUS3 = ChipSelect
: 001 - A/B/C/D_DBUS4 = ChipSelect
: 010 - A/B/C/D_DBUS5 = ChipSelect
: 011 - A/B/C/D_DBUS6 = ChipSelect
: 100 - A/B/C/D_DBUS7 = ChipSelect
BIT5: для ChipSelect активный уровень 1, если этот бит равен 0
ClockRate. Этот параметр принимает значение тактовой частоты SPI в Гц. Допустимы значения от 0 до 30 МГц.
LatencyTimer. Требуемое значение в миллисекундах для таймера задержки (latency timer), допустимый диапазон 0 .. 255. Однако FTDI рекомендует следующие значения для latency timer:
2 .. 255 Для полноскоростных (full speed) устройств (FT2232D). 1 .. 255 Для высокоскоростных (full speed) устройств (FT232H, FT2232H, FT4232H).
configOptions. В таблице ниже описано назначение бит этого поля.
№ бит
Описание
Знач.
Назначение
Макрос (если он есть)
1 .. 0
Эти биты задают один из стандартных режимов SPI (описание режимов см. в [5]), которые можно настроить для SPI master.
00
SPI MODE0
SPI_CONFIG_OPTION_MODE0
01
SPI MODE1
SPI_CONFIG_OPTION_MODE1
10
SPI MODE2
SPI_CONFIG_OPTION_MODE2
11
SPI MODE3
SPI_CONFIG_OPTION_MODE3
4 .. 2
Эти биты определяют, какие линии должны использоваться для сигнала выборки SPI (chip select, CS).
000
xDBUS3
SPI_CONFIG_OPTION_CS_DBUS3
001
xDBUS4
SPI_CONFIG_OPTION_CS_DBUS4
010
xDBUS5
SPI_CONFIG_OPTION_CS_DBUS5
011
xDBUS6
SPI_CONFIG_OPTION_CS_DBUS6
100
xDBUS7
SPI_CONFIG_OPTION_CS_DBUS7
5
Этот бит задает, должен ли быть активным лог. 0 для сигнала выборки.
0
Активный уровень лог. 1
SPI_CONFIG_OPTION_CS_ACTIVEHIGH
1
Активный уровень лог. 0
SPI_CONFIG_OPTION_CS_ACTIVELOW
31..6
Зарезервировано
Примечание: xDBUS0 .. xDBUS7 соответствуют линиям ADBUS0 .. ADBUS7, если используется первый канал MPSSE, иначе линиям BDBUS0 .. BDBUS7, если используется второй канал (конечно, если он доступен для этого чипа).
Режимы SPI:
SPI MODE0 - данные захватываются по фронту нарастания уровня сигнала тактов, выводятся по спаду уровня сигнала тактов. SPI MODE1 - данные захватываются по спаду уровня сигнала тактов, выводятся по фронту нарастания уровня сигнала тактов. SPI MODE2 - данные захватываются по спаду уровня сигнала тактов, выводятся по фронту нарастания уровня сигнала тактов. SPI MODE3 - данные захватываются по фронту нарастания уровня сигнала тактов, выводятся по спаду уровня сигнала тактов.
Поробнее про режимы SPI см. Википедию или [5].
Pins. Это поле задает направления и значения линий, связанных с младшим байтом канала MPSSE после того, как вызываны SPI_InitChannel и SPI_CloseChannel.
№ бит
Описание
Комментарий
7 .. 0
Направление линий после того, как была вызвана SPI_InitChannel.
Лог. 1 соответствует выходу, и лог. 0 входу.
15 .. 8
Состояния линий после того, как была вызвана SPI_InitChannel.
Лог. 1 соответствует лог. 1 на выходе, лог. 0 соответствует лог. 0 на выходе.
23 .. 16
Направление линий после того, как была вызвана SPI_CloseChannel.
Лог. 1 соответствует выходу, и лог. 0 входу.
31 .. 24
Состояния линий после того, как была вызвана SPI_CloseChannel.
Лог. 1 соответствует лог. 1 на выходе, лог. 0 соответствует лог. 0 на выходе.
Обратите внимание, что направления сигналов SCLK, MOSI и указнного сигнала выборки будут перезаписаны в 1, и направление MISO подобным образом будет перезаписано в 0, независимо от значений, которые были переданы из приложения пользователя. Остальные 4 линии будут настроены в соответствии с этим параметром.
reserved. Это поле зарезервировано и не должно использоваться.
[Пример использования]
Этот пример демонстрирует, как подключить FT2232H к устройству SPI (микросхема EEPROM-памяти 93LC56B), и как её программировать с использованием библиотеки libMPSSE-SPI.
Рис. 3. Схема подключения FT2232H к SPI EEPROM 93LC56B.
Обратите внимание, что чип FT2232H может быть доступен на готовом модуле (например [6]), который содежит все компоненты схемы на рис. 3, кроме микросхемы 93LC56B и подключенных к ней верхних подтягивающих резисторов (pull-up). Чип FT2232H работает как SPI master, подключенный к PC через интерфейс USB.
Пример программы. В системе должен быть установлен требуемый драйвер D2XX (это зависит от используемой операционной системы [3]). Если используется Linux PC, то должны быть удалены драйверы по умолчанию usbserial и ftdi_sio (с помощью команды rmmod).
Как только схема, показанная на рис. 3, подключена к PC, и установлены соответствующие драйверы, мы можем поместить код следующего примера (sample-static.c), файлы D2XX.h, libMPSSE_spi.h и библиотеку libMPSSE.a в одну из папок. После этого скомпилируйте и запустите пример.
status = SPI_GetNumChannels(&channels);
APP_CHECK_STATUS(status);
printf("Number of available SPI channels = %d\n", channels);
if(channels>0)
{
for(i=0; i < channels; i++)
{
status = SPI_GetChannelInfo(i, &devList);
APP_CHECK_STATUS(status);
printf("Information on channel number %d:\n", i);
/* Печать информации об устройстве */
printf(" Flags=0x%x\n", devList.Flags);
printf(" Type=0x%x\n", devList.Type);
printf(" ID=0x%x\n", devList.ID);
printf(" LocId=0x%x\n", devList.LocId);
printf(" SerialNumber=%s\n", devList.SerialNumber);
printf(" Description=%s\n", devList.Description);
// ftHandle == 0, если канал не открыт:
printf(" ftHandle=0x%x\n", devList.ftHandle);
}
/* Открытие первого доступного канала */
status = SPI_OpenChannel(CHANNEL_TO_OPEN, &ftHandle);
APP_CHECK_STATUS(status);
printf("\nhandle=0x%x status=0x%x\n", ftHandle, status);
status = SPI_InitChannel(ftHandle, &channelConf);
APP_CHECK_STATUS(status);
Показанная выше программа выполняет запись данных в микросхему EEPROM по адресам 0 .. 15. Записываемое значение генерируется из адреса +3, например если адрес 5, то по этому адресу записывается значение 8. Когда этот пример программы компилируется и запускается, мы должны увидеть следующий вывод:
Пример кода, который можно скачать по ссылке [3], рассчитан на современную версию Visual Studio (не менее 2019). Чтобы его скомпилировать в среде Visual Studio 2010 Ultimate, мне пришлось немного повозиться. Ниже описан процесс по шагам.
1. Установите Visual Studio 2010 Ultimate.
2. Создайте проект Visual C++ -> Консольное приложение Win32.
4. Создайте главный модуль исходного кода по аналогии с примером из AN_178 (*.cpp, см. врезку выше).
5. Добавьте в проект модуль ftdi_infra.c из архива LibMPSSE_1.0.3.zip, предварительно переименовав его в *.cpp.
6. Оберните в комментарий префикс FTDIMPSSE_API у функций из ftdi_infra.cpp.
7. Распакуйте библиотеку libmpsse-windows-1.0.3.zip\release\build\Win32\libmpsse.lib в директорию проекта. Добавьте её в проект перетаскиванием в корень дерева проекта.
8. Настройте в проекте пути до подключения нужных заголовков.
9. Скомпилируйте проект.
10. Распакуйте libmpsse-windows-1.0.3.zip\release\build\Win32\libmpsse.dll в каталог, где находится *.exe файл компилируемого проекта (обычно по умолчанию это папка Debug).