2026-10-02 14:59:10 +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` |
Оба работают одновременно: можно грузить битстрим, не закрывая терминал.
## Скачать
Готовые файлы — в [релизах ](http://gitea.vector.ru/Gromov_IA/BL616-firmware/releases ):
| Файл | Что это |
|---|---|
| `TangProgrammer-<версия>-win64.zip` | **программатор с окном** — распаковать и запустить, внутри всё нужное (openFPGALoader, BLFlashCommand, прошивки моста) |
| `TangProgrammer.exe` | только программа — для клона этого репозитория (рядом должна быть папка `tools\` ) |
2026-10-02 15:17:58 +03:00
| `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 и памятка |
2026-10-02 14:59:10 +03:00
| `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` ):
```powershell
.\scripts\flash.ps1
` ``
*(пишет загрузчик Sipeed из ` bin\` и собранную прошивку моста
`build\build_out\tang25k_debugger_bl616.bin` )*;
2026-10-02 15:17:58 +03:00
* вручную, BouffaloLabDevCube или BLFlashCommand: архив
`bl616_bridge_firmware-…zip` из релиза,
2026-10-02 14:59:10 +03:00
`bl616_bootloader_0x20000_nano20k_signed.bin` по адресу `0x0` и
2026-10-02 15:17:58 +03:00
`tang25k_debugger_bl616.bin` по адресу `0x20000` (команда — в `README.txt`
архива).
2026-10-02 14:59:10 +03:00
5. Переподключите USB. Появятся «DirtyJTAG» и новый COM-порт.
Перед первой прошивкой стоит сохранить полный дамп флеш-памяти BL616
(плата в загрузчике, как в шаге 3):
```powershell
.\ 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 не попадает.
## Обновление прошивки
```powershell
.\ scripts \ build . ps1
.\ scripts \ flash . ps1
```
`flash.ps1` сам переводит работающую прошивку в загрузчик (открывает её
COM-порт на «магической» скорости **1234 бод** ) и прошивает. После записи
**переподключите USB** — флаг «загрузиться в ISP» живёт до снятия питания.
Другие способы попасть в загрузчик: держать **S3** при подключении USB
(если эта прошивка уже стоит) или перемычка TDO→3V3 (работает всегда).
## Возврат штатной прошивки Sipeed
```powershell
.\ 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` .
```powershell
$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` .
## Сборка из исходников
```powershell
.\ 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 Мбод.
Сборка — из папки проекта, например:
```powershell
cd fpga_test \ loopback ; & C: \ Gowin \ Gowin_V1 . 9 . 12_x64 \ IDE \ bin \ gw_sh . exe build . tcl ; cd ..\..
```
```powershell
& $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. Собрать прошивку и тестовые битстримы, затем файлы релиза:
```powershell
.\scripts\build.ps1
.\scripts\make_release.ps1 # dist\release\v<версия>\ + SHA256SUMS.txt
` ``
3. Закоммитить, поставить тег и отправить:
` ``powershell
git tag -a v1.0.0 -m "v1.0.0"
git push origin main v1.0.0
` ``
4. Опубликовать релиз с файлами — нужен токен Gitea с правом
` write:repository` (Настройки → Приложения → Создать токен):
` ``powershell
$env:GITEA_TOKEN = "<токен>"
.\scripts\publish_release.ps1
` ``
Или вручную: «Релизы» → «Новый релиз» → тег, текст из ` CHANGELOG.md`,
2026-10-02 15:17:58 +03:00
файлы из ` dist\release\v<версия>\`. Веб-форма Gitea на этом сервере
принимает не больше 5 файлов — поэтому релиз и собирается ровно из пяти.
2026-10-02 14:59:10 +03:00
## Ограничения
* 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 и счётчики байт.