- make_release.ps1: образы BL616 (прошивка моста, загрузчик и штатная прошивка Sipeed) и настройки BLFlashCommand с путями к соседним файлам собираются в один архив bl616_bridge_firmware-v<версия>.zip с памяткой bin/release_readme.txt; - make_portable.ps1, make_release.ps1: zip через ZipFile с '/' в путях — Compress-Archive из PowerShell 5.1 пишет '\', и распаковщики кроме Проводника считают его частью имени файла; - make_portable.ps1: без файлов, которые BLFlashCommand оставляет в chips\ после прошивки (img_create\, eflash_loader_cfg.ini); - README, CHANGELOG: новый состав релиза.
Прошивка отладчика 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\) |
bl616_bridge_firmware-<версия>.zip |
образы BL616 для ручной прошивки: прошивка моста tang25k_debugger_bl616.bin (адрес 0x20000), загрузчик Sipeed bl616_bootloader_0x20000_nano20k_signed.bin (0x0), штатная прошивка Sipeed bl616_fpga_partner_25kDock.bin (0x0, для отката), настройки BLFlashCommand и памятка |
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_bridge_firmware-…zipиз релиза,bl616_bootloader_0x20000_nano20k_signed.binпо адресу0x0иtang25k_debugger_bl616.binпо адресу0x20000(команда — вREADME.txtархива).
- Переподключите 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<версия>\. Веб-форма Gitea на этом сервере принимает не больше 5 файлов — поэтому релиз и собирается ровно из пяти.
Ограничения
- 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 и счётчики байт.