В прошлой статье я писал, что такое JTAG и TAP контроллер. Эти знания нам помогут сделать свой простой программатор для ПЛИС компании Альтера.
Я хочу сделать очень простой программатор, который будет работать через последовательный порт. Последовательный порт хорош тем, что он весьма распространен, прост в программировании и, к тому же, существуют недорогие устройства USB-to-COM. Есть надежда, что мой программатор будет работать и через такой переходник. На компьютере я буду запускать мою специальную программу, управляющую программатором. Нам ее предстоит написать (в смысле я ее уже написал и расскажу как она работает).
Итак, в разъеме JTAG есть 4 существенные для нас сигнала: TDI, TMS, TCK и TDO.
Первые три сигнала являются входами для программируемой микросхемы ПЛИС, то есть мы с компьютера должны ими управлять. Управление каждым сигналом должно быть произвольным, любой из них мы можем в любой момент времени установить или сбросить. У последовательного порта есть несколько сигналов, подходящих для этих целей:
- RTS - он будет соответствовать сигналу TDI интерфейса JTAG
- DTR - он будет соответствовать сигналу TMS
- TX - будет соответствовать сигналу TCK
Кроме этого, на JTAG есть выходной сигнал TDO, состояние которого нам нужно уметь читать с компьютера. Будем использовать для этих целей сигнал CTS последовательного порта.
С сигналами разобрались, но есть одна проблема. Нужно сделать преобразователь уровней сигналов последовательного порта. Конечно можно использовать специализированные микросхемы преобразователей уровня, их существует великое множество. Например, вот такая есть микросхема
Мы (как всегда) пойдем своим путем. Сделаем программатор по вот такой схеме:
Несколько резисторов, стабилитроны, светодиоды для отладки программы и.. это все - проще не бывает.
Вот фотографии нашего программатора, вид сверху:
Вид снизу:
Программу я буду писать на языке C в среде Microsoft Visual Studio v10.
Моя программа будет состоять как бы из двух логических частей. Первая часть - это управление сигналами последовательного порта, а значит это и управление сигналами JTAG. Вторая часть программы - это чтение *.SVF файла, его интерпретация и последовательное исполнение. В прошлой статье я писал, что SVF файл описывает последовательность команд для TAP контроллера программируемой микросхемы. Среда Altera Quartus II может генерировать SVF файлы для откомпилированных проектов.
Для управления последовательным портом я буду пользоваться API функциями OS Windows:
- CreateFile(..) - используется, чтобы открыть последовательный порт
- EscapeCommFunction(..) - с параметрами SETRTS или CLRRTS для установки или сброса сигнала TDI
- EscapeCommFunction(..) - с параметрами SETDTR или CLRDTR для установки или сброса сигнала TMS
- EscapeCommFunction(..) - с параметрами SETBREAK или CLRBREAK для установки или сброса сигнала TCK
- GetCommModemStatus(..) - чтобы прочитать состояние линии CTS и соответственно узнать значение сигнала TDO от интерфейса JTAG
В программе определены две очень важные функции:
int sir(int nclk, int val);
int sdr(int nclk, int val);
Первая функция sir(..) записывает в регистр команд TAP контроллера программируемой микросхемы значение val длинной nclk бит. Вторая функция sdr(..) записывает в регистр данных TAP контроллера программируемой микросхемы значение val длинной nclk бит.
Функции выглядят примерно одинаково и делают примерно одно и то же. Используя сигнал TMS и TCK они переводят TAP контроллер в состояние записи соответствующего регистра IR или DR согласно диаграмме состояний (TAP state-machine) описанной в предыдущей статье. Сигнал TDI используется для последовательной передачи данных в регистр TAP, а сигнал TDO используется для чтения из контроллера ответных данных.
Теперь об интерпретаторе SVF файла.
Итак, Вы сделали проект для ПЛИС, откомпилировали его с помощью Quartus и получили SVF файл для программирования микросхемы.
SVF - это текстовый файл. Наша программа будет построчно считывать его и интерпретировать команду в этой строке и исполнять ее. Я не знаю всех подробностей стандарта SVF файлов, но то что я вижу в файле сгенерированном квартусом - это очень простой файл. Одна строка - одна команда. Нет никаких условных или безусловных переходов или подпрограмм. Таким образом, чтение и построчное исполнение SVF файла - вполне удобное для нас решение.
Собственно нужно реализовать только несколько основных команд: RUNTEST, SIR, SDR. Как вы конечно догадались команда SIR - записать число в регистр команд TAP и SDR - записать число в регистр данных. RUNTEST - это пауза, когда контроллер остается в состоянии IDLE. Скажу честно, что паузы я в своей программе выдерживаю не строго. У нас и так получится очень медленная частота записи из-за программной реализации протокола передачи. Так что выдерживать паузы согласно SVF надеюсь не обязательно.
Ну вот собственно программа написана и откомпилирована с помощью Visual Studio.
Вы можете скачать ее исходники и бинарный файл на нашем сайте:
Программа консольная, принимает 2 параметра в командной строке: имя последовательного порта и имя файла SVF. Например, вот так:
c:\MarsBlaster.exe COM4 my_proj.svf
Подключаю плату Марсоход к нашему программатору, подключаем его к компьютеру подаем питание.
Вот как идет программирование:
Вот еще видео, как идет программирование с другого ракурса:
Похоже все работает!!!
PS: ложка дегтя.
Через переходник USB-to-COM тоже работает, но очень медленно. Программирование платы Марсоход (включая проверку после записи) занимает около 5 минут. Причина в том, что управление сигналами идет через USB и чтение ответного сигнала TDO занимает очень много времени (2-3 миллисекунды). Избавиться от этого вот так просто не получится. Нужно делать более сложный программатор, с более сложной логикой работы, что бы обмен вести не побитно, а хотя бы байтами, тогда можно сделать гораздо быстрее.
Ну и еще обратите внимание на схеме программатора есть "обратная связь" с 6й на 3ю ножки разъема COM порта. Это то же нужно - как раз для работы через переходник USB-to-COM. Эта обратная связь позволяет точно сказать пришли ли данные о статусе TDO или еще нет. Я устанавливаю TCK и читаю через обратную связь его же - пришел он или еще нет. Если пришел, значит с ним пришел и TDO. Немного мудрено получилось, но работает.
Подробнее...