Микросхемы 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.
![AN 129 JTAG state machine fig11](/images/stories/programming/AN_129-JTAG-state-machine-fig11.png)
Рис. 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 тактовых импульсов.
![AN 129 JTAG TAP chain fig12](/images/stories/programming/AN_129-JTAG-TAP-chain-fig12.png)
Рис. 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].
![AN 129 JTAG example circuit fig21](/images/stories/programming/AN_129-JTAG-example-circuit-fig21.png)
Рис. 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; // Успешный выход из программы
}
![AN 129 JTAG SN74BCT8244A timing example observation fig31](/images/stories/programming/AN_129-JTAG-SN74BCT8244A-timing-example-observation-fig31.png)
Рис 3.1. Осциллограмма сигналов на выводах SN74BCT8244A.
Обратите внимание, что выход TDI всегда управляется, и вход TDO подтянут к лог. 1 микросхемой SN74BCT8244A. В даташите Texas Instruments показано несколько областей "don’t care" (не имеет значения), что на этом скриншоте соответствует лог. 1.
Ниже показано, как генерируется TCK без какой-либо активности на TDI, TDO или TMS.
![AN 129 JTAG SN74BCT8244A TCK generation fig32](/images/stories/programming/AN_129-JTAG-SN74BCT8244A-TCK-generation-fig32.png)
Рис. 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 - примеры кода, драйверы, документация. |