- 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.
285 lines
18 KiB
Markdown
285 lines
18 KiB
Markdown
# Прошивка отладчика 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 и счётчики байт.
|