Из любого описания на FPGA известно, что для хранения их конфигураций используются специальные микросхемы – конфигураторы. Например, для Altera Cyclone используются микросхемы EPCS. Вот схема от типичной макетной платы с кристаллом семейства Cyclone IV. На ней мы видим конфигуратор EPCS16. Всё бы ничего, но традиционно эти конфигураторы достаточно дороги, поэтому хотелось бы использовать что-нибудь подешевле.
Подробности в длиннющем тексте ниже. Если же очень интересно, но лень читать так много букв, то можно упростить задачу, посмотрев подробное 20-минутное видео.
Итак, вернёмся к нашей проблеме. Если повертеть в руках ту самую макетную плату с кристаллом семейства Cyclone IV, то мы увидим очень удивительную вещь.
Вот она, ПЛИСина, а вот конфигурационная ПЗУ:
Как ни странно, это никакой не EPCS, а обычная 25-тая флешка. Такие флешки стоят дёшево и продаются достаточно много у кого.
Но, как говорится, не все йогурты одинаково полезны. В частности, наши заказчики на радостях закупили подобные флешки, припаяли на плату и получили глобальную проблему. Заходим в программатор, грузим файл, подготовленный для прошивки, начинаем его прошивать и получаем ошибку:
Вот сообщение об ошибке:
Error (209025): Can't recognize silicon ID for device 1. A device's silicon ID is different from its JTAG ID. Verify that all cables are securely connected, select a different device, or check the power on the target system. Make sure the device pins are connected and configured correctly.
Не опознан идентификатор устройства. То есть у флешки неизвестный идентификатор с точки зрения квартуса. Конкретно у наших заказчиков были закуплены кристаллы 25P32, которые вообще не поддерживаются в принципе, но в жизни может быть и более приземлённая ситуация. В частности, на фото выше припаяна флешка от ST, а определяется она как MICRON. Китайские продавцы и не такое могут намаркировать, а когда партия закуплена и не работает – что можно сделать?
Я полез на форумы. Все русскоязычные, какие удалось осмотреть, пестрели обсуждениями, у каких поставщиков и что следует брать, чтобы не напороться на подобную проблему. Но в нашем случае никто покупать новую партию не хотел. В англоязычных источниках удалось найти лишь одну статью с решением, но в современной среде Quartus Prime данное решение «в лоб» не сработает. Поэтому мы взялись задокументировать данную проблему для современной среды, на русском языке и в видео формате.
Итак, как вообще программируется ПЗУшина?
В ПЛИС вливается специальная конфигурация, по которой становится возможно по JTAG достукиваться до флешки. И потом, пользуясь этой конфигурацией, мы заливаем данные. Оказывается, можно сделать подобную конфигурацию, которая даст нам доступ к флешке и даст прошить, невзирая на ID, причём при этом не придётся писать ни строчки собственного кода, да и утилиты все будут использоваться из поставки Quartus Prime (либо Qiartus II, кто пользуется старыми версиями среды разработки).
То есть нам предстоит сделать 3 шага:
- Сделать конфигурацию, которая достукивается до флешки.
- Написать файл, в котором флешка описывается.
- Прошить.
Давайте этим и займёмся. Начнём с разработки собственной «прошивки» (она же конфигурация), не написав при этом ни одной строчки своего кода.
Заходим в Quartus:
Создаём новый проект:
Назовём его, скажем, flasher:
Это имя следует запомнить – оно нам ещё понадобится.
Создаём пустой проект, семейство у меня Cyclone IV E, используемый в проекте кристалл вот такой:
Так. Заканчиваем создание проекта, нажимаем Finish. Проект создан. Как уже было сказано, мы не пишем ни одной строчки своего кода. Но заставить среду сделать что-то всё-таки нужно. Для этого идем в Tools – Platform Designer.
Вот он загрузился. Конкретно у меня в этой плате кварц на 60 Гц, поэтому я подправлю установки частоты:
То, что я делаю сейчас, мы делаем один раз для платформы. То есть если изготовлена какая-то плата, то вот этот загрузчик будет для нее для любого проекта работать.
Я подготовил кварц – теперь мы ставим процессор. В библиотеке слева находим «Процессоры и Периферия», «Встроенные процессоры» и затем – Nios II Processor:
Выбираем его и нажимаем «Добавить».
В открывшемся окне, в свойствах, выбираем Nios II/e, потому что он абсолютно бесплатный и к нему не нужна никакая лицензия.
Ошибки сообщают нам, что не настроены вектора. Мы не собираемся ничего программировать для этого процессора. Поэтому вектора мы просто направляем в первое попавшееся место из списка:
Нам очень важно, чтобы у процессора работал модуль JTAG:
После наших манипуляций ошибки ушли.
С процессором закончено. Нажимаем Finish и двигаемся дальше.
Теперь мы идём в основные функции. Здесь есть конфигураторы:
Раскрываем список конфигураторов – ближе к концу находим EPCS-ки – наши конфигураторы:
Всё оставляем по умолчанию:
Теперь начинаем их связывать. Тактовые сигналы пропускаем на оба модуля, сигнал сброса пропускаем на оба модуля. Сигнал сброса, выходящий из аппаратуры JTAG, – debug_reset_request – мы также пропускаем на оба модуля. Дальше data_master пропускаем на оба модуля. Instruction_master пропускаем только на отладчик. И запрос на прерывания мы также пропускаем:
Дальше мы переходим к внешним ножкам – external. Экспортируем их, для чего дважды щелкаем в поле Double-click to export:
Для простоты назову epcs, чтобы меньше длина была:
Теперь привычным движением руки назначаем базовые адреса:
И назначаем прерывания:
Автоматически назначенный адрес для нашего flash-контроллера – 0×800 – нам следует запомнить:
Он нам еще пригодится. А всё остальное, в принципе, само сделалось и будет работать.
Сейчас очень важно, так как мы не собираемся писать ни одной строчки своего кода, чтобы имя процессорной системы совпадало с именем проекта. Проект у нас был flasher.
Сохраняем систему, называем flasher:
Именно тогда у нас топ-модуль будет именно этот процессор, и поэтому нам не придется ничего делать.
Следующий наш шаг:
Все оставляем по умолчанию, потому что мы просто пользуемся тем, что уже готово:
Завершаем:
Появилось сообщение о том, что нам надо не забыть добавить файл в проект:
Давайте добавим. Идём в Project – Add/Remove Files in Project:
Находим наш файл на компьютере.
Вот он, наш файл flasher с расширением qsys.
Добавили его:
Теперь делаем черновую компиляцию:
Она завершилась успешно.
Теперь, когда она прошла, мы можем назначить выводы. Идем в Pin Planner:
JTAG-овские ножки нам назначать не надо – мы назначаем ножки флешки.
Для каждой микросхемы, для каждого корпуса они свои. В принципе, можно смотреть документацию на микросхему или на свою плату. Например, вот у нас двенадцатая ножка DCLK:
У меня список уже подготовлен – просто вобьём по нему.
Так, epcs_data0, LOCATION: PIN13, epcs_dclk – PIN12, epcs_sce – PIN8, epcs_sdo – PIN6. И конкретно на плате наших заказчиков тактовая частота PIN24, reset_n – PIN88.
Ножки назначили. Запускаем компиляцию. Выдаются ошибки:
Все потому, что я сделал вид, что забыл произвести очень важную настройку. Мы сейчас подключили флешку к служебным линиям. И, по окончании конфигурирования, часть этих линий вообще не доступна, а часть – используется для служебных целей. Поэтому нам выдали сообщения, что у нас конфликт:
Чтобы это устранить, идем в Assignments – Device:
Device and Pin Options:
Здесь выбираем Dual-Purpose Pins. И все эти линии по окончании программирования мы просим сделать обычными линиями ввода-вывода:
Жмём OK, запускаем компилятор. И всё получилось.
Итак, первый шаг завершен. У нас получилась конфигурация, через которую мы можем достукиваться до флешки.
Теперь наша задача – сделать файл, с помощью которого система нашу флешку будет опознавать.
Идём во все программы, Intel FPGA (для старых версий это будет Altera), Nios II Command Shell.
Здесь мы идём в каталог, где мы только что все собрали. При этом не забываем, что слэши тут должны быть не обратные, а прямые, и что результирующий файл flasher.sof лежит в каталоге output_files:
Теперь начинаем произносить волшебные заклинания. Итак, нам нужно влить только что сформированную конфигурацию. Для этого мы пишем:
nios2-configure-sof flasher.sof
и нажимаем Enter:
Файл залился – теперь у нас есть доступ к флешке. Для того, чтобы определить все, что касается доступа к флешке, нам нужно запустить следующую программу:
nios2-flash-programmer --epcs --base=0x800--debug.
где 0x800 – это тот самый адрес, который автоматически назначился на блок epcs и который надо было не забыть.
Нажимаем Enter:
Что он нам сказал? Он попытался осмотреть ту область, которую мы назвали. И по смещению 0 по адресу 800 не нашёл ничего. По адресу с00 он нашёл то, что нам требуется:
Теперь мы запоминаем не просто базовый адрес 800, а конкретный адрес с00 – в дальнейшем работа будет вестись с ним.
Он нашел флешку, ее идентификатор 202016, но сказал, что понятия не имеет, что с ней делать, потому что её не знает.
Вот документация на нашу флешку:
Её полный идентификатор 202016 – именно его она возвращает в ответ на команду запроса своего кода.
Так что всё правильно – флешка нашлась правильная.
Он нам говорит, что должен быть файл с секцией EPCS-202016.
Замечательно. Изменить – Пометить. Выделяем её имя и берём в буфер обмена.
Создаём файл ovr.txt и секцию с именем, которое только что скопировали:
В документации на нашу флешку, в разделе Memory Map, мы можем посмотреть, что она состоит из 64 секторов. Каждый сектор имеет размер 64 Кбайт, потому что от 0000 до FFFF.
Поэтому файл с конфигурацией, который мы только что создали, должен выглядеть вот так:
64 сектора размером по 64 Кбайта, или 65536 байта, каждый.
Второй шаг готов. У нас имеются файлы flasher.sof и ovr.txt, который содержит конфигурацию флешки.
Переходим к третьему шагу.
Напомню, что рабочий проект был USB16_my. А файл для прошивания назывался Test1.sof. Мы копируем flasher.sof и ovr.txt к нему.
Теперь мы закончили все подготовительные шаги – приступаем к непосредственным боевым действиям. Чтобы подчеркнуть отсутствие связи между подготовкой и работой, я войду в терминал ещё раз, как будто это происходит на следующий день, через неделю, через месяц или через любой срок после завершения подготовки.
Первое, что нам нужно сделать, это сформировать выходной файл. Потому что файл sof не шьется в ПЗУ – шьется немного другой файл. Для того чтобы его сформировать, мы пишем:
Получился файл Test1.flash:
Теперь, чисто формально, пришёл черёд действий, которые должны делать сборщики плат. В первую очередь, они точно так же должны загрузить наш flasher, то есть:
После чего они должны прошить ПЗУ:
Собственно, на этом всё. Задача решена, флешка прошита – можно ее использовать, даже несмотря на то, что основной путь говорил про несовпадение ID-шников. И совершенно не требуется покупать дорогие конфигураторы или искать, у какого поставщика 25-е флешки имеют совместимые ID. Мы подготовили «прошивальщик» для нашей конкретной платы (и любых других, где стоит такой же кристалл и Reset с генератором подключены к тому же выводу), мы подготовили текстовый файл для конфигуратора, после чего влили «прошивку», пользуясь утилитами, идущими в комплекте поставки штатной среды Quartus Prime (они же шли и со средой Quartus II).
Автор: Павел Локтев