# Прошивка отладчика 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\`) | | `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`): ```powershell .\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): ```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`, файлы из `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 и счётчики байт.