Gromov_IA 928b3c5359 Релиз из пяти файлов: веб-форма Gitea больше не принимает
- 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: новый состав релиза.
2026-10-02 15:17:58 +03:00

Прошивка отладчика 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, теряется — передачи к ПК всегда заканчиваются коротким пакетом.

Установка (один раз)

  1. Закройте Gowin Programmer / BouffaloLabDevCube, если они открыты.
  2. Отключите USB-C (JTAG/UART) от платы.
  3. Замкните тестовые точки TDO и 3V3 (нижняя сторона Dock, левый верхний угол), подключите USB, разомкните. Появится устройство «Bouffalo CDC DEMO» (COM-порт).
  4. Прошейте мост одним из способов:
    • TangProgrammer из релиза: вкладка «Прошивка моста (BL616)» → «Записать прошивку моста»;
    • из исходников (нужны scripts\setup.ps1 и scripts\build.ps1):
      .\scripts\flash.ps1
      
      (пишет загрузчик Sipeed из bin\ и собранную прошивку моста 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 архива).
  5. Переподключите 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

Выпуск релиза

  1. Поднять FW_VERSION_STR в src/sys.h и описать изменения в CHANGELOG.md.
  2. Собрать прошивку и тестовые битстримы, затем файлы релиза:
    .\scripts\build.ps1
    .\scripts\make_release.ps1     # dist\release\v<версия>\ + SHA256SUMS.txt
    
  3. Закоммитить, поставить тег и отправить:
    git tag -a v1.0.0 -m "v1.0.0"
    git push origin main v1.0.0
    
  4. Опубликовать релиз с файлами — нужен токен Gitea с правом write:repository (Настройки → Приложения → Создать токен):
    $env:GITEA_TOKEN = "<токен>"
    .\scripts\publish_release.ps1
    
    Или вручную: «Релизы» → «Новый релиз» → тег, текст из CHANGELOG.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 и счётчики байт.

S
Description
Замена штатной прошивки встроенного отладчика (BL616) на плате Sipeed Tang Primer 25K Dock. Вместо эмуляции FT2232 плата становится составным USB-устройством из двух независимых функций JTAG и UART
Readme
3.3 MiB
2026-10-02 14:59:10 +03:00
Languages
C# 60%
C 27.4%
PowerShell 8.8%
Python 2.3%
Verilog 0.7%
Other 0.7%