Программирование PC Подключение к JTAG TAP через FT2232H Tue, October 08 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Подключение к JTAG TAP через FT2232H Печать
Добавил(а) microsin   

Микросхемы 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

Рис. 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

Рис. 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

Рис. 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

Рис 3.1. Осциллограмма сигналов на выводах SN74BCT8244A.

Обратите внимание, что выход TDI всегда управляется, и вход TDO подтянут к лог. 1 микросхемой SN74BCT8244A. В даташите Texas Instruments показано несколько областей "don’t care" (не имеет значения), что на этом скриншоте соответствует лог. 1.

Ниже показано, как генерируется TCK без какой-либо активности на TDI, TDO или TMS.

AN 129 JTAG SN74BCT8244A TCK generation fig32

Рис. 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 - примеры кода, драйверы, документация.

 

Добавить комментарий


Защитный код
Обновить

Top of Page