Микросхемы FT2232H и FT4232H это первые микросхемы UART/FIFO компании FTDI, реализующие высокоскоростное подключение к USB (USB 2.0 Hi-Speed) на максимальной скорости 480 мегабит/сек). Эти микросхемы также могут быть сконфигурированы для реализации различных последовательных интерфейсов с использованием внутренней системы MPSSE (Multi-Protocol Synchronous Serial Engine). У FT2232H [2] имеется 2 независимых порта, и они оба могут быть сконфигурированы для использования MPSSE. У микросхемы FT4232H имеется 4 независимых порта, однако только канал A и канал B этой микросхемы могут быть сконфигурированы для использования MPSSE.
Микросхема FT232H, представленная в 2011 году, построена на основе семейства FTDI Hi-Speed USB. У FT232H есть один порт UART/FIFO IC и только один интерфейс MPSSE, как и несколько новых режимов.
Использование MPSSE может упростить использование синхронных последовательных протоколов (для применения в разработке преобразования USB в SPI, I2C, JTAG, и т. п.). В этом апноуте (перевод [1]) рассматривается аппаратура и программное обеспечение, требуемая для эмуляции подключения к цепочке тестирования JTAG TAP микросхемы SN74BCT8244A (8-разрядный буфер) с помощью FT2232H. Пользователи могут взять показанный пример схемы и функциональный код программного обеспечения, чтобы начать на этой основе свою собственную разработку. Имейте в виду, что приведенный листинг программного кода дан только как иллюстрация принципа работы с JTAG для пограничного тестирования (Boundary Scan), и этот код не поддерживается компанией FTDI. FT232H и FT4232H также могут быть использованы вместе с примером, показанном в этом апноуте, хотя разводка выводов и выбор порта должен подходить к соответствующей микросхеме.
В этом приложении также удвоены ожидаемые для SN74BCT8244A интервалы времени JTAG, чтобы доказать функционирование примера.
[Введение в FTDI MPSSE]
Multi-Protocol Synchronous Serial Engine (MPSSE) это функция определенных клиентских микросхем FTDI, которая позволяет эмулировать несколько синхронных последовательных протоколов, включая SPI, I2C и JTAG.
Один блок MPSSE доступен в микросхеме FT2232D, клиентском устройстве Full-Speed USB 2.0. FT2232D может осуществлять синхронный последовательный обмен данными на скорости до 6 Mbps (6 мегабод).
Как уже упоминалось, в микросхемах FT2232H и FT4232H имеется по 2 блока MPSSE, и обе эти микросхемы являются клиентскими устройствами Hi-Speed USB 2.0. Каждый из блоков MPSSE может осуществлять синхронный обмен данными на скорости до 30 Mbps (30 мегабод). MPSSE в FT2232H и FT4232H предоставляют новые команды для дополнительных режимов тактирования, что используется в режиме интерфейса CPU и синхронном режиме FIFO (параллельная шина). FT232H содержит один блок MPSSE, синхронный CPU FIFO и новые режимы чипа FT1248. Дополнительную информацию про эти новые режимы см. в апноуте AN_135 (базовая информация про MPSSE) и AN_167 (базовая информация про динамический параллельный/последовательный интерфейс чипа FT1248).
В этом апноуте описано использование MPSSE для эмуляции интерфейса JTAG. Здесь есть много ссылок на апноут AN_108 (описание командного процессора блока MPSSE и режимов эмуляции шины хоста MCU), который также доступен на сайте FTDI.
[Что такое JTAG]
Современные электронные устройства состоят из большого количества сложных интегральных схем. Обычная встраиваемая система может содержать в себе несколько процессоров (CPU), программируемых устройств, микросхемы памяти и т. п. При такой сложности часть невозможно проверять и тестировать функциональность имеющегося дизайна.
В 1990 году институт инженеров электричества и электроники (Institute of Electrical and Electronics Engineers, IEEE) ратифицировала стандарт 1149.1, который был разработан организацией Joint Test Action Group (JTAG). Этот стандарт определил основной смысл реализации технологии пограничного сканирования (boundary-scan), предназначенной для проверки функциональности интегральных схем. Технология позволяет устройствам от разных вендоров быть предоставленными в одной цепочке тестирования, чтобы предоставить доступ ко всем их выводам входов и выходов (I/O). Вместе с использованием дополнительного оборудования, такого как матрицы щупов, стало возможным делать полную проверку всей схемы электронного устройства в процессе производства. Технологию пограничного тестирования IEEE 1149.1 часто называют "стандартом JTAG". Многие опубликованные документы и статьи взаимозаменяемо используют эти термины.
IEEE 1149.1 в последний раз был обновлен в 2001 году. Дополнение стандартов IEEE 1149.1 предоставляет такие возможности, как проверку аналоговых схем в дополнение к тесту цифровых схем. Вот эти дополнительные стандарты: 1149.4 - Analog Boundary Scan (аналоговое пограничное сканирование), 1149.6 - Advanced I/O (усовершенствованный ввод/вывод) и 1532 - In System Configuration (конфигурирование внутри системы). Последний стандарт обычно используется для программируемых устройств памяти и конфигурирования программируемой логики, такой как микросхемы FPGA и CPLD.
JTAG (IEEE 1149.1) определяет синхронную машину состояний, в которой 16 состояний, как показано на рис. 1.1.
Рис. 1.1. IEEE 1149.1 (JTAG) state machine.
К схеме пограничного сканирования осуществляется доступ через контроллер TAP (сокращение от Test Access Port, порт доступа к тестированию) со специально определенными, обязательными сигналами ввода/вывода: Test Clock (TCK) - вход для поступление тактов машины состояний, Test Mode Select (TMS) - вход, используемый для навигации по состояниям машины, Test Data In (TDI) - вход, на который поступают последовательные данные или инструкции и Test Data Out (TDO) - выход, содержащий последовательные данные или инструкции. Контроллер TAP может предоставлять опциональный (не обязательный) пятый сигнал Test Reset (TRST#) - это вход, на который подается асинхронный сброс (импульсом лог. 0), который принудительно переводит машину в состояние Test-Logic-Reset. Важно заметить, что даже без сигнала TRST# машину состояний всегда можно перевести в Test-Logic-Reset из любого другого состояния путем удерживания TMS в лог. 1 для максимального количества из 5 тактовых импульсов.
Рис. 1.2. Цепочка TAP IEEE 1149.1 (JTAG).
Как показано на рис. 1.2, устройства в цепочке JTAG используют общие сигналы TCK и TMS. Это принудительно переводит машины состояний всех устройств в одинаковое состояние. Мастер-контроллер JTAG подключает свой выход данных к сигналу TDI. Каждое устройство в цепочке подключает свой вход TDI к сигналу TDO предыдущего устройства. И наконец, последнее устройство в цепочке подключает свой выходной сигнал TDO ко входу данных мастер-контроллера. Также возможны и другие схемы соединения, что выходит за рамки рассмотрения этого апноута.
IEEE 1149.1 идентифицирует переходы между состояниями по логическому уровню TMS в моменты фронта сигнала тактов TCK. Загрузка регистров инструкции и данных в TAP, как и последовательный ввод данных в TDI и вывод из TDO, происходит по фронту нарастания уровня на сигнале тактов TCK. Спад уровня TCK используется для защелкивания данных ответов в доступные регистры устройства пограничного сканирования. Регистры в каждом JTAG TAP имеют разную ширину. Важно поддерживать уровень TMS, пока данные вдвигаются в регистры и выдвигаются из них.
SN74BCT8244A содержит следующие регистры JTAG TAP:
Таблица 1.1. Регистры JTAG TAP буфера SN74BCT8244.
Регистр |
Размер |
Instruction |
8 бит |
Boundary-Scan |
18 бит |
Boundary-Scan Control |
2 бита |
Bypass |
1 бит |
Если в цепочке TAP имеется несколько устройств, то каждый тип регистра в них может быть разной длины для каждого устройства. Это должна учитывать управляющая программа мастера JTAG. Всего есть 6 состояний по всей диаграмме состояний JTAG, которые разработаны, чтобы снабдить различные устройства разными длинами регистров. Согласно рис. 1.1 это состояния Test-Logic-Reset, Run-Test-Idle, Shift-DR, Pause-DR, Shift-IR и Pause-IR. Удержание TMS в подходящем уровне переводит машину в нужное состояние, пока требуемые биты вдвигаются во все регистры всех устройств цепочки TAP.
[Пример схемы JTAG]
Здесь показана простая микросхема SN74BCT8244A с блоком JTAG TAP компании Texas Instruments (www.ti.com). Это устройство содержит 8-битный буфер с двумя выводами разрешения выхода и JTAG TAP для предоставления тестирования по методу пограничного сканирования. Для этого примера использовался FT2232H Mini Module, подключенный по схеме на рис. 2.1. Подробную информацию про подключение USB и питания можно найти в даташите на микросхему FT2232H [2], даташите на плату FT2232H Mini-Module или даташите на модуль DLP-USB1232H. Также можно использовать плату FT2232H Board [4].
Рис. 2.1. Пример тестовой схемы, где для JTAG используется FT2232H.
При использовании MPSSE четыре вывода FT2232H определены для синхронного последовательного интерфейса. В дополнение к самой микросхеме FT2232H, в таблице ниже перечислены соответствующие выводы двух модулей, где применена микросхема FT2232H.
Таблица 2.1. Подключение FT2232H для организации JTAG.
Функция JTAG |
FT2232H, Port A, номер вывода |
FT2232H Mini Module, номер вывода |
DLP-USB1232H, номер вывода |
TCK (выход) |
16 (ADBUS0) |
CN2-7 (ADBUS0) |
18 (ADBUS0) |
TDI (выход) |
17 (ADBUS1) |
CN2-10 (ADBUS1) |
16 (ADBUS1) |
TDO (вход) |
18 (ADBUS2) |
CN2-9 (ADBUS2) |
2 (ADBUS2) |
TMS (выход) |
19 (ADBUS3) |
CN2-12 (ADBUS3) |
5 (ADBUS3) |
Имена TDI и TDO для мастер-контроллера выглядят, как не подходящие его входу и выходу; однако, это корректные имена сигналов, соответствующие входу и выходу JTAG TAP. Входные выводы SN74BCT8244A внутри этой микросхемы подтянуты к лог. 1. Для этой схемы примера они остаются не подключенными, что фиксирует входной уровень как лог. 1, и переводит выходы в третье состояние.
Для этого апноута к SN74BCT8244A подключен Port A микросхемы FT2232H. С микросхемами FT2232H и FT4232H вместо Port A может использоваться Port B. Совместно с модификацией подключения выводов Port B, управляющая программа приложения (см. ниже) также потребует модификацию, чтобы для доступа использовался блок MPSSE порта B.
Сигнал TRST# предоставляется микросхемой SN74BCT8244A; однако он требует входного уровня 10V на выводе TMS. Для упрощения схемы в этом примере TRST# не реализован. Обратите внимание, что при использовании TAP со стандартным напряжением I/O для этой функции может использоваться один из не использованных выводов GPIO микросхемы FT2232H.
FT2232H требует VCCIO = 3.3V, хотя её входы допускают уровни логики 5V (5V tolerant). Поэтому допустимо напрямую подключить FT2232H к SN74BCT8244A, которая получает питание 5V. Изучение обоих даташитов на эти микросхемы показывает, что пороги уровней лог. 1 и лог. 0 удовлетворяются, как и не будут превышены максимально допустимые напряжения.
[Пример программы для управления JTAG на FT2232H]
В этой программе в 2 раза увеличены интервалы времени, которые были даны в примере на странице Page 14 даташита Texas Instruments на микросхему SN74BCT8244A, и наблюдались полученные сигналы. Этот пример состоит из 25 тактов TCK. Были задействованы все состояния контроллера JTAG TAP, за исключением Pause-IR, Exit2-IR, Pause-DR и Exit2-DR. Эти не используемые состояния обычно нужны только когда устройство находится в более длинной цепочке JTAG, или когда имеются очень длинные регистры пограничного сканирования.
Пример управляющей программы использует драйвер устройства FTDI D2XX. Она написана в линейном стиле, чтобы продемонстрировать реальные байты, отправляемые в блок MPSSE, и результирующие данные, которые считываются из MPSSE. Здесь секции, которые читают и записывают выводы данных (TDI и TDO), должны комбинироваться с манипулированием выводом управления (TMS), чтобы получить изменения состояний. Результирующие данные должны тщательно наблюдаться, и на них должна быть соответствующая реакция. Возможно, что данные могут потребовать такого сдвига, чтобы получить формат, который более удобен для программиста.
В дополнение к дублированию интервалов времени примера, высокоскоростные (Hi-Speed) микросхемы FTDI (FT2232H и FT4232H) поддерживают генерацию TCK без тактирования каких-либо данных на их выход из MPSSE. Это демонстрируется в конце листинга программы. После листинга кода показаны осциллограммы ожидаемого вида и с ожидаемыми интервалами времени.
Примечание: FT2232H и FT4232H требуют драйвера устройства версии 2.06.00 или более свежей. FT232H требует драйвера устройства версии 2.08.14 или более свежей. Обычно хорошей идеей будет загрузить с сайта FTDI последнюю версию драйвера для всех периферийных устройств FTDI.
Пример программы написан на C++, и был скомпилирован в консольное приложение в среде Microsoft® Visual Studio 2008.
// AN_129_Hi-Speed_JTAG_with_MPSSE.cpp []: определяет точку входа
// в консольное приложение.
#include "stdafx.h"
#include < windows.h >
#include < stdio.h >
#include "ftd2xx.h"
int _tmain(int argc, _TCHAR* argv[])
{
FT_HANDLE ftHandle; // хендл для устройства FTDI
FT_STATUS ftStatus; // результат каждого вызова D2XX
DWORD dwNumDevs; // количество устройств
unsigned int uiDevIndex = 0xF; // устройство в списке, которое используется
BYTE byOutputBuffer[1024]; // буфер, который содержит команды MPSSE, и данные
// для отправки в FT2232H
BYTE byInputBuffer[1024]; // буфер для хранения данных, прочитанных из FT2232H
DWORD dwCount = 0; // главный индекс цикла
DWORD dwNumBytesToSend = 0; // индекс выходного буфера
DWORD dwNumBytesSent = 0; // счетчик реально отправленных байт -
// используется в FT_Write
DWORD dwNumBytesToRead = 0; // количество байт, доступных для чтения во входном
// буфере драйвера
DWORD dwNumBytesRead = 0; // количество реально прочитанных данных -
// используется в FT_Read
DWORD dwClockDivisor = 0x05DB; // значение делителя тактов, частота SCL =
// 60/((1+0x05DB)*2) (МГц) = 20 кГц
// Проверка - присутствует ли устройство FTDI?
printf("Checking for FTDI devices...\n");
ftStatus = FT_CreateDeviceInfoList(&dwNumDevs);
// Получение количества устройств FTDI
if (ftStatus != FT_OK) // команда выполнилась успешно?
{
printf("Error in getting the number of devices\n");
return 1; // Выход по ошибке
}
if (dwNumDevs < 1) // Выход, если не видится ни одно устройство
{
printf("There are no FTDI devices installed\n");
return 1; // Выход по ошибке
}
printf("%d FTDI devices found - count includes individual ports on a single chip\n",
dwNumDevs);
// Открытие порта - чтобы упростить код, для этого апноута предполагается, что
// первое устройство будет микросхемой FT2232H или FT4232H. Более тщательные
// проверки перед открытием порта могут быть сделаны на основе чтения дескрипторов
// устройства, места подключения, серийного номера и т. д.
printf("\nAssume first device has the MPSSE and open it...\n");
ftStatus = FT_Open(0, &ftHandle);
if (ftStatus != FT_OK)
{
printf("Open Failed with error %d\n", ftStatus);
return 1; // Выход по ошибке
}
// Конфигурирование параметров порта
printf("\nConfiguring port for MPSSE use...\n");
ftStatus |= FT_ResetDevice(ftHandle);
// Сброс устройства USB
// Сначала очищается буфер приема USB, для чего считываются все старые данные
// из буфера приема FT2232H. Получение количества байт в буфере приема FT2232H:
ftStatus |= FT_GetQueueStatus(ftHandle, &dwNumBytesToRead);
// Чтение данных из буфера приема FT2232H:
if ((ftStatus == FT_OK) && (dwNumBytesToRead > 0))
FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);
// Установка размеров передачи запроса USB в 64K:
ftStatus |= FT_SetUSBParameters(ftHandle, 65536, 65535);
// Запрет символов события и ошибки (event, error characters):
ftStatus |= FT_SetChars(ftHandle, false, 0, false, 0);
// Установка таймаута чтения и записи в миллисекундах:
ftStatus |= FT_SetTimeouts(ftHandle, 0, 5000);
// Установка таймера латентности (по умолчанию 16 мс):
ftStatus |= FT_SetLatencyTimer(ftHandle, 16);
// Сброс контроллера:
ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x00);
// Разрешить режим MPSSE:
ftStatus |= FT_SetBitMode(ftHandle, 0x0, 0x02);
if (ftStatus != FT_OK)
{
printf("Error in initializing the MPSSE %d\n", ftStatus);
FT_Close(ftHandle);
return 1; // Выход по ошибке
}
Sleep(50); // ожидание, чтобы все, связанное с USB, запустилось
// и начало работать
// -----------------------------------------------------------
// В этой точке MPSSE готов для получения команд
// -----------------------------------------------------------
// -----------------------------------------------------------
// Синхронизация MPSSE осуществляется отправкой не существующего
// кода операции (0xAA), на что MPSSE ответить кодом "Bad
// Command" (0xFA, ошибочная команда), за которым будет идти
// сама эта ошибочная команда (0xAA).
// -----------------------------------------------------------
// Добавление к очереди ошибочной команды xAA:
byOutputBuffer[dwNumBytesToSend++] = 0xAA; //'\xAA';
// Отправка плохой команды:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
do
{
// Получение количества байт во входном буфере устройства:
ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead);
} while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK));
// Цикл завершится, если произошла ошибка, или по таймауту
bool bCommandEchod = false;
// Чтение данных из входного буфера:
ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);
// Проверка: был ли получен ответ "Bad command" и эхо команды:
for (dwCount = 0; dwCount < dwNumBytesRead - 1; dwCount++)
{
if ((byInputBuffer[dwCount] == 0xFA) && (byInputBuffer[dwCount+1] == 0xAA))
{
bCommandEchod = true;
break;
}
}
if (bCommandEchod == false)
{
printf("Error in synchronizing the MPSSE\n");
FT_Close(ftHandle);
return 1; // Выход по ошибке
}
// -----------------------------------------------------------
// Конфигурирование настроек MPSSE для JTAG. В блок MPSSE
// можно послать несколько команд одним вызовом FT_Write.
// -----------------------------------------------------------
dwNumBytesToSend = 0; // начало с чистого индекса
// Настройка команд, относящихся к Hi-Speed для FTx232H.
// Использование главной частоты 60 МГц (запрет делителя на 5):
byOutputBuffer[dwNumBytesToSend++] = 0x8A;
// Выключение адаптивного тактирования (оно может требоваться для ARM):
byOutputBuffer[dwNumBytesToSend++] = 0x97;
// Запрет трехфазного тактирования:
byOutputBuffer[dwNumBytesToSend++] = 0x8D;
// Отправка команд, относящихся к Hi-Speed:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Установка начальных состояний интерфейса MPSSE - младший байт, оба направления
// ножек и выходные значения.
// Имя вывода Сигнал Направление Конфигурация Нач. состояние Конфигурация
// ADBUS0 TCK output 1 лог. 0 0
// ADBUS1 TDI output 1 лог. 0 0
// ADBUS2 TDO input 0 0
// ADBUS3 TMS output 1 лог. 1 1
// ADBUS4 GPIOL0 input 0 0
// ADBUS5 GPIOL1 input 0 0
// ADBUS6 GPIOL2 input 0 0
// ADBUS7 GPIOL3 input 0 0
// Установка бит данных младшего байта порта MPSSE:
byOutputBuffer[dwNumBytesToSend++] = 0x80;
// Начальное состояние в вышеуказанной конфигурации:
byOutputBuffer[dwNumBytesToSend++] = 0x08;
// Направление работы выводов, как в вышеуказанной конфигурации:
byOutputBuffer[dwNumBytesToSend++] = 0x0B;
// Отправка команд конфигурации для младшего GPIO:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Установка начальных состояний интерфейса MPSSE - младший байт, оба направления
// ножек и выходные значения.
// Имя вывода Сигнал Направление Конфигурация Нач. состояние Конфигурация
// ACBUS0 GPIOH0 input 0 0
// ACBUS1 GPIOH1 input 0 0
// ACBUS2 GPIOH2 input 0 0
// ACBUS3 GPIOH3 input 0 0
// ACBUS4 GPIOH4 input 0 0
// ACBUS5 GPIOH5 input 0 0
// ACBUS6 GPIOH6 input 0 0
// ACBUS7 GPIOH7 input 0 0
// Установка бит данных младшего байта порта MPSSE:
byOutputBuffer[dwNumBytesToSend++] = 0x82;
// Начальное состояние в вышеуказанной конфигурации:
byOutputBuffer[dwNumBytesToSend++] = 0x00;
// Направление работы выводов, как в вышеуказанной конфигурации:
byOutputBuffer[dwNumBytesToSend++] = 0x00;
// Отправка команд конфигурации для старшего GPIO:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Установка частоты TCK (0xValueH старший байт значения,
// 0xValueL младший байт значения):
// TCK = 60MHz /((1 + [(1 +0xValueH*256) OR 0xValueL])*2)
// Команда для установки делителя тактов:
byOutputBuffer[dwNumBytesToSend++] = '\x86';
// Установка 0xValueL делителя тактов:
byOutputBuffer[dwNumBytesToSend++] = dwClockDivisor & 0xFF;
// Установка 0xValueH делителя тактов:
byOutputBuffer[dwNumBytesToSend++] = (dwClockDivisor >> 8) & 0xFF;
// Отправка команд для делителя тактов:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Запрет внутренней петли замыкания входа на выход (internal loop-back,
// эта петля может использоваться для самопроверки):
byOutputBuffer[dwNumBytesToSend++] = 0x85;
// Отправка команды запрета loop-back:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Навигация TMS по состояниям Test-Logic-Reset -> Run-Test-Idle ->
// Select-DR-Scan -> Select-IR-Scan: TMS=1 TMS=0 TMS=1 TMS=1
// Не читать данные в состояниях Test-Logic-Reset, Run-Test-Idle, Select-DR-Scan,
// Select-IR-Scan:
byOutputBuffer[dwNumBytesToSend++] = 0x4B;
// Количество тактовых импульсов = длина + 1 (здесь 6 тактов):
byOutputBuffer[dwNumBytesToSend++] = 0x05;
// Данные сдвигаются младшим битом (LSB) вперед, поэтому для TMS
// будет шаблон 101100:
byOutputBuffer[dwNumBytesToSend++] = 0x0D;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// В настоящий TMS = лог. 0. Машина TAP находится в состоянии Shift-IR,
// так что теперь будем использовать команду TDI/TDO, чтобы выдвинуть единички
// через выход TDI при чтении входа TDO. Несмотря на то, что нужно вдвинуть 8 бит,
// здесь тактируется только 7. 8-й будет вдвинут совместно со следующей
// командой TMS. Данные тактируем на выход через состояния Capture-IR, Shift-IR
// и Exit-IR, читая при этом возвращаемый результат:
byOutputBuffer[dwNumBytesToSend++] = 0x3B;
// Количество тактовых импульсов = длина + 1 (здесь 7 тактов):
byOutputBuffer[dwNumBytesToSend++] = 0x06;
// Выдвигаем 1111111 (последний бит игнорируется):
byOutputBuffer[dwNumBytesToSend++] = 0xFF;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
// Отправка команды TMS:
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Здесь команда TMS, передаваемая с 1 тактом. При этом данные также вдвигаются.
// Тактирование TMS, чтение одного бита:
byOutputBuffer[dwNumBytesToSend++] = 0x6B;
// Количество тактовых импульсов = длина + 1 (здесь 1 такт):
byOutputBuffer[dwNumBytesToSend++] = 0x00;
// Данные сдвигаются младшим битом вперед, так что TMS становится лог. 1. Также
// бит 7 попадает на выход TDI, и также 1 бит лог. 1 оставит TMS в состоянии
// лог. 1 для следующих команд:
byOutputBuffer[dwNumBytesToSend++] = 0x83;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Навигация TMS от Exit-IR через Update-IR -> Select-DR-Scan -> Capture-DR:
// TMS=1 TMS=1 TMS=0
// Не читаем данные в состояниях Update-IR -> Select-DR-Scan -> Capture-DR
byOutputBuffer[dwNumBytesToSend++] = 0x4B;
// Количество тактовых импульсов = длина + 1 (здесь 4 такта):
byOutputBuffer[dwNumBytesToSend++] = 0x03;
// Данные сдвигаются младшим битом вперед, так что данные для TMS будут 110:
byOutputBuffer[dwNumBytesToSend++] = 0x83;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Сейчас TMS = лог. 0. Машина TAP находится в состоянии Shift-DR, так что теперь
// используем команду TDI/TDO для того, чтобы выдвинуть 101 на выход TDI, читая
// при этом вход TDO. Несмотря на то, что нужно вдвинуть 3 бита, здесь генерируется
// только 2 такта. Третий будет выдаваться вместе со следующей командой TMS.
// Выдвигаем данные наружу через состояния Shift-DR и Exit-DR:
byOutputBuffer[dwNumBytesToSend++] = 0x3B;
// Количество тактовых импульсов = длина + 1 (здесь 2 такта):
byOutputBuffer[dwNumBytesToSend++] = 0x01;
// Выдвигаем 101 (последний бит игнорируется):
byOutputBuffer[dwNumBytesToSend++] = 0x01;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Здесь выдается команда TMS с одним тактом. Данные продолжают вдвигаться.
// Выдвигаем TMS, читаем 1 бит:
byOutputBuffer[dwNumBytesToSend++] = 0x6B;
// Количество тактовых импульсов = длина + 1 (здесь 1 такт):
byOutputBuffer[dwNumBytesToSend++] = 0x00;
// Данные сдвигаются младшим битом вперед, так что TMS становится в лог. 1. Также
// бит 7 выдвигается на выход TDI, и также 1 бит лог. 1 оставит TMS в состоянии
// лог. 1 для следующих команд:
byOutputBuffer[dwNumBytesToSend++] = 0x83;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
// Навигация TMS по состояниям Update-DR -> Select-DR-Scan -> Select-IR-Scan
// -> Test Logic Reset: TMS=1 TMS=1 TMS=1 TMS=1. Не читаем данные в состояниях
// Update-DR -> Select-DR-Scan -> Select-IR-Scan -> Test Logic Reset:
byOutputBuffer[dwNumBytesToSend++] = 0x4B;
// Количество тактовых импульсов = длина + 1 (здесь 4 такта):
byOutputBuffer[dwNumBytesToSend++] = 0x03;
// Данные сдвигаются младшим битом вперед, так что данные TMS будут 101100:
byOutputBuffer[dwNumBytesToSend++] = 0xFF;
// Отправка команды TMS:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
do
{
// Получение количества байт во входном буфере устройства:
ftStatus = FT_GetQueueStatus(ftHandle, &dwNumBytesToRead);
} while ((dwNumBytesToRead == 0) && (ftStatus == FT_OK));
// завершение цикла при ошибке или по таймауту
// Чтение данных из входного буфера:
ftStatus = FT_Read(ftHandle, &byInputBuffer, dwNumBytesToRead, &dwNumBytesRead);
printf("\n");
printf("TI SN74BCT8244A IR default value is 0x81\n");
printf("The value scanned by the FT2232H is 0x%x\n",
byInputBuffer[dwNumBytesRead - 3]);
printf("\n");
printf("TI SN74BCT8244A DR bypass expected data is 00000010 = 0x2\n");
printf(" The value scanned by the FT2232H = 0x%x\n",
(byInputBuffer[dwNumBytesRead-1] >> 5));
// Генерация тактов для получения состояния Test-Logic-Reset. В состоянии
// Test-Logic-Reset не производится никаких действий, только демонстрируется
// генерация тактов без какой-либо передачи данных. Генерация тактов:
byOutputBuffer[dwNumBytesToSend++] = 0x8F;
// (0x0002 + 1) * 8 = 24 такта
byOutputBuffer[dwNumBytesToSend++] = 0x02;
byOutputBuffer[dwNumBytesToSend++] = 0x00;
// Выдача команд для тактов:
ftStatus = FT_Write(ftHandle, byOutputBuffer, dwNumBytesToSend, &dwNumBytesSent);
dwNumBytesToSend = 0; // сброс указателя на выходной буфер
/*
// -----------------------------------------------------------
// Закроем все используемые ресурсы:
// -----------------------------------------------------------
*/
printf("\nJTAG program executed successfully.\n");
printf("Press Enter to continue\n");
getchar(); // Ожидание нажатия клавиши возврата каретки
FT_Close(ftHandle); // Закрытие порта
return 0; // Успешный выход из программы
}
Рис 3.1. Осциллограмма сигналов на выводах SN74BCT8244A.
Обратите внимание, что выход TDI всегда управляется, и вход TDO подтянут к лог. 1 микросхемой SN74BCT8244A. В даташите Texas Instruments показано несколько областей "don’t care" (не имеет значения), что на этом скриншоте соответствует лог. 1.
Ниже показано, как генерируется TCK без какой-либо активности на TDI, TDO или TMS.
Рис. 3.2. Генерация TCK.
Генерация тактов полезна для запуска внутреннего теста внутри определенного TAP. Здесь имеется несколько опций, которые включают генерацию определенного количества импульсов, или выдача импульсов, пока сигнал GPIO не перейдет в известное значение. В этом примере генерируется 24 тактовых импульса.
[Ссылки]
1. AN_129 Interfacing FTDI USB Hi-Speed Devices to a JTAG TAP site:ftdichip.com. 2. FT2232H: двухканальная высокоскоростная USB микросхема для I/O. 3. AN_108 Command Processor for MPSSE and MCU Host Bus Emulation Modes site:ftdichip.com. 4. FT2232H Board - макетная плата на высокоскоростном чипе моста USB фирмы FTDI. 5. 170129FT2232-JTAG-Boundary-Scan.zip - примеры кода, драйверы, документация. |