- src/: прошивка встроенного отладчика BL616 — составное USB-устройство 1209:C0CA: DirtyJTAG v3 (WinUSB через MS OS 2.0) + CDC-ACM UART к FPGA B3/C3; UART до 20 Мбод на DMA, JTAG до 30 МГц через аппаратный SPI; - bin/: загрузчик Sipeed (0x0) и штатная прошивка 2025030317 для отката; - gui/: TangProgrammer.exe (C# WinForms, .NET Framework 4) — загрузка FPGA в SRAM и во флеш-память, копия и стирание флеш-памяти FPGA, прошивка моста; светлая и тёмная тема; - scripts/: setup, build, flash, build_gui, make_portable, а также make_release и publish_release для релизов Gitea; - fpga_test/, tests/: тестовые проекты Gowin (loopback, stream) и тесты UART на Python; - tools/openFPGALoader/: openFPGALoader 1.1.1 для Windows x64.
18 KiB
Прошивка отладчика BL616 для Tang Primer 25K
Замена штатной прошивки встроенного отладчика (BL616) на плате Sipeed Tang Primer 25K Dock. Вместо эмуляции FT2232 плата становится составным USB-устройством из двух независимых функций:
| Функция | Что это | Драйвер Windows |
|---|---|---|
| JTAG | DirtyJTAG v3 (1209:C0CA, интерфейс 0) для openFPGALoader -c dirtyJtag |
WinUSB, ставится сам (MS OS 2.0) — Zadig не нужен |
| UART | CDC-ACM, обычный COM-порт к пинам FPGA B3/C3 | встроенный usbser.sys |
Оба работают одновременно: можно грузить битстрим, не закрывая терминал.
Скачать
Готовые файлы — в релизах:
| Файл | Что это |
|---|---|
TangProgrammer-<версия>-win64.zip |
программатор с окном — распаковать и запустить, внутри всё нужное (openFPGALoader, BLFlashCommand, прошивки моста) |
TangProgrammer.exe |
только программа — для клона этого репозитория (рядом должна быть папка tools\) |
tang25k_debugger_bl616.bin |
прошивка моста, пишется по адресу 0x20000 |
bl616_bootloader_0x20000_nano20k_signed.bin |
загрузчик Sipeed, пишется по адресу 0x0 вместе с прошивкой моста |
bl616_fpga_partner_25kDock.bin |
штатная прошивка Sipeed (0x0) — для отката |
fpga_test_bitstreams-GW5A-25.zip |
тестовые битстримы loopback.fs и stream.fs для проверки UART |
SHA256SUMS.txt |
контрольные суммы |
Чтобы только пользоваться платой, достаточно архива TangProgrammer-…-win64.zip:
он прошивает и мост (один раз), и FPGA. SDK и сборка не нужны.
Что получилось (проверено на плате)
| UART, скорости | любые от 300 бод до 20 Мбод (делитель от 160 МГц); проверено 9600 … 12 Мбод в обе стороны без единой потери |
| UART, формат | 5–8 бит, чётность none/odd/even, 1 / 1.5 / 2 стоп-бита |
| UART, поток FPGA → ПК | 10 Мбод непрерывно (1 МБ/с) 30 с — 0 ошибок; точность частоты подтверждена генератором FPGA |
| UART, ПК → FPGA | управление потоком по USB (NAK), данные не теряются при любой скорости |
| UART, буфер | кольцевой DMA-буфер 64 КБ на приём, 16 КБ на передачу |
| JTAG | --detect за ~40 мс; загрузка GW5A-25 в SRAM ≈ 2 с при 6 МГц |
| JTAG, частота | до 30 МГц; длинные сдвиги идут через аппаратный SPI BL616 |
Стресс-тест: сотни прогонов петли с произвольными скоростями и объёмами — без ошибок.
Как это устроено
Загрузка. У BL616 на этих платах прожжён eFuse: ROM запускает с адреса
0x0 только образ, зашифрованный ключом Sipeed. Поэтому по 0x0 пишется
загрузчик Sipeed (bin/bl616_bootloader_0x20000_nano20k_signed.bin,
выпущен Sipeed для Nano 20K; ключ у всех плат серии общий — проверено
сравнением шифротекстов штатных прошивок), а он безусловно передаёт
управление нашей прошивке по 0x20000.
Распиновка BL616 (схема Tang_25K_60033):
| Сигнал | BL616 | FPGA |
|---|---|---|
| TMS | GPIO0 | B1 |
| TCK | GPIO1 | C1 |
| TDO | GPIO2 (он же BOOT) | A2 |
| TDI | GPIO3 | A3 |
| UART TX (ПК → FPGA) | GPIO11 | B3 (uart_rx в FPGA) |
| UART RX (FPGA → ПК) | GPIO10 | C3 (uart_tx в FPGA) |
| светодиод LED5 | GPIO20 | — |
| кнопка S3 | GPIO12 | — |
Кварц BL616 на Dock — 26 МГц (а не 40 МГц, как в SDK по умолчанию).
Почему штатный UART работал плохо, а этот нет — коротко о найденных особенностях BL616, которые обходит прошивка:
- приёмник UART BL616 намертво зависает, если сменить скорость посреди приходящего байта (типичная ситуация: FPGA уже шлёт данные, а терминал открывается на другой скорости); сброс бита EN, как делает SDK, не помогает — прошивка делает полный программный сброс блока UART1 при каждой реальной смене параметров и держит сторожевой таймер;
usbser.sysпишет порциями, кратными 512 байтам, без завершающего нулевого пакета — приём ведётся строго по одному пакету;- нулевой пакет (ZLP) на IN, запрошенный пока прошлый пакет ещё в FIFO, теряется — передачи к ПК всегда заканчиваются коротким пакетом.
Установка (один раз)
- Закройте Gowin Programmer / BouffaloLabDevCube, если они открыты.
- Отключите USB-C (JTAG/UART) от платы.
- Замкните тестовые точки TDO и 3V3 (нижняя сторона Dock, левый верхний угол), подключите USB, разомкните. Появится устройство «Bouffalo CDC DEMO» (COM-порт).
- Прошейте мост одним из способов:
- TangProgrammer из релиза: вкладка «Прошивка моста (BL616)» → «Записать прошивку моста»;
- из исходников (нужны
scripts\setup.ps1иscripts\build.ps1):(пишет загрузчик Sipeed из.\scripts\flash.ps1bin\и собранную прошивку мостаbuild\build_out\tang25k_debugger_bl616.bin); - вручную, BouffaloLabDevCube или BLFlashCommand: файлы из релиза,
bl616_bootloader_0x20000_nano20k_signed.binпо адресу0x0иtang25k_debugger_bl616.binпо адресу0x20000.
- Переподключите USB. Появятся «DirtyJTAG» и новый COM-порт.
Перед первой прошивкой стоит сохранить полный дамп флеш-памяти BL616 (плата в загрузчике, как в шаге 3):
.\third_party\bouffalo_sdk\tools\bflb_tools\bouffalo_flash_cube\BLFlashCommand.exe --interface=uart --baudrate=2000000 --port=COMxx --chipname=bl616 --cpu_id= --flash --read --start=0x0 --len=0x400000 --file=backup\flash_full_4M.bin
Папка backup\ в git не попадает.
Обновление прошивки
.\scripts\build.ps1
.\scripts\flash.ps1
flash.ps1 сам переводит работающую прошивку в загрузчик (открывает её
COM-порт на «магической» скорости 1234 бод) и прошивает. После записи
переподключите USB — флаг «загрузиться в ISP» живёт до снятия питания.
Другие способы попасть в загрузчик: держать S3 при подключении USB (если эта прошивка уже стоит) или перемычка TDO→3V3 (работает всегда).
Возврат штатной прошивки Sipeed
.\scripts\flash.ps1 -Restore
(или в TangProgrammer: «Вернуть штатную прошивку Sipeed»). Пишет bin/bl616_fpga_partner_25kDock.bin (версия 2025030317, sha256
1be5c1f9…aacd) — ровно то, что стояло на плате.
Программатор с окном: TangProgrammer.exe
Замена Gowin Programmer поверх openFPGALoader, без консоли. Готовая программа —
архив TangProgrammer-…-win64.zip из релиза; в клоне репозитория её собирает
.\scripts\build_gui.ps1 (появляется TangProgrammer.exe в корне, рядом с
tools\). Ничего ставить не нужно (.NET Framework 4 есть в Windows). Вверху окна — состояние моста
(подключён / загрузчик BL616 / штатная прошивка / нет платы), оно
обновляется само при подключении USB.
Вкладка «FPGA»
- битстрим
.fsвыбирается кнопкой «Обзор…» (Ctrl+O), из списка последних или перетаскиванием в окно; под полем — модель FPGA из файла, размер и время сборки (предупреждение, если файл собран не для GW5A-25); - «Загрузить в SRAM» (F5) — до отключения питания; «Записать во Flash» — во внешнюю флеш-память FPGA, с проверкой;
- «Загружать в SRAM автоматически, когда файл пересобран» — для работы вместе с
Gowin IDE: после каждой сборки новый
.fsсразу попадает в FPGA; - «Определить FPGA», «Перезапуск из Flash» (FPGA заново грузится из своей флеш-памяти, как после включения питания).
Вкладка «Флеш-память FPGA» — определение микросхемы (на этой плате XTX,
JEDEC 0B4017, 8 МБ), резервная копия в .bin (первый 1 МБ с конфигурацией
или вся микросхема; по умолчанию читается дважды и сравнивается), запись
.bin/.fs во флеш (пустой хвост 0xFF не пишется) и стирание всей микросхемы.
Время на этой плате: запись .fs с проверкой ≈ 8 с, копия 1 МБ ≈ 3 с на одно
чтение, стирание ≈ 13 с.
Вкладка «Прошивка моста (BL616)» — то же, что scripts\flash.ps1: записать
прошивку моста или вернуть штатную Sipeed.
Справа вверху — тема: как в Windows, светлая или тёмная. Настройки хранятся в
%LOCALAPPDATA%\Tang25kProgrammer\settings.ini. Пересборка программы:
.\scripts\build_gui.ps1 (исходники — в gui\).
Если запись во флеш-память FPGA прервалась с ошибкой, программа сама повторяет её один раз: недописанная флеш-память означает, что FPGA не загрузится при включении.
На другой компьютер — архив из релиза или свой:
.\scripts\make_portable.ps1 собирает dist\TangProgrammer\ и
dist\TangProgrammer.zip (≈ 14 МБ) — программа, openFPGALoader, BLFlashCommand
(только exe и chips\ вместо 238 МБ папки SDK), прошивки моста и памятка
README.txt. Распаковать в любую папку, куда можно писать (не в Program Files),
и запустить TangProgrammer.exe. Нужна Windows 10/11 x64; драйверы для платы
Windows ставит сама.
Использование из консоли
JTAG — нужен openFPGALoader ≥ 1.1.0 (в 1.1.0 исправлена работа DirtyJTAG
с GW5A). Готовая сборка для Windows лежит в tools\openFPGALoader\bin.
$ofl = ".\tools\openFPGALoader\bin\openFPGALoader.exe"
& $ofl -c dirtyJtag --detect # GW5A-25, idcode 0x0001281b
& $ofl -c dirtyJtag design.fs # загрузить битстрим в SRAM (до отключения питания)
& $ofl -c dirtyJtag --freq 15M design.fs # загрузить в SRAM быстрее
& $ofl -c dirtyJtag -f design.fs # прошить битстрим во внешнюю флеш-память FPGA (навсегда)
& $ofl -c dirtyJtag --dump-flash --file-size 1048576 copy.bin # копия первого 1 МБ флеш-памяти FPGA
& $ofl -c dirtyJtag -f copy.bin # записать образ обратно (с адреса 0)
& $ofl -c dirtyJtag --bulk-erase # стереть всю флеш-память FPGA
--unprotect-flash с этой микросхемой флеш-памяти не использовать: её нет в
справочнике openFPGALoader 1.1.1, и эта функция на ней падает. Защита записи
(биты BP) на плате и так снята.
UART — любой терминал или pyserial на появившемся COM-порту, скорость и формат задаются как обычно. При открытии порта (DTR=1) накопленные за время простоя данные сбрасываются, как у FTDI.
Gowin Programmer эта прошивка не поддерживает (он работает только с FTDI).
Для него — flash.ps1 -Restore.
Сборка из исходников
.\scripts\setup.ps1 # Bouffalo SDK v2.3.16 + тулчейн T-Head в third_party\
.\scripts\build.ps1 # build\build_out\tang25k_debugger_bl616.bin
Если проект лежит на сетевом диске, который смотрит на эту же машину
(например D: → \\PC\Projects), скрипты сами собирают по локальному пути
— через SMB сборка в десятки раз медленнее.
Тесты
fpga_test\ — два тестовых проекта Gowin (готовые .fs есть в релизе):
loopback—uart_tx = uart_rx, петля на любой скорости;stream— FPGA сама шлёт счётчик на ровно 10 Мбод.
Сборка — из папки проекта, например:
cd fpga_test\loopback; & C:\Gowin\Gowin_V1.9.12_x64\IDE\bin\gw_sh.exe build.tcl; cd ..\..
& $ofl -c dirtyJtag fpga_test\loopback\impl\pnr\loopback.fs
python tests\uart_loopback_test.py --port COM14
& $ofl -c dirtyJtag fpga_test\stream\impl\pnr\stream.fs
python tests\uart_stream_test.py --port COM14 --seconds 30 --switches 10
Выпуск релиза
- Поднять
FW_VERSION_STRвsrc/sys.hи описать изменения вCHANGELOG.md. - Собрать прошивку и тестовые битстримы, затем файлы релиза:
.\scripts\build.ps1 .\scripts\make_release.ps1 # dist\release\v<версия>\ + SHA256SUMS.txt - Закоммитить, поставить тег и отправить:
git tag -a v1.0.0 -m "v1.0.0" git push origin main v1.0.0 - Опубликовать релиз с файлами — нужен токен Gitea с правом
write:repository(Настройки → Приложения → Создать токен):Или вручную: «Релизы» → «Новый релиз» → тег, текст из$env:GITEA_TOKEN = "<токен>" .\scripts\publish_release.ps1CHANGELOG.md, файлы изdist\release\v<версия>\.
Ограничения
- Gowin Programmer не работает (только openFPGALoader).
- Чётность mark/space не поддерживается аппаратно (передаётся как «нет»).
- DTR/RTS и BREAK не выведены на FPGA — на плате нет таких линий.
- Нулевой пакет на JTAG-IN не отправляется: клиенты DirtyJTAG читают ответ известной длины.
Структура
src/ прошивка (main, JTAG, UART-мост, USB-дескрипторы, плата)
gui/ исходники TangProgrammer.exe (C# WinForms, .NET Framework 4)
bin/ загрузчик Sipeed и штатная прошивка для отката
scripts/ setup / build / flash / build_gui / make_portable / make_release / publish_release
fpga_test/ тестовые проекты Gowin (loopback, stream)
tests/ тесты UART на Python (pyserial)
tools/ openFPGALoader 1.1.1 для Windows
Не в git (создаются скриптами):
third_party/ Bouffalo SDK и тулчейн (setup.ps1)
build/ сборка прошивки моста: build\build_out\tang25k_debugger_bl616.bin (build.ps1)
dist/ переносная версия программы и файлы релиза (make_portable.ps1, make_release.ps1)
backup/ дампы флеш-памяти своей платы
Диагностика: vendor-запрос 0x42 к устройству (bmRequestType=0xC0)
возвращает версию, частоту JTAG, скорость UART и счётчики байт.