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

285 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Прошивка отладчика 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 и счётчики байт.