Files
BL616-firmware/README.md
T
Gromov_IA 8bc1583805 Прошивка моста BL616 для Tang Primer 25K и программатор TangProgrammer
- 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.
2026-10-02 14:59:10 +03:00

18 KiB
Raw Permalink Blame History

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

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

  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_bootloader_0x20000_nano20k_signed.bin по адресу 0x0 и tang25k_debugger_bl616.bin по адресу 0x20000.
  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<версия>\.

Ограничения

  • 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 и счётчики байт.